- /*
- * Poem Reader AMX Mod Plugin
- * [inc] Joe Dalton <joe-dalton@fahr-zur-hoelle.org>
- * Created 21.09.2003
- *
- * Reads lines from a file and partitions them into poems.
- * One or more empty lines denote a new poem.
- * Lines starting with a semicolon are comments.
- * After waiting INITIAL_INTERVAL seconds, begins to print the poems using server say.
- * It then prints a line, waits for 'poem_line_interval' seconds, prints the next line
- * and so on, until the poem ends, then waits for 'poem_interval' seconds and prints
- * the next poem. After printing the last poem it starts over with the first one.
- *
- * Use the console command 'poem' to control the Poem Reader. 'poem help' displays
- * a list of available commands.
- */
- #include <amxmodx>
- #include <amxmisc>
- /* adjust these to your needs ************************************************/
- // maximum number of poems
- #define MAX_POEMS 128
- // maximum number of total poem lines
- #define MAX_LINES 256
- // maximum no. of characters per line
- #define MAX_LINE_LEN 128
- // task id
- #define TASK_ID 1234032
- // seconds after map start in which the first task begins
- #define INITIAL_INTERVAL 30
- // default interval between poems
- stock const DEFAULT_INTERVAL[] = "900"
- // default interval between lines of one poem
- stock const DEFAULT_LINE_INTERVAL[] = "1"
- // poems file name, $basedir is a placeholder for amx dir (default addons/amx)
- stock const POEMS_FILE[] = "poems.ini"
- // poem console command permission
- stock const ADMIN_POEM = ADMIN_RCON
- /* never change these! *******************************************************/
- stock const POEM_NAME[] = "Poem Reader"
- stock const POEM_VERSION[] = "1.2b"
- stock const POEM_AUTHOR[] = "[inc] Joe Dalton"
- stock const CVAR_VERSION[] = "poem_version"
- stock const CVAR_INTERVAL[] = "poem_interval"
- stock const CVAR_LINE_INTERVAL[] = "poem_line_interval"
- stock const LOCALINFO_CURRENT_POEM[] = "poem_current"
- stock const LOCALINFO_TASK_TIME[] = "poem_task_time"
- stock const CONCMD_POEM[] = "poem"
- stock const POEMCMD_HELP[] = "help"
- stock const POEMCMD_STATUS[] = "status"
- stock const POEMCMD_VERSION[] = "version"
- stock const POEMCMD_RESET[] = "reset"
- stock const POEMCMD_RELOAD[] = "reload"
- stock const POEMCMD_PAUSE[] = "pause"
- stock const POEMCMD_RESUME[] = "resume"
- // file containing the actual poems
- static poems_file[64]
- // poem lines
- static poems[MAX_LINES][MAX_LINE_LEN]
- // no. of lines per poem
- static poem_lengths[MAX_POEMS]
- // no. of poems
- static num_poems
- // no. of lines total
- static num_lines
- // current poem
- static current_poem
- // first line of the current poem
- static current_poem_line
- // next line read
- static current_line
- // time of the next line in seconds since 1970/01/01 00:00:00
- static task_time
- // paused or not?
- static bool:paused
- public plugin_init() {
- register_plugin(POEM_NAME, POEM_VERSION, POEM_AUTHOR)
- register_cvar(CVAR_INTERVAL, DEFAULT_INTERVAL)
- register_cvar(CVAR_LINE_INTERVAL, DEFAULT_LINE_INTERVAL)
- register_cvar(CVAR_VERSION, POEM_VERSION, FCVAR_SERVER)
- register_concmd(CONCMD_POEM,"cmd_poem",ADMIN_POEM, "<command> - 'poem help' displays a list of available commands");
- //build_path( poems_file , 63 , POEMS_FILE )
- get_configsdir( poems_file, 63 )
- format( poems_file, 63, "%s/%s", poems_file, POEMS_FILE )
- load_poems()
- restore_status()
- start_reading()
- return PLUGIN_CONTINUE
- }
- public plugin_end() {
- save_status()
- return PLUGIN_CONTINUE
- }
- /*
- * Reads a poem line, calculates the next line and sets a task to read it.
- * Called by the registered tasks, see set_poem_task().
- */
- public read_poem() {
- new interval = 1
- if(!paused) {
- if(is_developer()) { // debug
- server_print("Poem %d, line %d = %s", current_poem, current_line, poems[current_line])
- server_print("Poem starts on line %d", current_poem_line)
- }
- print_poem_line()
- new next_poem_line = current_poem_line + poem_lengths[current_poem]
- if(is_developer()) // debug
- server_print("Next poem starts on line %d", next_poem_line)
- if(current_line >= next_poem_line) { // it's the beginning of the next poem
- current_poem++
- current_poem_line = current_line
- interval = get_cvar_num(CVAR_INTERVAL)
- if(current_poem >= num_poems) { // start over
- reset()
- next_poem_line = poem_lengths[0]
- }
- }
- else
- interval = get_cvar_num(CVAR_LINE_INTERVAL)
- if(is_developer()) // debug
- server_print("Next poem line %d in %d seconds^n", current_line, interval)
- }
- //set task for next line
- set_poem_task(interval)
- return PLUGIN_CONTINUE
- }
- /*
- * Handler for poem console command. Called by AMXMod.
- * id player id
- * level player acces level
- * cid command id
- */
- public cmd_poem(const id, const level, const cid) {
- if (cmd_access(id, level, cid, 0)) {
- new cmd[32]
- read_argv(1, cmd, 31)
- if(is_developer())
- server_print("%s %s", CONCMD_POEM, cmd)
- if(strlen(cmd) == 0 || equali(POEMCMD_HELP, cmd)) {
- console_print(id, "%s commands:", POEM_NAME)
- print_cmd_help(id, POEMCMD_HELP, "this message")
- print_cmd_help(id, POEMCMD_STATUS, "display status information")
- print_cmd_help(id, POEMCMD_RESET, "continue with the first line of the first poem")
- print_cmd_help(id, POEMCMD_RELOAD, "reload the poems file (also resets)")
- print_cmd_help(id, POEMCMD_PAUSE, "pause reading")
- print_cmd_help(id, POEMCMD_RESUME, "resume reading")
- print_cmd_help(id, POEMCMD_VERSION, "display Poem Reader version")
- }
- else if (equali(POEMCMD_STATUS, cmd)) {
- if(paused)
- console_print(id, "%s is paused", POEM_NAME)
- else {
- new time_formatted[20]
- format_time(time_formatted, 19, "%m/%d/%Y %H:%M:%S", task_time)
- new interval = task_time - get_systime()
- console_print(id, "Reading %d poems with %d total lines", num_poems, num_lines)
- console_print(id, "Poem %d, next line %d in %ds (%s) = %s",
- current_poem, current_line, interval, time_formatted, poems[current_line])
- /*new interval = task_time - get_systime()
- console_print(id, "Poem %d, next line %d in %ds = %s",
- current_poem, current_line, interval, poems[current_line])*/
- }
- }
- else if (equali(POEMCMD_RESET, cmd)) {
- remove_task(TASK_ID);
- task_time = 0
- reset()
- start_reading()
- console_print(id, "%s reset", POEM_NAME)
- }
- else if (equali(POEMCMD_RELOAD, cmd)) {
- load_poems()
- console_print(id, "%s reloaded", POEM_NAME)
- }
- else if (equali(POEMCMD_PAUSE, cmd)) {
- paused = true
- console_print(id, "%s paused", POEM_NAME)
- }
- else if (equali(POEMCMD_RESUME, cmd)) {
- paused = false
- console_print(id, "%s resumed", POEM_NAME)
- }
- else if (equali(POEMCMD_VERSION, cmd)) {
- console_print(id, "%s Version %s (%s)", POEM_NAME, POEM_VERSION, POEM_AUTHOR)
- }
- else {
- console_print(id, "%s: Invalid command %s %s", POEM_NAME, CONCMD_POEM, cmd)
- }
- } // if
- return PLUGIN_HANDLED
- }
- /* private functions *********************************************************/
- /*
- * Log and start reading, see set_poem_task().
- */
- start_reading() {
- if(num_poems > 0) {
- log_message("[AMX] %s: Reading %d poems with %d total lines", POEM_NAME, num_poems, num_lines)
- if(!is_dedicated_server())
- server_print("%s: Reading %d poems with %d total lines", POEM_NAME, num_poems, num_lines)
- new systime = get_systime()
- new interval = INITIAL_INTERVAL
- if(task_time > systime) // restore scheduled task
- interval = task_time - systime
- set_poem_task(interval)
- }
- }
- /*
- * Print the current poem line.
- */
- print_poem_line() {
- if(is_dedicated_server())
- server_cmd("say %s", poems[current_line])
- else { // simulate server say, because on listenserver server say == loopback client say
- new hostname[64]
- get_cvar_string("hostname", hostname, 63)
- client_print(0, print_chat, "<%s> %s", hostname, poems[current_line])
- }
- current_line++
- }
- /*
- * Load the poems from the poems file.
- * Initializes num_poems, num_lines, poems[] and poem_lengths[]
- */
- load_poems() {
- if (!file_exists(poems_file))
- {
- log_message("[AMX] %s error: Poems file %s not found", POEM_NAME, poems_file)
- if(!is_dedicated_server())
- server_print("[AMX] %s error: Poems file %s not found", POEM_NAME, poems_file)
- return false
- }
- else {
- reset()
- new i=0, line[MAX_LINE_LEN], len, bool:newpoem = true
- num_lines = num_poems = 0
- while(read_file(poems_file, i, line, MAX_LINE_LEN-1, len)) {
- if(num_lines > MAX_LINES) {
- new msg[] = "[AMX] %s error: Too many poem lines, max. %d"
- log_message(msg, POEM_NAME, MAX_LINES)
- if(!is_dedicated_server())
- server_print(msg, POEM_NAME, MAX_LINES)
- break;
- }
- if(num_poems > MAX_POEMS) {
- new msg[] = "[AMX] %s error: Too many poems, max. %d"
- log_message(msg, POEM_NAME, MAX_POEMS)
- if(!is_dedicated_server())
- server_print(msg, POEM_NAME, MAX_POEMS)
- break;
- }
- if (strlen(line) > 0) {
- if(contain(line, ";") != 0) { // ignore comments
- if (newpoem)
- num_poems++;
- newpoem = false
- poems[num_lines++] = line
- poem_lengths[num_poems]++
- }
- }
- else if (!newpoem) { // one or more empty lines start a new poem
- newpoem = true
- }
- i++
- }
- }
- if(is_developer())
- dump_poems()
- return true
- }
- /*
- * Set the task to read the current poem line and save the time it will trigger.
- */
- set_poem_task(const interval) {
- set_task(float(interval),"read_poem", TASK_ID)
- task_time = get_systime() + interval
- }
- /*
- * Reset, so reading will continue on first line of first poem.
- */
- reset()
- current_poem = current_line = current_poem_line = 0
- /*
- * Store the current status as localinfo, so it can be restored after a mapchange.
- * Called by plugin_end().
- */
- save_status() {
- set_localinfo_num(LOCALINFO_CURRENT_POEM, current_poem)
- set_localinfo_num(LOCALINFO_TASK_TIME, task_time)
- if (is_developer())
- server_print("%s status saved: current_poem %d, task_time %d^n",
- POEM_NAME, current_poem, task_time)
- }
- /*
- * Restore task_time, current_poem, current_line and current_poem_line.
- * Called by plugin_init().
- */
- restore_status() {
- task_time = get_localinfo_num(LOCALINFO_TASK_TIME)
- /*if(get_systime() >= task_time) {
- if(task_time != 0)
- remove_task(TASK_ID)
- task_time = 0
- }*/
- current_poem = get_localinfo_num(LOCALINFO_CURRENT_POEM)
- current_line = 0
- for(new i = 0; i < current_poem; i++)
- current_line += poem_lengths[i]
- current_poem_line = current_line
- if(is_developer())
- server_print("%s status restored: current_poem %d, current_poem_line %d, current_line %d, task_time %d^n",
- POEM_NAME, current_poem, current_poem_line, current_line, task_time)
- }
- /*
- * Prints usage notes for a poem command to the client console.
- * Called by cmd_poem() on console command 'poem help'.
- */
- print_cmd_help(const id, const command[], const description[])
- console_print(id, "%11s: %s", command, description)
- /* utility functions *********************************************************/
- /* Convenience function. */
- stock get_localinfo_num(const name[]) {
- new temp[32]
- get_localinfo(name, temp, 31)
- if(strlen(temp) > 0)
- return str_to_num(temp)
- return 0
- }
- /* Convenience function. */
- stock set_localinfo_num(const name[], const value) {
- new temp[32]
- num_to_str(value, temp, 31)
- set_localinfo(name, temp)
- }
- /* Convenience function. */
- stock is_developer()
- return get_cvar_num("developer") != 0
- /*
- * For debugging.
- * Output the currently loaded poems and their lengths to the server console.
- */
- stock dump_poems() {
- for(new poem = 0; poem < num_poems; poem++) {
- server_print("Poem %d has %d lines", poem, poem_lengths[poem])
- }
- server_print("")
- for(new line = 0; line < num_lines; line++) {
- server_print("Poem line %d: %s", line, poems[line])
- }
- server_print("")
- }