diff --git a/source/src/clientgame.cpp b/source/src/clientgame.cpp index 204319d2..8bfc6d0e 100644 --- a/source/src/clientgame.cpp +++ b/source/src/clientgame.cpp @@ -259,25 +259,30 @@ void otherplayers() // End add }; -struct scriptsleep -{ - int wait; - string cmd; - scriptsleep(int msec, char *command) { wait = msec+lastmillis; s_strcpy(cmd, command); }; -}; - +struct scriptsleep { int wait; char *cmd; }; vector sleeps; -/*int sleepwait = 0; -string sleepcmd;*/ -//void addsleep(char *msec, char *cmd) { sleepwait = atoi(msec)+lastmillis; strcpy_s(sleepcmd, cmd); }; -void addsleep(char *msec, char *cmd) { scriptsleep s(atoi(msec), cmd); sleeps.add(s); }; +void addsleep(char *msec, char *cmd) +{ + scriptsleep &s = sleeps.add(); + s.wait = atoi(msec)+lastmillis; + s.cmd = newstring(cmd); +}; + COMMANDN(sleep, addsleep, ARG_2STR); void updateworld(int curtime, int lastmillis) // main game update loop { - //if(sleepwait && lastmillis>sleepwait) { sleepwait = 0; execute(sleepcmd); }; - loopv(sleeps) if(sleeps[i].wait && lastmillis > sleeps[i].wait) { execute(sleeps[i].cmd); sleeps.remove(i); i--; }; + loopv(sleeps) + { + scriptsleep &s = sleeps[i]; + if(s.wait && lastmillis > s.wait) + { + execute(s.cmd); + delete[] s.cmd; + sleeps.remove(i--); + }; + }; physicsframe(); checkakimbo(); checkweaponswitch(); @@ -594,13 +599,14 @@ extern void kickallbots(void); void startmap(char *name) // called just after a map load { + loopv(sleeps) delete[] sleeps[i].cmd; + sleeps.setsize(0); //if(netmapstart()) { gamemode = 0;}; //needs fixed to switch modes? netmapstart(); //should work //monsterclear(); // Added by Rick kickallbots(); if(m_botmode) BotManager.BeginMap(name); -// else sleepwait = 0; // End add by Rick projreset(); if(m_ctf) preparectf(); diff --git a/source/src/command.cpp b/source/src/command.cpp index a2805cf0..8728cb75 100644 --- a/source/src/command.cpp +++ b/source/src/command.cpp @@ -13,7 +13,7 @@ struct ident int *storage; // ID_VAR void (*fun)(); // ID_VAR, ID_COMMAND int narg; // ID_VAR, ID_COMMAND - char *action; // ID_ALIAS + char *action, *executing; // ID_ALIAS bool persist; }; @@ -28,14 +28,15 @@ void alias(char *name, char *action) if(!b) { name = newstring(name); - ident b = { ID_ALIAS, name, 0, 0, 0, 0, 0, newstring(action) }; + ident b = { ID_ALIAS, name, 0, 0, 0, 0, 0, newstring(action), 0, false }; idents->access(name, &b); } - else + else if(b->type==ID_ALIAS) { - if(b->type==ID_ALIAS) b->action = exchangestr(b->action, action); - else conoutf("cannot redefine builtin %s with an alias", name); - }; + if(b->action!=b->executing) delete[] b->action; + b->action = newstring(action); + } + else conoutf("cannot redefine builtin %s with an alias", name); }; COMMAND(alias, ARG_2STR); @@ -45,7 +46,7 @@ COMMAND(alias, ARG_2STR); int variable(char *name, int min, int cur, int max, int *storage, void (*fun)(), bool persist) { if(!idents) idents = new hashtable; - ident v = { ID_VAR, name, min, max, storage, fun, 0, 0, persist }; + ident v = { ID_VAR, name, min, max, storage, fun, 0, 0, 0, persist }; idents->access(name, &v); return cur; }; @@ -122,7 +123,7 @@ char *lookup(char *n) // find value of ident reference return n; }; -int execute(char *p, bool isdown) // all evaluation happens here, recursively +int execute(char *p) // all evaluation happens here, recursively { const int MAXWORDS = 25; // limit, remove char *w[MAXWORDS]; @@ -157,60 +158,53 @@ int execute(char *p, bool isdown) // all evaluation happens here, case ID_COMMAND: // game defined commands switch(id->narg) // use very ad-hoc function signature, and just call it { - case ARG_1INT: if(isdown) ((void (__cdecl *)(int))id->fun)(ATOI(w[1])); break; - case ARG_2INT: if(isdown) ((void (__cdecl *)(int, int))id->fun)(ATOI(w[1]), ATOI(w[2])); break; - case ARG_3INT: if(isdown) ((void (__cdecl *)(int, int, int))id->fun)(ATOI(w[1]), ATOI(w[2]), ATOI(w[3])); break; - case ARG_4INT: if(isdown) ((void (__cdecl *)(int, int, int, int))id->fun)(ATOI(w[1]), ATOI(w[2]), ATOI(w[3]), ATOI(w[4])); break; - case ARG_NONE: if(isdown) ((void (__cdecl *)())id->fun)(); break; - case ARG_1STR: if(isdown) ((void (__cdecl *)(char *))id->fun)(w[1]); break; - case ARG_2STR: if(isdown) ((void (__cdecl *)(char *, char *))id->fun)(w[1], w[2]); break; - case ARG_3STR: if(isdown) ((void (__cdecl *)(char *, char *, char*))id->fun)(w[1], w[2], w[3]); break; - case ARG_5STR: if(isdown) ((void (__cdecl *)(char *, char *, char*, char*, char*))id->fun)(w[1], w[2], w[3], w[4], w[5]); break; - case ARG_6STR: if(isdown) ((void (__cdecl *)(char *, char *, char*, char*, char*, char*))id->fun)(w[1], w[2], w[3], w[4], w[5], w[6]); break; - case ARG_DOWN: ((void (__cdecl *)(bool))id->fun)(isdown); break; - case ARG_DWN1: ((void (__cdecl *)(bool, char *))id->fun)(isdown, w[1]); break; - case ARG_1EXP: if(isdown) val = ((int (__cdecl *)(int))id->fun)(execute(w[1])); break; - case ARG_2EXP: if(isdown) val = ((int (__cdecl *)(int, int))id->fun)(execute(w[1]), execute(w[2])); break; - case ARG_1EST: if(isdown) val = ((int (__cdecl *)(char *))id->fun)(w[1]); break; - case ARG_2EST: if(isdown) val = ((int (__cdecl *)(char *, char *))id->fun)(w[1], w[2]); break; - case ARG_VARI: if(isdown) + case ARG_1INT: ((void (__cdecl *)(int))id->fun)(ATOI(w[1])); break; + case ARG_2INT: ((void (__cdecl *)(int, int))id->fun)(ATOI(w[1]), ATOI(w[2])); break; + case ARG_3INT: ((void (__cdecl *)(int, int, int))id->fun)(ATOI(w[1]), ATOI(w[2]), ATOI(w[3])); break; + case ARG_4INT: ((void (__cdecl *)(int, int, int, int))id->fun)(ATOI(w[1]), ATOI(w[2]), ATOI(w[3]), ATOI(w[4])); break; + case ARG_NONE: ((void (__cdecl *)())id->fun)(); break; + case ARG_1STR: ((void (__cdecl *)(char *))id->fun)(w[1]); break; + case ARG_2STR: ((void (__cdecl *)(char *, char *))id->fun)(w[1], w[2]); break; + case ARG_3STR: ((void (__cdecl *)(char *, char *, char*))id->fun)(w[1], w[2], w[3]); break; + case ARG_5STR: ((void (__cdecl *)(char *, char *, char*, char*, char*))id->fun)(w[1], w[2], w[3], w[4], w[5]); break; + case ARG_6STR: ((void (__cdecl *)(char *, char *, char*, char*, char*, char*))id->fun)(w[1], w[2], w[3], w[4], w[5], w[6]); break; + case ARG_DOWN: ((void (__cdecl *)(bool))id->fun)(addreleaseaction(id->name)!=NULL); break; + case ARG_1EXP: val = ((int (__cdecl *)(int))id->fun)(execute(w[1])); break; + case ARG_2EXP: val = ((int (__cdecl *)(int, int))id->fun)(execute(w[1]), execute(w[2])); break; + case ARG_1EST: val = ((int (__cdecl *)(char *))id->fun)(w[1]); break; + case ARG_2EST: val = ((int (__cdecl *)(char *, char *))id->fun)(w[1], w[2]); break; + case ARG_VARI: { - string r; // limit, remove + int len = max(numargs-2, 0); + for(int i = 1; ifun)(r); + delete[] r; break; - } + }; }; break; case ID_VAR: // game defined variabled - if(isdown) + if(!w[1][0]) conoutf("%s = %d", c, *id->storage); // var with no value just prints its current value + else if(id->min>id->max) conoutf("variable is read-only"); + else { - if(!w[1][0]) conoutf("%s = %d", c, *id->storage); // var with no value just prints its current value - else + int i1 = ATOI(w[1]); + if(i1min || i1>id->max) { - if(id->min>id->max) - { - conoutf("variable is read-only"); - } - else - { - int i1 = ATOI(w[1]); - if(i1min || i1>id->max) - { - i1 = i1min ? id->min : id->max; // clamp to valid range - conoutf("valid range for %s is %d..%d", c, id->min, id->max); - } - *id->storage = i1; - }; - if(id->fun) ((void (__cdecl *)())id->fun)(); // call trigger function if available - }; + i1 = i1min ? id->min : id->max; // clamp to valid range + conoutf("valid range for %s is %d..%d", c, id->min, id->max); + } + *id->storage = i1; + if(id->fun) ((void (__cdecl *)())id->fun)(); // call trigger function if available }; break; @@ -220,9 +214,11 @@ int execute(char *p, bool isdown) // all evaluation happens here, s_sprintfd(t)("arg%d", i); // set any arguments as (global) arg values so functions can access them alias(t, w[i]); }; - char *action = newstring(id->action); // create new string here because alias could rebind itself - val = execute(action, isdown); - delete[] action; + char *wasexecuting = id->executing; + id->executing = id->action; + val = execute(id->action); + if(id->executing!=id->action && id->executing!=wasexecuting) delete[] id->executing; + id->executing = wasexecuting; break; }; loopj(numargs) delete[] w[j]; diff --git a/source/src/console.cpp b/source/src/console.cpp index 59f164e1..680add8d 100644 --- a/source/src/console.cpp +++ b/source/src/console.cpp @@ -94,14 +94,25 @@ void renderconsole() // render buffer taking into // keymap is defined externally in keymap.cfg -struct keym { int code; char *name; char *action; } keyms[256]; -int numkm = 0; +struct keym +{ + int code; + char *name, *action; + vector releaseactions; + + ~keym() { DELETEA(name); DELETEA(action); releaseactions.deletecontentsa(); }; +}; +vector keyms; + +keym *keypressed = NULL; +char *keyaction = NULL; void keymap(char *code, char *key, char *action) { - keyms[numkm].code = atoi(code); - keyms[numkm].name = newstring(key); - keyms[numkm++].action = newstringbuf(action); + keym &km = keyms.add(); + km.code = atoi(code); + km.name = newstring(key); + km.action = newstring(action); }; COMMAND(keymap, ARG_3STR); @@ -109,9 +120,11 @@ COMMAND(keymap, ARG_3STR); void bindkey(char *key, char *action) { for(char *x = key; *x; x++) *x = toupper(*x); - loopi(numkm) if(strcmp(keyms[i].name, key)==0) + loopv(keyms) if(!strcmp(keyms[i].name, key)) { - s_strcpy(keyms[i].action, action); + keym &km = keyms[i]; + if(!keypressed || keyaction!=km.action) delete[] km.action; + km.action = newstring(action); return; }; conoutf("unknown key \"%s\"", key); @@ -119,6 +132,20 @@ void bindkey(char *key, char *action) COMMANDN(bind, bindkey, ARG_2STR); +char *addreleaseaction(char *s) +{ + if(!keypressed) return NULL; + keypressed->releaseactions.add(newstring(s)); + return keypressed->name; +}; + +void onrelease(char *s) +{ + addreleaseaction(s); +}; + +COMMAND(onrelease, ARG_1STR); + void saycommand(char *init) // turns input to the command line on or off { SDL_EnableUNICODE(saycommandon = (init!=NULL)); @@ -276,7 +303,7 @@ void keypress(int code, bool isdown, int cooked) vhistory.add(newstring(commandbuf)); // cap this? }; histpos = vhistory.length(); - if(commandbuf[0]=='/') execute(commandbuf, true); + if(commandbuf[0]=='/') execute(commandbuf); else toserver(commandbuf); }; saycommand(NULL); @@ -289,11 +316,23 @@ void keypress(int code, bool isdown, int cooked) } else if(!menukey(code, isdown)) // keystrokes go to menu { - loopi(numkm) if(keyms[i].code==code) // keystrokes go to game, lookup in keymap and execute + loopv(keyms) if(keyms[i].code==code) // keystrokes go to game, lookup in keymap and execute { - string temp; - s_strcpy(temp, keyms[i].action); - execute(temp, isdown); + keym &k = keyms[i]; + if(isdown) + { + keyaction = k.action; + keypressed = &k; + k.releaseactions.deletecontentsa(); + execute(keyaction); + keypressed = NULL; + if(keyaction!=k.action) delete[] keyaction; + } + else if(k.releaseactions.length()) + { + loopv(k.releaseactions) execute(k.releaseactions[i]); + k.releaseactions.deletecontentsa(); + }; return; }; }; diff --git a/source/src/menus.cpp b/source/src/menus.cpp index f4170d57..fef9ea92 100644 --- a/source/src/menus.cpp +++ b/source/src/menus.cpp @@ -234,7 +234,7 @@ bool menukey(int code, bool isdown) else if(menusel>=n) menusel = 0; menus[vmenu].menusel = menusel; char *haction = menus[vmenu].items[menusel].hoveraction; - if(menusel != oldmenusel && haction) execute(haction, true); + if(menusel != oldmenusel && haction) execute(haction); } else { @@ -253,7 +253,7 @@ bool menukey(int code, bool isdown) } menustack.add(vmenu); menuset(-1); - if(action) execute(action, true); + if(action) execute(action); }; }; return true; diff --git a/source/src/protos.h b/source/src/protos.h index dee87c61..d65d1c0a 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -6,7 +6,7 @@ extern void setvar(char *name, int i); extern int getvar(char *name); extern bool identexists(char *name); extern bool addcommand(char *name, void (*fun)(), int narg); -extern int execute(char *p, bool down = true); +extern int execute(char *p); extern void exec(char *cfgfile); extern bool execfile(char *cfgfile); extern void resetcomplete(); @@ -21,6 +21,7 @@ extern void rendercommand(int x, int y); extern void renderconsole(); // extern void conoutf(const char *s, int a = 0, int b = 0, int c = 0); Moved to cube.h by Rick extern char *getcurcommand(); +extern char *addreleaseaction(char *s); // menus extern bool rendermenu();