Index: src/Command.mm ================================================================== --- src/Command.mm +++ src/Command.mm @@ -1,6 +1,7 @@ #import "Command.h" +#import "OFString+Cube.h" #include static OFArray * padArguments(OFArray *arguments, size_t count) @@ -36,38 +37,38 @@ switch (_argumentsTypes) { case ARG_1INT: if (isDown) { arguments = padArguments(arguments, 2); ((void(__cdecl *)(int))_function)( - [arguments[1] intValueWithBase:0]); + [arguments[1] cube_intValueWithBase:0]); } break; case ARG_2INT: if (isDown) { arguments = padArguments(arguments, 3); ((void(__cdecl *)(int, int))_function)( - [arguments[1] intValueWithBase:0], - [arguments[2] intValueWithBase:0]); + [arguments[1] cube_intValueWithBase:0], + [arguments[2] cube_intValueWithBase:0]); } break; case ARG_3INT: if (isDown) { arguments = padArguments(arguments, 4); ((void(__cdecl *)(int, int, int))_function)( - [arguments[1] intValueWithBase:0], - [arguments[2] intValueWithBase:0], - [arguments[3] intValueWithBase:0]); + [arguments[1] cube_intValueWithBase:0], + [arguments[2] cube_intValueWithBase:0], + [arguments[3] cube_intValueWithBase:0]); } break; case ARG_4INT: if (isDown) { arguments = padArguments(arguments, 5); ((void(__cdecl *)(int, int, int, int))_function)( - [arguments[1] intValueWithBase:0], - [arguments[2] intValueWithBase:0], - [arguments[3] intValueWithBase:0], - [arguments[4] intValueWithBase:0]); + [arguments[1] cube_intValueWithBase:0], + [arguments[2] cube_intValueWithBase:0], + [arguments[3] cube_intValueWithBase:0], + [arguments[4] cube_intValueWithBase:0]); } break; case ARG_NONE: if (isDown) ((void(__cdecl *)())_function)(); Index: src/MenuItem.m ================================================================== --- src/MenuItem.m +++ src/MenuItem.m @@ -21,15 +21,20 @@ int x, y; @try { x = _text.intValue; } @catch (OFInvalidFormatException *e) { x = 0; + } @catch (OFOutOfRangeException *e) { + x = 0; } - @try { + @ + try { y = otherItem.text.intValue; } @catch (OFInvalidFormatException *e) { + y = 0; + } @catch (OFOutOfRangeException *e) { y = 0; } if (x > y) return OFOrderedAscending; Index: src/clientgame.mm ================================================================== --- src/clientgame.mm +++ src/clientgame.mm @@ -1,10 +1,11 @@ // clientgame.cpp: core game related stuff #include "cube.h" #import "DynamicEntity.h" +#import "OFString+Cube.h" int nextmode = 0; // nextmode becomes gamemode after next map load VAR(gamemode, 1, 0, 0); void @@ -236,11 +237,11 @@ int sleepwait = 0; static OFString *sleepcmd = nil; void sleepf(OFString *msec, OFString *cmd) { - sleepwait = msec.intValue + lastmillis; + sleepwait = msec.cube_intValue + lastmillis; sleepcmd = cmd; } COMMANDN(sleep, sleepf, ARG_2STR) void Index: src/commands.mm ================================================================== --- src/commands.mm +++ src/commands.mm @@ -6,10 +6,11 @@ #include #import "Alias.h" #import "Command.h" #import "Identifier.h" +#import "OFString+Cube.h" #import "Variable.h" // contains ALL vars/commands/aliases static OFMutableDictionary *identifiers; @@ -178,10 +179,58 @@ } conoutf(@"unknown alias lookup: %@", [n substringFromIndex:1]); return n; } + +int +executeIdentifier(__kindof Identifier *identifier, + OFArray *arguments, bool isDown) +{ + if (identifier == nil) { + @try { + return [arguments[0] intValueWithBase:0]; + } @catch (OFInvalidFormatException *e) { + conoutf(@"unknown command: %@", arguments[0]); + return 0; + } @catch (OFOutOfRangeException *e) { + conoutf(@"invalid value: %@", arguments[0]); + return 0; + } + } + + if ([identifier isKindOfClass:Command.class]) + // game defined commands use very ad-hoc function signature, + // and just call it + return [identifier callWithArguments:arguments isDown:isDown]; + + if ([identifier isKindOfClass:Variable.class]) { + if (!isDown) + return 0; + + // game defined variables + if (arguments.count < 2 || arguments[1].length == 0) + [identifier printValue]; + else + [identifier + setValue:[arguments[1] cube_intValueWithBase:0]]; + } + + if ([identifier isKindOfClass:Alias.class]) { + // alias, also used as functions and (global) variables + for (int i = 1; i < arguments.count; i++) { + // set any arguments as (global) arg values so + // functions can access them + OFString *t = [OFString stringWithFormat:@"arg%d", i]; + alias(t, arguments[i]); + } + + return execute([identifier action], isDown); + } + + return 0; +} // all evaluation happens here, recursively int execute(OFString *string, bool isDown) { @@ -228,59 +277,12 @@ } // empty statement if (c.length == 0) continue; - __kindof Identifier *identifier = identifiers[c]; - if (identifier == nil) { - @try { - val = [c intValueWithBase:0]; - } @catch (OFInvalidFormatException *e) { - conoutf(@"unknown command: %@", c); - } - } else { - if ([identifier isKindOfClass:Command.class]) { - // game defined commands use very - // ad-hoc function signature, and just - // call it - OFArray *arguments = - [[OFArray alloc] - initWithObjects:w - count:numargs]; - val = [identifier - callWithArguments:arguments - isDown:isDown]; - } else if ([identifier - isKindOfClass:Variable.class]) { - // game defined variables - if (isDown) { - if (w[1].length == 0) - [identifier printValue]; - else - [identifier - setValue: - [w[1] - intValueWithBase: - 0]]; - } - } else if ([identifier - isKindOfClass:Alias.class]) { - // alias, also used as functions and - // (global) variables - for (int i = 1; i < numargs; i++) { - // set any arguments as - // (global) arg values so - // functions can access them - OFString *t = [OFString - stringWithFormat:@"arg%d", - i]; - alias(t, w[i]); - } - val = execute( - [identifier action], isDown); - } - } + val = executeIdentifier(identifiers[c], + [OFArray arrayWithObjects:w count:numargs], isDown); } return val; } } @@ -376,17 +378,16 @@ mode:@"w"]; } @catch (id e) { return; } - [stream writeString: - @"// automatically written on exit, do not modify\n" - @"// delete this file to have defaults.cfg overwrite these " - @"settings\n" - @"// modify settings in game, or put settings in " - @"autoexec.cfg to override anything\n" - @"\n"]; + [stream writeString:@"// automatically written on exit, do not modify\n" + @"// delete this file to have defaults.cfg " + @"overwrite these settings\n" + @"// modify settings in game, or put settings in " + @"autoexec.cfg to override anything\n" + @"\n"]; writeclientinfo(stream); [stream writeString:@"\n"]; [identifiers enumerateKeysAndObjectsUsingBlock:^( OFString *name, __kindof Identifier *identifier, bool *stop) { @@ -416,12 +417,12 @@ } COMMAND(writecfg, ARG_NONE) // below the commands that implement a small imperative language. thanks to the -// semantics of -// () and [] expressions, any control construct can be defined trivially. +// semantics of () and [] expressions, any control construct can be defined +// trivially. void intset(OFString *name, int v) { @autoreleasepool { @@ -437,11 +438,11 @@ void loopa(OFString *times, OFString *body) { @autoreleasepool { - int t = times.intValue; + int t = times.cube_intValue; loopi(t) { intset(@"i", i); execute(body); @@ -495,14 +496,13 @@ void at(OFString *s_, OFString *pos) { @autoreleasepool { - int n = pos.intValue; + int n = pos.cube_intValue; 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)); } } Index: src/console.mm ================================================================== --- src/console.mm +++ src/console.mm @@ -3,10 +3,11 @@ #include "cube.h" #include #import "KeyMapping.h" +#import "OFString+Cube.h" struct cline { char *cref; int outtime; }; @@ -104,12 +105,12 @@ keymap(OFString *code, OFString *key, OFString *action) { if (keyMappings == nil) keyMappings = [[OFMutableArray alloc] init]; - KeyMapping *mapping = [[KeyMapping alloc] initWithCode:code.intValue - name:key]; + KeyMapping *mapping = + [[KeyMapping alloc] initWithCode:code.cube_intValue name:key]; mapping.action = action; [keyMappings addObject:mapping]; } COMMAND(keymap, ARG_3STR) Index: src/editing.mm ================================================================== --- src/editing.mm +++ src/editing.mm @@ -2,10 +2,11 @@ // in world.cpp #include "cube.h" #import "DynamicEntity.h" +#import "OFString+Cube.h" bool editmode = false; // the current selection, used by almost all editing commands // invariant: all code assumes that these are kept inside MINBORD distance of @@ -603,12 +604,12 @@ newent(OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4) { EDITSEL; @autoreleasepool { newentity(sel.x, sel.y, (int)player1.o.z, what, - [a1 intValueWithBase:0], [a2 intValueWithBase:0], - [a3 intValueWithBase:0], [a4 intValueWithBase:0]); + [a1 cube_intValueWithBase:0], [a2 cube_intValueWithBase:0], + [a3 cube_intValueWithBase:0], [a4 cube_intValueWithBase:0]); } } COMMANDN(select, selectpos, ARG_4INT) COMMAND(edittag, ARG_1INT) Index: src/meson.build ================================================================== --- src/meson.build +++ src/meson.build @@ -8,10 +8,11 @@ 'KeyMapping.m', 'MD2.mm', 'MapModelInfo.m', 'Menu.m', 'MenuItem.m', + 'OFString+Cube.mm', 'Projectile.m', 'ServerInfo.mm', 'Variable.mm', 'client.mm', 'clientextras.mm', Index: src/renderextras.mm ================================================================== --- src/renderextras.mm +++ src/renderextras.mm @@ -204,10 +204,13 @@ loadsky(OFString *basename) { @autoreleasepool { static OFString *lastsky = @""; + basename = [basename stringByReplacingOccurrencesOfString:@"\\" + withString:@"/"]; + if ([lastsky isEqual:basename]) return; static const OFString *side[] = { @"ft", @"bk", @"lf", @"rt", @"dn", @"up" }; Index: src/rendergl.mm ================================================================== --- src/rendergl.mm +++ src/rendergl.mm @@ -1,10 +1,11 @@ // rendergl.cpp: core opengl rendering stuff #include "cube.h" #import "DynamicEntity.h" +#import "OFString+Cube.h" #ifdef DARWIN # define GL_COMBINE_EXT GL_COMBINE_ARB # define GL_COMBINE_RGB_EXT GL_COMBINE_RGB_ARB # define GL_SOURCE0_RBG_EXT GL_SOURCE0_RGB_ARB @@ -195,15 +196,19 @@ void texture(OFString *aframe, OFString *name) { @autoreleasepool { - int num = curtexnum++, frame = aframe.intValue; + int num = curtexnum++, frame = aframe.cube_intValue; + if (num < 0 || num >= 256 || frame < 0 || frame >= MAXFRAMES) return; + mapping[num][frame] = 1; - mapname[num][frame] = name; + mapname[num][frame] = + [name stringByReplacingOccurrencesOfString:@"\\" + withString:@"/"]; } } COMMAND(texture, ARG_2STR) int Index: src/rendermd2.mm ================================================================== --- src/rendermd2.mm +++ src/rendermd2.mm @@ -3,10 +3,11 @@ #include "cube.h" #import "DynamicEntity.h" #import "MD2.h" #import "MapModelInfo.h" +#import "OFString+Cube.h" static OFMutableDictionary *mdllookup = nil; static OFMutableArray *mapmodels = nil; static const int FIRSTMDL = 20; @@ -65,15 +66,16 @@ void mapmodel( OFString *rad, OFString *h, OFString *zoff, OFString *snap, OFString *name) { - MD2 *m = loadmodel(name); - m.mmi = [[MapModelInfo alloc] initWithRad:rad.intValue - h:h.intValue - zoff:zoff.intValue - snap:snap.intValue + MD2 *m = loadmodel([name stringByReplacingOccurrencesOfString:@"\\" + withString:@"/"]); + m.mmi = [[MapModelInfo alloc] initWithRad:rad.cube_intValue + h:h.cube_intValue + zoff:zoff.cube_intValue + snap:snap.cube_intValue name:m.loadname]; if (mapmodels == nil) mapmodels = [[OFMutableArray alloc] init]; Index: src/sound.mm ================================================================== --- src/sound.mm +++ src/sound.mm @@ -86,10 +86,12 @@ if (nosound) return; stopsound(); if (soundvol && musicvol) { @autoreleasepool { + name = [name stringByReplacingOccurrencesOfString:@"\\" + withString:@"/"]; OFString *path = [OFString stringWithFormat:@"packages/%@", name]; OFIRI *IRI = [Cube.sharedInstance.gameDataIRI IRIByAppendingPathComponent:path]; @@ -146,11 +148,12 @@ } if (snames == nil) snames = [[OFMutableArray alloc] init]; - [snames addObject:name]; + [snames addObject:[name stringByReplacingOccurrencesOfString:@"\\" + withString:@"/"]]; samples.add(NULL); return samples.length() - 1; } COMMAND(registersound, ARG_1EST) Index: src/weapon.mm ================================================================== --- src/weapon.mm +++ src/weapon.mm @@ -1,10 +1,11 @@ // weapon.cpp: all shooting and effects code #include "cube.h" #import "DynamicEntity.h" +#import "OFString+Cube.h" #import "Projectile.h" static const int MONSTERDAMAGEFACTOR = 4; static const int SGRAYS = 20; static const float SGSPREAD = 2; @@ -61,13 +62,13 @@ } void weapon(OFString *a1, OFString *a2, OFString *a3) { - selectgun((a1.length > 0 ? a1.intValue : -1), - (a2.length > 0 ? a2.intValue : -1), - (a3.length > 0 ? a3.intValue : -1)); + selectgun((a1.length > 0 ? a1.cube_intValue : -1), + (a2.length > 0 ? a2.cube_intValue : -1), + (a3.length > 0 ? a3.cube_intValue : -1)); } COMMAND(weapon, ARG_3STR) void createrays(OFVector3D &from,