Mercurial > traipse
diff plugins/xxinit2.py @ 0:4385a7d0efd1 grumpy-goblin
Deleted and repushed it with the 'grumpy-goblin' branch. I forgot a y
author | sirebral |
---|---|
date | Tue, 14 Jul 2009 16:41:58 -0500 |
parents | |
children | 5df1340bda13 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/xxinit2.py Tue Jul 14 16:41:58 2009 -0500 @@ -0,0 +1,2322 @@ +# Copyright (C) 2000-2001 The OpenRPG Project +# +# openrpg-dev@lists.sourceforge.net +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +############################################################################## + +from string import find, replace +import wx + +import os +import orpg.dirpath +import orpg.orpg_version +import orpg.plugindb +import orpg.pluginhandler +import hashlib +import random + +__version__ = "2.2.8" + +class v: + init_list = [] + +class Plugin(orpg.pluginhandler.PluginHandler): + # Initialization subroutine. + # + # !self : instance of self + # !openrpg : instance of the the base openrpg control + def __init__(self, plugindb, parent): + orpg.pluginhandler.PluginHandler.__init__(self, plugindb, parent) + + self.name = "Initiative Tool " + str(__version__) + self.author = "Woody, Darloth, updated by mDuo13, Veggiesama, magoo" + self.help = "Type /inittool2 to load a help node into your game tree. Check out\n" + self.help += "the readme, and double-click Commands & Help if you want to see examples." + + self.version = __version__ + self.orpg_min_version="1.7.0" + + + def plugin_enabled(self): + # Setup variables. + self.loaded = 0 # 1 = config has been loaded on startup + self.init_debug = 0 + v.init_list = [] # now an array of "Dict" (associative array): + # name : name of the effect of character + # type : 0 = character; 1 = effect + # init : init score + # duration : round remaining to the effect + # hidden : type 0 = shows up in public list only on init + # type 1 = does not print to public remaing rounds of effect + # pass : for SR4 + # rank : when multiple character at same init count, the plugin + # use the 'rank' to order them + # tag : unique tag assigned to each entry. + self.init_round = 1 + self.init_recording = 1 + self.init_title = "" + self.init_count = 0 + self.init_pass = 0 + self.init_listslot = 0 + self.init_listtag = "" + self.init_end = 0 + self.init_system = "D20" # D20 (default), SR4, RQ + self.sandglass_count = 0 # current count of the number of seconds of a character's turn + # Well, more or less true, it is a count of the number of time the function + # refresh_counter() has been called, which itself is supposed to be call each seconds. + self.sandglass_delay = 0 # 0 = off, anything else is the timer delay + self.sandglass_status = 0# 0 = running, 1 = pause + self.sandglass_skip_interval = 0 # after a number of interval, do a init_next(). 0 = disable + self.autosave_delay = 60 # 0 = off, else, will autosave every 'autosave' seconds - VEG 2.2.8 (set to 60) + self.autosave_count = 0 # current count of the number of seconds since last autosave + self.hide_id = 0 # 1 = do not show IDs to everyone; 0 = show IDs to everyone + self.hide_ondeck = 0 # 1 = do not show "on deck" message after every turn; 0 = show it + self.hide_justmovement = 0 # [SR4] 1 = do not show "just movement" messages + self.message_nowup = "NEXT UP FOR THE KILLING" # customizable "now up" message + self.msghand_timer = 0 # 0-60 = cycles the message handler to all players once every 60 seconds - VEG 2.2.6 + self.msghand_warning = 1 # 1 = manual override, removes the message warning if someone else in room has xxinit2 loaded - VEG 2.2.6 + self.reroll_type = 0 # 0 = reroll every round (normal), 1 = no reroll and keep last round inits - VEG 2.2.7 + self.ip_order = 0 # 0 = 1/2/3/4 (normal), 1 = 3/1/4/2 (Serbitar's house rule), 2 = 4/1/3/2 (TinkerGnome's house rule) - VEG 2.2.7 + + # Add commands + self.plugin_addcommand("/inittool2", self.CMD_inittool2, "Loads the help/example node into your game tree") + self.plugin_addcommand("/inittoggle", self.CMD_inittoggle, "Toggles initiative system (D20/SR4/RuneQuest") + self.plugin_addcommand("/initdebug", self.CMD_initdebug, "???") + self.plugin_addcommand("/initgui", self.CMD_initgui, "???") + #self.plugin_addcommand("/initsaveconfig", self.CMD_initsaveconfig, "Saves current configuration") #VEG 2.2.6 + #self.plugin_addcommand("/initloadconfig", self.CMD_initloadconfig, "Loads a previous configuration") #VEG 2.2.6 + self.plugin_addcommand("/initdefaultconfig", self.CMD_initdefaultconfig, "Loads the default configuration") + self.plugin_addcommand("/initshowconfig", self.CMD_initshowconfig, "Displays current configuration") + self.plugin_addcommand("/togglehideid", self.CMD_togglehideid, "Shows IDs in a public list") + self.plugin_addcommand("/togglehideondeck", self.CMD_togglehideondeck, "Shows 'On Deck' message after every turn") + self.plugin_addcommand("/togglehidejustmovement", self.CMD_togglehidejustmovement, "Shows 'Just Movement' messages in SR4") + self.plugin_addcommand("/init", self.CMD_init, "Toggles whether to record typed intiativies and textual initiative commands") + self.plugin_addcommand("/clear", self.CMD_clear, "Clears current initiative list") + self.plugin_addcommand("/start", self.CMD_start, "Clears current initiative list and prompts players to roll") + self.plugin_addcommand("/addfxhidden", self.CMD_addfxhidden, "Adds a hidden effect to the list") + self.plugin_addcommand("/addfx", self.CMD_addfx, "Adds an effect to the list") + self.plugin_addcommand("/addhidden", self.CMD_addhidden, "Adds a hidden character to the list") + self.plugin_addcommand("/add", self.CMD_add, "Adds a character to the list") + self.plugin_addcommand("/del", self.CMD_del, "Deletes a character/effect from the list") + self.plugin_addcommand("/changepass", self.CMD_changepass, "Changes current initiative pass [SR4-only]") + self.plugin_addcommand("/changedur", self.CMD_changedur, "Changes duration of specific effect") + #self.plugin_addcommand("/changefx", self.CMD_changefx, "Changes the initiative count of a specific effect") + self.plugin_addcommand("/change", self.CMD_change, "Changes the initiative count of a specific character") + self.plugin_addcommand("/togglehidden", self.CMD_togglehidden, "Toggles whether to show hidden characters in initiative list or not") + self.plugin_addcommand("/initsetslot", self.CMD_initsetslot, "Sets the initiative turn to the designated list slot") + self.plugin_addcommand("/rankup", self.CMD_rankup, "Alters turn priority of one character/effect in the same initiative count as other characters/effects (higher)") + self.plugin_addcommand("/rankdown", self.CMD_rankdown, "Alters turn priority of one character/effect in the same initiative count as other characters/effects (lower)") + self.plugin_addcommand("/initdelaynow", self.CMD_initdelaynow, "???") + self.plugin_addcommand("/sandglass", self.CMD_sandglass, "Toggles sandglass functionality and sets duration of timer") + self.plugin_addcommand("/sandglasspause", self.CMD_sandglasspause, "Pauses the sandglass") + self.plugin_addcommand("/sandglassresume", self.CMD_sandglassresume, "Resumes the sandglass from pause") + self.plugin_addcommand("/sandglassforceskip", self.CMD_sandglassforceskip, "Forces the turn to skip after a number of sandglass duration intervals") + self.plugin_addcommand("/list", self.CMD_list, "Displays a list of characters, effects, and turn order to yourself") + self.plugin_addcommand("/publiclist", self.CMD_publiclist, "Displays a list of characters, effects, and turn order to the room") + self.plugin_addcommand("/rnd", self.CMD_rnd, "Displays the current round") + self.plugin_addcommand("/pass", self.CMD_pass, "Displays the current pass [SR4-only]") + self.plugin_addcommand("/go", self.CMD_go, "Advances the turn order to the next character/effect") + self.plugin_addcommand("/initsave", self.CMD_initsave, "Saves current list of initiatives") + self.plugin_addcommand("/initload", self.CMD_initload, "Loads previous list of initiatives") + self.plugin_addcommand("/initautosave", self.CMD_initautosave, "Toggles autosave") + self.plugin_addcommand("/initautoload", self.CMD_initautoload, "Loads previous autosave of initiative") + self.plugin_addcommand("/nowupmsg", self.CMD_nowupmsg, "Customize your own Now Up Message") + self.plugin_addcommand("/msghandwarning", self.CMD_msghandwarning, "Toggles the message handler warning when multiple xxinit2's are loaded in the room") #VEG 2.2.6 + self.plugin_addcommand("/toggleroundreroll", self.CMD_toggleroundreroll, "Toggles method of round-by-round initiative in SR4") #VEG 2.2.7 + self.plugin_addcommand("/toggleiporder", self.CMD_toggleiporder, "Toggles order of IP execution in SR4") #VEG 2.2.7 + + # Add message handlers + self.plugin_add_msg_handler("xxinit2_checkifloaded", self.received_checkifloaded) #VEG 2.2.6 + self.plugin_add_msg_handler("xxinit2_returnloaded", self.received_returnloaded) #VEG 2.2.6 + + self.init_load(0) #VEG 2.2.8 - auto-loads last autosave at startup (helps if you crash) + + def plugin_disabled(self): + self.plugin_removecmd("/inittool2") + self.plugin_removecmd("/inittoggle") + self.plugin_removecmd("/initdebug") + self.plugin_removecmd("/initgui") + #self.plugin_removecmd("/initsaveconfig") #VEG 2.2.6 + #self.plugin_removecmd("/initloadconfig") #VEG 2.2.6 + self.plugin_removecmd("/initdefaultconfig") + self.plugin_removecmd("/initshowconfig") + self.plugin_removecmd("/togglehideid") + self.plugin_removecmd("/togglehideondeck") + self.plugin_removecmd("/togglehidejustmovement") + self.plugin_removecmd("/init") + self.plugin_removecmd("/clear") + self.plugin_removecmd("/start") + self.plugin_removecmd("/addfxhidden") + self.plugin_removecmd("/addfx") + self.plugin_removecmd("/addhidden") + self.plugin_removecmd("/add") + self.plugin_removecmd("/del") + self.plugin_removecmd("/changepass") + self.plugin_removecmd("/changedur") + #self.plugin_removecmd("/changefx") + self.plugin_removecmd("/change") + self.plugin_removecmd("/togglehidden") + self.plugin_removecmd("/initsetslot") + self.plugin_removecmd("/rankup") + self.plugin_removecmd("/rankdown") + self.plugin_removecmd("/initdelaynow") + self.plugin_removecmd("/sandglass") + self.plugin_removecmd("/sandglasspause") + self.plugin_removecmd("/sandglassresume") + self.plugin_removecmd("/sandglassforceskip") + self.plugin_removecmd("/list") + self.plugin_removecmd("/publiclist") + self.plugin_removecmd("/rnd") + self.plugin_removecmd("/pass") + self.plugin_removecmd("/go") + self.plugin_removecmd("/initsave") + self.plugin_removecmd("/initload") + self.plugin_removecmd("/initautosave") + self.plugin_removecmd("/initautoload") + self.plugin_removecmd("/nowupmsg") + self.plugin_removecmd("/msghandwarning") + self.plugin_removecmd("/toggleroundreroll") + self.plugin_removecmd("/toggleiporder") + + self.plugin_delete_msg_handler("xxinit2_checkifloaded") #VEG 2.2.6 + self.plugin_delete_msg_handler("xxinit2_returnloaded") #VEG 2.2.6 + + self.loaded = 0 + + try: + self.frame.Destroy() + except: + pass + + # Just received a query from another player; returning a "yes, I have xxinit2 loaded" message + def received_checkifloaded(self, playerid, data, xml_dom): #VEG 2.2.6 + #print "receive_checkifloaded called: id=" + str(playerid) + "... data = " + str(data) + self.plugin_send_msg(playerid, "<xxinit2_returnloaded/>") + + # Just received the "yes, I have xxinit2 loaded" message; printing a warning message + def received_returnloaded(self, playerid, data, xml_dom): #VEG 2.2.6 + if self.msghand_warning: + self.post_syserror("Warning: xxinit2 plugin detected on " + + str(self.session.get_player_by_player_id(playerid)[0]) + "'s system. \ + Having multiple copies of the xxinit2 plugin in the same room is not \ + advisable, because it may cause problems. It is suggested that only \ + one person in the room (the GM) have the xxinit2 plugin loaded. Go to \ + Tools-Plugins and uncheck the Initiative Tool 2.x to unload it. Type \ + /msghandwarning to simply turn this warning reminder off.") + + def post_msg(self, text, myself): + #This is called whenever a message from anyone is about to be posted + #to chat; it doesn't affect the copy of the message that gets sent to others + #Be careful; system and info messages trigger this too. + if self.init_recording: + if text.lower().find("showinits") != -1: + self.inits_list(1) + return text + elif text.lower().find("nextinit") != -1: + self.init_next() + return text + # all collected, certain values only valid in following systems: + # d20: player, init, effect, duration + # sr4: player, init, passes + # VEG 2.2.7 - The lines that "won't work with macros" are unable to function properly because of the double-layers + # of <font> tags that accompany macro sends. The string parsing gets screwed up. It's probably fixable + # without changing the way macros are handled, but it's beyond my skill level. =( =( =( + if myself==1: + if text.find(" effect ") != -1: + effect=text[text.rfind("'>")+2:text.find("[")] + duration=text[text.rfind("effect ")+7:text.find("</font>")] + init=text[text.rfind("=> ")+3:text.rfind(" effect")] + elif text.find(" init") != -1: + player=text[:text.find("[")] + passes=text[text.find("init ")+5:text.find("</font>")] + init=text[text.rfind("(")+1:text.rfind(")")] + else: + if text.find(" effect ") != -1: + effect=text[text.find("</b>: ")+6:text.find("[")] + duration=text[text.find("effect ")+7:-7] + init=text[text.rfind("=> ")+3:text.rfind(" effect")] + elif text.find(" init") != -1: + player=text[text.find("</b>: ")+6:text.find("[")] + passes=text[text.find("init ")+5:-7] + init=text[text.rfind("(")+1:text.rfind(")")] + try: + if self.isD20() or self.isRQ(): + if text.find(" effect ") != -1: + init=int(init) + duration=int(duration) + self.init_add([init,duration,effect], 1, 0) + elif text.find(" init") != -1: + init=int(init) + self.init_add([init,player], 0, 0) + elif self.isSR4(): + if text.find(" init ") != -1: + init=int(init) + passes=int(passes) + self.init_add([init,passes,player], 0, 0) + except: + print("Detected some sort of initiative input... failed!") + + return text + + + def refresh_counter(self): + #This is called once per second. That's all you need to know. + # load system config once at startup + if not self.loaded: + self.loaded = 1 + self.config_load() + self.config_show() + self.check_version() + + # do sandglass stuff it has to do + if not self.isEnded(): + self.sandglass() + + # do the autosaving stuff if needed + self.autosave() + + # VEG 2.2.6 + self.msghand_timer += 1 + if self.msghand_timer >= 60: # cycle playerlist only 1x every 60 sec + self.msghand_timer = 0 + self.plugin_send_msg("all", "<xxinit2_checkifloaded/>") + + ############################################################### + #### Command Functions + ############################################################### + + def CMD_inittool2(self, cmdargs): + f = open(orpg.dirpath.dir_struct["plugins"]+ "inittool2.xml","r") + f2 = open(orpg.dirpath.dir_struct["plugins"]+ "inittool2_player.xml","r") + self.gametree.insert_xml(f.read()) + self.gametree.insert_xml(f2.read()) + f.close() + f2.close() + return 1 + + def CMD_inittoggle(self, cmdargs): + if self.isSR4(): + self.init_system = "RQ" + self.init_clear() + self.post_sysmsg("Now using <font color='#0000ff'><i>RuneQuest</font></i> system.", 1) + elif self.isD20(): + self.init_system = "SR4" + self.init_clear() + self.post_sysmsg("Now using <font color='#0000ff'><i>Shadowrun 4th</font></i> system.", 1) + elif self.isRQ(): + self.init_system = "D20" + self.init_clear() + self.post_sysmsg("Now using <font color='#0000ff'><i>d20</font></i> system.", 1) + self.config_save() # VEG 2.2.6 + + def CMD_initdebug(self, cmdargs): + cmdargs = cmdargs.split(None,-1) + if cmdargs[0] == "on": + self.init_debug = 1 + self.post_sysmsg("Init debugging <font color='#0000ff'><i>on</i></font>.",1) + elif cmdargs[0] == "off": + self.init_debug = 0 + self.post_sysmsg("Init debugging <font color='#0000ff'><i>off</i></font>.",1) + + #def CMD_initsaveconfig(self, cmdargs): + # self.config_save() + + #def CMD_initloadconfig(self, cmdargs): + # self.config_load() + + def CMD_initdefaultconfig(self, cmdargs): + self.config_default() + + def CMD_initshowconfig(self, cmdargs): + self.config_show() + + def CMD_togglehideid(self, cmdargs): + self.hide_id = not self.hide_id + self.post_sysmsg("Hide IDs: " + str(self.hide_id), 1) + self.config_save() # VEG 2.2.6 + + def CMD_togglehideondeck(self, cmdargs): + self.hide_ondeck = not self.hide_ondeck + self.post_sysmsg("Hide 'On Deck': " + str(self.hide_ondeck), 1) + self.config_save() # VEG 2.2.6 + + def CMD_togglehidejustmovement(self, cmdargs): + self.hide_justmovement = not self.hide_justmovement + self.post_sysmsg("Hide 'Just Movement' [SR4-only]: " + str(self.hide_justmovement), 1) + self.config_save() # VEG 2.2.6 + + def CMD_init(self, cmdargs): + if self.init_recording: + self.init_recording=0 + self.post_sysmsg("Init recording <font color='#0000ff'><i>off</i></font>.") + else: + self.init_recording=1 + self.post_sysmsg("Init recording <font color='#0000ff'><i>on</i></font>.") + self.config_save() # VEG 2.2.6 + + def CMD_clear(self, cmdargs): + self.init_clear() + self.post_sysmsg("Clearing Initiative List !", 1) + + def CMD_start(self, cmdargs): + self.init_clear() + self.post_my_msg("<hr><font color='#ff0000'><b>Starting Round</font> <font color='#0000ff'># <i>1</font> [" + self.init_system + "]</b>", 1) + self.post_my_msg("<font color='#0000ff'><b>Roll New Initiatives</b></font><hr>", 1) + + def CMD_addfxhidden(self, cmdargs): + cmdargs = cmdargs.split(None,2) + if self.isD20() or self.isRQ(): + self.init_add(cmdargs, 1, 1) + else: + self.post_syserror("Invalid input. Effects and durations do not work with " + str(self.init_system) + " system.") + + def CMD_addfx(self, cmdargs): + cmdargs = cmdargs.split(None,2) + if self.isD20() or self.isRQ(): + self.init_add(cmdargs, 1, 0) + else: + self.post_syserror("Invalid input. Effects and durations do not work with " + str(self.init_system) + " system.") + + def CMD_addhidden(self, cmdargs): + if self.isD20() or self.isRQ(): + cmdargs = cmdargs.split(None,1) + elif self.isSR4(): + cmdargs = cmdargs.split(None,2) + self.init_add(cmdargs, 0, 1) + + def CMD_add(self, cmdargs): + if self.isD20() or self.isRQ(): + cmdargs = cmdargs.split(None,1) + elif self.isSR4(): + cmdargs = cmdargs.split(None,2) + self.init_add(cmdargs, 0, 0) + + def CMD_del(self, cmdargs): + id = int(cmdargs) + self.init_delete(id-1, 1) # subtract 1 because public lists shows with +1 + + def CMD_changepass(self, cmdargs): + cmdargs = cmdargs.split(None,-1) + if self.isSR4(): + try: + id = int(cmdargs[0])-1 # subtract 1 because public lists shows with +1 + new_pass = int(cmdargs[1]) + if new_pass < 1 or new_pass > 4: + self.post_syserror("Invalid input [" + str(self.init_system) + "]. Passes must be greater than/equal to 1 and less than/equal to 4.") + else: + v.init_list[id]["passes"] = new_pass + self.post_sysmsg("<font color='#0000ff'><i>" + str(v.init_list[id]["name"]) + "</font></i>'s initiative \ + pass total has been changed to <font color='#0000ff'><i>" + str(new_pass) + "</font></i> passes !", 1) + except: + self.post_syserror("Invalid input [" + str(self.init_system) + "]. That command only works on passes. Correct command is /changepass init_# new_pass_#") + + else: + self.post_syserror("Invalid input. There are no initiative passes in the " + str(self.init_system) + " system. Try SR4 !") + + def CMD_changedur(self, cmdargs): + cmdargs = cmdargs.split(None,-1) + if self.isD20() or self.isRQ(): + try: + id = int(cmdargs[0])-1 # subtract 1 because public lists shows with +1 + new_duration = int(cmdargs[1]) + hidden = v.init_list[id]["hidden"] + + if self.init_debug == 1: + print "id : " + str(id) + print "new_dur : " + str(new_duration) + print "hidden : " + str(hidden) + + if new_duration == 0: + self.post_syserror("Invalid input [" + str(self.init_system) + "]. Set duration to '1' if you want the effect to end next time it comes up. \ + Otherwise, delete the effect with the /del command.", not hidden) + return + elif new_duration < 0: + self.post_syserror("Invalid input [" + str(self.init_system) + "]. New duration must be greater than or equal to 1.", not hidden) + return + + if self.isEffect(id): + v.init_list[id]["duration"] = new_duration + self.post_sysmsg("<font color='#0000ff'><i>" + str(v.init_list[id]["name"]) + "</font></i> has been changed \ + to last <font color='#0000ff'><i>" + str(new_duration) + "</font></i> round(s) !", not hidden) + else: + self.post_syserror("Invalid input [" + str(self.init_system) + "]. That command only works on effects. Correct command is /changedur init_# new_duration_#") + + except Exception, e: + #print str(e) + self.post_syserror("Invalid input [" + str(self.init_system) + "]. That command only works on effects. Correct command is /changedur init_# new_duration_#") + + else: + self.post_syserror("Invalid input. Effects and durations do not work with " + str(self.init_system) + ".") + + #def CMD_changefx(self, cmdargs): + # cmdargs = cmdargs.split(None,-1) + # if self.isD20() or self.isRQ(): + # self.init_change(cmdargs,1) + # else: + # self.post_syserror(">Invalid input. Effects and durations do not work with " + str(self.init_system) + ".") + + #def CMD_change(self, cmdargs): + # cmdargs = cmdargs.split(None,-1) + # self.init_change(cmdargs,0) + + def CMD_change(self, cmdargs): # VEG 2.2.7 + cmdargs = cmdargs.split(None,-1) + id = int(cmdargs[0])-1 + new_init = int(cmdargs[1]) + if self.isEffect(id): + if self.isD20() or self.isRQ(): + self.init_change(id, new_init, 1) + else: + self.post_syserror(">Invalid input. Effects and durations do not work with " + str(self.init_system) + ".") + else: + self.init_change(id, new_init, 0) + + def CMD_togglehidden(self, cmdargs): + id = int(cmdargs) - 1 + self.toggle_hidden(id) + + def CMD_initsetslot(self, cmdargs): + id = int(cmdargs) - 1 + self.init_set_slot(id) + + def CMD_rankup(self, cmdargs): + cmdargs = cmdargs.split(None,-1) + id = int(cmdargs[0]) - 1 + try: + cmdargs[1] + n = 0 - int(cmdargs[1]) + except: + # default num of steps to move + n = -1 + self.init_move(id, n) + + def CMD_rankdown(self, cmdargs): + cmdargs = cmdargs.split(None,-1) + id = int(cmdargs[0]) - 1 + try: + cmdargs[1] + n = int(cmdargs[1]) + except: + n = 1 + self.init_move(id, n) + + def CMD_initdelaynow(self, cmdargs): + id = int(cmdargs) - 1 + self.init_delay_now(id) + + def CMD_sandglass(self, cmdargs): + try: + delay = int(cmdargs) + self.set_sandglass(delay) + except: + self.post_syserror("Invalid input. /sandglass (#_of_secs)") + + def CMD_sandglasspause(self, cmdargs): + self.sandglass_pause() + self.post_sysmsg("<br><b>Sandglass paused</b>", 1) + + def CMD_sandglassresume(self, cmdargs): + self.sandglass_resume() + self.post_sysmsg("<br><b>Sandglass resumed</b>", 1) + + def CMD_sandglassforceskip(self, cmdargs): + try: + interval = int(cmdargs) + self.set_sandglass_force_skip(interval) + except Exception, e: + #self.post_my_msg(str(e)) + self.post_syserror("Invalid input. /sandglassforceskip (#_of_intervals)") + + def CMD_list(self, cmdargs): + self.inits_list(0) + + def CMD_publiclist(self, cmdargs): + self.inits_list(1) + + def CMD_rnd(self, cmdargs): + try: + new_round = int(cmdargs) + self.init_round = new_round + self.post_sysmsg("Round number has been changed. It is now Round # <font color='#ff0000'>" + str(new_round) + "</font>",1) + except: + self.post_sysmsg("It is currently Round # <font color='#ff0000'>" + str(self.init_round) + "</font>",1) + + def CMD_pass(self, cmdargs): + try: + new_pass = int(cmdargs) + if self.isSR4() and new_pass >= 1 and new_pass <= 4: + self.init_pass = new_pass + self.init_count = 0 + self.init_listslot = 0 + self.post_sysmsg("Initiative Pass has been changed. It is currently Pass # <font color='#ff0000'>" + str(self.init_pass) + "</font>",1) + elif not self.isSR4(): + self.post_syserror("Invalid input. Initiative system must be set to SR4 for passes to function.") + else: + self.post_syserror("Invalid input. Passes must be greater than/equal to 1 and less than/equal to 4.") + except: + if self.isSR4(): + self.post_sysmsg("It is currently Pass # <font color='#ff0000'>" + str(self.init_pass) + "</font>",1) + else: + self.post_syserror("Invalid input. Initiative system must be set to SR4 for passes to function.") + + def CMD_go(self, cmdargs): + self.init_next() + + def CMD_initsave(self, cmdargs): + cmdargs = cmdargs.split(None,1) + slot = int(cmdargs[0]) + try: + self.init_title = cmdargs[1] + except: + self.init_title = "untitled" + + if slot < 1 or slot > 5: + self.post_syserror("Invalid input. Slot # must be between 1 and 5.") + else: + self.init_save(slot, 1) + + def CMD_initload(self, cmdargs): + try: + slot = int(cmdargs) + except: + slot = 1 + + if slot < 1 or slot > 5: + self.post_syserror("Invalid input. Slot # must be between 1 and 5.") + else: + self.init_load(slot) + + def CMD_initautosave(self, cmdargs): + delay = int(cmdargs) + self.set_autosave(delay) + + def CMD_initautoload(self, cmdargs): + self.init_load(0) + + def CMD_nowupmsg(self, cmdargs): + self.message_nowup = str(cmdargs) + self.post_my_msg("<b>Now Up Message: </b>" + self.message_nowup) + self.config_save() # VEG 2.2.6 + + def CMD_msghandwarning(self, cmdargs): # VEG 2.2.6 + if self.msghand_warning: + self.msghand_warning=0 + self.post_sysmsg("Message handler warning <font color='#0000ff'><i>off</i></font>.") + else: + self.msghand_warning=1 + self.post_sysmsg("Message handler warning <font color='#0000ff'><i>on</i></font>.") + self.config_save() + + def CMD_toggleroundreroll(self, cmdargs): # VEG 2.2.7 + if self.reroll_type: + self.reroll_type=0 + self.post_sysmsg("Reroll toggle set to <font color='#0000ff'><i>Reroll Every Round (default)</i></font>.") + else: + self.reroll_type=1 + self.post_sysmsg("Reroll toggle set to <font color='#0000ff'><i>Keep Same Inits Every Round (house rule)</i></font>.") + self.config_save() + + def CMD_toggleiporder(self, cmdargs): # VEG 2.2.7 + if self.ip_order == 0: # changes IP order to 3/1/4/2 (Serbitar's house rule) + self.ip_order=1 + self.post_sysmsg("IP order set to <font color='#0000ff'><i>3/1/4/2 (Serbitar's)</i></font>.") + elif self.ip_order == 1: # changes IP order to 4/1/3/2 (TinkerGnome's house rule) + self.ip_order=2 + self.post_sysmsg("IP order set to <font color='#0000ff'><i>4/1/3/2 (TinkerGnome's)</i></font>.") + elif self.ip_order == 2: # changes IP order to 1/2/3/4 + self.ip_order=0 + self.post_sysmsg("IP order set to <font color='#0000ff'><i>1/2/3/4 (normal)</i></font>.") + self.config_save() + + ############################################################### + #### Base Functions + ############################################################### + + def init_clear(self): + v.init_list = [] + self.init_round = 1 + self.init_count = 0 + self.init_pass = 0 + self.init_listslot = 0 + self.init_listtag = "" + self.init_end = 0 + self.sandglass_count = 0 + self.sandglass_status = 0 + + + def init_add(self, text, effect, hidden): + if (effect==1) and (self.isD20() or self.isRQ()): #d20 effects + try: + if len(text) == 3: + h = {} + count = int(text[0]) + 1 # effects only decrement (and end) + # before the count in which they + # were added on, so add 1 + h["type"] = 1 # effect + h["init"] = count + h["name"] = "*" + str(text[2]) + h["duration"] = int(text[1]) + h["rank"] = self.get_next_rank(h["init"]) + h["hidden"] = hidden + h["tag"] = self.get_unique_tag(h["name"]) + + if hidden == 1: + duration_str = "?" + else: + duration_str = str(h["duration"]) + + v.init_list += [h] + + self.post_sysmsg("<i><font color='#0000ff'>" + h["name"] + "</font></i> effect added to list at init count <i><font color='#0000ff'>" + str(h["init"]) + "</font></i>, lasting <font color='#0000ff'><i>" + duration_str + "</i></font> round(s) !", 1) + self.init_sort() + except: + self.post_syserror("Invalid input [" + str(self.init_system) + "]. Correct command is: /addfx init_# duration_# description") + + elif self.isD20(): #d20 characters + try: + if len(text) == 2: + h = {} + h["type"] = 0 # character + h["init"] = int(text[0]) + h["name"] = str(text[1]) + h["rank"] = self.get_next_rank(h["init"]) + h["hidden"] = hidden + h["tag"] = self.get_unique_tag(h["name"]) + + v.init_list += [h] + + self.post_sysmsg("<font color='#0000ff'><i>" + h["name"] + "</font></i> added to list at init count <i><font color='#0000ff'>" + str(h["init"]) + "</font></i> !", not hidden) + self.init_sort() + except: + self.post_syserror("Invalid input [" + str(self.init_system) + "]. Correct command is: /add init_# description", not hidden) + + elif self.isSR4(): #SR4 characters + try: + if len(text) == 3: + h = {} + h["type"] = 0 # character + h["init"] = int(text[0]) + h["name"] = str(text[2]) + h["passes"] = int(text[1]) + h["rank"] = self.get_next_rank(h["init"]) + h["hidden"] = hidden + h["tag"] = self.get_unique_tag(h["name"]) + + v.init_list+=[h] + + self.post_sysmsg("<font color='#0000ff'><i>" + h["name"] + "</font></i> added to list at init count \ + <font color='#0000ff'><i>" + str(h["init"]) + "</font></i> with <font color='#0000ff'><i>" + str(h["passes"])+ "</font></i> \ + passes !", not hidden) + + self.init_sort() + + except: + self.post_syserror("Invalid input [" + str(self.init_system) + "]. Correct command is: /add init_# passes_# description", not hidden) + + elif self.isRQ(): #RQ characters + try: + if len(text) == 2: + h = {} + h["type"] = 0 # character + h["init"] = int(text[0]) + h["name"] = str(text[1]) + h["rank"] = self.get_next_rank(h["init"]) + h["hidden"] = hidden + h["tag"] = self.get_unique_tag(h["name"]) + + v.init_list += [h] + + self.post_sysmsg("<font color='#0000ff'><i>" + h["name"] + "</font></i> added to list at Strike Rank \ + <font color='#0000ff'><i>" + str(h["init"]) + "</font></i> !", not hidden) + + self.init_sort() + except: + self.post_syserror("Invalid input [" + str(self.init_system) + "]. Correct command is: /add SR description", not hidden) + + + def init_delete(self, id, public): + try: + name = v.init_list[id]["name"] + is_last = 0 + is_self = 0 + is_effect = 0 + if public == 1: + self.post_sysmsg("<font color='#0000ff'><i>" + name + "</font></i> has been removed from the initiative list !", not v.init_list[id]["hidden"]) + if self.isLast(id): + is_last = 1 + if self.init_listslot == id: + is_self = 1 + if self.isEffect(id): + is_effect = 1 + + del v.init_list[id] + + if is_effect: + self.init_listslot -= 1 + elif is_last and is_self: + self.init_next() + elif is_self == 1: + self.init_listslot -= 1 + self.init_next() + self.init_sort() + except: + if public == 1: + self.post_syserror("Invalid input [" + str(self.init_system) + "]. Correct command is: /del list_number") + + + def init_change(self, id, new_init, effect): + try: + proceed = 0 + old_name = v.init_list[id]["name"] + + if v.init_list[id]["init"] == new_init: + self.post_syserror("Invalid input [" + str(self.init_system) + "]. Already at init count <font color='#0000ff'>" + str(new_init) + "</font>. Try /rankup or /rankdown instead.") + return + + if effect == 1 and (self.isD20() or self.isRQ()): #d20 and RQ effects + if self.isEffect(id): + proceed = 1 + self.post_sysmsg("<font color='#0000ff'><i>" + old_name + "</font></i> has had its init count changed \ + to <font color='#0000ff'><i>" + str(new_init) + "</font></i>.", not v.init_list[id]["hidden"]) + else: + self.post_syserror("Invalid input [" + str(self.init_system) + "]. Not an effect. Try /change instead.") + + else: #d20, SR4, RQ characters + if self.isEffect(id): + self.post_syserror("Invalid input [" + str(self.init_system) + "]. Not a character. Try /changefx instead.") + else: + proceed = 1 + self.post_sysmsg("<font color='#0000ff'><i>" + old_name + "</font></i>'s init count has changed to \ + <font color='#0000ff'><i>" + str(new_init) + "</font></i>.", not v.init_list[id]["hidden"]) + if proceed==1: + + listslot_as_changed = 0 + # hacks if currently selected listslot /change's, we select the next tag + if not self.isEnded() and id == self.init_listslot: + if not self.isLast(id): + self.init_listtag = v.init_list[id + 1]["tag"] + listslot_as_changed = 1 + self.sandglass_reset() + else: + self.init_listtag = v.init_list[self.getLast()]["tag"] + self.init_next() + + v.init_list[id]["init"] = new_init + + # set the rank to the lowest rank available... + v.init_list[id]["rank"] = self.get_next_rank(v.init_list[id]["init"]) + + self.init_sort() + + # tell if listslot as changed + if listslot_as_changed == 1: + if self.init_count >= v.init_list[id]['init']: + self.init_listslot -= 1 + self.init_count = v.init_list[self.init_listslot]['init'] + else: + self.init_listslot -= 1 + self.init_next() + #self.post_now_up(self.init_listslot, self.message_nowup + ": ") + #self.init_next() + + except: + if effect == 1: + self.post_syserror("Invalid input [" + str(self.init_system) + "]. Correct command is: /changefx list_# new_init_# (example: /change 1 4)") + else: + self.post_syserror("Invalid input [" + str(self.init_system) + "]. Correct command \ + is: /change list_# new_init_# (example: /change 1 4)") + + + def init_sort(self): + if self.isD20(): + self.sort_high() + elif self.isSR4(): + self.sort_high() + elif self.isRQ(): + self.sort_low() + else: + self.sort_high() + + + def sort_low(self): + v.init_list.sort(self.sort_low_initlist) + # this part readjusts the listslot when other objects are + # changed, added, moved or deleted from v.init_list + #count = self.init_count + if self.isEnded(): + return + n = 0 + last_tag = self.init_listtag + last_id = self.init_listslot + found = 0 + + for m in v.init_list: + id = v.init_list.index(m) # first listslot's id + + if v.init_list[id]["tag"] == last_tag: + self.init_listslot = id + found = 1 + break + + # if can't find, it got /del'd + if found == 0 and self.init_listtag != "": + # next slot should've been bumped up, we re selecting it + try: + self.init_listtag = v.init_list[self.init_listslot]["tag"] + except: + #we del'd the last one... do nuttin + pass + + + def sort_high(self): + v.init_list.sort(self.sort_high_initlist) + v.init_list.reverse() + # this part readjusts the listslot when other objects are + # changed, added, moved or deleted from v.init_list + #count = self.init_count + + if self.isEnded(): + return + n = 0 + last_tag = self.init_listtag + last_id = self.init_listslot + found = 0 + for m in v.init_list: + id = v.init_list.index(m) # first listslot's id + #print "sid : " + str(id) + if v.init_list[id]["tag"] == last_tag: + self.init_listslot = id + found = 1 + break + # if can't find, it got /del'd + if found == 0 and self.init_listtag != "": + # next slot should've been bumped up, we re selecting it + try: + self.init_listtag = v.init_list[self.init_listslot]["tag"] + except: + #we del'd the last one... do nuttin + pass + + + def sort_low_initlist(self, x, y): + if x['init'] < y['init']: + return -1 + elif x['init'] > y['init']: + return 1 + elif x['init'] == y['init']: + # if same init, we sort by rank + if x['rank'] > y['rank']: + return -1 + elif x['rank'] < y['rank']: + return 1 + else: + return 0 + else: # shouldnt enter here + return 0 + + + def sort_high_initlist(self, x, y): + if x['init'] < y['init']: + return -1 + elif x['init'] > y['init']: + return 1 + elif x['init'] == y['init']: + # if same init, we sort by rank + if x['rank'] < y['rank']: + return -1 + elif x['rank'] > y['rank']: + return 1 + else: + return 0 + else: # shouldnt enter here + return 0 + + + def init_next(self): + if self.isD20(): + self.init_next_D20() + elif self.isSR4(): + self.init_next_SR4() + elif self.isRQ(): + self.init_next_RQ() + + + def init_next_D20(self): + + if self.isEnded(): + self.init_listslot = -1 # offsets +1 coming later, starts 0 + self.init_listtag = "" + self.init_end = 1 + + if not self.isEnded(): + try: + self.init_listslot += 1 #toldya + id = self.init_listslot + init = str(v.init_list[id]["init"]) + name = str(v.init_list[id]["name"]) + self.init_listtag = v.init_list[id]["tag"] + self.init_count = v.init_list[id]["init"] + + if self.isEffect(id): + v.init_list[id]["duration"] -= 1 #subtract 1 rnd from duration + if self.getRoundsLeftInEffect(id) == 0: + self.post_effect(id, "EFFECT ENDING:") + self.init_delete(id, 0) + + #nextslot = id #this effect got deleted, so id = former id+1 + + # hack if two consecutive effects and this one has ended + #if self.isEffect(nextslot): + # print "nextslot IS an effect" + # self.init_listslot -= 1 # zalarian + # id = self.init_listslot # zalarian + #else: + # print "nextslot IS NOT an effect" + # v.init_list[id]["hidden"] = 0 + # self.post_now_up(id, self.message_nowup + ": ") + + # reset the sandglass for this turn + self.sandglass_reset() + else: + if v.init_list[id]["hidden"] == 1: + rounds_left = "?" + else: + rounds_left = self.getRoundsLeftInEffect(id) + + if self.hide_id == 0: + str_id = str(id+1) + ":" + else: + str_id = "" + + self.post_effect(id, "EFFECT:") + + nextslot = id + 1 + + if self.isEffect(nextslot): + self.init_next_D20() + else: #normal character, not effect + v.init_list[id]["hidden"] = 0 + + self.post_now_up(id, self.message_nowup + ": ") + + # reset the sandglass for this turn + self.sandglass_reset() + + except Exception, e: + + self.init_end = 0 + self.init_round += 1 + self.init_count = 0 + self.post_sysmsg("<hr><font color='#ff0000'>End of Round<br>Starting Round <font color='#0000ff'><i># " + str(self.init_round) + "</font></i></font><hr>",1) + + + def init_next_SR4(self, do_not_advance_past_init=0): + if self.isEnded(): + self.init_listslot = -1 # offsets +1 coming later, starts 0 + self.init_listtag = "" + self.init_end = 1 + + if not self.isEnded(): + if self.init_pass == 0: + self.init_pass +=1 + if self.init_pass > 4: + self.init_end = 0 + self.init_round += 1 + self.init_pass = 0 + msg = "<hr><font color='#ff0000'>End of Round<br>Starting Round <font color='#0000ff'><i># " + str(self.init_round) + "</font></i></font><hr>" + + if self.reroll_type == 0: # Reroll Every Round (default) - VEG 2.2.7 + v.init_list = [] + msg += "<font color='#0000ff'>Roll New Initiatives</font><hr>" + else: # Keep Same Inits Every Round - VEG 2.2.7 + pass + self.post_sysmsg(msg,1) + + else: + try: + valid_char = 0 + just_movement = 0 + while valid_char != 1: + self.init_listslot += 1 #toldya + id = self.init_listslot + passes = v.init_list[id]["passes"] #exception raised here if noone left + + if self.ip_order == 0: # ip order: 1/2/3/4 (normal) - VEG 2.2.7 + if passes >= self.init_pass: + valid_char = 1 + elif self.hide_justmovement != 1: # not enough passes, but still gain movement + just_movement = 1 + valid_char = 1 + + else: # ip order: 3/1/4/2 (Serbitar's house rule) or 4/1/3/2 (TinkerGnome's house rule) - VEG 2.2.7 + if self.init_pass == 1: # first pass: only people with 3+ (S) or 4+ (TG) IPs go + if self.ip_order == 1 and passes >= 3: # ip order: 3/1/4/2 + valid_char = 1 + elif self.ip_order == 2 and passes >= 4: # ip order: 4/1/3/2 + valid_char = 1 + elif self.hide_justmovement != 1: + just_movement = 1 + valid_char = 1 + elif self.init_pass == 2: # second pass: only people with 1+ IPs go + if passes >= 1: + valid_char = 1 + elif self.hide_justmovement != 1: + just_movement = 1 + valid_char = 1 + elif self.init_pass == 3: # third pass: only people with 4+ (S) or 3+ (TG) IPs go + if self.ip_order == 1 and passes >= 4: # ip order: 4/1/4/2 + valid_char = 1 + elif self.ip_order == 2 and passes >= 3: # ip order: 3/1/3/2 + valid_char = 1 + elif self.hide_justmovement != 1: + just_movement = 1 + valid_char = 1 + elif self.init_pass == 4: # fourth pass: only people with 2+ IPs go + if passes >= 2: + valid_char = 1 + elif self.hide_justmovement != 1: + just_movement = 1 + valid_char = 1 + + init = str(v.init_list[id]["init"]) + name = str(v.init_list[id]["name"]) + self.init_listtag = v.init_list[id]["tag"] + self.init_count = v.init_list[id]["init"] + v.init_list[id]["hidden"] = 0 # no more hidden + + if just_movement == 0: + self.post_now_up(id, self.message_nowup + ": ") + else: + self.post_movement(id, " JUST MOVEMENT:") + + # reset the sandglass for this turn + self.sandglass_reset() + + if just_movement==1 and self.isMovement(id + 1) and do_not_advance_past_init==0: + self.init_next_SR4() # for convenience sake, characters who only have movement + # will be grouped together. + # do_not_advance_past_init is a hackfix to avoid some + # problems found with this trick + elif self.sharesInit(id + 1): # rules say characters who share an init take + self.init_next_SR4(1) # actions simultaneously (for the most part) + + except: + old_pass = self.init_pass + self.init_pass += 1 + self.init_count = 0 + self.init_end = 0 + if self.init_pass != 5: + self.post_sysmsg("<hr><font color='#ff0000'>End of Pass <font color='#0000ff'><i>#"\ + + str(old_pass) + "</font></i><br>Starting New Pass <font color='#0000ff'><i># " \ + + str(self.init_pass) + "</font></i></font><hr>", 1) + else: + self.init_next_SR4() + + + def init_next_RQ(self): + if self.isEnded(): + self.init_listslot = -1 # offsets +1 coming later, starts 0 + self.init_listtag = "" + self.init_end = 1 + + if not self.isEnded(): + try: + self.init_listslot += 1 #toldya + id = self.init_listslot + init = str(v.init_list[id]["init"]) + name = str(v.init_list[id]["name"]) + self.init_listtag = v.init_list[id]["tag"] + self.init_count = v.init_list[id]["init"] + + if self.isEffect(id): + v.init_list[id]["duration"] -= 1 #subtract 1 rnd from duration + if self.getRoundsLeftInEffect(id) == 0: + self.post_effect(id, "EFFECT ENDING:") + self.init_delete(id, 0) + + # hack if two consecutive effects and this one has ended + #if self.isEffect(nextslot): + # self.init_listslot -= 1 # zalarian + # id = self.init_listslot # zalarian + #else: + # v.init_list[id]["hidden"] = 0 + + # self.post_now_up(id, self.message_nowup + ": ") + + # reset the sandglass for this turn + self.sandglass_reset() + else: + if v.init_list[id]["hidden"] == 1: + rounds_left = "?" + else: + rounds_left = self.getRoundsLeftInEffect(id) + + + if self.hide_id == 0: + str_id = str(id+1) + ":" + else: + str_id = "" + + self.post_effect(id, "EFFECT:") + + nextslot = id + 1 + + if self.isEffect(nextslot): + self.init_next_RQ() + else: #normal character, not effect + v.init_list[id]["hidden"] = 0 + + self.post_now_up(id, self.message_nowup + ": ") + + # reset the sandglass for this turn + self.sandglass_reset() + + except Exception, e: + self.init_end = 0 + self.init_round += 1 + self.init_count = 0 + self.post_sysmsg("<hr><font color='#ff0000'>End of Round<br>Starting Round <font color='#0000ff'><i># " + str(self.init_round) + "</font></i></font><hr>",1) + + def init_set_slot(self, id): + try: + if self.isEnded(): + raise + else: + if id == self.init_listslot: + self.post_syserror("Slot <font color='#0000ff'>#" + str(id + 1) + "</font> already selected.") + else: + self.init_listtag = v.init_list[id]["tag"] + self.init_listslot = id + self.sandglass_reset() + self.post_sysmsg("<font color='#0000ff'><i>" + v.init_list[id]["name"] + "</font></i> selected !") + + except: + self.post_syserror("Can't select slot <font color='#0000ff'>#" + str(id) + "</font>. Round must be started.") + + def init_move(self, id, n): + try: + # how many inits we have so far + list_size = len(v.init_list) + + if self.init_debug == 1: + print "list_size : " + str(list_size) + print "id : " + str(id) + print "pre n : " + str(n) + + if id >= list_size: + self.post_syserror("Can't move an unknown ID (<font color='#0000ff'>" + str(id+1) + "</font>) !") + return + + # are we going UP or DOWN ? + if n > 0: + up = 0 + step = 1 + # can't move down last object + if self.isLast(id): + self.post_syserror("Can't move <font color='#0000ff'>" + v.init_list[id]["name"] + "</font> this way! (Already at the last init)") + return + + max_move = list_size - id # maximum num of moves we could possibly do + # cant move more than max_move position!! + if n > max_move: + n = max_move + elif n < 0: + up = 1 + step = -1 + #can't move up first object + if self.isFirst(id): + self.post_syserror("Can't move <font color='#0000ff'>" + v.init_list[id]["name"] + "</font> this way ! (Already at the first init)") + return + + max_move = id # maximum num of move we could possibly do + # cant move more than max_move position!! + if n > max_move: + n = -max_move + else: + # shouldnt be here + self.post_syserror("Can't move <font color='#0000ff'>" + v.init_list[id]["name"] + "</font> !") + return 1 + + if self.init_debug == 1: + print "n : " + str(n) + print "step : " + str(step) + print "max_move : " + str(max_move) + print "up : " + str(up) + print "len : " + str(len(range(id , (id + n + step), step))) + + # suppose we're not moving, id_n will be the target id we're moving to + id_n = id + + # find the last init we can go with 'n' steps and staying on the init count of object 'id' + for k in range(id + step , (id + n + step), step): + #print "k... " + str(k) + if v.init_list[k]["init"] != v.init_list[id]["init"]: + # cant more further than k + step.. go away + break + else: + id_n = k + + # we can't move if id_n is the same as id. probably only alone on this init count + if id_n == id: + self.post_syserror("Can't move <font color='#0000ff'>" + v.init_list[id]["name"] + "</font> ! (you may only rankup/rankdown within the same init value)</i>") + return + + if self.init_debug == 1: + print "id_n : " + str(id_n) + + # now we have to set the rank correctly + if up and self.isFirst(id_n): + # going up and we're moving in first position of all inits + v.init_list[id]["rank"] = v.init_list[id_n]["rank"] + 1 + elif not up and self.isLast(id_n): + # going down and we're moving in last position of all inits + v.init_list[id]["rank"] = v.init_list[id_n]["rank"] - 1 + elif v.init_list[id_n + step]["init"] != v.init_list[id]["init"]: + # moving in first (up) or last (down) position of the current init count + v.init_list[id]["rank"] = v.init_list[id_n]["rank"] - step + elif up and v.init_list[id_n + step]["init"] == v.init_list[id]["init"]: + # moving up somewhere between multiple id of the same init count + v.init_list[id]["rank"] = v.init_list[id_n]["rank"] - (step * (v.init_list[id_n + step]["rank"] - v.init_list[id_n]["rank"]) / 2.0) + elif not up and v.init_list[id_n + step]["init"] == v.init_list[id]["init"]: + # moving down somewhere between multiple id of the same init count + v.init_list[id]["rank"] = v.init_list[id_n]["rank"] + (step * (v.init_list[id_n + step]["rank"] - v.init_list[id_n]["rank"]) / 2.0) + + self.post_sysmsg("<font color='#0000ff'><i>" + v.init_list[id]["name"] + "</font></i> moved !", not v.init_list[id]["hidden"]) + + # hack, if we're moving the selected slot or at the selected + # slot, we're staying at the same position. + if not self.isEnded(): + if id_n == self.init_listslot: + # we're moving AT the selected slot + self.init_listtag = v.init_list[id]["tag"] + self.sandglass_reset() + self.post_now_up(id, self.message_nowup + ": ") + # works fine unless you try to rank by more than one step, so + # currently this section (or the other) is bugged + if id == self.init_listslot: + # we're moving THE selected slot + if up: + self.init_listtag = v.init_list[id-1]["tag"] + else: + self.init_listtag = v.init_list[id+1]["tag"] + self.post_now_up(id_n, self.message_nowup + ": ") + # works fine unless you try to rank by more than one step, so + # currently this section (or the other) is bugged + self.sandglass_reset() + + + # sort that list again + self.init_sort() + + except: + self.post_syserror("Can't move <font color='#0000ff'>" + v.init_list[id]["name"] + "</font> ! (May only rankup/rankdown within the same init value)") + + + def init_delay_now(self, id): + try: + # can't delay if round ended + if self.isEnded(): + self.post_syserror("Can't delay until the round has started.", 0) + return + + if self.isD20() or self.isRQ(): + # get current tag + tag_current = v.init_list[self.init_listslot]["tag"] + tag_delay = v.init_list[id]["tag"] + name_delay = v.init_list[id]["name"] + + # can't delay current listslot + if self.init_listslot == id: + self.post_syserror("Can't delay current selected slot.", 0) + return + + # if not on the same init count + if v.init_list[self.init_listslot]["init"] != v.init_list[id]["init"]: + # generate array needed by init_change() as first parameter + tab = [ 0, id + 1, v.init_list[self.init_listslot]["init"]] + self.init_change(tab, v.init_list[id]["type"]) + self.init_sort() + + #print "name_delay : " + str(name_delay) + #print "tag_delay : " + str(tag_delay) + #print "tag_current : " + str(tag_current) + #print "slot_tag : " + str(v.init_list[self.init_listslot]["tag"]) + #print "listslot : " + str(self.init_listslot) + + # must rankup if needed (init_change() move at the end of a group if at same init count + if not (v.init_list[self.init_listslot]["tag"] == tag_delay): + # must find where is tag_delay and move it before tag_current + for m in v.init_list: + if m["tag"] == tag_delay: + new_id_delay = v.init_list.index(m) + break + + step = (self.init_listslot - new_id_delay) + self.init_move(new_id_delay, step) + #self.init_listtag = tag_delay + self.init_sort() + + self.post_now_up(self.init_listslot, "NOW UP FOR THE KILLING (DELAYED ACTION):") + + self.sandglass_reset() + + else: + self.post_syserror(">Can't delay in " + str(self.init_system) + ".") + + except Exception, e: + print str(e) + self.post_syserror("Invalid input [" + str(self.init_system) + "]. Correct command is: /initdelaynow list_number") + + ############################################################### + #### Sandglass Functions + ############################################################### + + # will send reminder to the chat if needed + def sandglass(self): + try: + if self.sandglass_delay == 0 or self.sandglass_status == 1: + pass + # send reminder except for effect + elif not self.isEnded() and not self.isEffect(self.init_listslot): + self.sandglass_count += 1 + if self.sandglass_skip_interval and not (self.sandglass_count % (self.sandglass_delay * self.sandglass_skip_interval)): + uname = v.init_list[self.init_listslot]["name"] + self.post_sysmsg("TIME'S UP <font color='#0000ff'><i>" + uname + "</font></i>!!! (<i>" + str(self.sandglass_count) + " seconds elapsed</i>)", 1) + self.init_next() + elif not (self.sandglass_count % self.sandglass_delay): + self.post_sysmsg("REMINDER to <font color='#0000ff'><i>" + v.init_list[self.init_listslot]["name"] + "</font></i> : IT'S YOUR TURN! (<i>" + str(self.sandglass_count) + " seconds elapsed</i>)", 1) + + except: + pass + + + def sandglass_reset(self): + try: + if self.sandglass_delay > 0: + self.sandglass_count = 0 + self.sandglass_resume() + except: + pass + + + # status : 0 = running + # 1 = pause + def sandglass_pause(self): + try: + if self.sandglass_delay > 0: + self.sandglass_status = 1 + except: + pass + + + def sandglass_resume(self): + try: + if self.sandglass_delay > 0: + self.sandglass_status = 0 + except: + pass + + def set_sandglass_force_skip(self,interval): + self.sandglass_skip_interval = interval + if interval == 0: + self.post_sysmsg("Sandglass force turn skip is now off.", 1) + else: + self.post_sysmsg("Sandglass force turn skip is now set to " + str(interval) + " interval(s).", 1) + self.config_save() # VEG 2.2.6 + + def set_sandglass(self, delay): + self.sandglass_delay = delay + if delay == 0: + self.post_sysmsg("Sandglass is now off.", 1) + else: + self.post_sysmsg("Sandglass is now set to " + str(delay) + " seconds.", 1) + self.config_save() # VEG 2.2.6 + + ############################################################### + #### Config/Save/Load Functions + ############################################################### + + def init_save(self, slot, public): + try: + modname = "xxinit2-" + str(slot) + + self.plugindb.SetString(modname, "init_recording", str(self.init_recording)) + self.plugindb.SetString(modname, "init_round", str(self.init_round)) + self.plugindb.SetString(modname, "init_title", str(self.init_title)) + self.plugindb.SetString(modname, "init_count", str(self.init_count)) + self.plugindb.SetString(modname, "init_pass", str(self.init_pass)) + self.plugindb.SetString(modname, "init_listslot", str(self.init_listslot)) + self.plugindb.SetString(modname, "init_listtag", str(self.init_listtag)) + self.plugindb.SetString(modname, "init_end", str(self.init_end)) + self.plugindb.SetString(modname, "init_system", str(self.init_system)) + self.plugindb.SetString(modname, "init_list", repr(v.init_list)) + self.plugindb.SetString(modname, "sandglass_status", repr(self.sandglass_status)) + + if self.init_title != "": + title_str = " <i>[" + self.init_title + "]</i>" + else: + title_str = "" + + if slot == 0: + #self.post_sysmsg("Initiative list autosaved successfully.", public) + # this is annoying, so i disabled the text output + pass + else: + self.post_sysmsg("Initiative list saved successfully on slot #" + str(slot) + title_str + ".", public) + + except Exception, e: + print "err saving : " + str(e) + + + def init_load(self, slot): + try: + self.init_clear() + + modname = "xxinit2-" + str(slot) + + self.init_recording = int(self.plugindb.GetString(modname, "init_recording","0")) + self.init_round = int(self.plugindb.GetString(modname, "init_round", "0")) + self.init_title = str(self.plugindb.GetString(modname, "init_title", "")) + self.init_count = int(self.plugindb.GetString(modname, "init_count", "0")) + self.init_pass = int(self.plugindb.GetString(modname, "init_pass", "0")) + self.init_listslot = int(self.plugindb.GetString(modname, "init_listslot", "0")) + self.init_listtag = str(self.plugindb.GetString(modname, "init_listtag", "")) + self.init_end = int(self.plugindb.GetString(modname, "init_end", "0")) + self.init_system = str(self.plugindb.GetString(modname, "init_system", "")) + v.init_list = eval(self.plugindb.GetString(modname, "init_list", "")) + self.sandglass_status = eval(self.plugindb.GetString(modname, "sandglass_status", "0")) + + if self.init_title != "": + title_str = " <i>[" + self.init_title + "]</i>" + else: + title_str = "" + + if slot == 0: + self.post_sysmsg("Last autosaved initiative list loaded successfully.") + else: + self.post_sysmsg("Initiative list slot #" + str(slot) + title_str + " loaded successfully.") + self.config_save() # VEG 2.2.6 + + except Exception, e: + #print "err loading: " + e + self.post_syserror("Error loading Initiative list.") + + + def autosave(self): + try: + slot = 0 + if self.autosave_delay != 0: + self.autosave_count += 1 + if not (self.autosave_count % self.autosave_delay): + self.autosave_count = 0 + self.init_save(slot, 0) + + except Exception, e: + print str(e) + + + def set_autosave(self, delay): + + self.autosave_delay = delay + + if delay == 0: + self.post_sysmsg("Autosave is now off.") + else: + self.post_sysmsg("Autosave is now done every " + str(delay) + " seconds.") + + + def config_save(self): + try: + modname = "xxinit2-config" + + # don't want python to convert this to the strings "TRUE" or "FALSE" + if self.init_recording == 0: + self.init_recording = 0 + else: + self.init_recording = 1 + + if self.hide_id == 0: + self.hide_id = 0 + else: + self.hide_id = 1 + + if self.hide_ondeck == 0: + self.hide_ondeck = 0 + else: + self.hide_ondeck = 1 + + if self.hide_justmovement == 0: + self.hide_justmovement = 0 + else: + self.hide_justmovement = 1 + + self.plugindb.SetString(modname, "init_recording", str(self.init_recording)) + self.plugindb.SetString(modname, "init_system", str(self.init_system)) + self.plugindb.SetString(modname, "sandglass_count", str(self.sandglass_count)) + self.plugindb.SetString(modname, "sandglass_delay", str(self.sandglass_delay)) + self.plugindb.SetString(modname, "sandglass_skip_interval", str(self.sandglass_skip_interval)) + self.plugindb.SetString(modname, "autosave_delay", str(self.autosave_delay)) + self.plugindb.SetString(modname, "autosave_count", str(self.autosave_count)) + self.plugindb.SetString(modname, "hide_id", str(self.hide_id)) + self.plugindb.SetString(modname, "hide_ondeck", str(self.hide_ondeck)) + self.plugindb.SetString(modname, "hide_justmovement",str(self.hide_justmovement)) + self.plugindb.SetString(modname, "message_nowup", str(self.message_nowup)) + self.plugindb.SetString(modname, "msghand_timer", str(self.msghand_timer)) # VEG 2.2.6 + self.plugindb.SetString(modname, "msghand_warning", str(self.msghand_warning)) # VEG 2.2.6 + self.plugindb.SetString(modname, "reroll_type", str(self.reroll_type)) # VEG 2.2.7 + self.plugindb.SetString(modname, "ip_order", str(self.ip_order)) # VEG 2.2.7 + + #self.post_sysmsg("Configuration saved successfully.",0) + print "Initiative configuration saved successfully." + + except: + self.post_syserror("Error saving configuration.",0) + + + def config_load(self): + + try: + modname = "xxinit2-config" + + self.init_recording = int(self.plugindb.GetString(modname, "init_recording","0")) + self.init_system = str(self.plugindb.GetString(modname, "init_system", "")) + self.sandglass_count = int(self.plugindb.GetString(modname, "sandglass_count", "0")) + self.sandglass_delay = int(self.plugindb.GetString(modname, "sandglass_delay", "0")) + self.sandglass_skip_interval = int(self.plugindb.GetString(modname, "sandglass_skip_interval", "0")) + self.autosave_delay = int(self.plugindb.GetString(modname, "autosave_delay", "0")) + self.autosave_count = int(self.plugindb.GetString(modname, "autosave_count", "0")) + self.hide_id = int(self.plugindb.GetString(modname, "hide_id", "0")) + self.hide_ondeck = int(self.plugindb.GetString(modname, "hide_ondeck", "0")) + self.hide_justmovement = int(self.plugindb.GetString(modname, "hide_justmovement", "0")) + self.message_nowup = str(self.plugindb.GetString(modname, "message_nowup", "")) + self.msghand_timer = int(self.plugindb.GetString(modname, "msghand_timer", "0")) # VEG 2.2.6 + self.msghand_warning = int(self.plugindb.GetString(modname, "msghand_warning", "0")) # VEG 2.2.6 + self.reroll_type = int(self.plugindb.GetString(modname, "reroll_type", "0")) # VEG 2.2.7 + self.ip_order = int(self.plugindb.GetString(modname, "ip_order", "0")) # VEG 2.2.7 + + # if system blank... no config was loaded + if self.init_system == "": + raise + + self.post_sysmsg("Configuration loaded successfully.",0) + self.config_save() # VEG 2.2.6 + + except: + self.config_default() + + + def config_default(self): + + self.init_recording = 1 + self.init_system = "D20" + self.sandglass_count = 0 + self.sandglass_delay = 0 + self.sandglass_status = 0 + self.sandglass_skip_interval = 0 + self.autosave_delay = 60 + self.autosave_count = 0 + self.hide_id = 0 + self.hide_ondeck = 0 + self.hide_justmovement = 0 + self.message_nowup = "NEXT UP FOR THE KILLING" + self.msghand_timer = 0 + self.msghand_warning = 1 + self.reroll_type = 0 + self.ip_order = 0 + + self.post_sysmsg("Default configuration loaded successfully.",0) + self.config_save() # VEG 2.2.6 + + def config_show(self): + + try: + self.post_sysmsg("<br><u>Init Tool system config v" + str(self.version) + "</u><br>") + + if self.init_recording == 0: + buf = "disabled"; + else: + buf = "enabled"; + self.post_my_msg("<b>Init Recording:</b> " + str(buf)) + + self.post_my_msg("<b>System:</b> " + str(self.init_system)) + + if self.sandglass_delay == 0: + buf = "disabled"; + else: + buf = str(self.sandglass_delay) + " seconds" + if self.sandglass_status == 1: + buf += str(" [ paused ]") + + self.post_my_msg("<b>Sandglass:</b> " + str(buf)) + + if self.sandglass_skip_interval == 0: + buf = "disabled"; + else: + buf = "every " + str(self.sandglass_skip_interval) + " interval(s)." + self.post_my_msg("<b>Sandglass force skip:</b> " + str(buf)) + + if self.autosave_delay == 0: + buf = "disabled"; + else: + buf = str(self.autosave_delay) + " seconds" + self.post_my_msg("<b>Autosave:</b> " + str(buf)) + + if self.msghand_warning == 0: # VEG 2.2.6 + buf = "disabled"; + else: + buf = "enabled"; + self.post_my_msg("<b>Show Message Handler Warning:</b> " + str(buf)) + + if self.hide_id == 0: + buf = "disabled"; + else: + buf = "enabled"; + self.post_my_msg("<b>Hide IDs:</b> " + str(buf)) + + if self.hide_ondeck == 0: + buf = "disabled"; + else: + buf = "enabled"; + self.post_my_msg("<b>Hide 'On Deck':</b> " + str(buf)) + + if self.hide_justmovement == 0: + buf = "disabled"; + else: + buf = "enabled"; + self.post_my_msg("<b>[SR4-only] Hide 'Just Movement':</b> " + str(buf)) + + if self.reroll_type == 0: # VEG 2.2.7 + buf = "reroll inits every round (normal)"; + else: + buf = "keep same inits every round (house rule)"; + self.post_my_msg("<b>[SR4-only] Init Reroll?:</b> " + str(buf)) + + if self.ip_order == 0: # VEG 2.2.7 + buf = "1/2/3/4 (normal)"; + elif self.ip_order == 1: + buf = "3/1/4/2 (Serbitar's house rule)" + elif self.ip_order == 2: + buf = "4/1/3/2 (TinkerGnome's house rule)"; + self.post_my_msg("<b>[SR4-only] IP Order:</b> " + str(buf)) + + self.post_my_msg("<b>Now Up Message:</b> " + str(self.message_nowup)) + + except: + self.post_syserror("Error reading configuration.",0) + + ############################################################### + #### Display Functions + ############################################################### + + def inits_list(self, public): + if self.isD20(): + self.inits_list_D20(public) + elif self.isSR4(): + self.inits_list_SR4(public) + elif self.isRQ(): + self.inits_list_RQ(public) + + def inits_list_D20(self, public): + + current_count = str(self.init_count) + + if self.sandglass_delay == 0: + current_sandglass = "off" + else: + current_sandglass = str(self.sandglass_delay) + " sec." + if self.sandglass_status == 1: + current_sandglass += str(" [ paused ]") + + msg = "<br><br><b>Initiatives (Current Count: " + current_count + "; Sandglass: " + current_sandglass + "):</b><br>" + for m in v.init_list: + + # dont show public if character (type 0) + if public and m["type"] == 0 and m["hidden"] == 1: + continue + + # id in the list appears as 1 to (N+1), in reality it's 0 to N + id = v.init_list.index(m) + idplusone = str(id+1) + + if not self.isEnded() and self.init_listslot == id: + msg += "<b>" + + # we dont want to show IDs to everyone + if public and self.hide_id: + msg += " " + else: + msg += " <font color='#ff0000'>" + idplusone + ") :</font>" + + if self.isEffect(id): + # example + # 5: (*14) <i>Effect: Tlasco's Bless (4)</i> + if public and m["hidden"] == 1: + duration = "?" + else: + duration = m["duration"] + msg += " [" + str(m["init"])+"] " + msg += "<font color='#0000ff'><i>Effect: " + str(m["name"]) + " (" + str(duration) + ")</i>" + else: + # example + # 6: (14) Tlasco + msg+= " ["+str(m["init"])+"] <font color='#0000ff'>" + str(m["name"]) + if self.init_debug: + #msg+= " [rank:" + str(m["rank"]) + "; tag: " + str(m["tag"]) + "]</font>" + msg+= " [rank:" + str(m["rank"]) + "; type: " + str(m["type"]) + "]</font>" + #msg+= " [rank:" + str(m["rank"]) + "]</font>" + else: + msg+= "</font>" + + if not public and m["hidden"] == 1: + msg += " <i>[H]</i>" + + if not self.isEnded() and self.init_listslot == id: + msg += "</b>" + + msg += "<br>" + self.post_my_msg(msg,public) + + + def inits_list_SR4(self, public): + + if self.sandglass_delay == 0: + current_sandglass = "off" + else: + current_sandglass = str(self.sandglass_delay) + " sec." + if self.sandglass_status == 1: + current_sandglass += str(" [ paused ]") + + if self.ip_order == 0: + current_ip_order = "1/2/3/4 (normal)" + elif self.ip_order == 1: + current_ip_order = "3/1/4/2 (Serbitar's house rule)" + else: + current_ip_order = "4/1/3/2 (TinkerGnome's house rule)" + current_count = str(self.init_count) + current_pass = str(self.init_pass) + + msg = "<br><br><b>Initiatives (Current Pass: " + current_pass \ + + "; Current Count: " + current_count + "), Sandglass: " \ + + current_sandglass + ", IP Order: " + current_ip_order \ + + "</b><br>" + msg += "<table border='1'><tr> <th></th>" + + if self.init_pass==1: + msg += "<th><b><font color='#ff0000'>Pass 1</font></b></th>" + else: + msg += "<th>Pass 1</th>" + + if self.init_pass==2: + msg += "<th><b><font color='#ff0000'>Pass 2</font></b></th>" + else: + msg += "<th>Pass 2</th>" + + if self.init_pass==3: + msg += "<th><b><font color='#ff0000'>Pass 3</font></b></th>" + else: + msg += "<th>Pass 3</th>" + + if self.init_pass==4: + msg += "<th><b><font color='#ff0000'>Pass 4</font></b></th></tr>" + else: + msg += "<th>Pass 4</th></tr>" + + for m in v.init_list: + # id in the list appears as 1 to (N+1), in reality it's 0 to N + id = v.init_list.index(m) + idplusone = str(id+1) + # example + # | Init Pass 1 | Init Pass 2 | etc... | | + # --------------------------- + # 6: Tlasco | 13 | 13 | (blank) | (blank) | + + # we dont want to show IDs to everyone + if public and self.hide_id: + msg += " <tr><th>" + else: + msg += " <tr><td><font color='#ff0000'>" + idplusone + ":</font> " + + # bold the current player's name + if not self.isEnded() and self.init_listslot == id: + msg += "<b><font color='#0000ff'>" + str(m["name"]) + "</font></b></td>" + else: + msg += "<font color='#0000ff'>" + str(m["name"]) + "</font></td>" + + ip = self.ip_order #ip==0 is 1/2/3/4 (normal) - VEG 2.2.7 + #ip==1 is 3/1/4/2 (Serbitar's house rule) + #ip==2 is 4/1/3/2 (TinkerGnome's house rule) + passes = m["passes"] + # pass one + if (ip==0 and passes >= 1) or (ip==1 and passes >= 3) or (ip==2 and passes >= 4): + msg += "<td align=center>"+str(m["init"]) + "</td>" + else: + msg += "<td> </td>" + # pass two + if (ip==0 and passes >= 2) or (ip==1 and passes >= 1) or (ip==2 and passes >= 1): + msg += "<td align=center>"+str(m["init"]) + "</td>" + else: + msg += "<td> </td>" + # pass three + if (ip==0 and passes >= 3) or (ip==1 and passes >= 4) or (ip==2 and passes >= 3): + msg += "<td align=center>" + str(m["init"]) + "</td>" + else: + msg += "<td> </td>" + # pass four + if (ip==0 and passes >= 4) or (ip==1 and passes >= 2) or (ip==2 and passes >= 2): + msg += "<td align=center>" + str(m["init"]) + "</td>" + else: + msg += "<td> </td>" + + msg += "</tr>" + + msg += "</table>" + self.post_my_msg(msg, public) + + + def inits_list_RQ(self, public): + current_count = str(self.init_count) + + if self.sandglass_delay == 0: + current_sandglass = "off" + else: + current_sandglass = str(self.sandglass_delay) + " sec." + if self.sandglass_status == 1: + current_sandglass += str(" [ paused ]") + + msg = "<br><br><b>Initiatives (Current Strike Rank: " + current_count + "; Sandglass: " + current_sandglass + "):</b><br>" + for m in v.init_list: + + # dont show public if character (type 0) + if public and m["type"] == 0 and m["hidden"] == 1: + continue + + # id in the list appears as 1 to (N+1), in reality it's 0 to N + id = v.init_list.index(m) + idplusone = str(id+1) + + if not self.isEnded() and self.init_listslot == id: + msg += "<b>" + + # we dont want to show IDs to everyone + if public and self.hide_id: + msg += " " + else: + msg += " <font color='#ff0000'>" + idplusone + ") :</font>" + + if self.isEffect(id): + # example + # 5: (*14) <i>Effect: Tlasco's Bless (4)</i> + if public and m["hidden"] == 1: + duration = "?" + else: + duration = m["duration"] + msg += " [" + str(m["init"])+"] " + msg += "<font color='#0000ff'><i>Effect: " + str(m["name"]) + " (" + str(duration) + ")</i>" + else: + # example + # 6: (14) Tlasco + msg+= " ["+str(m["init"])+"] <font color='#0000ff'>" + str(m["name"]) + if self.init_debug: + #msg+= " [rank:" + str(m["rank"]) + "; tag: " + str(m["tag"]) + "]</font>" + msg+= " [rank:" + str(m["rank"]) + "; type: " + str(m["type"]) + "]</font>" + #msg+= " [rank:" + str(m["rank"]) + "]</font>" + else: + msg+= "</font>" + + if not public and m["hidden"] == 1: + msg += " <i>[H]</i>" + + if not self.isEnded() and self.init_listslot == id: + msg += "</b>" + + msg += "<br>" + self.post_my_msg(msg, public) + + + def post_now_up(self, id, text): + + #if v.init_list[id]["hidden"] == 0: + if self.hide_id == 0: + id_str = "<font color='#000000'><b>" + str(id + 1) + ")</b></font>" + else: + id_str = "" + + try: + id_next = self.getNext(id) + str_on_deck = "" + if id_next != -1: + if self.hide_ondeck != 1: + str_on_deck = "<br><i><font color='#000000'>(on deck: [" + str(v.init_list[id_next]["init"]) + "] " + str(v.init_list[id_next]["name"]) + ")</font></i>" + + except Exception, e: + print str(e) + + self.post_my_msg("<table border=1 width=100% align='center'>\ + <tr>\ + <td>" + str(id_str) + " <font color='#ff0000'><b><u>" + str(text)\ + + "</u></b></font><font color='#0000ff'><b>"\ + + " <font color='#000000'></b>[" + str(v.init_list[id]["init"]) + "]<b></font> "\ + + str(v.init_list[id]["name"]) + "</b></font> " + str_on_deck + "\ + </td>\ + </tr>\ + </table>", 1) + + def post_movement(self, id, text): + + #if v.init_list[id]["hidden"] == 0: + if self.hide_id == 0: + id_str = "<font color='#000000'><b>" + str(id + 1) + ")</b></font>" + else: + id_str = "" + + self.post_my_msg("<table border=1 width=100% align='center'>\ + <tr>\ + <td>" + str(id_str) + " <font color='#0000ff'><b><i>" + str(text)\ + + "</i></b></font><font color='#0000ff'><b>"\ + + " <font color='#000000'></b>[" + str(v.init_list[id]["init"]) + "]<b></font> "\ + + str(v.init_list[id]["name"]) + "</b></font> \ + </td>\ + </tr>\ + </table>", 1) + + def post_effect(self, id, text): + + if self.hide_id == 0: + id_str = "<font color='#000000'><b>" + str(id + 1) + ")</b></font>" + else: + id_str = "" + + if v.init_list[id]["hidden"] == 1: + rounds_left = "?" + else: + rounds_left = self.getRoundsLeftInEffect(id) + + if(self.getRoundsLeftInEffect(id) > 0): + self.post_my_msg("<table border=1 width=100% align='center'>\ + <tr>\ + <td>" + str(id_str) + " <font color='#0000ff'><b><i>" + str(text)\ + + "</i></b></font><font color='#0000ff'>"\ + + " <font color='#000000'>[" + str(v.init_list[id]["init"]) + "]</font> <i>"\ + + str(v.init_list[id]["name"]) + "</i></font> : <b>" + str(rounds_left) + "</b> round(s) remaining.\ + </td>\ + </tr>\ + </table>", 1) + else: + self.post_my_msg("<table border=1 width=100% align='center'>\ + <tr>\ + <td>" + str(id_str) + " <font color='#0000ff'><b><i>" + str(text)\ + + "</i></b></font><i>"\ + + " [" + str(v.init_list[id]["init"]) + "] <font color='#0000ff'>"\ + + str(v.init_list[id]["name"]) + "</font></i>\ + </td>\ + </tr>\ + </table>", 1) + + + def post_my_msg(self, msg,send=0): + tmp = self.init_recording + + # have to disable the tool in order to post or else you get a clone + self.init_recording = 0 + self.chat.Post(msg,send) + + self.init_recording = tmp + + + def post_syserror(self, msg, send=0): + self.post_my_msg("<font color='#ff0000'><b><i>" + msg + "</i></b></font>", send) + + + def post_sysmsg(self, msg,send=0): + self.post_my_msg("<b>" + msg + "</b>", send) + + + def toggle_hidden(self, id): + try: + #print "id : " + str(id) + v.init_list[id]["hidden"] = not v.init_list[id]["hidden"] + if v.init_list[id]["hidden"] == 1: + tmp = "hidden" + else: + tmp = "visible" + self.post_sysmsg(str(v.init_list[id]["name"]) + " now " + tmp + ".") + + except: + self.post_syserror("Invalid format. Correct command is: /togglehidden init_#") + + ############################################################### + #### Conditional + Other Functions + ############################################################### + + def check_version(self): + if(int(replace(orpg.orpg_version.VERSION, ".", "")) < int(replace(self.orpg_min_version, ".", ""))): + self.post_sysmsg("<br><font color='#ff0000'>WARNING</font>: You are currently using OpenRPG " + str(orpg.orpg_version.VERSION) + " but you need OpenRPG " + str(self.orpg_min_version) + " or greater to run the Initiative Tool " + str(self.version) + "<br>Use it at your own risk!</b><br>") + + def isD20(self): + if self.init_system == "D20": + return 1 + else: + return 0 + + def isSR4(self): + if self.init_system == "SR4": + return 1 + else: + return 0 + + def isRQ(self): + if self.init_system == "RQ": + return 1 + else: + return 0 + + def isEnded(self): + if self.init_end == 0: + return 1 + else: + return 0 + + def getFirst(self): + return(0) + + def getLast(self): + return(len(v.init_list)-1) + + def isEffect(self, id): + # if it's type 1, then it's an effect + try: + if (self.isD20() or self.isRQ()) and v.init_list[id]["type"] == 1: + return 1 + else: + return 0 + except: + return 0 + + def getRoundsLeftInEffect(self, id): + rounds_left = v.init_list[id]["duration"] + return rounds_left + + def isMovement(self, id): # sr4 only, used to spam movement-only characters + try: # in passes where they receive no actions + passes = v.init_list[id]["passes"] + if self.ip_order == 0: # Normal 1/2/3/4 --- VEG 2.2.7 + if passes < self.init_pass: + return 1 + else: + return 0 + elif self.ip_order == 1: # Serbitar's 3/1/4/2 --- VEG 2.2.7 + if (self.init_pass == 1) and (passes < 3): + return 1 + elif (self.init_pass == 2) and (passes < 1): + return 1 + elif (self.init_pass == 3) and (passes < 4): + return 1 + elif (self.init_pass == 4) and (passes < 2): + return 1 + else: + return 0 + elif self.ip_order == 2: # TinkerGnome's 4/1/3/2 --- VEG 2.2.7 + if (self.init_pass == 1) and (passes < 4): + return 1 + elif (self.init_pass == 2) and (passes < 1): + return 1 + elif (self.init_pass == 3) and (passes < 3): + return 1 + elif (self.init_pass == 4) and (passes < 2): + return 1 + else: + return 0 + except: + return 0 + + def sharesInit(self,id): + try: + if v.init_list[id]["init"] == v.init_list[self.init_listslot]["init"]: + return 1 + else: + return 0 + except: # last init will be an error, don't start new round yet + return 0 + + # get the id of the next (non effect) non-hidden character after the given id + # return -1 : no character is next + def getNext(self, id): + lst_size = len(v.init_list) + + # list empty + if lst_size < 2: + return(-1) + + lst = [] + id_found = -1 + + # if we'r at the last init, the next one is at the beginning of the list + if self.isLast(id): + for m in v.init_list: + id_m = v.init_list.index(m) + if self.isHidden(id_m) or self.isEffect(id_m): + pass + else: + id_found = id_m + break; + else: + try: + for id_m in range(id+1, self.getLast()+1): + if self.isHidden(id_m) or self.isEffect(id_m): + pass + else: + id_found = id_m + break; + + except Exception, e: + return(-1) + + # maybe we haven't found yet, must search at the beginning of the list + if id_found == -1 and not self.isFirst(id): + for id_m in range(0, id): + if self.isHidden(id_m) or self.isEffect(id_m): + pass + else: + id_found = id_m + break; + + if id_found != id: + return(id_found) + else: + return(-1) + + def isHidden(self, id): + try: + if v.init_list[id]["hidden"] == 1: + return(1) + else: + return(0) + + except: + return(0) + + def isFirst(self, id): + if id == 0: + return 1 + else: + return 0 + + def isLast(self, id): + if id == (len(v.init_list)-1): + return 1 + else: + return 0 + + def get_next_rank(self, init): + # when adding/changing an object, this function is used to get a unique rank of this init count + # new object are added at the end of an init count, so we need a 'rank' lower than the + # other object of the same init count. + rank = 0; + for m in v.init_list: + if m["init"] == init: + x = m["rank"] - 1 + if rank > x: + rank = x + return rank + + def get_unique_tag(self, name): + m = hashlib.new() + m.update(str(random.random()) + str(name)) + return m.hexdigest() + +### VEG 2.2.6 +### Init GUI stuff below + + def CMD_initgui(self, cmdargs): + self.frame = InitToolFrame(NULL, -1, "Initiative Tool GUI") + self.frame.Show(true) + +class InitToolFrame(wx.Frame): + def __init__(self, parent, ID, title): + wx.Frame.__init__(self, parent, ID, title, size=(400, 300)) + + self.panel = wx.Panel(self,-1) #, style=wx.SUNKEN_BORDER) + + #self.panel.SetBackgroundColour("RED") + + self.x_id = 5 + self.x_name = 25 + self.x_init = 200 + self.x_change = 225 + self.x_delete = 275 + self.y = 0 + b = 0 + + wx.StaticText ( self.panel, -1, "ID", (self.x_id, self.y) ) + wx.StaticText ( self.panel, -1, "Name", (self.x_name, self.y) ) + wx.StaticText ( self.panel, -1, "Init#", (self.x_init, self.y) ) + self.y+=20 + + var_ID=0 + var_Name=0 + var_Init=0 + + for m in v.init_list: + var_ID = str(v.init_list.index(m)+1) + ")" + var_Name = self.strip_html(m["name"]) + var_Init = str(m["init"]) + + wx.StaticText ( self.panel, -1, var_ID, (self.x_id, self.y) ) + wx.StaticText ( self.panel, -1, var_Name, (self.x_name, self.y) ) + wx.TextCtrl ( self.panel, -1, var_Init, (self.x_init, self.y), (20,20), wx.TE_READONLY) + wx.Button(self.panel, -1, "Change", (self.x_change, self.y), (50,20) ) + wx.Button(self.panel, -1, "Delete", (self.x_delete, self.y), (50,20) ) + self.y+=20 + + #for i in range(0,4): + # if i == 0: + # var_ID = str(0) + # var_Name = "Hignar" + # var_Init = str(14) + # elif i == 1: + # var_ID = str(1) + # var_Name = "Aiur" + # var_Init = str(12) + # elif i == 2: + # var_ID = str(2) + # var_Name = "Effect: Tlasco's Bless" + # var_Init = str(4) + # elif i == 3: + # var_ID = str(3) + # var_Name = "Tlasco" + # var_Init = str(3) + # wxStaticText ( self.panel, -1, var_ID, (self.x_id, self.y) ) + # wxStaticText ( self.panel, -1, var_Name, (self.x_name, self.y) ) + # wxStaticText ( self.panel, -1, var_Init, (self.x_init, self.y) ) + # wxButton(self.panel, -1, "Change", (self.x_change, self.y), (50,20) ) + # wxButton(self.panel, -1, "Delete", (self.x_delete, self.y), (50,20) ) + # self.y+=20 + + def strip_html(self, text): + finished = 0 + while not finished: + finished = 1 + # check if there is an open tag left + start = text.find("<") + if start >= 0: + # if there is, check if the tag gets closed + stop = text[start:].find(">") + if stop >= 0: + # if it does, strip it, and continue loop + text = text[:start] + text[start+stop+1:] + finished = 0 + return text