Index: src/Command.h ================================================================== --- src/Command.h +++ src/Command.h @@ -1,18 +1,18 @@ #import "Identifier.h" OF_ASSUME_NONNULL_BEGIN -#define COMMAND(name, nargs, block_) \ - OF_CONSTRUCTOR() \ - { \ - enqueueInit(^{ \ - [Identifier \ - addIdentifier:[Command commandWithName:@ #name \ - argumentsTypes:nargs \ - block:block_]]; \ - }); \ +#define COMMAND(name, nargs, block_) \ + OF_CONSTRUCTOR() \ + { \ + enqueueInit(^{ \ + Identifier.identifiers[@ #name] = \ + [Command commandWithName:@ #name \ + argumentsTypes:nargs \ + block:block_]; \ + }); \ } @interface Command: Identifier @property (readonly, nonatomic) int argumentsTypes; Index: src/Cube.m ================================================================== --- src/Cube.m +++ src/Cube.m @@ -2,10 +2,11 @@ #include "cube.h" #import "Command.h" #import "Player.h" +#import "Variable.h" OF_APPLICATION_DELEGATE(Cube) VARF(gamespeed, 10, 100, 1000, if (multiplayer()) gamespeed = 100); VARP(minmillis, 0, 5, 1000); Index: src/Identifier.h ================================================================== --- src/Identifier.h +++ src/Identifier.h @@ -2,14 +2,13 @@ OF_ASSUME_NONNULL_BEGIN @interface Identifier: OFObject @property (readonly, copy, nonatomic) OFString *name; +@property (class, readonly, nonatomic) + OFMutableDictionary *identifiers; -+ (void)addIdentifier:(__kindof Identifier *)identifier; -+ (__kindof Identifier *)identifierForName:(OFString *)name; -+ (void)enumerateIdentifiersUsingBlock:(void (^)(__kindof Identifier *))block; - (instancetype)init OF_UNAVAILABLE; - (instancetype)initWithName:(OFString *)name; @end OF_ASSUME_NONNULL_END Index: src/Identifier.m ================================================================== --- src/Identifier.m +++ src/Identifier.m @@ -8,26 +8,13 @@ { if (self == Identifier.class) identifiers = [[OFMutableDictionary alloc] init]; } -+ (void)addIdentifier:(__kindof Identifier *)identifier -{ - identifiers[identifier.name] = identifier; -} - -+ (__kindof Identifier *)identifierForName:(OFString *)name -{ - return identifiers[name]; -} - -+ (void)enumerateIdentifiersUsingBlock:(void (^)(__kindof Identifier *))block -{ - [identifiers enumerateKeysAndObjectsUsingBlock:^( - OFString *name, __kindof Identifier *identifier, bool *stop) { - block(identifier); - }]; ++ (OFMutableDictionary *)identifiers +{ + return identifiers; } - (instancetype)initWithName:(OFString *)name { self = [super init]; Index: src/Monster.m ================================================================== --- src/Monster.m +++ src/Monster.m @@ -4,10 +4,11 @@ #include "cube.h" #import "Entity.h" #import "Player.h" +#import "Variable.h" static OFMutableArray *monsters; static int nextmonster, spawnremain, numkilled, monstertotal, mtimestart; @implementation Monster Index: src/Variable.h ================================================================== --- src/Variable.h +++ src/Variable.h @@ -1,27 +1,98 @@ #import "Identifier.h" OF_ASSUME_NONNULL_BEGIN +#define VARP(name, min_, cur, max_) \ + int name = cur; \ + \ + OF_CONSTRUCTOR() \ + { \ + enqueueInit(^{ \ + Variable *variable = \ + [Variable variableWithName:@ #name \ + min:min_ \ + max:max_ \ + storage:&name \ + function:NULL \ + persisted:true]; \ + Identifier.identifiers[@ #name] = variable; \ + }); \ + } +#define VAR(name, min_, cur, max_) \ + int name = cur; \ + \ + OF_CONSTRUCTOR() \ + { \ + enqueueInit(^{ \ + Variable *variable = \ + [Variable variableWithName:@ #name \ + min:min_ \ + max:max_ \ + storage:&name \ + function:NULL \ + persisted:false]; \ + Identifier.identifiers[@ #name] = variable; \ + }); \ + } +#define VARF(name, min_, cur, max_, body) \ + static void var_##name(); \ + static int name = cur; \ + \ + OF_CONSTRUCTOR() \ + { \ + enqueueInit(^{ \ + Variable *variable = \ + [Variable variableWithName:@ #name \ + min:min_ \ + max:max_ \ + storage:&name \ + function:var_##name \ + persisted:false]; \ + Identifier.identifiers[@ #name] = variable; \ + }); \ + } \ + \ + static void var_##name() { body; } +#define VARFP(name, min_, cur, max_, body) \ + static void var_##name(); \ + static int name = cur; \ + \ + OF_CONSTRUCTOR() \ + { \ + enqueueInit(^{ \ + Variable *variable = \ + [Variable variableWithName:@ #name \ + min:min_ \ + max:max_ \ + storage:&name \ + function:var_##name \ + persisted:true]; \ + Identifier.identifiers[@ #name] = variable; \ + }); \ + } \ + \ + static void var_##name() { body; } + @interface Variable: Identifier @property (readonly, nonatomic) int min, max; @property (readonly, nonatomic) int *storage; -@property (readonly, nonatomic) void (*__cdecl function)(); +@property (readonly, nullable, nonatomic) void (*function)(); @property (readonly, nonatomic) bool persisted; + (instancetype)variableWithName:(OFString *)name min:(int)min max:(int)max storage:(int *)storage - function:(void (*__cdecl)())function + function:(void (*_Nullable)())function persisted:(bool)persisted; - (instancetype)initWithName:(OFString *)name OF_UNAVAILABLE; - (instancetype)initWithName:(OFString *)name min:(int)min max:(int)max storage:(int *)storage - function:(void (*__cdecl)())function + function:(void (*_Nullable)())function persisted:(bool)persisted; - (void)printValue; - (void)setValue:(int)value; @end Index: src/clientgame.m ================================================================== --- src/clientgame.m +++ src/clientgame.m @@ -6,10 +6,11 @@ #import "DynamicEntity.h" #import "Entity.h" #import "Monster.h" #import "OFString+Cube.h" #import "Player.h" +#import "Variable.h" int nextmode = 0; // nextmode becomes gamemode after next map load VAR(gamemode, 1, 0, 0); COMMAND(mode, ARG_1INT, ^(int n) { Index: src/clients.m ================================================================== --- src/clients.m +++ src/clients.m @@ -2,10 +2,11 @@ #include "cube.h" #import "Command.h" #import "Player.h" +#import "Variable.h" static ENetHost *clienthost = NULL; static int connecting = 0; static int connattempts = 0; static int disconnecting = 0; Index: src/commands.m ================================================================== --- src/commands.m +++ src/commands.m @@ -16,16 +16,16 @@ } void alias(OFString *name, OFString *action) { - Alias *alias = [Identifier identifierForName:name]; + Alias *alias = Identifier.identifiers[name]; if (alias == nil) - [Identifier addIdentifier:[Alias aliasWithName:name - action:action - persisted:true]]; + Identifier.identifiers[name] = [Alias aliasWithName:name + action:action + persisted:true]; else { if ([alias isKindOfClass:Alias.class]) alias.action = action; else conoutf( @@ -35,36 +35,23 @@ COMMAND(alias, ARG_2STR, ^(OFString *name, OFString *action) { alias(name, action); }) -int -variable(OFString *name, int min, int cur, int max, int *storage, - void (*function)(), bool persisted) -{ - [Identifier addIdentifier:[Variable variableWithName:name - min:min - max:max - storage:storage - function:function - persisted:persisted]]; - return cur; -} - void setvar(OFString *name, int i) { - Variable *variable = [Identifier identifierForName:name]; + Variable *variable = Identifier.identifiers[name]; if ([variable isKindOfClass:Variable.class]) *variable.storage = i; } int getvar(OFString *name) { - Variable *variable = [Identifier identifierForName:name]; + Variable *variable = Identifier.identifiers[name]; if ([variable isKindOfClass:Variable.class]) return *variable.storage; return 0; @@ -71,17 +58,17 @@ } bool identexists(OFString *name) { - return ([Identifier identifierForName:name] != nil); + return (Identifier.identifiers[name] != nil); } OFString * getalias(OFString *name) { - Alias *alias = [Identifier identifierForName:name]; + Alias *alias = Identifier.identifiers[name]; if ([alias isKindOfClass:Alias.class]) return alias.action; return nil; @@ -151,11 +138,11 @@ // find value of ident referenced with $ in exp OFString * lookup(OFString *n) { __kindof Identifier *identifier = - [Identifier identifierForName:[n substringFromIndex:1]]; + Identifier.identifiers[[n substringFromIndex:1]]; if ([identifier isKindOfClass:Variable.class]) { return [OFString stringWithFormat:@"%d", *[identifier storage]]; } else if ([identifier isKindOfClass:Alias.class]) return [identifier action]; @@ -258,11 +245,11 @@ } // empty statement if (c.length == 0) continue; - val = executeIdentifier([Identifier identifierForName:c], + val = executeIdentifier(Identifier.identifiers[c], [OFArray arrayWithObjects:w count:numargs], isDown); } return val; } @@ -290,12 +277,12 @@ completesize = s.length - 1; completeidx = 0; } __block int idx = 0; - [Identifier enumerateIdentifiersUsingBlock:^( - __kindof Identifier *identifier) { + [Identifier.identifiers enumerateKeysAndObjectsUsingBlock:^( + OFString *name, __kindof Identifier *identifier, bool *stop) { if (strncmp(identifier.name.UTF8String, s.UTF8String + 1, completesize) == 0 && idx++ == completeidx) [s replaceCharactersInRange:OFMakeRange(1, s.length - 1) withString:identifier.name]; @@ -357,33 +344,33 @@ @"autoexec.cfg to override anything\n" @"\n"]; writeclientinfo(stream); [stream writeString:@"\n"]; - [Identifier - enumerateIdentifiersUsingBlock:^(__kindof Identifier *identifier) { - if (![identifier isKindOfClass:Variable.class] || - ![identifier persisted]) - return; - - [stream writeFormat:@"%@ %d\n", identifier.name, - *[identifier storage]]; - }]; + [Identifier.identifiers enumerateKeysAndObjectsUsingBlock:^( + OFString *name, __kindof Identifier *identifier, bool *stop) { + if (![identifier isKindOfClass:Variable.class] || + ![identifier persisted]) + return; + + [stream writeFormat:@"%@ %d\n", identifier.name, + *[identifier storage]]; + }]; [stream writeString:@"\n"]; writebinds(stream); [stream writeString:@"\n"]; - [Identifier - enumerateIdentifiersUsingBlock:^(__kindof Identifier *identifier) { - if (![identifier isKindOfClass:Alias.class] || - [identifier.name hasPrefix:@"nextmap_"]) - return; - - [stream writeFormat:@"alias \"%@\" [%@]\n", identifier.name, - [identifier action]]; - }]; + [Identifier.identifiers enumerateKeysAndObjectsUsingBlock:^( + OFString *name, __kindof Identifier *identifier, bool *stop) { + if (![identifier isKindOfClass:Alias.class] || + [identifier.name hasPrefix:@"nextmap_"]) + return; + + [stream writeFormat:@"alias \"%@\" [%@]\n", identifier.name, + [identifier action]]; + }]; [stream close]; } COMMAND(writecfg, ARG_NONE, ^{ Index: src/cube.h ================================================================== --- src/cube.h +++ src/cube.h @@ -329,55 +329,10 @@ ARG_1EST, ARG_2EST, ARG_VARI }; -// nasty macros for registering script functions, abuses globals to avoid -// excessive infrastructure -#define VARP(name, min, cur, max) \ - int name; \ - OF_CONSTRUCTOR() \ - { \ - enqueueInit(^{ \ - 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); \ - }); \ - } -#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); \ - }); \ - } \ - void var_##name() { body; } -#define VARFP(name, min, cur, max, body) \ - void var_##name(); \ - static int name; \ - OF_CONSTRUCTOR() \ - { \ - enqueueInit(^{ \ - name = variable( \ - @ #name, min, cur, max, &name, var_##name, true); \ - }); \ - } \ - void var_##name() { body; } - -#define ATOI(s) strtol(s, NULL, 0) // supports hexadecimal numbers - #ifdef WIN32 # define WIN32_LEAN_AND_MEAN # include "windows.h" # define _WINDOWS # define ZLIB_DLL Index: src/editing.m ================================================================== --- src/editing.m +++ src/editing.m @@ -6,28 +6,39 @@ #import "Command.h" #import "DynamicEntity.h" #import "Monster.h" #import "OFString+Cube.h" #import "Player.h" +#import "Variable.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 // the edge of the map -struct block sel; +struct block sel = { 0, 0, 0, 0 }; OF_CONSTRUCTOR() { enqueueInit(^{ - sel = (struct block) { - 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), - }; + static const struct { + OFString *name; + int *storage; + } vars[4] = { { @"selx", &sel.x }, { @"sely", &sel.y }, + { @"selxs", &sel.xs }, { @"selys", &sel.ys } }; + + for (size_t i = 0; i < 4; i++) { + Variable *variable = + [Variable variableWithName:vars[i].name + min:0 + max:4096 + storage:vars[i].storage + function:NULL + persisted:false]; + Identifier.identifiers[vars[i].name] = variable; + } }); } int selh = 0; bool selset = false; Index: src/physics.m ================================================================== --- src/physics.m +++ src/physics.m @@ -9,10 +9,11 @@ #import "DynamicEntity.h" #import "Entity.h" #import "MapModelInfo.h" #import "Monster.h" #import "Player.h" +#import "Variable.h" // collide with player or monster static bool plcollide( DynamicEntity *d, DynamicEntity *o, float *headspace, float *hi, float *lo) Index: src/protos.h ================================================================== --- src/protos.h +++ src/protos.h @@ -3,12 +3,10 @@ #ifdef __cplusplus extern "C" { #endif // command -extern int variable(OFString *name, int min, int cur, int max, int *storage, - void (*fun)(), bool persist); extern void setvar(OFString *name, int i); extern int getvar(OFString *name); extern bool identexists(OFString *name); extern int execute(OFString *p, bool down); extern void exec(OFString *cfgfile); Index: src/rendercubes.m ================================================================== --- src/rendercubes.m +++ src/rendercubes.m @@ -2,10 +2,11 @@ // the vertex array for different cube surfaces. #include "cube.h" #import "Command.h" +#import "Variable.h" static struct vertex *verts = NULL; int curvert; static int curmaxverts = 10000; Index: src/renderextras.m ================================================================== --- src/renderextras.m +++ src/renderextras.m @@ -3,10 +3,11 @@ #include "cube.h" #import "Command.h" #import "Entity.h" #import "Player.h" +#import "Variable.h" void line(int x1, int y1, float z1, int x2, int y2, float z2) { glBegin(GL_POLYGON); Index: src/rendergl.m ================================================================== --- src/rendergl.m +++ src/rendergl.m @@ -6,10 +6,11 @@ #import "Command.h" #import "Monster.h" #import "OFString+Cube.h" #import "Player.h" +#import "Variable.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 Index: src/renderparticles.m ================================================================== --- src/renderparticles.m +++ src/renderparticles.m @@ -1,10 +1,11 @@ // renderparticles.cpp #include "cube.h" #import "Player.h" +#import "Variable.h" #define MAXPARTICLES 10500 const int NUMPARTCUTOFF = 20; struct particle { OFVector3D o, d; Index: src/savegamedemo.m ================================================================== --- src/savegamedemo.m +++ src/savegamedemo.m @@ -5,10 +5,11 @@ #import "Command.h" #import "Entity.h" #import "Monster.h" #import "Player.h" +#import "Variable.h" #ifdef OF_BIG_ENDIAN static const int islittleendian = 0; #else static const int islittleendian = 1; Index: src/sound.m ================================================================== --- src/sound.m +++ src/sound.m @@ -1,9 +1,10 @@ #include "cube.h" #import "Command.h" #import "Player.h" +#import "Variable.h" #include VARP(soundvol, 0, 255, 255); VARP(musicvol, 0, 128, 255); Index: src/worldlight.m ================================================================== --- src/worldlight.m +++ src/worldlight.m @@ -3,10 +3,11 @@ #include "cube.h" #import "DynamicEntity.h" #import "Entity.h" #import "Monster.h" +#import "Variable.h" extern bool hasoverbright; VAR(lightscale, 1, 4, 100);