diff --git a/config/docs.cfg b/config/docs.cfg index 2ccb75a8..9cb14ef3 100644 --- a/config/docs.cfg +++ b/config/docs.cfg @@ -1,24 +1,24 @@ // auto generated script to make the command reference readable for ActionCube -// section: Editing Reference +docsection [Editing Reference] -doccommand [edittoggle] [switches between map edit mode and normal.] [(default key = e). In map edit mode you can select bits of the map by clicking or dragging your crosshair on the floor or ceiling (using the "attack" command, normally MOUSE1), then use the commands below to modify the selection. While in edit mode, physics & collision don't apply (noclip), and key repeat is ON. Note that if you fly outside the map, cube still renders the world as if you were standing on the floor directly below the camera.]; +docident [edittoggle] [switches between map edit mode and normal.] [(default key = e). In map edit mode you can select bits of the map by clicking or dragging your crosshair on the floor or ceiling (using the "attack" command, normally MOUSE1), then use the commands below to modify the selection. While in edit mode, physics & collision don't apply (noclip), and key repeat is ON. Note that if you fly outside the map, cube still renders the world as if you were standing on the floor directly below the camera.]; -doccommand [edittex] [Changes the texture on current selection by browsing through a list of textures directly shown on the cubes. ] [Default keys are the six keys above the cursor keys, which each 2 of them cycle one type (and numpad 7/4 for upper). The way this works is slightly strange at first, but allows for very fast texture assignment. All textures are in 3 individual lists for each type (both wall kinds treated the same), and each time a texture is used, it is moved to the top of the list. So after a bit of editing, all your most frequently used textures will come first when pressing these keys, and the most recently used texture is set immediately when you press the forward key for the type. These lists are saved with the map. make a selection (including wall bits) and press these keys to get a feel for what they do.]; -docargument [T] [an integer denoting the type] [floor = 0, lower or wall = 1, ceiling = 2, upper wall = 3]; -docargument [D] [D is the direction you want to cycle the textures in] [1 = forwards, -1 = backwards]; +docident [edittex] [Changes the texture on current selection by browsing through a list of textures directly shown on the cubes. ] [Default keys are the six keys above the cursor keys, which each 2 of them cycle one type (and numpad 7/4 for upper). The way this works is slightly strange at first, but allows for very fast texture assignment. All textures are in 3 individual lists for each type (both wall kinds treated the same), and each time a texture is used, it is moved to the top of the list. So after a bit of editing, all your most frequently used textures will come first when pressing these keys, and the most recently used texture is set immediately when you press the forward key for the type. These lists are saved with the map. make a selection (including wall bits) and press these keys to get a feel for what they do.]; +docargument [T] [an integer denoting the type] [0 (floor), 1 (lower or wall), 2 (ceiling), 3 (upper wall)]; +docargument [D] [the direction you want to cycle the textures in] [1 (forwards), -1 (backwards)]; -doccommand [editheight] [Changes the height of the current selection.] [Default keys are [ and ] for floor level, and o/p for ceiling.]; -docargument [T] [an integer denoting the type] [floor = 0, lower or wall = 1, ceiling = 2]; -docargument [D] [the delta value to move it in] [1 = forwards, -1 = backwards]; +docident [editheight] [Changes the height of the current selection.] [Default keys are [ and ] for floor level, and o/p for ceiling.]; +docargument [T] [an integer denoting the type] [0 (floor), 1 (lower or wall), 2 (ceiling)]; +docargument [D] [the delta value to move it in] [1 (forwards), -1 (backwards)]; -doccommand [newent] [adds a new entity] [(x,y) is determined by the current selection (the red dot corner) and z by the camera height, of said type. Type is a string giving the type of entity, such as "light", and may optionally take values (depending on the entity).]; -docargument [type] [the entity type] [light,playerstart,shells,bullets,rockets,health,ammo,clips,mapmodel,ctf-flag,ladder]; +docident [newent] [adds a new entity] [(x,y) is determined by the current selection (the red dot corner) and z by the camera height, of said type. Type is a string giving the type of entity, such as "light", and may optionally take values (depending on the entity).]; +docargument [type] [the entity type] [light, playerstart, shells, bullets, rockets, health, ammo, clips, mapmodel, ctf-flag, ladder]; docargument [value1] [see documentation: newent 'type'] []; docargument [value2] [see documentation: newent 'type'] []; docargument [value3] [see documentation: newent 'type'] []; docargument [value4] [see documentation: newent 'type'] []; -doccommand [newent light] [adds a new light entity] [if only argument R is specified, it is interpreted as brightness for white light]; +docident [newent light] [adds a new light entity] [if only argument R is specified, it is interpreted as brightness for white light]; docargument [radius] [the light radius] [1..32]; docargument [R] [red colour component. see remarks below.] [1..255]; docargument [G] [green colour component] [1..255]; diff --git a/source/src/clients2c.cpp b/source/src/clients2c.cpp index 7386d931..de711968 100644 --- a/source/src/clients2c.cpp +++ b/source/src/clients2c.cpp @@ -238,7 +238,7 @@ void parsemessages(int cn, playerent *d, ucharbuf &p) } case SV_GIBDAMAGE: gib = true; - case SV_DAMAGE: + case SV_DAMAGE: { if(!d) return; int target = getint(p); diff --git a/source/src/command.cpp b/source/src/command.cpp index 982c7149..1b6f5ca4 100644 --- a/source/src/command.cpp +++ b/source/src/command.cpp @@ -195,7 +195,7 @@ int execute(char *p) // all evaluation happens here, } break; - case ID_VAR: // game defined variabled + case ID_VAR: // game defined variables 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 %s is read-only", id->name); else @@ -365,3 +365,9 @@ void writecfg() COMMAND(writecfg, ARG_NONE); +vector identnames() +{ + vector names; + enumerateht(*idents) names.add(idents->enumc->key); + return names; +} diff --git a/source/src/docs.cpp b/source/src/docs.cpp index 3d6f104b..d0261103 100644 --- a/source/src/docs.cpp +++ b/source/src/docs.cpp @@ -2,42 +2,99 @@ #include "cube.h" +void renderdocsection(void *menu, bool init); + struct docargument { char *token, *desc, *values; }; -struct doccommand +struct docident { char *name, *desc, *remarks; vector arguments; }; -hashtable docs; -doccommand *lastdoc; - -void adddoccommand(char *name, char *desc, char *remarks) +struct docsection { - if(!name || !desc) return; + char *name; + vector idents; +}; + +vector sections; +hashtable docidents; // manage globally instead of a section tree because cmds must be unique +docsection *lastsection = NULL; +docident *lastident = NULL; + +void adddocsection(char *name) +{ + if(!name) return; + docsection &s = sections.add(); + s.name = newstring(name); + lastsection = &s; + addmenu(s.name, NULL, true, renderdocsection); +} + +void adddocident(char *name, char *desc, char *remarks) +{ + if(!name || !desc || !lastsection) return; name = newstring(name); - doccommand &c = docs[name]; + docident &c = docidents[name]; + lastsection->idents.add(&c); c.name = name; c.desc = newstring(desc); c.remarks = remarks && strlen(remarks) ? newstring(remarks) : NULL; - lastdoc = &c; + lastident = &c; } void adddocargument(char *token, char *desc, char *values) { - if(!token || !desc || !lastdoc) return; - docargument &a = lastdoc->arguments.add(); + if(!token || !desc || !lastident) return; + docargument &a = lastident->arguments.add(); a.token = newstring(token); a.desc = newstring(desc); a.values = values && strlen(values) ? newstring(values) : NULL; } -COMMANDN(doccommand, adddoccommand, ARG_3STR); +int stringsort(const char **a, const char **b) { return strcmp(*a, *b); } + +void doctodo() +{ + vector inames = identnames(); + inames.sort(stringsort); + conoutf("documentation TODO"); + conoutf("undocumented identifiers:"); + loopv(inames) if(!docidents.access(inames[i])) conoutf(inames[i]); + conoutf("documented but unimplemented identifiers:"); + enumerateht(docidents) if(!strchr(docidents.enumc->data.name, ' ') && !identexists(docidents.enumc->data.name)) + conoutf(docidents.enumc->data.name); + conoutf("done"); +} + +void docfind(char *search) +{ + enumerateht(docidents) + { + docident &i = docidents.enumc->data; + char *searchstrings[] = { i.name, i.desc, i.remarks }; + loopi(3) + { + char *r = strstr(searchstrings[i], search); + if(!r) continue; + const int matchchars = 200; + string match; + s_strncpy(match, r-searchstrings[i] > matchchars/2 ? r-matchchars/2 : searchstrings[i], matchchars/2); + conoutf("%s\t%s", docidents.enumc->data, match); + break; + } + } +} + +COMMANDN(docsection, adddocsection, ARG_1STR); +COMMANDN(docident, adddocident, ARG_3STR); COMMANDN(docargument, adddocargument, ARG_3STR); +COMMAND(doctodo, ARG_NONE); +COMMAND(docfind, ARG_1STR); VAR(loaddoc, 0, 1, 1); int numargs(char *args) @@ -78,7 +135,7 @@ void renderdoc(int x, int y) { string cmd; s_strncpy(cmd, c, clen-i+1); - doccommand *doc = docs.access(cmd); + docident *doc = docidents.access(cmd); if(doc) { const int doclinewidth = (VIRTW*2)/FONTH; @@ -118,7 +175,13 @@ void renderdoc(int x, int y) arg = numargs(args); } } - else arg = numargs(args); + else arg = numargs(args); + + if(arg >= 0) + { + char *c = cmd; + while((c = strchr(c, ' ')) && c++) arg--; // multipart idents need a fixed argument offset + } } loopv(doc->arguments) @@ -141,3 +204,42 @@ void renderdoc(int x, int y) } } +void *docmenu = NULL; + +struct msection { char *name; string cmd; }; + +int msectionsort(const msection *a, const msection *b) +{ + return strcmp(a->name, b->name); +} + +void renderdocsection(void *menu, bool init) +{ + struct msection { char *name; string cmd; }; + static vector msections; + msections.setsize(0); + + enumerateht(docidents) + { + msection &s = msections.add(); + s.name = docidents.enumc->key; + s_sprintf(s.cmd)("saycommand [/%s ]", docidents.enumc->key); + } + msections.sort(msectionsort); + loopv(msections) { menumanual(menu, i, msections[i].name, msections[i].cmd); } +} + +void renderdocmenu(void *menu, bool init) +{ + struct action { string cmd; }; + static vector actions; + actions.setsize(0); + + loopv(sections) + { + action &a = actions.add(); + s_sprintf(a.cmd)("showmenu [%s]", sections[i].name); + menumanual(menu, i, sections[i].name, a.cmd); + } +} + diff --git a/source/src/main.cpp b/source/src/main.cpp index 72903c4e..1038096c 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -254,13 +254,14 @@ int main(int argc, char **argv) initsound(); initlog("cfg"); - extern void *scoremenu, *teammenu, *ctfmenu, *servmenu, *kickmenu, *banmenu; + extern void *scoremenu, *teammenu, *ctfmenu, *servmenu, *kickmenu, *banmenu, *docmenu; scoremenu = addmenu("score", "frags\tpj\tping\tname\tcn", false, renderscores); teammenu = addmenu("team score", "frags\tpj\tping\tteam\tname\tcn", false, renderscores); ctfmenu = addmenu("ctf score", "flags\tfrags\tpj\tping\tteam\tname\tcn", false, renderscores); servmenu = addmenu("server", "ping\tplr\tserver", true, refreshservers); kickmenu = addmenu("kick player", NULL, true, refreshmastermenu); banmenu = addmenu("ban player", NULL, true, refreshmastermenu); + docmenu = addmenu("reference", NULL, true, renderdocmenu); persistidents = false; exec("config/keymap.cfg"); diff --git a/source/src/protocol.cpp b/source/src/protocol.cpp index d11da2d9..6f4aadee 100644 --- a/source/src/protocol.cpp +++ b/source/src/protocol.cpp @@ -76,8 +76,8 @@ void getstring(char *text, ucharbuf &p, int len) const char *modenames[] = { - "team deathmatch", "coopedit", "deathmatch", "survior", - "team survior", "ctf", "pistol frenzy", "bot team deathmatch", "bot deathmatch", "last swiss standing", + "team deathmatch", "coopedit", "deathmatch", "survivor", + "team survivor", "ctf", "pistol frenzy", "bot team deathmatch", "bot deathmatch", "last swiss standing", "one shot, one kill", "team one shot, one kill", "bot one shot, one skill" }; diff --git a/source/src/protos.h b/source/src/protos.h index 8744563d..a6423bec 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -15,6 +15,7 @@ extern void complete(char *s); extern void alias(char *name, char *action); extern char *getalias(char *name); extern void writecfg(); +extern vector identnames(); // console extern void keypress(int code, bool isdown, int cooked); @@ -335,4 +336,5 @@ extern PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3f_; // docs extern void renderdoc(int x, int y); +extern void renderdocmenu(void *menu, bool init); diff --git a/source/src/serverms.cpp b/source/src/serverms.cpp index 08541763..03eac385 100644 --- a/source/src/serverms.cpp +++ b/source/src/serverms.cpp @@ -78,7 +78,8 @@ void updatemasterserver(int seconds) if(seconds>updmaster) // send alive signal to masterserver every hour of uptime { s_sprintfd(path)("%sregister.do?action=add", masterpath); - httpgetsend(masterserver, masterbase, path, "actioncubeserver", "ActionCube Server"); + s_sprintfd(agent)("ActionCube Server %d", getvar("version")); + httpgetsend(masterserver, masterbase, path, "actioncubeserver", agent); masterrep[0] = 0; masterb.data = masterrep; masterb.dataLength = MAXTRANS-1; @@ -96,7 +97,8 @@ void checkmasterreply() uchar *retrieveservers(uchar *buf, int buflen) { s_sprintfd(path)("%sretrieve.do?item=list", masterpath); - httpgetsend(masterserver, masterbase, path, "actioncubeserver", "ActionCube Server"); + s_sprintfd(agent)("ActionCube Client %d", getvar("version")); + httpgetsend(masterserver, masterbase, path, "actioncubeclient", agent); ENetBuffer eb; buf[0] = 0; eb.data = buf; diff --git a/source/src/tools.h b/source/src/tools.h index 087a970a..66d93912 100644 --- a/source/src/tools.h +++ b/source/src/tools.h @@ -450,8 +450,9 @@ template struct hashtable } }; -#define enumeratekt(ht,k,e,t,f,b) loopi((ht).size) for(hashtable::chain *enumc = (ht).table[i]; enumc; enumc = enumc->next) { hashtable::const_key &e = enumc->key; t &f = enumc->data; b; } +#define enumeratekt(ht,k,e,t,f,b) loopi((ht).size) for(hashtable::chain *enumc = (ht).table[i]; enumc; enumc = enumc->next) { hashtable::const_key &e = enumc->key; t &f = enumc->data; b; } #define enumerate(ht,t,e,b) loopi((ht).size) for((ht).enumc = (ht).table[i]; (ht).enumc; (ht).enumc = (ht).enumc->next) { t &e = (ht).enumc->data; b; } +#define enumerateht(ht) loopi((ht).size) for((ht).enumc = (ht).table[i]; (ht).enumc; (ht).enumc = (ht).enumc->next) inline char *newstring(size_t l) { return new char[l+1]; } inline char *newstring(const char *s, size_t l) { return s_strncpy(newstring(l), s, l+1); } diff --git a/source/src/weapon.cpp b/source/src/weapon.cpp index 2be8bf89..c828f082 100644 --- a/source/src/weapon.cpp +++ b/source/src/weapon.cpp @@ -624,7 +624,7 @@ void raydamage(vec &from, vec &to, playerent *d) hitpush(i, gdam, o, d, from, to, gib); shorten(from, o->o, to); } -} +} void spreadandrecoil(vec &from, vec &to, playerent *d) {