Index: src/Cube.mm ================================================================== --- src/Cube.mm +++ src/Cube.mm @@ -200,20 +200,20 @@ log("sound"); initsound(); log("cfg"); - newmenu("frags\tpj\tping\tteam\tname"); - newmenu("ping\tplr\tserver"); - exec("data/keymap.cfg"); - exec("data/menus.cfg"); - exec("data/prefabs.cfg"); - exec("data/sounds.cfg"); - exec("servers.cfg"); - if (!execfile("config.cfg")) - execfile("data/defaults.cfg"); - exec("autoexec.cfg"); + newmenu(@"frags\tpj\tping\tteam\tname"); + newmenu(@"ping\tplr\tserver"); + exec(@"data/keymap.cfg"); + exec(@"data/menus.cfg"); + exec(@"data/prefabs.cfg"); + exec(@"data/sounds.cfg"); + exec(@"servers.cfg"); + if (!execfile(@"config.cfg")) + execfile(@"data/defaults.cfg"); + exec(@"autoexec.cfg"); log("localconnect"); localconnect(); // if this map is changed, also change depthcorrect() changemap(@"metl3"); Index: src/client.mm ================================================================== --- src/client.mm +++ src/client.mm @@ -55,55 +55,61 @@ enet_peer_throttle_configure(clienthost->peers, throttle_interval * 1000, throttle_accel, throttle_decel); } void -newname(char *name) -{ - c2sinit = false; - strn0cpy(player1->name, name, 16); -} - -void -newteam(char *name) -{ - c2sinit = false; - strn0cpy(player1->team, name, 5); -} - -COMMANDN(team, newteam, ARG_1CSTR) -COMMANDN(name, newname, ARG_1CSTR) +newname(OFString *name) +{ + c2sinit = false; + @autoreleasepool { + strn0cpy(player1->name, name.UTF8String, 16); + } +} +COMMANDN(name, newname, ARG_1STR) + +void +newteam(OFString *name) +{ + c2sinit = false; + @autoreleasepool { + strn0cpy(player1->team, name.UTF8String, 5); + } +} +COMMANDN(team, newteam, ARG_1STR) void writeclientinfo(FILE *f) { fprintf(f, "name \"%s\"\nteam \"%s\"\n", player1->name, player1->team); } void -connects(char *servername) -{ - disconnect(1); // reset state - addserver(servername); - - conoutf(@"attempting to connect to %s", servername); - ENetAddress address = {ENET_HOST_ANY, CUBE_SERVER_PORT}; - if (enet_address_set_host(&address, servername) < 0) { - conoutf(@"could not resolve server %s", servername); - return; - }; - - clienthost = enet_host_create(NULL, 1, rate, rate); - - if (clienthost) { - enet_host_connect(clienthost, &address, 1); - enet_host_flush(clienthost); - connecting = lastmillis; - connattempts = 0; - } else { - conoutf(@"could not connect to server"); - disconnect(); +connects(OFString *servername) +{ + @autoreleasepool { + disconnect(1); // reset state + addserver(servername); + + conoutf(@"attempting to connect to %s", servername.UTF8String); + ENetAddress address = {ENET_HOST_ANY, CUBE_SERVER_PORT}; + if (enet_address_set_host(&address, servername.UTF8String) < + 0) { + conoutf(@"could not resolve server %s", servername); + return; + } + + clienthost = enet_host_create(NULL, 1, rate, rate); + + if (clienthost) { + enet_host_connect(clienthost, &address, 1); + enet_host_flush(clienthost); + connecting = lastmillis; + connattempts = 0; + } else { + conoutf(@"could not connect to server"); + disconnect(); + } } } void disconnect(int onlyclean, int async) @@ -171,11 +177,11 @@ conoutf(@"%s", text); } COMMAND(echo, ARG_VARI) COMMANDN(say, toserver, ARG_VARI) -COMMANDN(connect, connects, ARG_1CSTR) +COMMANDN(connect, connects, ARG_1STR) COMMANDN(disconnect, trydisconnect, ARG_NONE) // collect c2s messages conveniently vector messages; @@ -216,15 +222,17 @@ bool senditemstoserver = false; // after a map change, since server doesn't have map data string clientpassword; void -password(char *p) +password(OFString *p) { - strcpy_s(clientpassword, p); + @autoreleasepool { + strcpy_s(clientpassword, p.UTF8String); + } } -COMMAND(password, ARG_1CSTR) +COMMAND(password, ARG_1STR) bool netmapstart() { senditemstoserver = true; @@ -235,12 +243,12 @@ initclientnet() { ctext[0] = 0; toservermap = @""; clientpassword[0] = 0; - newname("unnamed"); - newteam("red"); + newname(@"unnamed"); + newteam(@"red"); } void sendpackettoserv(void *packet) { Index: src/clientextras.mm ================================================================== --- src/clientextras.mm +++ src/clientextras.mm @@ -11,11 +11,11 @@ int frame[] = {178, 184, 190, 137, 183, 189, 197, 164, 46, 51, 54, 32, 0, 0, 40, 1, 162, 162, 67, 168}; int range[] = {6, 6, 8, 28, 1, 1, 1, 1, 8, 19, 4, 18, 40, 1, 6, 15, 1, 1, 1, 1}; void -renderclient(dynent *d, bool team, char *mdlname, bool hellpig, float scale) +renderclient(dynent *d, bool team, OFString *mdlname, bool hellpig, float scale) { int n = 3; float speed = 100.0f; float mz = d->o.z - d->eyeheight + 1.55f * scale; int basetime = -((intptr_t)d & 0xFFF); @@ -25,11 +25,11 @@ n = 2; r = range[3]; } else { n = (intptr_t)d % 3; r = range[n]; - }; + } basetime = d->lastaction; int t = lastmillis - d->lastaction; if (t < 0 || t > 20000) return; if (t > (r - 1) * 100) { @@ -59,31 +59,31 @@ } else { n = 14; speed = 1200 / d->maxspeed * scale; if (hellpig) speed = 300 / d->maxspeed; - }; + } if (hellpig) { n++; scale *= 32; mz -= 1.9f; - }; + } rendermodel(mdlname, frame[n], range[n], 0, 1.5f, d->o.x, mz, d->o.y, d->yaw + 90, d->pitch / 2, team, scale, speed, 0, basetime); -}; +} extern int democlientnum; void renderclients() { dynent *d; loopv(players) if ((d = players[i]) && (!demoplayback || i != democlientnum)) - renderclient( - d, isteam(player1->team, d->team), "monster/ogro", false, 1.0f); -}; + renderclient(d, isteam(player1->team, d->team), @"monster/ogro", + false, 1.0f); +} // creation of scoreboard pseudo-menu bool scoreson = false; @@ -159,30 +159,31 @@ }; // sendmap/getmap commands, should be replaced by more intuitive map downloading void -sendmap(const char *mapname) +sendmap(OFString *mapname) { @autoreleasepool { - if (*mapname) + if (mapname.length > 0) save_world(mapname); - changemap(@(mapname)); - mapname = getclientmap().UTF8String; + changemap(mapname); + mapname = getclientmap(); int mapsize; - uchar *mapdata = readmap(mapname, &mapsize); + uchar *mapdata = readmap(mapname.UTF8String, &mapsize); if (!mapdata) return; ENetPacket *packet = enet_packet_create( NULL, MAXTRANS + mapsize, ENET_PACKET_FLAG_RELIABLE); uchar *start = packet->data; uchar *p = start + 2; putint(p, SV_SENDMAP); - sendstring(mapname, p); + sendstring(mapname.UTF8String, p); putint(p, mapsize); if (65535 - (p - start) < mapsize) { - conoutf(@"map %s is too large to send", mapname); + conoutf( + @"map %s is too large to send", mapname.UTF8String); free(mapdata); enet_packet_destroy(packet); return; }; memcpy(p, mapdata, mapsize); @@ -189,14 +190,14 @@ p += mapsize; free(mapdata); *(ushort *)start = ENET_HOST_TO_NET_16(p - start); enet_packet_resize(packet, p - start); sendpackettoserv(packet); - conoutf(@"sending map %s to server...", mapname); + conoutf(@"sending map %s to server...", mapname.UTF8String); sprintf_sd(msg)( "[map %s uploaded to server, \"getmap\" to receive it]", - mapname); + mapname.UTF8String); toserver(msg); } } void @@ -211,7 +212,7 @@ enet_packet_resize(packet, p - start); sendpackettoserv(packet); conoutf(@"requesting map from server..."); } -COMMAND(sendmap, ARG_1CSTR) +COMMAND(sendmap, ARG_1STR) COMMAND(getmap, ARG_NONE) Index: src/clientgame.mm ================================================================== --- src/clientgame.mm +++ src/clientgame.mm @@ -1,8 +1,10 @@ // clientgame.cpp: core game related stuff #include "cube.h" + +#include int nextmode = 0; // nextmode becomes gamemode after next map load VAR(gamemode, 1, 0, 0); void @@ -229,28 +231,32 @@ respawnself(); } } int sleepwait = 0; -string sleepcmd; +static OFString *sleepcmd = nil; void -sleepf(char *msec, char *cmd) +sleepf(OFString *msec, OFString *cmd) { - sleepwait = atoi(msec) + lastmillis; - strcpy_s(sleepcmd, cmd); -}; + sleepwait = (int)msec.longLongValue + lastmillis; + sleepcmd = cmd; +} COMMANDN(sleep, sleepf, ARG_2STR) void updateworld(int millis) // main game update loop { if (lastmillis) { curtime = millis - lastmillis; if (sleepwait && lastmillis > sleepwait) { sleepwait = 0; - execute(sleepcmd); - }; + @autoreleasepool { + std::unique_ptr cmd( + strdup(sleepcmd.UTF8String)); + execute(cmd.get()); + } + } physicsframe(); checkquad(curtime); if (m_arena) arenarespawn(); moveprojectiles((float)curtime); @@ -506,15 +512,15 @@ @autoreleasepool { clientmap = @(name); } if (editmode) toggleedit(); - setvar("gamespeed", 100); - setvar("fog", 180); - setvar("fogcolour", 0x8099B3); + setvar(@"gamespeed", 100); + setvar(@"fog", 180); + setvar(@"fogcolour", 0x8099B3); showscores(false); intermission = false; framesinmap = 0; conoutf(@"game mode is %s", modestr(gamemode)); } COMMANDN(map, changemap, ARG_1STR) Index: src/command.mm ================================================================== --- src/command.mm +++ src/command.mm @@ -1,9 +1,11 @@ // command.cpp: implements the parsing and execution of a tiny script language // which is largely backwards compatible with the quake console language. #include "cube.h" + +#include enum { ID_VAR, ID_COMMAND, ID_ALIAS }; @interface Ident : OFObject @property (nonatomic) int type; // one of ID_* above @@ -34,81 +36,69 @@ // contains ALL vars/commands/aliases OFMutableDictionary *idents; void -alias(char *name, char *action) -{ - @autoreleasepool { - Ident *b = idents[@(name)]; - - if (!b) { - Ident *b = [[Ident alloc] init]; - b.type = ID_ALIAS; - b.name = @(name); - b.action = @(action); - b.persist = true; - - idents[b.name] = b; - } else { - if (b.type == ID_ALIAS) - b.action = @(action); - else - conoutf( - @"cannot redefine builtin %s with an alias", - name); - } - } -} - +alias(OFString *name, OFString *action) +{ + Ident *b = idents[name]; + + if (b == nil) { + Ident *b = [[Ident alloc] init]; + b.type = ID_ALIAS; + b.name = name; + b.action = action; + b.persist = true; + + idents[b.name] = b; + } else { + if (b.type == ID_ALIAS) + b.action = action; + else + conoutf( + @"cannot redefine builtin %s with an alias", name.UTF8String); + } +} COMMAND(alias, ARG_2STR) int -variable(char *name, int min, int cur, int max, int *storage, void (*fun)(), +variable(OFString *name, int min, int cur, int max, int *storage, void (*fun)(), bool persist) { if (idents == nil) idents = [[OFMutableDictionary alloc] init]; - @autoreleasepool { - Ident *v = [[Ident alloc] init]; - v.type = ID_VAR; - v.name = @(name); - v.min = min; - v.max = max; - v.storage = storage; - v.fun = fun; - v.persist = persist; - - idents[v.name] = v; - } + Ident *v = [[Ident alloc] init]; + v.type = ID_VAR; + v.name = name; + v.min = min; + v.max = max; + v.storage = storage; + v.fun = fun; + v.persist = persist; + + idents[name] = v; return cur; } void -setvar(char *name, int i) +setvar(OFString *name, int i) { - @autoreleasepool { - *idents[@(name)].storage = i; - } + *idents[name].storage = i; } int -getvar(char *name) +getvar(OFString *name) { - @autoreleasepool { - return *idents[@(name)].storage; - } + return *idents[name].storage; } bool -identexists(char *name) +identexists(OFString *name) { - @autoreleasepool { - return (idents[@(name)] != nil); - } + return (idents[name] != nil); } OFString * getalias(OFString *name) { @@ -294,38 +284,67 @@ case ARG_NONE: if (isdown) ((void(__cdecl *)()) ID.fun)(); break; - case ARG_1CSTR: - if (isdown) - ((void(__cdecl *)( - char *))ID.fun)( - w[1]); + case ARG_1STR: + if (isdown) { + @autoreleasepool { + ((void( + __cdecl *)( + OFString *)) + ID.fun)( + @(w[1])); + } + } break; case ARG_2STR: - if (isdown) - ((void(__cdecl *)( - char *, - char *))ID.fun)( - w[1], w[2]); + if (isdown) { + @autoreleasepool { + ((void( + __cdecl *)( + OFString *, + OFString *)) + 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]); + if (isdown) { + @autoreleasepool { + ((void( + __cdecl *)( + OFString *, + OFString *, + OFString *)) + 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]); + if (isdown) { + @autoreleasepool { + ((void( + __cdecl *)( + OFString *, + OFString *, + OFString *, + OFString *, + OFString *)) + ID.fun)( + @(w[1]), + @(w[2]), + @(w[3]), + @(w[4]), + @(w[5])); + } + } break; case ARG_DOWN: ((void(__cdecl *)(bool))ID.fun)( isdown); break; @@ -381,21 +400,10 @@ } ((void(__cdecl *)( char *))ID.fun)(r); break; } - case ARG_1STR: - if (isdown) { - @autoreleasepool { - ((void( - __cdecl *)( - OFString *)) - ID.fun)( - @(w[1])); - } - } - break; } break; // game defined variables case ID_VAR: @@ -477,15 +485,20 @@ // alias, also used as functions and (global) // variables case ID_ALIAS: for (int i = 1; i < numargs; i++) { - // set any arguments as - // (global) arg values so - // functions can access them - sprintf_sd(t)("arg%d", i); - alias(t, w[i]); + @autoreleasepool { + // set any arguments as + // (global) arg values + // so functions can + // access them + OFString *t = [OFString + stringWithFormat: + @"arg%d", i]; + alias(t, @(w[i])); + } } // create new string here because alias // could rebind itself char *action = newstring(ID.action.UTF8String); @@ -539,27 +552,32 @@ if (completeidx >= idx) completeidx = 0; } bool -execfile(char *cfgfile) -{ - string s; - strcpy_s(s, cfgfile); - char *buf = loadfile(path(s), NULL); - if (!buf) - return false; - execute(buf); - free(buf); - return true; +execfile(OFString *cfgfile) +{ + @autoreleasepool { + string s; + strcpy_s(s, cfgfile.UTF8String); + char *buf = loadfile(path(s), NULL); + if (!buf) + return false; + execute(buf); + free(buf); + return true; + } } void -exec(char *cfgfile) +exec(OFString *cfgfile) { - if (!execfile(cfgfile)) - conoutf(@"could not read \"%s\"", cfgfile); + if (!execfile(cfgfile)) { + @autoreleasepool { + conoutf(@"could not read \"%s\"", cfgfile.UTF8String); + } + } } void writecfg() { @@ -598,40 +616,54 @@ // below the commands that implement a small imperative language. thanks to the // semantics of // () and [] expressions, any control construct can be defined trivially. void -intset(char *name, int v) -{ - string b; - itoa(b, v); - alias(name, b); -} - -void -ifthen(char *cond, char *thenp, char *elsep) -{ - execute(cond[0] != '0' ? thenp : elsep); -} - -void -loopa(char *times, char *body) -{ - int t = atoi(times); - loopi(t) - { - intset("i", i); - execute(body); - } -} - -void -whilea(char *cond, char *body) -{ - while (execute(cond)) - execute(body); -} // can't get any simpler than this :) +intset(OFString *name, int v) +{ + @autoreleasepool { + alias(name, [OFString stringWithFormat:@"%d", v]); + } +} + +void +ifthen(OFString *cond, OFString *thenp, OFString *elsep) +{ + @autoreleasepool { + std::unique_ptr cmd(strdup( + (cond.UTF8String[0] != '0' ? thenp : elsep).UTF8String)); + + execute(cmd.get()); + } +} + +void +loopa(OFString *times, OFString *body_) +{ + @autoreleasepool { + int t = (int)times.longLongValue; + std::unique_ptr body(strdup(body_.UTF8String)); + + loopi(t) + { + intset(@"i", i); + execute(body.get()); + } + } +} + +void +whilea(OFString *cond_, OFString *body_) +{ + @autoreleasepool { + std::unique_ptr cond(strdup(cond_.UTF8String)); + std::unique_ptr body(strdup(body_.UTF8String)); + + while (execute(cond.get())) + execute(body.get()); + } +} void onrelease(bool on, char *body) { if (!on) @@ -639,11 +671,13 @@ } void concat(char *s) { - alias("s", s); + @autoreleasepool { + alias(@"s", @(s)); + } } void concatword(char *s) { @@ -664,23 +698,28 @@ n++; return n + 1; } void -at(char *s, char *pos) +at(OFString *s_, OFString *pos) { - int n = atoi(pos); - loopi(n) s += strspn(s += strcspn(s, " \0"), " "); - s[strcspn(s, " \0")] = 0; - concat(s); + @autoreleasepool { + int n = (int)pos.longLongValue; + std::unique_ptr copy(strdup(s_.UTF8String)); + char *s = copy.get(); + + loopi(n) s += strspn(s += strcspn(s, " \0"), " "); + s[strcspn(s, " \0")] = 0; + concat(s); + } } COMMANDN(loop, loopa, ARG_2STR) COMMANDN(while, whilea, ARG_2STR) COMMANDN(if, ifthen, ARG_3STR) COMMAND(onrelease, ARG_DWN1) -COMMAND(exec, ARG_1CSTR) +COMMAND(exec, ARG_1STR) COMMAND(concat, ARG_VARI) COMMAND(concatword, ARG_VARI) COMMAND(at, ARG_2STR) COMMAND(listlen, ARG_1EST) Index: src/console.mm ================================================================== --- src/console.mm +++ src/console.mm @@ -1,9 +1,11 @@ // console.cpp: the console buffer, its display, and command line control #include "cube.h" + #include +#include struct cline { char *cref; int outtime; }; @@ -92,29 +94,34 @@ char *action; } keyms[256]; int numkm = 0; void -keymap(char *code, char *key, char *action) +keymap(OFString *code, OFString *key, OFString *action) { - keyms[numkm].code = atoi(code); - keyms[numkm].name = newstring(key); - keyms[numkm++].action = newstringbuf(action); + @autoreleasepool { + keyms[numkm].code = (int)code.longLongValue; + keyms[numkm].name = newstring(key.UTF8String); + keyms[numkm++].action = newstringbuf(action.UTF8String); + } } 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) - { - strcpy_s(keyms[i].action, action); - return; - }; - conoutf(@"unknown key \"%s\"", key); +bindkey(OFString *key_, OFString *action) +{ + @autoreleasepool { + std::unique_ptr key(strdup(key_.UTF8String)); + for (char *x = key.get(); *x; x++) + *x = toupper(*x); + loopi(numkm) if (strcmp(keyms[i].name, key.get()) == 0) + { + strcpy_s(keyms[i].action, action.UTF8String); + return; + } + conoutf(@"unknown key \"%s\"", key.get()); + } } COMMANDN(bind, bindkey, ARG_2STR) void saycommand(char *init) // turns input to the command line on or off @@ -123,20 +130,21 @@ if (!editmode) keyrepeat(saycommandon); if (!init) init = ""; strcpy_s(commandbuf, init); -}; +} +COMMAND(saycommand, ARG_VARI) void -mapmsg(char *s) +mapmsg(OFString *s) { - strn0cpy(hdr.maptitle, s, 128); + @autoreleasepool { + strn0cpy(hdr.maptitle, s.UTF8String, 128); + } } - -COMMAND(saycommand, ARG_VARI) -COMMAND(mapmsg, ARG_1CSTR) +COMMAND(mapmsg, ARG_1STR) #ifndef _WIN32 # include # include #endif Index: src/cube.h ================================================================== --- src/cube.h +++ src/cube.h @@ -108,11 +108,11 @@ struct block { int x, y, xs, ys; }; struct mapmodelinfo { int rad, h, zoff, snap; - char *name; + const char *name; }; enum { GUN_FIST = 0, GUN_SG, @@ -377,22 +377,21 @@ ARG_1INT, ARG_2INT, ARG_3INT, ARG_4INT, ARG_NONE, - ARG_1CSTR, + ARG_1STR, ARG_2STR, ARG_3STR, ARG_5STR, ARG_DOWN, ARG_DWN1, ARG_1EXP, ARG_2EXP, ARG_1EST, ARG_2EST, - ARG_VARI, - ARG_1STR + ARG_VARI }; // nasty macros for registering script functions, abuses globals to avoid // excessive infrastructure #define COMMANDN(name, fun, nargs) \ @@ -406,31 +405,31 @@ #define VARP(name, min, cur, max) \ int name; \ OF_CONSTRUCTOR() \ { \ enqueueInit(^{ \ - name = \ - variable(#name, min, cur, max, &name, NULL, true); \ + name = variable( \ + @ #name, min, cur, max, &name, NULL, true); \ }); \ } #define VAR(name, min, cur, max) \ int name; \ OF_CONSTRUCTOR() \ { \ enqueueInit(^{ \ name = variable( \ - #name, min, cur, max, &name, NULL, false); \ + @ #name, min, cur, max, &name, NULL, false); \ }); \ } #define VARF(name, min, cur, max, body) \ void var_##name(); \ static int name; \ OF_CONSTRUCTOR() \ { \ enqueueInit(^{ \ name = variable( \ - #name, min, cur, max, &name, var_##name, false); \ + @ #name, min, cur, max, &name, var_##name, false); \ }); \ } \ void var_##name() { body; } #define VARFP(name, min, cur, max, body) \ void var_##name(); \ @@ -437,11 +436,11 @@ static int name; \ OF_CONSTRUCTOR() \ { \ enqueueInit(^{ \ name = variable( \ - #name, min, cur, max, &name, var_##name, true); \ + @ #name, min, cur, max, &name, var_##name, true); \ }); \ } \ void var_##name() { body; } #define ATOI(s) strtol(s, NULL, 0) // supports hexadecimal numbers Index: src/editing.mm ================================================================== --- src/editing.mm +++ src/editing.mm @@ -7,16 +7,23 @@ // the current selection, used by almost all editing commands // invariant: all code assumes that these are kept inside MINBORD distance of // the edge of the map -block sel = { - variable("selx", 0, 0, 4096, &sel.x, NULL, false), - variable("sely", 0, 0, 4096, &sel.y, NULL, false), - variable("selxs", 0, 0, 4096, &sel.xs, NULL, false), - variable("selys", 0, 0, 4096, &sel.ys, NULL, false), -}; +block sel; + +OF_CONSTRUCTOR() +{ + enqueueInit(^{ + sel = { + variable(@"selx", 0, 0, 4096, &sel.x, NULL, false), + variable(@"sely", 0, 0, 4096, &sel.y, NULL, false), + variable(@"selxs", 0, 0, 4096, &sel.xs, NULL, false), + variable(@"selys", 0, 0, 4096, &sel.ys, NULL, false), + }; + }); +} int selh = 0; bool selset = false; #define loopselxy(b) \ @@ -591,16 +598,19 @@ EDITSELMP; loopselxy(s->tag = tag); }; void -newent(char *what, char *a1, char *a2, char *a3, char *a4) +newent(OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4) { EDITSEL; - newentity(sel.x, sel.y, (int)player1->o.z, what, ATOI(a1), ATOI(a2), - ATOI(a3), ATOI(a4)); -}; + @autoreleasepool { + newentity(sel.x, sel.y, (int)player1->o.z, what, + (int)a1.longLongValue, (int)a2.longLongValue, + (int)a3.longLongValue, (int)a4.longLongValue); + } +} COMMANDN(select, selectpos, ARG_4INT) COMMAND(edittag, ARG_1INT) COMMAND(replace, ARG_NONE) COMMAND(archvertex, ARG_3INT) Index: src/entities.mm ================================================================== --- src/entities.mm +++ src/entities.mm @@ -2,27 +2,27 @@ #include "cube.h" vector ents; -char *entmdlnames[] = { - "shells", - "bullets", - "rockets", - "rrounds", - "health", - "boost", - "g_armour", - "y_armour", - "quad", - "teleporter", +static OFString *entmdlnames[] = { + @"shells", + @"bullets", + @"rockets", + @"rrounds", + @"health", + @"boost", + @"g_armour", + @"y_armour", + @"quad", + @"teleporter", }; int triggertime = 0; void -renderent(entity &e, char *mdlname, float z, float yaw, int frame = 0, +renderent(entity &e, OFString *mdlname, float z, float yaw, int frame = 0, int numf = 1, int basetime = 0, float speed = 10.0f) { rendermodel(mdlname, frame, numf, 0, 1.1f, e.x, z + S(e.x, e.y)->floor, e.y, yaw, 0, false, 1.0f, speed, 0, basetime); }; @@ -37,15 +37,19 @@ entity &e = ents[i]; if (e.type == MAPMODEL) { mapmodelinfo *mmi = getmminfo(e.attr2); if (!mmi) continue; - rendermodel(mmi->name, 0, 1, e.attr4, (float)mmi->rad, - e.x, - (float)S(e.x, e.y)->floor + mmi->zoff + e.attr3, - e.y, (float)((e.attr1 + 7) - (e.attr1 + 7) % 15), 0, - false, 1.0f, 10.0f, mmi->snap); + @autoreleasepool { + rendermodel(@(mmi->name), 0, 1, e.attr4, + (float)mmi->rad, e.x, + (float)S(e.x, e.y)->floor + mmi->zoff + + e.attr3, + e.y, + (float)((e.attr1 + 7) - (e.attr1 + 7) % 15), + 0, false, 1.0f, 10.0f, mmi->snap); + } } else { if (OUTBORD(e.x, e.y)) continue; if (e.type != CARROT) { if (!e.spawned && e.type != TELEPORT) @@ -65,28 +69,28 @@ case 2: case 0: if (!e.spawned) continue; - renderent(e, "carrot", + renderent(e, @"carrot", (float)(1 + sin(lastmillis / 100.0 + e.x + e.y) / 20), lastmillis / (e.attr2 ? 1.0f : 10.0f)); break; case 4: - renderent(e, "switch2", 3, + renderent(e, @"switch2", 3, (float)e.attr3 * 90, (!e.spawned && !triggertime) ? 1 : 0, (e.spawned || !triggertime) ? 1 : 2, triggertime, 1050.0f); break; case 5: - renderent(e, "switch1", -0.15f, + renderent(e, @"switch1", -0.15f, (float)e.attr3 * 90, (!e.spawned && !triggertime) ? 30 : 0, (e.spawned || !triggertime) ? 1 : 30, Index: src/menus.mm ================================================================== --- src/menus.mm +++ src/menus.mm @@ -24,21 +24,25 @@ { if ((vmenu = menu) >= 1) resetmovement(player1); if (vmenu == 1) menus[1].menusel = 0; -}; +} void -showmenu(char *name) -{ - loopv(menus) if (i > 1 && strcmp(menus[i].name, name) == 0) - { - menuset(i); - return; - }; -}; +showmenu(OFString *name_) +{ + @autoreleasepool { + const char *name = name_.UTF8String; + loopv(menus) if (i > 1 && strcmp(menus[i].name, name) == 0) + { + menuset(i); + return; + } + } +} +COMMAND(showmenu, ARG_1STR) int menucompare(mitem *a, mitem *b) { int x = atoi(a->text); @@ -101,16 +105,19 @@ }; return true; }; void -newmenu(char *name) +newmenu(OFString *name) { - gmenu &menu = menus.add(); - menu.name = newstring(name); - menu.menusel = 0; -}; + @autoreleasepool { + gmenu &menu = menus.add(); + menu.name = newstring(name.UTF8String); + menu.menusel = 0; + } +} +COMMAND(newmenu, ARG_1STR) void menumanual(int m, int n, char *text) { if (!n) @@ -119,22 +126,22 @@ mitem.text = text; mitem.action = ""; } void -menuitem(char *text, char *action) +menuitem(OFString *text, OFString *action) { - gmenu &menu = menus.last(); - mitem &mi = menu.items.add(); - mi.text = newstring(text); - mi.action = action[0] ? newstring(action) : mi.text; + @autoreleasepool { + gmenu &menu = menus.last(); + mitem &mi = menu.items.add(); + mi.text = newstring(text.UTF8String); + mi.action = + action.length > 0 ? newstring(action.UTF8String) : mi.text; + } } COMMAND(menuitem, ARG_2STR) -COMMAND(showmenu, ARG_1CSTR) -COMMAND(newmenu, ARG_1CSTR) - bool menukey(int code, bool isdown) { if (vmenu <= 0) return false; @@ -156,14 +163,17 @@ menusel = 0; menus[vmenu].menusel = menusel; } else { if (code == SDLK_RETURN || code == -2) { char *action = menus[vmenu].items[menusel].action; - if (vmenu == 1) - connects(getservername(menusel)); + if (vmenu == 1) { + @autoreleasepool { + connects(@(getservername(menusel))); + } + } menustack.add(vmenu); menuset(-1); execute(action, true); - }; - }; + } + } return true; }; Index: src/monster.mm ================================================================== --- src/monster.mm +++ src/monster.mm @@ -24,39 +24,39 @@ struct monstertype // see docs for how these values modify behaviour { short gun, speed, health, freq, lag, rate, pain, loyalty, mscale, bscale; short painsound, diesound; - char *name, *mdlname; + OFConstantString *name, *mdlname; } monstertypes[NUMMONSTERTYPES] = { {GUN_FIREBALL, 15, 100, 3, 0, 100, 800, 1, 10, 10, S_PAINO, S_DIE1, - "an ogre", "monster/ogro"}, - {GUN_CG, 18, 70, 2, 70, 10, 400, 2, 8, 9, S_PAINR, S_DEATHR, "a rhino", - "monster/rhino"}, + @"an ogre", @"monster/ogro"}, + {GUN_CG, 18, 70, 2, 70, 10, 400, 2, 8, 9, S_PAINR, S_DEATHR, @"a rhino", + @"monster/rhino"}, {GUN_SG, 14, 120, 1, 100, 300, 400, 4, 14, 14, S_PAINE, S_DEATHE, - "ratamahatta", "monster/rat"}, + @"ratamahatta", @"monster/rat"}, {GUN_RIFLE, 15, 200, 1, 80, 300, 300, 4, 18, 18, S_PAINS, S_DEATHS, - "a slith", "monster/slith"}, - {GUN_RL, 13, 500, 1, 0, 100, 200, 6, 24, 24, S_PAINB, S_DEATHB, "bauul", - "monster/bauul"}, + @"a slith", @"monster/slith"}, + {GUN_RL, 13, 500, 1, 0, 100, 200, 6, 24, 24, S_PAINB, S_DEATHB, @"bauul", + @"monster/bauul"}, {GUN_BITE, 22, 50, 3, 0, 100, 400, 1, 12, 15, S_PAINP, S_PIGGR2, - "a hellpig", "monster/hellpig"}, + @"a hellpig", @"monster/hellpig"}, {GUN_ICEBALL, 12, 250, 1, 0, 10, 400, 6, 18, 18, S_PAINH, S_DEATHH, - "a knight", "monster/knight"}, + @"a knight", @"monster/knight"}, {GUN_SLIMEBALL, 15, 100, 1, 0, 200, 400, 2, 13, 10, S_PAIND, S_DEATHD, - "a goblin", "monster/goblin"}, + @"a goblin", @"monster/goblin"}, }; dynent * basicmonster(int type, int yaw, int state, int trigger, int move) { if (type >= NUMMONSTERTYPES) { conoutf(@"warning: unknown monster in spawn: %d", type); type = 0; - }; + } dynent *m = newdynent(); monstertype *t = &monstertypes[m->mtype = type]; m->eyeheight = 2.0f; m->aboveeye = 1.9f; m->radius *= t->bscale / 10.0f; @@ -76,11 +76,13 @@ loopi(NUMGUNS) m->ammo[i] = 10000; m->pitch = 0; m->roll = 0; m->state = CS_ALIVE; m->anger = 0; - strcpy_s(m->name, t->name); + @autoreleasepool { + strcpy_s(m->name, t->name.UTF8String); + } monsters.add(m); return m; }; void @@ -404,6 +406,6 @@ monsterrender() { loopv(monsters) renderclient(monsters[i], false, monstertypes[monsters[i]->mtype].mdlname, monsters[i]->mtype == 5, monstertypes[monsters[i]->mtype].mscale / 10.0f); -}; +} Index: src/protos.h ================================================================== --- src/protos.h +++ src/protos.h @@ -1,20 +1,20 @@ // protos for ALL external functions in cube... // command -extern int variable(char *name, int min, int cur, int max, int *storage, +extern int variable(OFString *name, int min, int cur, int max, int *storage, void (*fun)(), bool persist); -extern void setvar(char *name, int i); -extern int getvar(char *name); -extern bool identexists(char *name); +extern void setvar(OFString *name, int i); +extern int getvar(OFString *name); +extern bool identexists(OFString *name); extern bool addcommand(OFString *name, void (*fun)(), int narg); extern int execute(char *p, bool down = true); -extern void exec(char *cfgfile); -extern bool execfile(char *cfgfile); +extern void exec(OFString *cfgfile); +extern bool execfile(OFString *cfgfile); extern void resetcomplete(); extern void complete(char *s); -extern void alias(char *name, char *action); +extern void alias(OFString *name, OFString *action); extern OFString *getalias(OFString *name); extern void writecfg(); // console extern void keypress(int code, bool isdown, int cooked); @@ -31,14 +31,14 @@ extern bool rendermenu(); extern void menuset(int menu); extern void menumanual(int m, int n, char *text); extern void sortmenu(int start, int num); extern bool menukey(int code, bool isdown); -extern void newmenu(char *name); +extern void newmenu(OFString *name); // serverbrowser -extern void addserver(char *servername); +extern void addserver(OFString *servername); extern char *getservername(int n); extern void writeservercfg(); // rendergl extern void gl_init(int w, int h); @@ -68,11 +68,11 @@ extern void finishstrips(); extern void setarraypointers(); // client extern void localservertoclient(uchar *buf, int len); -extern void connects(char *servername); +extern void connects(OFString *servername); extern void disconnect(int onlyclean = 0, int async = 0); extern void toserver(char *text); extern void addmsg(int rel, int num, int type, ...); extern bool multiplayer(); extern bool allowedittoggle(); @@ -104,11 +104,11 @@ extern void fixplayer1range(); // clientextras extern void renderclients(); extern void renderclient( - dynent *d, bool team, char *mdlname, bool hellpig, float scale); + dynent *d, bool team, OFString *mdlname, bool hellpig, float scale); void showscores(bool on); extern void renderscores(); // world extern void setupworld(int factor); @@ -119,11 +119,11 @@ extern int findentity(int type, int index = 0); extern void trigger(int tag, int type, bool savegame); extern void resettagareas(); extern void settagareas(); extern entity *newentity( - int x, int y, int z, char *what, int v1, int v2, int v3, int v4); + int x, int y, int z, OFString *what, int v1, int v2, int v3, int v4); // worldlight extern void calclight(); extern void dodynlight( vec &vold, vec &v, int reach, int strength, dynent *owner); @@ -180,11 +180,11 @@ extern void particle_splash(int type, int num, int fade, vec &p); extern void particle_trail(int type, int fade, vec &from, vec &to); extern void render_particles(int time); // worldio -extern void save_world(const char *fname); +extern void save_world(OFString *fname); extern void load_world(char *mname); extern void writemap(char *mname, int msize, uchar *mdata); extern uchar *readmap(const char *mname, int *msize); extern void loadgamerest(); extern void incomingdemodata(uchar *buf, int len, bool extras = false); @@ -206,11 +206,11 @@ extern void playsoundc(int n); extern void initsound(); extern void cleansound(); // rendermd2 -extern void rendermodel(char *mdl, int frame, int range, int tex, float rad, +extern void rendermodel(OFString *mdl, int frame, int range, int tex, float rad, float x, float y, float z, float yaw, float pitch, bool teammate, float scale, float speed, int snap = 0, int basetime = 0); extern mapmodelinfo *getmminfo(int i); // server Index: src/renderextras.mm ================================================================== --- src/renderextras.mm +++ src/renderextras.mm @@ -145,34 +145,34 @@ glDisable(GL_BLEND); glDepthMask(GL_TRUE); }; string closeent; -char *entnames[] = { - "none?", - "light", - "playerstart", - "shells", - "bullets", - "rockets", - "riflerounds", - "health", - "healthboost", - "greenarmour", - "yellowarmour", - "quaddamage", - "teleport", - "teledest", - "mapmodel", - "monster", - "trigger", - "jumppad", - "?", - "?", - "?", - "?", - "?", +OFString *entnames[] = { + @"none?", + @"light", + @"playerstart", + @"shells", + @"bullets", + @"rockets", + @"riflerounds", + @"health", + @"healthboost", + @"greenarmour", + @"yellowarmour", + @"quaddamage", + @"teleport", + @"teledest", + @"mapmodel", + @"monster", + @"trigger", + @"jumppad", + @"?", + @"?", + @"?", + @"?", + @"?", }; void renderents() // show sparkly thingies for map entities in edit mode { @@ -188,35 +188,42 @@ particle_splash(2, 2, 40, v); }; int e = closestent(); if (e >= 0) { entity &c = ents[e]; - sprintf_s(closeent)("closest entity = %s (%d, %d, %d, %d), " - "selection = (%d, %d)", - entnames[c.type], c.attr1, c.attr2, c.attr3, c.attr4, - getvar("selxs"), getvar("selys")); - }; -}; - -void -loadsky(char *basename) -{ - static string lastsky = ""; - if (strcmp(lastsky, basename) == 0) - return; - char *side[] = {"ft", "bk", "lf", "rt", "dn", "up"}; - int texnum = 14; - loopi(6) - { - sprintf_sd(name)("packages/%s_%s.jpg", basename, side[i]); - int xs, ys; - if (!installtex(texnum + i, path(name), xs, ys, true)) - conoutf(@"could not load sky textures"); - }; - strcpy_s(lastsky, basename); -} -COMMAND(loadsky, ARG_1CSTR) + @autoreleasepool { + sprintf_s(closeent)( + "closest entity = %s (%d, %d, %d, %d), " + "selection = (%d, %d)", + entnames[c.type].UTF8String, c.attr1, c.attr2, + c.attr3, c.attr4, getvar(@"selxs"), + getvar(@"selys")); + } + } +} + +void +loadsky(OFString *basename) +{ + @autoreleasepool { + static OFString *lastsky = @""; + if ([lastsky isEqual:basename]) + return; + char *side[] = {"ft", "bk", "lf", "rt", "dn", "up"}; + int texnum = 14; + loopi(6) + { + sprintf_sd(name)( + "packages/%s_%s.jpg", basename.UTF8String, side[i]); + int xs, ys; + if (!installtex(texnum + i, path(name), xs, ys, true)) + conoutf(@"could not load sky textures"); + } + lastsky = basename; + } +} +COMMAND(loadsky, ARG_1STR) float cursordepth = 0.9f; GLint viewport[4]; GLdouble mm[16], pm[16]; vec worldpos; Index: src/rendergl.mm ================================================================== --- src/rendergl.mm +++ src/rendergl.mm @@ -148,19 +148,21 @@ curtexnum = 0; } COMMAND(texturereset, ARG_NONE) void -texture(char *aframe, char *name) -{ - int num = curtexnum++, frame = atoi(aframe); - if (num < 0 || num >= 256 || frame < 0 || frame >= MAXFRAMES) - return; - mapping[num][frame] = 1; - char *n = mapname[num][frame]; - strcpy_s(n, name); - path(n); +texture(OFString *aframe, OFString *name) +{ + @autoreleasepool { + int num = curtexnum++, frame = (int)aframe.longLongValue; + if (num < 0 || num >= 256 || frame < 0 || frame >= MAXFRAMES) + return; + mapping[num][frame] = 1; + char *n = mapname[num][frame]; + strcpy_s(n, name.UTF8String); + path(n); + } } COMMAND(texture, ARG_2STR) int lookuptexture(int tex, int &xs, int &ys) @@ -300,20 +302,20 @@ VAR(fog, 64, 180, 1024); VAR(fogcolour, 0, 0x8099B3, 0xFFFFFF); VARP(hudgun, 0, 1, 1); -char *hudgunnames[] = {"hudguns/fist", "hudguns/shotg", "hudguns/chaing", - "hudguns/rocket", "hudguns/rifle"}; +OFString *hudgunnames[] = {@"hudguns/fist", @"hudguns/shotg", @"hudguns/chaing", + @"hudguns/rocket", @"hudguns/rifle"}; void drawhudmodel(int start, int end, float speed, int base) { rendermodel(hudgunnames[player1->gunselect], start, end, 0, 1.0f, player1->o.x, player1->o.z, player1->o.y, player1->yaw + 90, player1->pitch, false, 1.0f, speed, 0, base); -}; +} void drawhudgun(float fovy, float aspect, int farplane) { if (!hudgun /*|| !player1->gunselect*/) Index: src/rendermd2.mm ================================================================== --- src/rendermd2.mm +++ src/rendermd2.mm @@ -214,38 +214,41 @@ fatal("loadmodel: ", name1); sprintf_sd(name2)("packages/models/%s/skin.jpg", m->loadname); int xs, ys; installtex(FIRSTMDL + m->mdlnum, path(name2), xs, ys); m->loaded = true; - }; -}; + } +} int modelnum = 0; md2 * -loadmodel(char *name) -{ - if (!mdllookup) - mdllookup = new hashtable; - md2 **mm = mdllookup->access(name); - if (mm) - return *mm; - md2 *m = new md2(); - m->mdlnum = modelnum++; - mapmodelinfo mmi = {2, 2, 0, 0, ""}; - m->mmi = mmi; - m->loadname = newstring(name); - mdllookup->access(m->loadname, &m); - return m; -}; +loadmodel(OFString *name) +{ + @autoreleasepool { + if (!mdllookup) + mdllookup = new hashtable; + md2 **mm = mdllookup->access(name.UTF8String); + if (mm) + return *mm; + md2 *m = new md2(); + m->mdlnum = modelnum++; + mapmodelinfo mmi = {2, 2, 0, 0, ""}; + m->mmi = mmi; + m->loadname = newstring(name.UTF8String); + mdllookup->access(m->loadname, &m); + return m; + } +} void -mapmodel(char *rad, char *h, char *zoff, char *snap, char *name) +mapmodel( + OFString *rad, OFString *h, OFString *zoff, OFString *snap, OFString *name) { md2 *m = loadmodel(name); - mapmodelinfo mmi = { - atoi(rad), atoi(h), atoi(zoff), atoi(snap), m->loadname}; + mapmodelinfo mmi = {(int)rad.longLongValue, (int)h.longLongValue, + (int)zoff.longLongValue, (int)snap.longLongValue, m->loadname}; m->mmi = mmi; mapmodels.add(m); } COMMAND(mapmodel, ARG_5STR) @@ -261,11 +264,11 @@ { return i < mapmodels.length() ? &mapmodels[i]->mmi : NULL; } void -rendermodel(char *mdl, int frame, int range, int tex, float rad, float x, +rendermodel(OFString *mdl, int frame, int range, int tex, float rad, float x, float y, float z, float yaw, float pitch, bool teammate, float scale, float speed, int snap, int basetime) { md2 *m = loadmodel(mdl); Index: src/savegamedemo.mm ================================================================== --- src/savegamedemo.mm +++ src/savegamedemo.mm @@ -117,22 +117,24 @@ gzwrite(f, players[i], sizeof(dynent)); } } void -savegame(char *name) -{ - if (!m_classicsp) { - conoutf(@"can only save classic sp games"); - return; - } - sprintf_sd(fn)("savegames/%s.csgz", name); - savestate(fn); - stop(); - conoutf(@"wrote %s", fn); -} -COMMAND(savegame, ARG_1CSTR) +savegame(OFString *name) +{ + @autoreleasepool { + if (!m_classicsp) { + conoutf(@"can only save classic sp games"); + return; + } + sprintf_sd(fn)("savegames/%s.csgz", name.UTF8String); + savestate(fn); + stop(); + conoutf(@"wrote %s", fn); + } +} +COMMAND(savegame, ARG_1STR) void loadstate(char *fn) { stop(); @@ -155,28 +157,30 @@ goto out; string mapname; gzread(f, mapname, _MAXDEFSTR); nextmode = gzgeti(); @autoreleasepool { - changemap( - @(mapname)); // continue below once map has been loaded and - // client & server have updated + // continue below once map has been loaded and client & server + // have updated + changemap(@(mapname)); } return; out: conoutf(@"aborting: savegame/demo from a different version of cube or " @"cpu architecture"); stop(); } void -loadgame(char *name) +loadgame(OFString *name) { - sprintf_sd(fn)("savegames/%s.csgz", name); - loadstate(fn); + @autoreleasepool { + sprintf_sd(fn)("savegames/%s.csgz", name.UTF8String); + loadstate(fn); + } } -COMMAND(loadgame, ARG_1CSTR) +COMMAND(loadgame, ARG_1STR) void loadgameout() { stop(); @@ -241,28 +245,30 @@ int playbacktime = 0; int ddamage, bdamage; vec dorig; void -record(char *name) -{ - if (m_sp) { - conoutf(@"cannot record singleplayer games"); - return; - }; - int cn = getclientnum(); - if (cn < 0) - return; - sprintf_sd(fn)("demos/%s.cdgz", name); - savestate(fn); - gzputi(cn); - conoutf(@"started recording demo to %s", fn); - demorecording = true; - starttime = lastmillis; - ddamage = bdamage = 0; -} -COMMAND(record, ARG_1CSTR) +record(OFString *name) +{ + @autoreleasepool { + if (m_sp) { + conoutf(@"cannot record singleplayer games"); + return; + } + int cn = getclientnum(); + if (cn < 0) + return; + sprintf_sd(fn)("demos/%s.cdgz", name.UTF8String); + savestate(fn); + gzputi(cn); + conoutf(@"started recording demo to %s", fn); + demorecording = true; + starttime = lastmillis; + ddamage = bdamage = 0; + } +} +COMMAND(record, ARG_1STR) void demodamage(int damage, vec &o) { ddamage = damage; @@ -304,17 +310,19 @@ // the network } } void -demo(char *name) +demo(OFString *name) { - sprintf_sd(fn)("demos/%s.cdgz", name); - loadstate(fn); - demoloading = true; + @autoreleasepool { + sprintf_sd(fn)("demos/%s.cdgz", name.UTF8String); + loadstate(fn); + demoloading = true; + } } -COMMAND(demo, ARG_1CSTR) +COMMAND(demo, ARG_1STR) void stopreset() { conoutf(@"demo stopped (%d msec elapsed)", lastmillis - starttime); Index: src/serverbrowser.mm ================================================================== --- src/serverbrowser.mm +++ src/serverbrowser.mm @@ -145,29 +145,33 @@ char * getservername(int n) { return servers[n].name; -}; +} void -addserver(char *servername) -{ - loopv(servers) if (strcmp(servers[i].name, servername) == 0) return; - serverinfo &si = servers.insert(0, serverinfo()); - strcpy_s(si.name, servername); - si.full[0] = 0; - si.mode = 0; - si.numplayers = 0; - si.ping = 9999; - si.protocol = 0; - si.minremain = 0; - si.map[0] = 0; - si.sdesc[0] = 0; - si.address.host = ENET_HOST_ANY; - si.address.port = CUBE_SERVINFO_PORT; -}; +addserver(OFString *servername_) +{ + @autoreleasepool { + const char *servername = servername_.UTF8String; + loopv(servers) if (strcmp(servers[i].name, servername) == + 0) return; + serverinfo &si = servers.insert(0, serverinfo()); + strcpy_s(si.name, servername); + si.full[0] = 0; + si.mode = 0; + si.numplayers = 0; + si.ping = 9999; + si.protocol = 0; + si.minremain = 0; + si.map[0] = 0; + si.sdesc[0] = 0; + si.address.host = ENET_HOST_ANY; + si.address.port = CUBE_SERVINFO_PORT; + } +} void pingservers() { ENetBuffer buf; @@ -312,11 +316,11 @@ execute((char *)reply); }; servermenu(); } -COMMAND(addserver, ARG_1CSTR) +COMMAND(addserver, ARG_1STR) COMMAND(servermenu, ARG_NONE) COMMAND(updatefrommaster, ARG_NONE) void writeservercfg() @@ -325,6 +329,6 @@ if (!f) return; fprintf(f, "// servers connected to are added here automatically\n\n"); loopvrev(servers) fprintf(f, "addserver %s\n", servers[i].name); fclose(f); -}; +} Index: src/sound.mm ================================================================== --- src/sound.mm +++ src/sound.mm @@ -72,49 +72,51 @@ if (FSOUND_GetVersion() < FMOD_VERSION) fatal("old FMOD dll"); if (!FSOUND_Init(SOUNDFREQ, MAXCHAN, FSOUND_INIT_GLOBALFOCUS)) { conoutf(@"sound init failed (FMOD): %d", FSOUND_GetError()); nosound = true; - }; + } #endif -}; +} void -music(char *name) +music(OFString *name) { if (nosound) return; stopsound(); if (soundvol && musicvol) { - string sn; - strcpy_s(sn, "packages/"); - strcat_s(sn, name); + @autoreleasepool { + string sn; + strcpy_s(sn, "packages/"); + strcat_s(sn, name.UTF8String); #ifdef USE_MIXER - if (mod = Mix_LoadMUS(path(sn))) { - Mix_PlayMusic(mod, -1); - Mix_VolumeMusic((musicvol * MAXVOL) / 255); - }; + if (mod = Mix_LoadMUS(path(sn))) { + Mix_PlayMusic(mod, -1); + Mix_VolumeMusic((musicvol * MAXVOL) / 255); + } #else - if (mod = FMUSIC_LoadSong(path(sn))) { - FMUSIC_PlaySong(mod); - FMUSIC_SetMasterVolume(mod, musicvol); - } else if (stream = FSOUND_Stream_Open( - path(sn), FSOUND_LOOP_NORMAL, 0, 0)) { - int chan = FSOUND_Stream_Play(FSOUND_FREE, stream); - if (chan >= 0) { - FSOUND_SetVolume( - chan, (musicvol * MAXVOL) / 255); - FSOUND_SetPaused(chan, false); - }; - } else { - conoutf(@"could not play music: %s", sn); - }; + if (mod = FMUSIC_LoadSong(path(sn))) { + FMUSIC_PlaySong(mod); + FMUSIC_SetMasterVolume(mod, musicvol); + } else if (stream = FSOUND_Stream_Open( + path(sn), FSOUND_LOOP_NORMAL, 0, 0)) { + int chan = + FSOUND_Stream_Play(FSOUND_FREE, stream); + if (chan >= 0) { + FSOUND_SetVolume( + chan, (musicvol * MAXVOL) / 255); + FSOUND_SetPaused(chan, false); + } + } else { + conoutf(@"could not play music: %s", sn); + } #endif - }; + } + } } - -COMMAND(music, ARG_1CSTR) +COMMAND(music, ARG_1STR) #ifdef USE_MIXER vector samples; #else vector samples; @@ -127,12 +129,11 @@ { loopv(snames) if (strcmp(snames[i], name) == 0) return i; snames.add(newstring(name)); samples.add(NULL); return samples.length() - 1; -}; - +} COMMAND(registersound, ARG_1EST) void cleansound() { @@ -159,14 +160,13 @@ if (stereo && (v.x != 0 || v.y != 0)) { float yaw = -atan2(v.x, v.y) - player1->yaw * (PI / 180.0f); // relative angle of // sound along X-Y axis - pan = int( - 255.9f * - (0.5 * sin(yaw) + - 0.5f)); // range is from 0 (left) to 255 (right) + pan = int(255.9f * (0.5 * sin(yaw) + + 0.5f)); // range is from 0 (left) + // to 255 (right) }; }; vol = (vol * MAXVOL) / 255; #ifdef USE_MIXER Mix_Volume(chan, vol); @@ -223,12 +223,12 @@ soundsatonce++; else soundsatonce = 1; lastsoundmillis = lastmillis; if (soundsatonce > 5) - return; // avoid bursts of sounds with heavy packetloss and in - // sp + return; // avoid bursts of sounds with heavy packetloss + // and in sp if (n < 0 || n >= samples.length()) { conoutf(@"unregistered sound: %d", n); return; }; Index: src/tools.h ================================================================== --- src/tools.h +++ src/tools.h @@ -318,11 +318,11 @@ for (int i = (v).length() - 1; i >= 0; i--) template struct hashtable { struct chain { chain *next; - char *key; + const char *key; T data; }; int size; int numelems; @@ -342,37 +342,38 @@ hashtable(hashtable &v); void operator=(hashtable &v); T * - access(char *key, T *data = NULL) + access(const char *key, T *data = NULL) { unsigned int h = 5381; for (int i = 0, k; k = key[i]; i++) h = ((h << 5) + h) ^ k; // bernstein k=33 xor h = h & (size - 1); // primes not much of an advantage for (chain *c = table[h]; c; c = c->next) { - for (char *p1 = key, *p2 = c->key, ch; + char ch; + for (const char *p1 = key, *p2 = c->key; (ch = *p1++) == *p2++;) if (!ch) // if(strcmp(key,c->key)==0) { T *d = &c->data; if (data) c->data = *data; return d; - }; - }; + } + } if (data) { chain *c = (chain *)parent->alloc(sizeof(chain)); c->data = *data; c->key = key; c->next = table[h]; table[h] = c; numelems++; - }; + } return NULL; - }; + } }; #define enumerate(ht, t, e, b) \ loopi(ht->size) for (ht->enumc = ht->table[i]; ht->enumc; \ ht->enumc = ht->enumc->next) \ Index: src/weapon.mm ================================================================== --- src/weapon.mm +++ src/weapon.mm @@ -58,14 +58,17 @@ { return guns[gun].attackdelay; }; void -weapon(char *a1, char *a2, char *a3) +weapon(OFString *a1, OFString *a2, OFString *a3) { - selectgun(a1[0] ? atoi(a1) : -1, a2[0] ? atoi(a2) : -1, - a3[0] ? atoi(a3) : -1); + @autoreleasepool { + selectgun(a1.UTF8String[0] ? atoi(a1.UTF8String) : -1, + a2.UTF8String[0] ? atoi(a2.UTF8String) : -1, + a3.UTF8String[0] ? atoi(a3.UTF8String) : -1); + } } COMMAND(weapon, ARG_3STR) void createrays(vec &from, vec &to) // create random spread of rays for the shotgun Index: src/world.mm ================================================================== --- src/world.mm +++ src/world.mm @@ -1,10 +1,12 @@ // world.cpp: core map management stuff #include "cube.h" -extern char *entnames[]; // lookup from map entities above to strings +#include + +extern OFString *entnames[]; // lookup from map entities above to strings sqr *world = NULL; int sfactor, ssize, cubicsize, mipsize; header hdr; @@ -56,16 +58,26 @@ void trigger(int tag, int type, bool savegame) { if (!tag) return; + settag(tag, type); + if (!savegame && type != 3) playsound(S_RUMBLE); - sprintf_sd(aliasname)("level_trigger_%d", tag); - if (identexists(aliasname)) - execute(aliasname); + + @autoreleasepool { + OFString *aliasname = + [OFString stringWithFormat:@"level_trigger_%d", tag]; + + if (identexists(aliasname)) { + std::unique_ptr cmd(strdup(aliasname.UTF8String)); + execute(cmd.get()); + } + } + if (type == 2) endsp(false); } COMMAND(trigger, ARG_2INT) @@ -78,11 +90,11 @@ void remip(block &b, int level) { if (level >= SMALLEST_FACTOR) return; - int lighterr = getvar("lighterror") * 3; + int lighterr = getvar(@"lighterror") * 3; sqr *w = wmip[level]; sqr *v = wmip[level + 1]; int ws = ssize >> level; int vs = ssize >> (level + 1); block s = b; @@ -294,27 +306,31 @@ if (e < 0) { conoutf(@"no more entities"); return; }; int t = ents[e].type; - conoutf(@"%s entity deleted", entnames[t]); + @autoreleasepool { + conoutf(@"%s entity deleted", entnames[t].UTF8String); + } ents[e].type = NOTUSED; addmsg(1, 10, SV_EDITENT, e, NOTUSED, 0, 0, 0, 0, 0, 0, 0); if (t == LIGHT) calclight(); -}; +} int -findtype(char *what) +findtype(OFString *what) { - loopi(MAXENTTYPES) if (strcmp(what, entnames[i]) == 0) return i; - conoutf(@"unknown entity type \"%s\"", what); - return NOTUSED; + @autoreleasepool { + loopi(MAXENTTYPES) if ([what isEqual:entnames[i]]) return i; + conoutf(@"unknown entity type \"%s\"", what.UTF8String); + return NOTUSED; + } } entity * -newentity(int x, int y, int z, char *what, int v1, int v2, int v3, int v4) +newentity(int x, int y, int z, OFString *what, int v1, int v2, int v3, int v4) { int type = findtype(what); persistent_entity e = {(short)x, (short)y, (short)z, (short)v1, (uchar)type, (uchar)v2, (uchar)v3, (uchar)v4}; switch (type) { @@ -344,11 +360,11 @@ calclight(); return &ents.last(); }; void -clearents(char *name) +clearents(OFString *name) { int type = findtype(name); if (noteditmode() || multiplayer()) return; loopv(ents) @@ -358,11 +374,11 @@ e.type = NOTUSED; }; if (type == LIGHT) calclight(); } -COMMAND(clearents, ARG_1CSTR) +COMMAND(clearents, ARG_1STR) void scalecomp(uchar &c, int intens) { int n = c * intens / 100; Index: src/worldio.mm ================================================================== --- src/worldio.mm +++ src/worldio.mm @@ -5,11 +5,11 @@ void backup(char *name, char *backupname) { remove(backupname); rename(name, backupname); -}; +} string cgzname, bakname, pcfname, mcfname; static void setnames(const char *name) @@ -41,11 +41,11 @@ inline bool nhf(sqr *s) { return s->type != FHF && s->type != CHF; -}; +} void voptimize() // reset vdeltas on non-hf cubes { loop(x, ssize) loop(y, ssize) @@ -55,12 +55,12 @@ if (nhf(s) && nhf(S(x - 1, y)) && nhf(S(x - 1, y - 1)) && nhf(S(x, y - 1))) s->vdelta = 0; } else s->vdelta = 0; - }; -}; + } +} void topt(sqr *s, bool &wf, bool &uf, int &wt, int &ut) { sqr *o[4]; @@ -75,32 +75,32 @@ { wf = false; wt = s->wtex; ut = s->utex; return; - }; + } } else { loopi(4) if (!SOLID(o[i])) { if (o[i]->floor < s->floor) { wt = s->wtex; wf = false; - }; + } if (o[i]->ceil > s->ceil) { ut = s->utex; uf = false; - }; - }; - }; -}; + } + } + } +} void toptimize() // FIXME: only does 2x2, make atleast for 4x4 also { bool wf[4], uf[4]; sqr *s[4]; - for (int x = 2; x < ssize - 4; x += 2) + for (int x = 2; x < ssize - 4; x += 2) { for (int y = 2; y < ssize - 4; y += 2) { s[0] = S(x, y); int wt = s[0]->wtex, ut = s[0]->utex; topt(s[0], wf[0], uf[0], wt, ut); topt(s[1] = SWS(s[0], 0, 1, ssize), wf[1], uf[1], wt, @@ -113,13 +113,14 @@ { if (wf[i]) s[i]->wtex = wt; if (uf[i]) s[i]->utex = ut; - }; - }; -}; + } + } + } +} // these two are used by getmap/sendmap.. transfers compressed maps directly void writemap(char *mname, int msize, uchar *mdata) @@ -128,11 +129,11 @@ backup(cgzname, bakname); FILE *f = fopen(cgzname, "wb"); if (!f) { conoutf(@"could not write map to %s", cgzname); return; - }; + } fwrite(mdata, 1, msize, f); fclose(f); conoutf(@"wrote map %s as file %s", mname, cgzname); } @@ -142,36 +143,36 @@ setnames(mname); uchar *mdata = (uchar *)loadfile(cgzname, msize); if (!mdata) { conoutf(@"could not read map %s", cgzname); return NULL; - }; + } return mdata; } // save map as .cgz file. uses 2 layers of compression: first does simple // run-length encoding and leaves out data for certain kinds of cubes, then zlib // removes the last bits of redundancy. Both passes contribute greatly to the // miniscule map sizes. void -save_world(const char *mname) +save_world(OFString *mname) { @autoreleasepool { resettagareas(); // wouldn't be able to reproduce tagged areas // otherwise voptimize(); toptimize(); - if (!*mname) - mname = getclientmap().UTF8String; - setnames(mname); + if (mname.length == 0) + mname = getclientmap(); + setnames(mname.UTF8String); backup(cgzname, bakname); gzFile f = gzopen(cgzname, "wb9"); if (!f) { conoutf(@"could not write map to %s", cgzname); return; - }; + } hdr.version = MAPVERSION; hdr.numents = 0; loopv(ents) if (ents[i].type != NOTUSED) hdr.numents++; header tmp = hdr; endianswap(&tmp.version, sizeof(int), 4); @@ -181,12 +182,12 @@ { if (ents[i].type != NOTUSED) { entity tmp = ents[i]; endianswap(&tmp, sizeof(short), 4); gzwrite(f, &tmp, sizeof(persistent_entity)); - }; - }; + } + } sqr *t = NULL; int sc = 0; #define spurge \ while (sc) { \ gzputc(f, 255); \ @@ -195,11 +196,11 @@ sc -= 255; \ } else { \ gzputc(f, sc); \ sc = 0; \ } \ - }; + } loopk(cubicsize) { sqr *s = &world[k]; #define c(f) (s->f == t->f) // 4 types of blocks, to compress a bit: @@ -214,11 +215,11 @@ } else { spurge; gzputc(f, s->type); gzputc(f, s->wtex); gzputc(f, s->vdelta); - }; + } } else { if (t && c(type) && c(floor) && c(ceil) && c(ctex) && c(ftex) && c(utex) && c(wtex) && c(vdelta) && c(tag)) { sc++; @@ -231,20 +232,21 @@ gzputc(f, s->ftex); gzputc(f, s->ctex); gzputc(f, s->vdelta); gzputc(f, s->utex); gzputc(f, s->tag); - }; - }; + } + } t = s; - }; + } spurge; gzclose(f); conoutf(@"wrote map file %s", cgzname); settagareas(); } } +COMMANDN(savemap, save_world, ARG_1STR) void load_world(char *mname) // still supports all map formats that have existed // since the earliest cube betas! { @@ -254,11 +256,11 @@ setnames(mname); gzFile f = gzopen(cgzname, "rb9"); if (!f) { conoutf(@"could not read map %s", cgzname); return; - }; + } gzread(f, &hdr, sizeof(header) - sizeof(int) * 16); endianswap(&hdr.version, sizeof(int), 4); if (strncmp(hdr.head, "CUBE", 4) != 0) fatal("while reading map: header malformatted"); if (hdr.version > MAPVERSION) @@ -268,11 +270,11 @@ if (hdr.version >= 4) { gzread(f, &hdr.waterlevel, sizeof(int) * 16); endianswap(&hdr.waterlevel, sizeof(int), 16); } else { hdr.waterlevel = -100000; - }; + } ents.setsize(0); loopi(hdr.numents) { entity &e = ents.add(); gzread(f, &e, sizeof(persistent_entity)); @@ -281,12 +283,12 @@ if (e.type == LIGHT) { if (!e.attr2) e.attr2 = 255; // needed for MAPVERSION<=2 if (e.attr1 > 32) e.attr1 = 32; // 12_03 and below - }; - }; + } + } free(world); setupworld(hdr.sfactor); char texuse[256]; loopi(256) texuse[i] = 0; sqr *t = NULL; @@ -299,40 +301,40 @@ int n = gzgetc(f); for (int i = 0; i < n; i++, k++) memcpy(&world[k], t, sizeof(sqr)); k--; break; - }; + } case 254: // only in MAPVERSION<=2 { memcpy(s, t, sizeof(sqr)); s->r = s->g = s->b = gzgetc(f); gzgetc(f); break; - }; + } case SOLID: { s->type = SOLID; s->wtex = gzgetc(f); s->vdelta = gzgetc(f); if (hdr.version <= 2) { gzgetc(f); gzgetc(f); - }; + } s->ftex = DEFAULT_FLOOR; s->ctex = DEFAULT_CEIL; s->utex = s->wtex; s->tag = 0; s->floor = 0; s->ceil = 16; break; - }; + } default: { if (type < 0 || type >= MAXTYPE) { sprintf_sd(t)("%d @ %d", type, k); fatal("while reading map: type out of range: ", t); - }; + } s->type = type; s->floor = gzgetc(f); s->ceil = gzgetc(f); if (s->floor >= s->ceil) s->floor = s->ceil - 1; // for pre 12_13 @@ -340,23 +342,23 @@ s->ftex = gzgetc(f); s->ctex = gzgetc(f); if (hdr.version <= 2) { gzgetc(f); gzgetc(f); - }; + } s->vdelta = gzgetc(f); s->utex = (hdr.version >= 2) ? gzgetc(f) : s->wtex; s->tag = (hdr.version >= 5) ? gzgetc(f) : 0; s->type = type; - }; - }; + } + } s->defer = 0; t = s; texuse[s->wtex] = 1; if (!SOLID(s)) texuse[s->utex] = texuse[s->ftex] = texuse[s->ctex] = 1; - }; + } gzclose(f); calclight(); settagareas(); int xs, ys; loopi(256) if (texuse) lookuptexture(i, xs, ys); @@ -364,16 +366,19 @@ SDL_GetTicks() - lastmillis); conoutf(@"%s", hdr.maptitle); startmap(mname); loopl(256) { - sprintf_sd(aliasname)( - "level_trigger_%d", l); // can this be done smarter? - if (identexists(aliasname)) - alias(aliasname, ""); - }; - execfile("data/default_map_settings.cfg"); - execfile(pcfname); - execfile(mcfname); -} - -COMMANDN(savemap, save_world, ARG_1CSTR) + @autoreleasepool { + // can this be done smarter? + OFString *aliasname = + [OFString stringWithFormat:@"level_trigger_%d", l]; + if (identexists(aliasname)) + alias(aliasname, @""); + } + } + execfile(@"data/default_map_settings.cfg"); + @autoreleasepool { + execfile(@(pcfname)); + execfile(@(mcfname)); + } +} Index: src/worldlight.mm ================================================================== --- src/worldlight.mm +++ src/worldlight.mm @@ -169,23 +169,23 @@ { loop(x, ssize) loop(y, ssize) { sqr *s = S(x, y); s->r = s->g = s->b = 10; - }; + } loopv(ents) { entity &e = ents[i]; if (e.type == LIGHT) calclightsource(e); - }; + } block b = {1, 1, ssize - 2, ssize - 2}; postlightarea(b); - setvar("fullbright", 0); -}; + setvar(@"fullbright", 0); +} VARP(dynlight, 0, 16, 32); vector dlights; @@ -194,12 +194,12 @@ { while (!dlights.empty()) { block *backup = dlights.pop(); blockpaste(*backup); free(backup); - }; -}; + } +} void dodynlight(vec &vold, vec &v, int reach, int strength, dynent *owner) { if (!reach) @@ -228,11 +228,11 @@ persistent_entity l = {(short)v.x, (short)v.y, (short)v.z, (short)reach, LIGHT, (uchar)strength, 0, 0}; calclightsource(l); postlightarea(b); -}; +} // utility functions also used by editing code block * blockcopy(block &s) @@ -242,16 +242,16 @@ sqr *q = (sqr *)(b + 1); for (int x = s.x; x < s.xs + s.x; x++) for (int y = s.y; y < s.ys + s.y; y++) *q++ = *S(x, y); return b; -}; +} void blockpaste(block &b) { sqr *q = (sqr *)((&b) + 1); for (int x = b.x; x < b.xs + b.x; x++) for (int y = b.y; y < b.ys + b.y; y++) *S(x, y) = *q++; remipmore(b); -}; +} Index: src/worldocull.mm ================================================================== --- src/worldocull.mm +++ src/worldocull.mm @@ -22,14 +22,14 @@ computeraytable(float vx, float vy) { if (!ocull) return; - odist = getvar("fog") * 1.5f; + odist = getvar(@"fog") * 1.5f; float apitch = (float)fabs(player1->pitch); - float af = getvar("fov") / 2 + apitch / 1.5f + 3; + float af = getvar(@"fov") / 2 + apitch / 1.5f + 3; float byaw = (player1->yaw - 90 + af) / 360 * PI2; float syaw = (player1->yaw - 90 - af) / 360 * PI2; loopi(NUMRAYS) {