/* * Poem Reader AMX Mod Plugin * [inc] Joe Dalton * 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 #include /* 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, " - '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("") }