Clean up identifiers, use blocks for commands

FossilOrigin-Name: d7661be1b1dc8fda8e4de50f9a9d75907f498e6e07530241fb04be015ca3d9ae
This commit is contained in:
Jonathan Schleifer 2025-03-23 19:40:00 +00:00
parent e995b95a84
commit daa4c19312
25 changed files with 391 additions and 535 deletions

View file

@ -2,17 +2,27 @@
OF_ASSUME_NONNULL_BEGIN OF_ASSUME_NONNULL_BEGIN
#define COMMAND(name, nargs, block_) \
OF_CONSTRUCTOR() \
{ \
enqueueInit(^{ \
[Identifier \
addIdentifier:[Command commandWithName:@ #name \
argumentsTypes:nargs \
block:block_]]; \
}); \
}
@interface Command: Identifier @interface Command: Identifier
@property (readonly, nonatomic) void (*function)();
@property (readonly, nonatomic) int argumentsTypes; @property (readonly, nonatomic) int argumentsTypes;
+ (instancetype)commandWithName:(OFString *)name + (instancetype)commandWithName:(OFString *)name
function:(void (*)())function argumentsTypes:(int)argumentsTypes
argumentsTypes:(int)argumentsTypes; block:(id)block;
- (instancetype)initWithName:(OFString *)name OF_UNAVAILABLE; - (instancetype)initWithName:(OFString *)name OF_UNAVAILABLE;
- (instancetype)initWithName:(OFString *)name - (instancetype)initWithName:(OFString *)name
function:(void (*)())function argumentsTypes:(int)argumentsTypes
argumentsTypes:(int)argumentsTypes; block:(id)block;
- (int)callWithArguments:(OFArray<OFString *> *)arguments isDown:(bool)isDown; - (int)callWithArguments:(OFArray<OFString *> *)arguments isDown:(bool)isDown;
@end @end

View file

@ -20,23 +20,27 @@ padArguments(OFArray<OFString *> *arguments, size_t count)
} }
@implementation Command @implementation Command
{
id _block;
}
+ (instancetype)commandWithName:(OFString *)name + (instancetype)commandWithName:(OFString *)name
function:(void (*)())function
argumentsTypes:(int)argumentsTypes argumentsTypes:(int)argumentsTypes
block:(id)block
{ {
return [[self alloc] initWithName:name return [[self alloc] initWithName:name
function:function argumentsTypes:argumentsTypes
argumentsTypes:argumentsTypes]; block:block];
} }
- (instancetype)initWithName:(OFString *)name - (instancetype)initWithName:(OFString *)name
function:(void (*)())function
argumentsTypes:(int)argumentsTypes argumentsTypes:(int)argumentsTypes
block:(id)block
{ {
self = [super initWithName:name]; self = [super initWithName:name];
_function = function;
_argumentsTypes = argumentsTypes; _argumentsTypes = argumentsTypes;
_block = block;
return self; return self;
} }
@ -47,14 +51,14 @@ padArguments(OFArray<OFString *> *arguments, size_t count)
case ARG_1INT: case ARG_1INT:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 2); arguments = padArguments(arguments, 2);
((void(__cdecl *)(int))_function)( ((void (^)(int))_block)(
[arguments[1] cube_intValueWithBase:0]); [arguments[1] cube_intValueWithBase:0]);
} }
break; break;
case ARG_2INT: case ARG_2INT:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 3); arguments = padArguments(arguments, 3);
((void(__cdecl *)(int, int))_function)( ((void (^)(int, int))_block)(
[arguments[1] cube_intValueWithBase:0], [arguments[1] cube_intValueWithBase:0],
[arguments[2] cube_intValueWithBase:0]); [arguments[2] cube_intValueWithBase:0]);
} }
@ -62,7 +66,7 @@ padArguments(OFArray<OFString *> *arguments, size_t count)
case ARG_3INT: case ARG_3INT:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 4); arguments = padArguments(arguments, 4);
((void(__cdecl *)(int, int, int))_function)( ((void (^)(int, int, int))_block)(
[arguments[1] cube_intValueWithBase:0], [arguments[1] cube_intValueWithBase:0],
[arguments[2] cube_intValueWithBase:0], [arguments[2] cube_intValueWithBase:0],
[arguments[3] cube_intValueWithBase:0]); [arguments[3] cube_intValueWithBase:0]);
@ -71,7 +75,7 @@ padArguments(OFArray<OFString *> *arguments, size_t count)
case ARG_4INT: case ARG_4INT:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 5); arguments = padArguments(arguments, 5);
((void(__cdecl *)(int, int, int, int))_function)( ((void (^)(int, int, int, int))_block)(
[arguments[1] cube_intValueWithBase:0], [arguments[1] cube_intValueWithBase:0],
[arguments[2] cube_intValueWithBase:0], [arguments[2] cube_intValueWithBase:0],
[arguments[3] cube_intValueWithBase:0], [arguments[3] cube_intValueWithBase:0],
@ -80,57 +84,55 @@ padArguments(OFArray<OFString *> *arguments, size_t count)
break; break;
case ARG_NONE: case ARG_NONE:
if (isDown) if (isDown)
((void(__cdecl *)())_function)(); ((void (^)())_block)();
break; break;
case ARG_1STR: case ARG_1STR:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 2); arguments = padArguments(arguments, 2);
((void(__cdecl *)(OFString *))_function)(arguments[1]); ((void (^)(OFString *))_block)(arguments[1]);
} }
break; break;
case ARG_2STR: case ARG_2STR:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 3); arguments = padArguments(arguments, 3);
((void(__cdecl *)(OFString *, OFString *))_function)( ((void (^)(OFString *, OFString *))_block)(
arguments[1], arguments[2]); arguments[1], arguments[2]);
} }
break; break;
case ARG_3STR: case ARG_3STR:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 4); arguments = padArguments(arguments, 4);
((void(__cdecl *)( ((void (^)(OFString *, OFString *, OFString *))_block)(
OFString *, OFString *, OFString *))_function)(
arguments[1], arguments[2], arguments[3]); arguments[1], arguments[2], arguments[3]);
} }
break; break;
case ARG_5STR: case ARG_5STR:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 6); arguments = padArguments(arguments, 6);
((void(__cdecl *)(OFString *, OFString *, OFString *, ((void (^)(OFString *, OFString *, OFString *,
OFString *, OFString *))_function)(arguments[1], OFString *, OFString *))_block)(arguments[1],
arguments[2], arguments[3], arguments[4], arguments[2], arguments[3], arguments[4],
arguments[5]); arguments[5]);
} }
break; break;
case ARG_DOWN: case ARG_DOWN:
((void(__cdecl *)(bool))_function)(isDown); ((void (^)(bool))_block)(isDown);
break; break;
case ARG_DWN1: case ARG_DWN1:
arguments = padArguments(arguments, 2); arguments = padArguments(arguments, 2);
((void(__cdecl *)(bool, OFString *))_function)( ((void (^)(bool, OFString *))_block)(isDown, arguments[1]);
isDown, arguments[1]);
break; break;
case ARG_1EXP: case ARG_1EXP:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 2); arguments = padArguments(arguments, 2);
return ((int(__cdecl *)(int))_function)( return ((int (^)(int))_block)(
execute(arguments[1], isDown)); execute(arguments[1], isDown));
} }
break; break;
case ARG_2EXP: case ARG_2EXP:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 3); arguments = padArguments(arguments, 3);
return ((int(__cdecl *)(int, int))_function)( return ((int (^)(int, int))_block)(
execute(arguments[1], isDown), execute(arguments[1], isDown),
execute(arguments[2], isDown)); execute(arguments[2], isDown));
} }
@ -138,21 +140,20 @@ padArguments(OFArray<OFString *> *arguments, size_t count)
case ARG_1EST: case ARG_1EST:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 2); arguments = padArguments(arguments, 2);
return ((int(__cdecl *)(OFString *))_function)( return ((int (^)(OFString *))_block)(arguments[1]);
arguments[1]);
} }
break; break;
case ARG_2EST: case ARG_2EST:
if (isDown) { if (isDown) {
arguments = padArguments(arguments, 3); arguments = padArguments(arguments, 3);
return ((int(__cdecl *)(OFString *, return ((int (^)(OFString *, OFString *))_block)(
OFString *))_function)(arguments[1], arguments[2]); arguments[1], arguments[2]);
} }
break; break;
case ARG_VARI: case ARG_VARI:
if (isDown) if (isDown)
// limit, remove // limit, remove
((void(__cdecl *)(OFString *))_function)([[arguments ((void (^)(OFString *))_block)([[arguments
objectsInRange:OFMakeRange(1, arguments.count - 1)] objectsInRange:OFMakeRange(1, arguments.count - 1)]
componentsJoinedByString:@" "]); componentsJoinedByString:@" "]);
break; break;

View file

@ -2,6 +2,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
OF_APPLICATION_DELEGATE(Cube) OF_APPLICATION_DELEGATE(Cube)
@ -373,16 +374,11 @@ fatal(OFConstantString *s, ...)
[OFApplication terminateWithStatus:1]; [OFApplication terminateWithStatus:1];
} }
void // normal exit
quit() // normal exit COMMAND(quit, ARG_NONE, ^{
{
[Cube.sharedInstance quit]; [Cube.sharedInstance quit];
} })
COMMAND(quit, ARG_NONE)
void COMMAND(screenshot, ARG_NONE, ^{
screenshot()
{
[Cube.sharedInstance screenshot]; [Cube.sharedInstance screenshot];
} })
COMMAND(screenshot, ARG_NONE)

View file

@ -5,6 +5,9 @@ OF_ASSUME_NONNULL_BEGIN
@interface Identifier: OFObject @interface Identifier: OFObject
@property (readonly, copy, nonatomic) OFString *name; @property (readonly, copy, nonatomic) OFString *name;
+ (void)addIdentifier:(__kindof Identifier *)identifier;
+ (__kindof Identifier *)identifierForName:(OFString *)name;
+ (void)enumerateIdentifiersUsingBlock:(void (^)(__kindof Identifier *))block;
- (instancetype)init OF_UNAVAILABLE; - (instancetype)init OF_UNAVAILABLE;
- (instancetype)initWithName:(OFString *)name; - (instancetype)initWithName:(OFString *)name;
@end @end

View file

@ -1,6 +1,33 @@
#import "Identifier.h" #import "Identifier.h"
// contains ALL vars/commands/aliases
static OFMutableDictionary<OFString *, __kindof Identifier *> *identifiers;
@implementation Identifier @implementation Identifier
+ (void)initialize
{
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);
}];
}
- (instancetype)initWithName:(OFString *)name - (instancetype)initWithName:(OFString *)name
{ {
self = [super init]; self = [super init];

View file

@ -2,6 +2,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "Monster.h" #import "Monster.h"
@ -177,9 +178,7 @@ renderscores()
// sendmap/getmap commands, should be replaced by more intuitive map downloading // sendmap/getmap commands, should be replaced by more intuitive map downloading
void COMMAND(sendmap, ARG_1STR, (^(OFString *mapname) {
sendmap(OFString *mapname)
{
if (mapname.length > 0) if (mapname.length > 0)
save_world(mapname); save_world(mapname);
changemap(mapname); changemap(mapname);
@ -210,11 +209,9 @@ sendmap(OFString *mapname)
@"\"getmap\" to receive it]", @"\"getmap\" to receive it]",
mapname]; mapname];
toserver(msg); toserver(msg);
} }))
void COMMAND(getmap, ARG_NONE, ^{
getmap()
{
ENetPacket *packet = ENetPacket *packet =
enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
unsigned char *start = packet->data; unsigned char *start = packet->data;
@ -224,7 +221,4 @@ getmap()
enet_packet_resize(packet, p - start); enet_packet_resize(packet, p - start);
sendpackettoserv(packet); sendpackettoserv(packet);
conoutf(@"requesting map from server..."); conoutf(@"requesting map from server...");
} })
COMMAND(sendmap, ARG_1STR)
COMMAND(getmap, ARG_NONE)

View file

@ -2,6 +2,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "Entity.h" #import "Entity.h"
#import "Monster.h" #import "Monster.h"
@ -10,12 +11,9 @@
int nextmode = 0; // nextmode becomes gamemode after next map load int nextmode = 0; // nextmode becomes gamemode after next map load
VAR(gamemode, 1, 0, 0); VAR(gamemode, 1, 0, 0);
static void COMMAND(mode, ARG_1INT, ^(int n) {
mode(int n)
{
addmsg(1, 2, SV_GAMEMODE, nextmode = n); addmsg(1, 2, SV_GAMEMODE, nextmode = n);
} })
COMMAND(mode, ARG_1INT)
bool intermission = false; bool intermission = false;
@ -142,13 +140,10 @@ respawn()
int sleepwait = 0; int sleepwait = 0;
static OFString *sleepcmd = nil; static OFString *sleepcmd = nil;
void COMMAND(sleep, ARG_2STR, ^(OFString *msec, OFString *cmd) {
sleepf(OFString *msec, OFString *cmd)
{
sleepwait = msec.cube_intValue + lastmillis; sleepwait = msec.cube_intValue + lastmillis;
sleepcmd = cmd; sleepcmd = cmd;
} })
COMMANDN(sleep, sleepf, ARG_2STR)
void void
updateworld(int millis) // main game update loop updateworld(int millis) // main game update loop
@ -240,43 +235,34 @@ spawnplayer(DynamicEntity *d)
// movement input code // movement input code
#define dir(name, v, d, s, os) \ #define dir(name, v, d, s, os) \
static void name(bool isdown) \ COMMAND(name, ARG_DOWN, ^(bool isDown) { \
{ \ player1.s = isDown; \
player1.s = isdown; \ player1.v = isDown ? d : (player1.os ? -(d) : 0); \
player1.v = isdown ? d : (player1.os ? -(d) : 0); \
player1.lastMove = lastmillis; \ player1.lastMove = lastmillis; \
} })
dir(backward, move, -1, k_down, k_up); dir(backward, move, -1, k_down, k_up);
dir(forward, move, 1, k_up, k_down); dir(forward, move, 1, k_up, k_down);
dir(left, strafe, 1, k_left, k_right); dir(left, strafe, 1, k_left, k_right);
dir(right, strafe, -1, k_right, k_left); dir(right, strafe, -1, k_right, k_left);
void COMMAND(attack, ARG_DOWN, ^(bool on) {
attack(bool on)
{
if (intermission) if (intermission)
return; return;
if (editmode) if (editmode)
editdrag(on); editdrag(on);
else if ((player1.attacking = on)) else if ((player1.attacking = on))
respawn(); respawn();
} })
void COMMAND(jump, ARG_DOWN, ^(bool on) {
jumpn(bool on)
{
if (!intermission && (player1.jumpNext = on)) if (!intermission && (player1.jumpNext = on))
respawn(); respawn();
} })
COMMAND(backward, ARG_DOWN) COMMAND(showscores, ARG_DOWN, ^(bool isDown) {
COMMAND(forward, ARG_DOWN) showscores(isDown);
COMMAND(left, ARG_DOWN) })
COMMAND(right, ARG_DOWN)
COMMANDN(jump, jumpn, ARG_DOWN)
COMMAND(attack, ARG_DOWN)
COMMAND(showscores, ARG_DOWN)
void void
fixplayer1range() fixplayer1range()
@ -440,4 +426,6 @@ startmap(OFString *name) // called just after a map load
conoutf(@"game mode is %@", modestr(gamemode)); conoutf(@"game mode is %@", modestr(gamemode));
} }
COMMANDN(map, changemap, ARG_1STR) COMMAND(map, ARG_1STR, ^(OFString *name) {
changemap(name);
})

View file

@ -2,6 +2,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
static ENetHost *clienthost = NULL; static ENetHost *clienthost = NULL;
@ -60,7 +61,7 @@ throttle()
throttle_interval * 1000, throttle_accel, throttle_decel); throttle_interval * 1000, throttle_accel, throttle_decel);
} }
void static void
newname(OFString *name) newname(OFString *name)
{ {
c2sinit = false; c2sinit = false;
@ -70,9 +71,12 @@ newname(OFString *name)
player1.name = name; player1.name = name;
} }
COMMANDN(name, newname, ARG_1STR)
void COMMAND(name, ARG_1STR, ^(OFString *name) {
newname(name);
})
static void
newteam(OFString *name) newteam(OFString *name)
{ {
c2sinit = false; c2sinit = false;
@ -82,7 +86,10 @@ newteam(OFString *name)
player1.team = name; player1.team = name;
} }
COMMANDN(team, newteam, ARG_1STR)
COMMAND(team, ARG_1STR, ^(OFString *name) {
newteam(name);
})
void void
writeclientinfo(OFStream *stream) writeclientinfo(OFStream *stream)
@ -177,16 +184,18 @@ toserver(OFString *text)
ctext = text; ctext = text;
} }
void COMMAND(echo, ARG_VARI, ^(OFString *text) {
echo(OFString *text)
{
conoutf(@"%@", text); conoutf(@"%@", text);
} })
COMMAND(say, ARG_VARI, ^(OFString *text) {
COMMAND(echo, ARG_VARI) toserver(text);
COMMANDN(say, toserver, ARG_VARI) })
COMMANDN(connect, connects, ARG_1STR) COMMAND(connect, ARG_1STR, ^(OFString *servername) {
COMMANDN(disconnect, trydisconnect, ARG_NONE) connects(servername);
})
COMMAND(disconnect, ARG_NONE, ^{
trydisconnect();
})
// collect c2s messages conveniently // collect c2s messages conveniently
@ -239,12 +248,9 @@ bool senditemstoserver =
false; // after a map change, since server doesn't have map data false; // after a map change, since server doesn't have map data
OFString *clientpassword; OFString *clientpassword;
void COMMAND(password, ARG_1STR, ^(OFString *p) {
password(OFString *p)
{
clientpassword = p; clientpassword = p;
} })
COMMAND(password, ARG_1STR)
bool bool
netmapstart() netmapstart()

View file

@ -9,9 +9,6 @@
#import "OFString+Cube.h" #import "OFString+Cube.h"
#import "Variable.h" #import "Variable.h"
// contains ALL vars/commands/aliases
static OFMutableDictionary<OFString *, __kindof Identifier *> *identifiers;
static void static void
cleanup(char **string) cleanup(char **string)
{ {
@ -21,16 +18,13 @@ cleanup(char **string)
void void
alias(OFString *name, OFString *action) alias(OFString *name, OFString *action)
{ {
Alias *alias = identifiers[name]; Alias *alias = [Identifier identifierForName:name];
if (alias == nil) { if (alias == nil)
alias = [Alias aliasWithName:name action:action persisted:true]; [Identifier addIdentifier:[Alias aliasWithName:name
action:action
if (identifiers == nil) persisted:true]];
identifiers = [[OFMutableDictionary alloc] init]; else {
identifiers[name] = alias;
} else {
if ([alias isKindOfClass:Alias.class]) if ([alias isKindOfClass:Alias.class])
alias.action = action; alias.action = action;
else else
@ -38,49 +32,54 @@ alias(OFString *name, OFString *action)
@"cannot redefine builtin %@ with an alias", name); @"cannot redefine builtin %@ with an alias", name);
} }
} }
COMMAND(alias, ARG_2STR)
COMMAND(alias, ARG_2STR, ^(OFString *name, OFString *action) {
alias(name, action);
})
int int
variable(OFString *name, int min, int cur, int max, int *storage, variable(OFString *name, int min, int cur, int max, int *storage,
void (*function)(), bool persisted) void (*function)(), bool persisted)
{ {
Variable *variable = [Variable variableWithName:name [Identifier addIdentifier:[Variable variableWithName:name
min:min min:min
max:max max:max
storage:storage storage:storage
function:function function:function
persisted:persisted]; persisted:persisted]];
if (identifiers == nil)
identifiers = [[OFMutableDictionary alloc] init];
identifiers[name] = variable;
return cur; return cur;
} }
void void
setvar(OFString *name, int i) setvar(OFString *name, int i)
{ {
*[identifiers[name] storage] = i; Variable *variable = [Identifier identifierForName:name];
if ([variable isKindOfClass:Variable.class])
*variable.storage = i;
} }
int int
getvar(OFString *name) getvar(OFString *name)
{ {
return *[identifiers[name] storage]; Variable *variable = [Identifier identifierForName:name];
if ([variable isKindOfClass:Variable.class])
return *variable.storage;
return 0;
} }
bool bool
identexists(OFString *name) identexists(OFString *name)
{ {
return (identifiers[name] != nil); return ([Identifier identifierForName:name] != nil);
} }
OFString * OFString *
getalias(OFString *name) getalias(OFString *name)
{ {
Alias *alias = identifiers[name]; Alias *alias = [Identifier identifierForName:name];
if ([alias isKindOfClass:Alias.class]) if ([alias isKindOfClass:Alias.class])
return alias.action; return alias.action;
@ -88,21 +87,6 @@ getalias(OFString *name)
return nil; return nil;
} }
bool
addcommand(OFString *name, void (*function)(), int argumentsTypes)
{
Command *command = [Command commandWithName:name
function:function
argumentsTypes:argumentsTypes];
if (identifiers == nil)
identifiers = [[OFMutableDictionary alloc] init];
identifiers[name] = command;
return false;
}
// parse any nested set of () or [] // parse any nested set of () or []
static char * static char *
parseexp(char **p, int right) parseexp(char **p, int right)
@ -168,7 +152,8 @@ parseword(char **p)
OFString * OFString *
lookup(OFString *n) lookup(OFString *n)
{ {
__kindof Identifier *identifier = identifiers[[n substringFromIndex:1]]; __kindof Identifier *identifier =
[Identifier identifierForName:[n substringFromIndex:1]];
if ([identifier isKindOfClass:Variable.class]) { if ([identifier isKindOfClass:Variable.class]) {
return [OFString stringWithFormat:@"%d", *[identifier storage]]; return [OFString stringWithFormat:@"%d", *[identifier storage]];
@ -275,7 +260,7 @@ execute(OFString *string, bool isDown)
if (c.length == 0) if (c.length == 0)
continue; continue;
val = executeIdentifier(identifiers[c], val = executeIdentifier([Identifier identifierForName:c],
[OFArray arrayWithObjects:w count:numargs], isDown); [OFArray arrayWithObjects:w count:numargs], isDown);
} }
@ -307,8 +292,8 @@ complete(OFMutableString *s)
} }
__block int idx = 0; __block int idx = 0;
[identifiers enumerateKeysAndObjectsUsingBlock:^( [Identifier enumerateIdentifiersUsingBlock:^(
OFString *name, Identifier *identifier, bool *stop) { __kindof Identifier *identifier) {
if (strncmp(identifier.name.UTF8String, s.UTF8String + 1, if (strncmp(identifier.name.UTF8String, s.UTF8String + 1,
completesize) == 0 && completesize) == 0 &&
idx++ == completeidx) idx++ == completeidx)
@ -348,6 +333,10 @@ exec(OFString *cfgfile)
conoutf(@"could not read \"%@\"", cfgfile); conoutf(@"could not read \"%@\"", cfgfile);
} }
COMMAND(exec, ARG_1STR, ^(OFString *cfgfile) {
exec(cfgfile);
})
void void
writecfg() writecfg()
{ {
@ -370,34 +359,36 @@ writecfg()
writeclientinfo(stream); writeclientinfo(stream);
[stream writeString:@"\n"]; [stream writeString:@"\n"];
[identifiers enumerateKeysAndObjectsUsingBlock:^( [Identifier
OFString *name, __kindof Identifier *identifier, bool *stop) { enumerateIdentifiersUsingBlock:^(__kindof Identifier *identifier) {
if (![identifier isKindOfClass:Variable.class] || if (![identifier isKindOfClass:Variable.class] ||
![identifier persisted]) ![identifier persisted])
return; return;
[stream writeFormat:@"%@ %d\n", identifier.name, [stream writeFormat:@"%@ %d\n", identifier.name,
*[identifier storage]]; *[identifier storage]];
}]; }];
[stream writeString:@"\n"]; [stream writeString:@"\n"];
writebinds(stream); writebinds(stream);
[stream writeString:@"\n"]; [stream writeString:@"\n"];
[identifiers enumerateKeysAndObjectsUsingBlock:^( [Identifier
OFString *name, __kindof Identifier *identifier, bool *stop) { enumerateIdentifiersUsingBlock:^(__kindof Identifier *identifier) {
if (![identifier isKindOfClass:Alias.class] || if (![identifier isKindOfClass:Alias.class] ||
[identifier.name hasPrefix:@"nextmap_"]) [identifier.name hasPrefix:@"nextmap_"])
return; return;
[stream writeFormat:@"alias \"%@\" [%@]\n", identifier.name, [stream writeFormat:@"alias \"%@\" [%@]\n", identifier.name,
[identifier action]]; [identifier action]];
}]; }];
[stream close]; [stream close];
} }
COMMAND(writecfg, ARG_NONE) COMMAND(writecfg, ARG_NONE, ^{
writecfg();
})
// below the commands that implement a small imperative language. thanks to the // below the commands that implement a small imperative language. thanks to the
// semantics of () and [] expressions, any control construct can be defined // semantics of () and [] expressions, any control construct can be defined
@ -409,36 +400,28 @@ intset(OFString *name, int v)
alias(name, [OFString stringWithFormat:@"%d", v]); alias(name, [OFString stringWithFormat:@"%d", v]);
} }
void COMMAND(if, ARG_3STR, ^(OFString *cond, OFString *thenp, OFString *elsep) {
ifthen(OFString *cond, OFString *thenp, OFString *elsep)
{
execute((![cond hasPrefix:@"0"] ? thenp : elsep), true); execute((![cond hasPrefix:@"0"] ? thenp : elsep), true);
} })
void COMMAND(loop, ARG_2STR, ^(OFString *times, OFString *body) {
loopa(OFString *times, OFString *body)
{
int t = times.cube_intValue; int t = times.cube_intValue;
for (int i = 0; i < t; i++) { for (int i = 0; i < t; i++) {
intset(@"i", i); intset(@"i", i);
execute(body, true); execute(body, true);
} }
} })
void COMMAND(while, ARG_2STR, ^(OFString *cond, OFString *body) {
whilea(OFString *cond, OFString *body)
{
while (execute(cond, true)) while (execute(cond, true))
execute(body, true); execute(body, true);
} })
void COMMAND(onrelease, ARG_DWN1, ^(bool on, OFString *body) {
onrelease(bool on, OFString *body)
{
if (!on) if (!on)
execute(body, true); execute(body, true);
} })
void void
concat(OFString *s) concat(OFString *s)
@ -446,15 +429,15 @@ concat(OFString *s)
alias(@"s", s); alias(@"s", s);
} }
void COMMAND(concat, ARG_VARI, ^(OFString *s) {
concatword(OFString *s) concat(s);
{ })
concat([s stringByReplacingOccurrencesOfString:@" " withString:@""]);
}
int COMMAND(concatword, ARG_VARI, ^(OFString *s) {
listlen(OFString *a_) concat([s stringByReplacingOccurrencesOfString:@" " withString:@""]);
{ })
COMMAND(listlen, ARG_1EST, ^(OFString *a_) {
const char *a = a_.UTF8String; const char *a = a_.UTF8String;
if (!*a) if (!*a)
@ -466,11 +449,9 @@ listlen(OFString *a_)
n++; n++;
return n + 1; return n + 1;
} })
void COMMAND(at, ARG_2STR, ^(OFString *s_, OFString *pos) {
at(OFString *s_, OFString *pos)
{
int n = pos.cube_intValue; int n = pos.cube_intValue;
char *copy __attribute__((__cleanup__(cleanup))) = char *copy __attribute__((__cleanup__(cleanup))) =
strdup(s_.UTF8String); strdup(s_.UTF8String);
@ -481,91 +462,48 @@ at(OFString *s_, OFString *pos)
} }
s[strcspn(s, " \0")] = 0; s[strcspn(s, " \0")] = 0;
concat(@(s)); concat(@(s));
} })
COMMANDN(loop, loopa, ARG_2STR) COMMAND(+, ARG_2EXP, ^(int a, int b) {
COMMANDN(while, whilea, ARG_2STR)
COMMANDN(if, ifthen, ARG_3STR)
COMMAND(onrelease, ARG_DWN1)
COMMAND(exec, ARG_1STR)
COMMAND(concat, ARG_VARI)
COMMAND(concatword, ARG_VARI)
COMMAND(at, ARG_2STR)
COMMAND(listlen, ARG_1EST)
int
add(int a, int b)
{
return a + b; return a + b;
} })
COMMANDN(+, add, ARG_2EXP)
int COMMAND(*, ARG_2EXP, ^(int a, int b) {
mul(int a, int b)
{
return a * b; return a * b;
} })
COMMANDN(*, mul, ARG_2EXP)
int COMMAND(-, ARG_2EXP, ^(int a, int b) {
sub(int a, int b)
{
return a - b; return a - b;
} })
COMMANDN(-, sub, ARG_2EXP)
int COMMAND(div, ARG_2EXP, ^(int a, int b) {
divi(int a, int b)
{
return b ? a / b : 0; return b ? a / b : 0;
} })
COMMANDN(div, divi, ARG_2EXP)
int COMMAND(mod, ARG_2EXP, ^(int a, int b) {
mod(int a, int b)
{
return b ? a % b : 0; return b ? a % b : 0;
} })
COMMAND(mod, ARG_2EXP)
int COMMAND(=, ARG_2EXP, ^(int a, int b) {
equal(int a, int b)
{
return (int)(a == b); return (int)(a == b);
} })
COMMANDN(=, equal, ARG_2EXP)
int COMMAND(<, ARG_2EXP, ^(int a, int b) {
lt(int a, int b)
{
return (int)(a < b); return (int)(a < b);
} })
COMMANDN(<, lt, ARG_2EXP)
int COMMAND(>, ARG_2EXP, ^(int a, int b) {
gt(int a, int b)
{
return (int)(a > b); return (int)(a > b);
} })
COMMANDN(>, gt, ARG_2EXP)
int COMMAND(strcmp, ARG_2EST, ^(OFString *a, OFString *b) {
strcmpa(OFString *a, OFString *b)
{
return [a isEqual:b]; return [a isEqual:b];
} })
COMMANDN(strcmp, strcmpa, ARG_2EST)
int COMMAND(rnd, ARG_1EXP, ^(int a) {
rndn(int a) return (a > 0 ? rnd(a) : 0);
{ })
return a > 0 ? rnd(a) : 0;
}
COMMANDN(rnd, rndn, ARG_1EXP)
int COMMAND(millis, ARG_1EXP, ^(int unused) {
explastmillis()
{
return lastmillis; return lastmillis;
} })
COMMANDN(millis, explastmillis, ARG_1EXP)

View file

@ -4,6 +4,7 @@
#include <ctype.h> #include <ctype.h>
#import "Command.h"
#import "ConsoleLine.h" #import "ConsoleLine.h"
#import "KeyMapping.h" #import "KeyMapping.h"
#import "OFString+Cube.h" #import "OFString+Cube.h"
@ -17,14 +18,11 @@ int conskip = 0;
bool saycommandon = false; bool saycommandon = false;
static OFMutableString *commandbuf; static OFMutableString *commandbuf;
void COMMAND(conskip, ARG_1INT, ^(int n) {
setconskip(int n)
{
conskip += n; conskip += n;
if (conskip < 0) if (conskip < 0)
conskip = 0; conskip = 0;
} })
COMMANDN(conskip, setconskip, ARG_1INT)
static void static void
conline(OFString *sf, bool highlight) // add a line to the console buffer conline(OFString *sf, bool highlight) // add a line to the console buffer
@ -104,9 +102,7 @@ renderconsole()
static OFMutableArray<KeyMapping *> *keyMappings = nil; static OFMutableArray<KeyMapping *> *keyMappings = nil;
void COMMAND(keymap, ARG_3STR, ^(OFString *code, OFString *key, OFString *action) {
keymap(OFString *code, OFString *key, OFString *action)
{
if (keyMappings == nil) if (keyMappings == nil)
keyMappings = [[OFMutableArray alloc] init]; keyMappings = [[OFMutableArray alloc] init];
@ -114,12 +110,9 @@ keymap(OFString *code, OFString *key, OFString *action)
name:key]; name:key];
mapping.action = action; mapping.action = action;
[keyMappings addObject:mapping]; [keyMappings addObject:mapping];
} })
COMMAND(keymap, ARG_3STR)
void COMMAND(bind, ARG_2STR, ^(OFString *key, OFString *action) {
bindkey(OFString *key, OFString *action)
{
for (KeyMapping *mapping in keyMappings) { for (KeyMapping *mapping in keyMappings) {
if ([mapping.name caseInsensitiveCompare:key] == if ([mapping.name caseInsensitiveCompare:key] ==
OFOrderedSame) { OFOrderedSame) {
@ -129,11 +122,11 @@ bindkey(OFString *key, OFString *action)
} }
conoutf(@"unknown key \"%@\"", key); conoutf(@"unknown key \"%@\"", key);
} })
COMMANDN(bind, bindkey, ARG_2STR)
void // turns input to the command line on or off
saycommand(OFString *init) // turns input to the command line on or off static void
saycommand(OFString *init)
{ {
saycommandon = (init != nil); saycommandon = (init != nil);
if (saycommandon) if (saycommandon)
@ -149,15 +142,15 @@ saycommand(OFString *init) // turns input to the command line on or off
commandbuf = [init mutableCopy]; commandbuf = [init mutableCopy];
} }
COMMAND(saycommand, ARG_VARI)
void COMMAND(saycommand, ARG_VARI, ^(OFString *init) {
mapmsg(OFString *s) saycommand(init);
{ })
COMMAND(mapmsg, ARG_1STR, ^(OFString *s) {
memset(hdr.maptitle, '\0', sizeof(hdr.maptitle)); memset(hdr.maptitle, '\0', sizeof(hdr.maptitle));
strncpy(hdr.maptitle, s.UTF8String, 127); strncpy(hdr.maptitle, s.UTF8String, 127);
} })
COMMAND(mapmsg, ARG_1STR)
void void
pasteconsole() pasteconsole()
@ -168,9 +161,7 @@ pasteconsole()
static OFMutableArray<OFString *> *vhistory; static OFMutableArray<OFString *> *vhistory;
static int histpos = 0; static int histpos = 0;
void COMMAND(history, ARG_1INT, ^(int n) {
history(int n)
{
static bool rec = false; static bool rec = false;
if (!rec && n >= 0 && n < vhistory.count) { if (!rec && n >= 0 && n < vhistory.count) {
@ -178,8 +169,7 @@ history(int n)
execute(vhistory[vhistory.count - n - 1], true); execute(vhistory[vhistory.count - n - 1], true);
rec = false; rec = false;
} }
} })
COMMAND(history, ARG_1INT)
void void
keypress(int code, bool isDown) keypress(int code, bool isDown)

View file

@ -340,14 +340,6 @@ enum {
// nasty macros for registering script functions, abuses globals to avoid // nasty macros for registering script functions, abuses globals to avoid
// excessive infrastructure // excessive infrastructure
#define COMMANDN(name, fun, nargs) \
OF_CONSTRUCTOR() \
{ \
enqueueInit(^{ \
addcommand(@ #name, (void (*)())fun, nargs); \
}); \
}
#define COMMAND(name, nargs) COMMANDN(name, name, nargs)
#define VARP(name, min, cur, max) \ #define VARP(name, min, cur, max) \
int name; \ int name; \
OF_CONSTRUCTOR() \ OF_CONSTRUCTOR() \

View file

@ -3,6 +3,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "Monster.h" #import "Monster.h"
#import "OFString+Cube.h" #import "OFString+Cube.h"
@ -78,7 +79,10 @@ toggleedit()
selset = false; selset = false;
editing = editmode; editing = editmode;
} }
COMMANDN(edittoggle, toggleedit, ARG_NONE)
COMMAND(edittoggle, ARG_NONE, ^{
toggleedit();
})
void void
correctsel() // ensures above invariant correctsel() // ensures above invariant
@ -120,14 +124,12 @@ noselection()
if (noteditmode() || multiplayer()) \ if (noteditmode() || multiplayer()) \
return; return;
void COMMAND(select, ARG_4INT, (^(int x, int y, int xs, int ys) {
selectpos(int x, int y, int xs, int ys)
{
struct block s = { x, y, xs, ys }; struct block s = { x, y, xs, ys };
sel = s; sel = s;
selh = 0; selh = 0;
correctsel(); correctsel();
} }))
void void
makesel() makesel()
@ -272,9 +274,7 @@ makeundo()
pruneundos(undomegs << 20); pruneundos(undomegs << 20);
} }
void COMMAND(undo, ARG_NONE, ^{
editundo()
{
EDITMP; EDITMP;
if (undos.count == 0) { if (undos.count == 0) {
conoutf(@"nothing more to undo"); conoutf(@"nothing more to undo");
@ -284,24 +284,20 @@ editundo()
[undos removeLastItem]; [undos removeLastItem];
blockpaste(p); blockpaste(p);
OFFreeMemory(p); OFFreeMemory(p);
} })
static struct block *copybuf = NULL; static struct block *copybuf = NULL;
void COMMAND(copy, ARG_NONE, ^{
copy()
{
EDITSELMP; EDITSELMP;
if (copybuf) if (copybuf)
OFFreeMemory(copybuf); OFFreeMemory(copybuf);
copybuf = blockcopy(&sel); copybuf = blockcopy(&sel);
} })
void COMMAND(paste, ARG_NONE, ^{
paste()
{
EDITMP; EDITMP;
if (!copybuf) { if (!copybuf) {
conoutf(@"nothing to paste"); conoutf(@"nothing to paste");
@ -318,7 +314,7 @@ paste()
copybuf->x = sel.x; copybuf->x = sel.x;
copybuf->y = sel.y; copybuf->y = sel.y;
blockpaste(copybuf); blockpaste(copybuf);
} })
void void
tofronttex() // maintain most recently used of the texture lists when applying tofronttex() // maintain most recently used of the texture lists when applying
@ -378,7 +374,10 @@ editheight(int flr, int amount)
editheightxy(isfloor, amount, &sel); editheightxy(isfloor, amount, &sel);
addmsg(1, 7, SV_EDITH, sel.x, sel.y, sel.xs, sel.ys, isfloor, amount); addmsg(1, 7, SV_EDITH, sel.x, sel.y, sel.xs, sel.ys, isfloor, amount);
} }
COMMAND(editheight, ARG_2INT)
COMMAND(editheight, ARG_2INT, ^(int flr, int amount) {
editheight(flr, amount);
})
void void
edittexxy(int type, int t, const struct block *sel) edittexxy(int type, int t, const struct block *sel)
@ -399,9 +398,7 @@ edittexxy(int type, int t, const struct block *sel)
}); });
} }
void COMMAND(edittex, ARG_2INT, ^(int type, int dir) {
edittex(int type, int dir)
{
EDITSEL; EDITSEL;
if (type < 0 || type > 3) if (type < 0 || type > 3)
@ -419,11 +416,9 @@ edittex(int type, int dir)
int t = lasttex = hdr.texlists[atype][i]; int t = lasttex = hdr.texlists[atype][i];
edittexxy(type, t, &sel); edittexxy(type, t, &sel);
addmsg(1, 7, SV_EDITT, sel.x, sel.y, sel.xs, sel.ys, type, t); addmsg(1, 7, SV_EDITT, sel.x, sel.y, sel.xs, sel.ys, type, t);
} })
void COMMAND(replace, ARG_NONE, (^{
replace()
{
EDITSELMP; EDITSELMP;
for (int x = 0; x < ssize; x++) { for (int x = 0; x < ssize; x++) {
@ -452,7 +447,7 @@ replace()
struct block b = { 0, 0, ssize, ssize }; struct block b = { 0, 0, ssize, ssize };
remip(&b, 0); remip(&b, 0);
} }))
void void
edittypexy(int type, const struct block *sel) edittypexy(int type, const struct block *sel)
@ -460,7 +455,7 @@ edittypexy(int type, const struct block *sel)
loopselxy(s->type = type); loopselxy(s->type = type);
} }
void static void
edittype(int type) edittype(int type)
{ {
EDITSEL; EDITSEL;
@ -476,26 +471,17 @@ edittype(int type)
addmsg(1, 6, SV_EDITS, sel.x, sel.y, sel.xs, sel.ys, type); addmsg(1, 6, SV_EDITS, sel.x, sel.y, sel.xs, sel.ys, type);
} }
void COMMAND(heightfield, ARG_1INT, ^(int t) {
heightfield(int t)
{
edittype(t == 0 ? FHF : CHF); edittype(t == 0 ? FHF : CHF);
} })
COMMAND(heightfield, ARG_1INT)
void COMMAND(solid, ARG_1INT, ^(int t) {
solid(int t)
{
edittype(t == 0 ? SPACE : SOLID); edittype(t == 0 ? SPACE : SOLID);
} })
COMMAND(solid, ARG_1INT)
void COMMAND(corner, ARG_NONE, ^{
corner()
{
edittype(CORNER); edittype(CORNER);
} })
COMMAND(corner, ARG_NONE)
void void
editequalisexy(bool isfloor, const struct block *sel) editequalisexy(bool isfloor, const struct block *sel)
@ -517,17 +503,14 @@ editequalisexy(bool isfloor, const struct block *sel)
}); });
} }
void COMMAND(equalize, ARG_1INT, ^(int flr) {
equalize(int flr)
{
bool isfloor = (flr == 0); bool isfloor = (flr == 0);
EDITSEL; EDITSEL;
editequalisexy(isfloor, &sel); editequalisexy(isfloor, &sel);
addmsg(1, 6, SV_EDITE, sel.x, sel.y, sel.xs, sel.ys, isfloor); addmsg(1, 6, SV_EDITE, sel.x, sel.y, sel.xs, sel.ys, isfloor);
} })
COMMAND(equalize, ARG_1INT)
void void
setvdeltaxy(int delta, const struct block *sel) setvdeltaxy(int delta, const struct block *sel)
@ -536,22 +519,18 @@ setvdeltaxy(int delta, const struct block *sel)
remipmore(sel, 0); remipmore(sel, 0);
} }
void COMMAND(vdelta, ARG_1INT, ^(int delta) {
setvdelta(int delta)
{
EDITSEL; EDITSEL;
setvdeltaxy(delta, &sel); setvdeltaxy(delta, &sel);
addmsg(1, 6, SV_EDITD, sel.x, sel.y, sel.xs, sel.ys, delta); addmsg(1, 6, SV_EDITD, sel.x, sel.y, sel.xs, sel.ys, delta);
} })
#define MAXARCHVERT 50 #define MAXARCHVERT 50
int archverts[MAXARCHVERT][MAXARCHVERT]; int archverts[MAXARCHVERT][MAXARCHVERT];
bool archvinit = false; bool archvinit = false;
void COMMAND(archvertex, ARG_3INT, ^(int span, int vert, int delta) {
archvertex(int span, int vert, int delta)
{
if (!archvinit) { if (!archvinit) {
archvinit = true; archvinit = true;
for (int s = 0; s < MAXARCHVERT; s++) for (int s = 0; s < MAXARCHVERT; s++)
@ -561,11 +540,9 @@ archvertex(int span, int vert, int delta)
if (span >= MAXARCHVERT || vert >= MAXARCHVERT || span < 0 || vert < 0) if (span >= MAXARCHVERT || vert >= MAXARCHVERT || span < 0 || vert < 0)
return; return;
archverts[span][vert] = delta; archverts[span][vert] = delta;
} })
void COMMAND(arch, ARG_2INT, ^(int sidedelta, int _a) {
arch(int sidedelta, int _a)
{
EDITSELMP; EDITSELMP;
sel.xs++; sel.xs++;
@ -585,11 +562,9 @@ arch(int sidedelta, int _a)
: (archverts[sel->ys - 1][y] + : (archverts[sel->ys - 1][y] +
(x == 0 || x == sel->xs - 1 ? sidedelta : 0))); (x == 0 || x == sel->xs - 1 ? sidedelta : 0)));
remipmore(sel, 0); remipmore(sel, 0);
} })
void COMMAND(slope, ARG_2INT, ^(int xd, int yd) {
slope(int xd, int yd)
{
EDITSELMP; EDITSELMP;
int off = 0; int off = 0;
@ -606,11 +581,9 @@ slope(int xd, int yd)
struct block *sel = sel_; struct block *sel = sel_;
loopselxy(s->vdelta = xd * x + yd * y + off); loopselxy(s->vdelta = xd * x + yd * y + off);
remipmore(sel, 0); remipmore(sel, 0);
} })
void COMMAND(perlin, ARG_3INT, ^(int scale, int seed, int psize) {
perlin(int scale, int seed, int psize)
{
EDITSELMP; EDITSELMP;
sel.xs++; sel.xs++;
@ -630,7 +603,7 @@ perlin(int scale, int seed, int psize)
sel.xs--; sel.xs--;
sel.ys--; sel.ys--;
} })
VARF( VARF(
fullbright, 0, 0, 1, if (fullbright) { fullbright, 0, 0, 1, if (fullbright) {
@ -640,37 +613,20 @@ VARF(
world[i].r = world[i].g = world[i].b = 176; world[i].r = world[i].g = world[i].b = 176;
}); });
void COMMAND(edittag, ARG_1INT, ^(int tag) {
edittag(int tag)
{
EDITSELMP; EDITSELMP;
struct block *sel_ = &sel; struct block *sel_ = &sel;
// Ugly hack to make the macro work. // Ugly hack to make the macro work.
struct block *sel = sel_; struct block *sel = sel_;
loopselxy(s->tag = tag); loopselxy(s->tag = tag);
} })
void COMMAND(newent, ARG_5STR,
newent(OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4) ^(OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4) {
{ EDITSEL;
EDITSEL;
newentity(sel.x, sel.y, (int)player1.origin.z, what, newentity(sel.x, sel.y, (int)player1.origin.z, what,
[a1 cube_intValueWithBase:0], [a2 cube_intValueWithBase:0], [a1 cube_intValueWithBase:0], [a2 cube_intValueWithBase:0],
[a3 cube_intValueWithBase:0], [a4 cube_intValueWithBase:0]); [a3 cube_intValueWithBase:0], [a4 cube_intValueWithBase:0]);
} })
COMMANDN(select, selectpos, ARG_4INT)
COMMAND(edittag, ARG_1INT)
COMMAND(replace, ARG_NONE)
COMMAND(archvertex, ARG_3INT)
COMMAND(arch, ARG_2INT)
COMMAND(slope, ARG_2INT)
COMMANDN(vdelta, setvdelta, ARG_1INT)
COMMANDN(undo, editundo, ARG_NONE)
COMMAND(copy, ARG_NONE)
COMMAND(paste, ARG_NONE)
COMMAND(edittex, ARG_2INT)
COMMAND(newent, ARG_5STR)
COMMAND(perlin, ARG_3INT)

View file

@ -4,6 +4,7 @@
#import "Menu.h" #import "Menu.h"
#import "Command.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "MenuItem.h" #import "MenuItem.h"
@ -20,9 +21,7 @@ menuset(int menu)
menus[1].menusel = 0; menus[1].menusel = 0;
} }
void COMMAND(showmenu, ARG_1STR, ^(OFString *name) {
showmenu(OFString *name)
{
int i = 0; int i = 0;
for (Menu *menu in menus) { for (Menu *menu in menus) {
if (i > 1 && [menu.name isEqual:name]) { if (i > 1 && [menu.name isEqual:name]) {
@ -31,8 +30,7 @@ showmenu(OFString *name)
} }
i++; i++;
} }
} })
COMMAND(showmenu, ARG_1STR)
void void
sortmenu() sortmenu()
@ -97,7 +95,10 @@ newmenu(OFString *name)
[menus addObject:[Menu menuWithName:name]]; [menus addObject:[Menu menuWithName:name]];
} }
COMMAND(newmenu, ARG_1STR)
COMMAND(newmenu, ARG_1STR, ^(OFString *name) {
newmenu(name);
})
void void
menumanual(int m, int n, OFString *text) menumanual(int m, int n, OFString *text)
@ -109,17 +110,14 @@ menumanual(int m, int n, OFString *text)
[menus[m].items addObject:item]; [menus[m].items addObject:item];
} }
void COMMAND(menuitem, ARG_2STR, ^(OFString *text, OFString *action) {
menuitem(OFString *text, OFString *action)
{
Menu *menu = menus.lastObject; Menu *menu = menus.lastObject;
MenuItem *item = MenuItem *item =
[MenuItem itemWithText:text [MenuItem itemWithText:text
action:(action.length > 0 ? action : text)]; action:(action.length > 0 ? action : text)];
[menu.items addObject:item]; [menu.items addObject:item];
} })
COMMAND(menuitem, ARG_2STR)
bool bool
menukey(int code, bool isdown) menukey(int code, bool isdown)

View file

@ -10,7 +10,6 @@ extern int variable(OFString *name, int min, int cur, int max, int *storage,
extern void setvar(OFString *name, int i); extern void setvar(OFString *name, int i);
extern int getvar(OFString *name); extern int getvar(OFString *name);
extern bool identexists(OFString *name); extern bool identexists(OFString *name);
extern bool addcommand(OFString *name, void (*fun)(), int narg);
extern int execute(OFString *p, bool down); extern int execute(OFString *p, bool down);
extern void exec(OFString *cfgfile); extern void exec(OFString *cfgfile);
extern bool execfile(OFIRI *cfgfile); extern bool execfile(OFIRI *cfgfile);

View file

@ -3,6 +3,8 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
static struct vertex *verts = NULL; static struct vertex *verts = NULL;
int curvert; int curvert;
static int curmaxverts = 10000; static int curmaxverts = 10000;
@ -61,12 +63,9 @@ int ol3r, ol3g, ol3b, ol4r, ol4g, ol4b;
int firstindex; int firstindex;
bool showm = false; bool showm = false;
void COMMAND(showmip, ARG_NONE, ^{
showmip()
{
showm = !showm; showm = !showm;
} })
COMMAND(showmip, ARG_NONE)
void void
mipstats(int a, int b, int c) mipstats(int a, int b, int c)

View file

@ -2,6 +2,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "Entity.h" #import "Entity.h"
@ -203,9 +204,7 @@ renderents()
} }
} }
void COMMAND(loadsky, ARG_1STR, (^(OFString *basename) {
loadsky(OFString *basename)
{
static OFString *lastsky = @""; static OFString *lastsky = @"";
basename = [basename stringByReplacingOccurrencesOfString:@"\\" basename = [basename stringByReplacingOccurrencesOfString:@"\\"
@ -230,8 +229,7 @@ loadsky(OFString *basename)
} }
lastsky = basename; lastsky = basename;
} }))
COMMAND(loadsky, ARG_1STR)
float cursordepth = 0.9f; float cursordepth = 0.9f;
GLint viewport[4]; GLint viewport[4];

View file

@ -2,6 +2,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "Monster.h" #import "Monster.h"
#import "OFString+Cube.h" #import "OFString+Cube.h"
@ -185,16 +186,11 @@ purgetextures()
int curtexnum = 0; int curtexnum = 0;
void COMMAND(texturereset, ARG_NONE, ^{
texturereset()
{
curtexnum = 0; curtexnum = 0;
} })
COMMAND(texturereset, ARG_NONE)
void COMMAND(texture, ARG_2STR, (^(OFString *aframe, OFString *name) {
texture(OFString *aframe, OFString *name)
{
int num = curtexnum++, frame = aframe.cube_intValue; int num = curtexnum++, frame = aframe.cube_intValue;
if (num < 0 || num >= 256 || frame < 0 || frame >= MAXFRAMES) if (num < 0 || num >= 256 || frame < 0 || frame >= MAXFRAMES)
@ -203,8 +199,7 @@ texture(OFString *aframe, OFString *name)
mapping[num][frame] = 1; mapping[num][frame] = 1;
mapname[num][frame] = [name stringByReplacingOccurrencesOfString:@"\\" mapname[num][frame] = [name stringByReplacingOccurrencesOfString:@"\\"
withString:@"/"]; withString:@"/"];
} }))
COMMAND(texture, ARG_2STR)
int int
lookuptexture(int tex, int *xs, int *ys) lookuptexture(int tex, int *xs, int *ys)

View file

@ -2,6 +2,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "MD2.h" #import "MD2.h"
#import "MapModelInfo.h" #import "MapModelInfo.h"
@ -54,31 +55,27 @@ loadmodel(OFString *name)
return m; return m;
} }
void COMMAND(mapmodel, ARG_5STR,
mapmodel( ^(OFString *rad, OFString *h, OFString *zoff, OFString *snap,
OFString *rad, OFString *h, OFString *zoff, OFString *snap, OFString *name) OFString *name) {
{ MD2 *m =
MD2 *m = loadmodel([name stringByReplacingOccurrencesOfString:@"\\" loadmodel([name stringByReplacingOccurrencesOfString:@"\\"
withString:@"/"]); withString:@"/"]);
m.mmi = [MapModelInfo infoWithRad:rad.cube_intValue m.mmi = [MapModelInfo infoWithRad:rad.cube_intValue
h:h.cube_intValue h:h.cube_intValue
zoff:zoff.cube_intValue zoff:zoff.cube_intValue
snap:snap.cube_intValue snap:snap.cube_intValue
name:m.loadname]; name:m.loadname];
if (mapmodels == nil) if (mapmodels == nil)
mapmodels = [[OFMutableArray alloc] init]; mapmodels = [[OFMutableArray alloc] init];
[mapmodels addObject:m]; [mapmodels addObject:m];
} })
COMMAND(mapmodel, ARG_5STR)
void COMMAND(mapmodelreset, ARG_NONE, ^{
mapmodelreset()
{
[mapmodels removeAllObjects]; [mapmodels removeAllObjects];
} })
COMMAND(mapmodelreset, ARG_NONE)
MapModelInfo * MapModelInfo *
getmminfo(int i) getmminfo(int i)

View file

@ -3,6 +3,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "Entity.h" #import "Entity.h"
#import "Monster.h" #import "Monster.h"
@ -129,9 +130,7 @@ savestate(OFIRI *IRI)
} }
} }
void COMMAND(savegame, ARG_1STR, (^(OFString *name) {
savegame(OFString *name)
{
if (!m_classicsp) { if (!m_classicsp) {
conoutf(@"can only save classic sp games"); conoutf(@"can only save classic sp games");
return; return;
@ -143,8 +142,7 @@ savegame(OFString *name)
savestate(IRI); savestate(IRI);
stop(); stop();
conoutf(@"wrote %@", IRI.string); conoutf(@"wrote %@", IRI.string);
} }))
COMMAND(savegame, ARG_1STR)
void void
loadstate(OFIRI *IRI) loadstate(OFIRI *IRI)
@ -184,15 +182,12 @@ out:
stop(); stop();
} }
void COMMAND(loadgame, ARG_1STR, (^(OFString *name) {
loadgame(OFString *name)
{
OFString *path = [OFString stringWithFormat:@"savegames/%@.csgz", name]; OFString *path = [OFString stringWithFormat:@"savegames/%@.csgz", name];
OFIRI *IRI = OFIRI *IRI =
[Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent:path]; [Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent:path];
loadstate(IRI); loadstate(IRI);
} }))
COMMAND(loadgame, ARG_1STR)
void void
loadgameout() loadgameout()
@ -268,9 +263,7 @@ int playbacktime = 0;
int ddamage, bdamage; int ddamage, bdamage;
OFVector3D dorig; OFVector3D dorig;
void COMMAND(record, ARG_1STR, (^(OFString *name) {
record(OFString *name)
{
if (m_sp) { if (m_sp) {
conoutf(@"cannot record singleplayer games"); conoutf(@"cannot record singleplayer games");
return; return;
@ -289,8 +282,7 @@ record(OFString *name)
demorecording = true; demorecording = true;
starttime = lastmillis; starttime = lastmillis;
ddamage = bdamage = 0; ddamage = bdamage = 0;
} }))
COMMAND(record, ARG_1STR)
void void
demodamage(int damage, const OFVector3D *o) demodamage(int damage, const OFVector3D *o)
@ -337,16 +329,13 @@ incomingdemodata(unsigned char *buf, int len, bool extras)
} }
} }
void COMMAND(demo, ARG_1STR, (^(OFString *name) {
demo(OFString *name)
{
OFString *path = [OFString stringWithFormat:@"demos/%@.cdgz", name]; OFString *path = [OFString stringWithFormat:@"demos/%@.cdgz", name];
OFIRI *IRI = OFIRI *IRI =
[Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent:path]; [Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent:path];
loadstate(IRI); loadstate(IRI);
demoloading = true; demoloading = true;
} }))
COMMAND(demo, ARG_1STR)
void void
stopreset() stopreset()
@ -549,13 +538,10 @@ demoplaybackstep()
// if(player1->state!=CS_DEAD) showscores(false); // if(player1->state!=CS_DEAD) showscores(false);
} }
void COMMAND(stop, ARG_NONE, ^{
stopn()
{
if (demoplayback) if (demoplayback)
stopreset(); stopreset();
else else
stop(); stop();
conoutf(@"demo stopped"); conoutf(@"demo stopped");
} })
COMMANDN(stop, stopn, ARG_NONE)

View file

@ -4,6 +4,7 @@
#include "SDL_thread.h" #include "SDL_thread.h"
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "ResolverResult.h" #import "ResolverResult.h"
#import "ResolverThread.h" #import "ResolverThread.h"
#import "ServerInfo.h" #import "ServerInfo.h"
@ -126,6 +127,10 @@ addserver(OFString *servername)
[servers addObject:[ServerInfo infoWithName:servername]]; [servers addObject:[ServerInfo infoWithName:servername]];
} }
COMMAND(addserver, ARG_1STR, ^(OFString *servername) {
addserver(servername);
})
void void
pingservers() pingservers()
{ {
@ -245,7 +250,7 @@ refreshservers()
}]; }];
} }
void static void
servermenu() servermenu()
{ {
if (pingsock == ENET_SOCKET_NULL) { if (pingsock == ENET_SOCKET_NULL) {
@ -262,9 +267,11 @@ servermenu()
menuset(1); menuset(1);
} }
void COMMAND(servermenu, ARG_NONE, ^{
updatefrommaster() servermenu();
{ })
COMMAND(updatefrommaster, ARG_NONE, ^{
const int MAXUPD = 32000; const int MAXUPD = 32000;
unsigned char buf[MAXUPD]; unsigned char buf[MAXUPD];
unsigned char *reply = retrieveservers(buf, MAXUPD); unsigned char *reply = retrieveservers(buf, MAXUPD);
@ -276,11 +283,7 @@ updatefrommaster()
execute(@((char *)reply), true); execute(@((char *)reply), true);
} }
servermenu(); servermenu();
} })
COMMAND(addserver, ARG_1STR)
COMMAND(servermenu, ARG_NONE)
COMMAND(updatefrommaster, ARG_NONE)
void void
writeservercfg() writeservercfg()

View file

@ -1,5 +1,6 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#include <SDL_mixer.h> #include <SDL_mixer.h>
@ -47,9 +48,7 @@ initsound()
Mix_AllocateChannels(MAXCHAN); Mix_AllocateChannels(MAXCHAN);
} }
void COMMAND(music, ARG_1STR, (^(OFString *name) {
music(OFString *name)
{
if (nosound) if (nosound)
return; return;
@ -69,15 +68,12 @@ music(OFString *name)
Mix_VolumeMusic((musicvol * MAXVOL) / 255); Mix_VolumeMusic((musicvol * MAXVOL) / 255);
} }
} }
} }))
COMMAND(music, ARG_1STR)
static OFMutableData *samples; static OFMutableData *samples;
static OFMutableArray<OFString *> *snames; static OFMutableArray<OFString *> *snames;
int COMMAND(registersound, ARG_1EST, ^int(OFString *name) {
registersound(OFString *name)
{
int i = 0; int i = 0;
for (OFString *iter in snames) { for (OFString *iter in snames) {
if ([iter isEqual:name]) if ([iter isEqual:name])
@ -98,8 +94,7 @@ registersound(OFString *name)
[samples addItem:&sample]; [samples addItem:&sample];
return samples.count - 1; return samples.count - 1;
} })
COMMAND(registersound, ARG_1EST)
void void
cleansound() cleansound()
@ -216,9 +211,6 @@ playsound(int n, const OFVector3D *loc)
updatechanvol(chan, loc); updatechanvol(chan, loc);
} }
void COMMAND(sound, ARG_1INT, ^(int n) {
sound(int n)
{
playsound(n, NULL); playsound(n, NULL);
} })
COMMAND(sound, ARG_1INT)

View file

@ -2,6 +2,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "Monster.h" #import "Monster.h"
#import "OFString+Cube.h" #import "OFString+Cube.h"
@ -62,14 +63,11 @@ reloadtime(int gun)
return guns[gun].attackdelay; return guns[gun].attackdelay;
} }
void COMMAND(weapon, ARG_3STR, ^(OFString *a1, OFString *a2, OFString *a3) {
weapon(OFString *a1, OFString *a2, OFString *a3)
{
selectgun((a1.length > 0 ? a1.cube_intValue : -1), selectgun((a1.length > 0 ? a1.cube_intValue : -1),
(a2.length > 0 ? a2.cube_intValue : -1), (a2.length > 0 ? a2.cube_intValue : -1),
(a3.length > 0 ? a3.cube_intValue : -1)); (a3.length > 0 ? a3.cube_intValue : -1));
} })
COMMAND(weapon, ARG_3STR)
// create random spread of rays for the shotgun // create random spread of rays for the shotgun
void void

View file

@ -2,6 +2,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#import "Entity.h" #import "Entity.h"
#import "Monster.h" #import "Monster.h"
@ -91,7 +92,10 @@ trigger(int tag, int type, bool savegame)
if (type == 2) if (type == 2)
[Monster endSinglePlayerWithAllKilled:false]; [Monster endSinglePlayerWithAllKilled:false];
} }
COMMAND(trigger, ARG_2INT)
COMMAND(trigger, ARG_2INT, ^(int tag, int type, bool savegame) {
trigger(tag, type, savegame);
})
// main geometric mipmapping routine, recursively rebuild mipmaps within block // main geometric mipmapping routine, recursively rebuild mipmaps within block
// b. tries to produce cube out of 4 lower level mips as well as possible, sets // b. tries to produce cube out of 4 lower level mips as well as possible, sets
@ -304,9 +308,7 @@ closestent() // used for delent and edit mode ent display
return (bdist == 99999 ? -1 : best); return (bdist == 99999 ? -1 : best);
} }
void COMMAND(entproperty, ARG_2INT, ^(int prop, int amount) {
entproperty(int prop, int amount)
{
int e = closestent(); int e = closestent();
if (e < 0) if (e < 0)
return; return;
@ -324,11 +326,9 @@ entproperty(int prop, int amount)
ents[e].attr4 += amount; ents[e].attr4 += amount;
break; break;
} }
} })
void COMMAND(delent, ARG_NONE, ^{
delent()
{
int e = closestent(); int e = closestent();
if (e < 0) { if (e < 0) {
conoutf(@"no more entities"); conoutf(@"no more entities");
@ -340,7 +340,7 @@ delent()
addmsg(1, 10, SV_EDITENT, e, NOTUSED, 0, 0, 0, 0, 0, 0, 0); addmsg(1, 10, SV_EDITENT, e, NOTUSED, 0, 0, 0, 0, 0, 0, 0);
if (t == LIGHT) if (t == LIGHT)
calclight(); calclight();
} })
int int
findtype(OFString *what) findtype(OFString *what)
@ -397,9 +397,7 @@ newentity(int x, int y, int z, OFString *what, int v1, int v2, int v3, int v4)
return e; return e;
} }
void COMMAND(clearents, ARG_1STR, ^(OFString *name) {
clearents(OFString *name)
{
int type = findtype(name); int type = findtype(name);
if (noteditmode() || multiplayer()) if (noteditmode() || multiplayer())
@ -411,8 +409,7 @@ clearents(OFString *name)
if (type == LIGHT) if (type == LIGHT)
calclight(); calclight();
} })
COMMAND(clearents, ARG_1STR)
static unsigned char static unsigned char
scalecomp(unsigned char c, int intens) scalecomp(unsigned char c, int intens)
@ -423,9 +420,7 @@ scalecomp(unsigned char c, int intens)
return n; return n;
} }
void COMMAND(scalelights, ARG_2INT, ^(int f, int intens) {
scalelights(int f, int intens)
{
for (Entity *e in ents) { for (Entity *e in ents) {
if (e.type != LIGHT) if (e.type != LIGHT)
continue; continue;
@ -444,8 +439,7 @@ scalelights(int f, int intens)
} }
calclight(); calclight();
} })
COMMAND(scalelights, ARG_2INT)
int int
findentity(int type, int index) findentity(int type, int index)
@ -551,20 +545,14 @@ empty_world(int factor, bool force)
} }
} }
void COMMAND(mapenlarge, ARG_NONE, ^{
mapenlarge()
{
empty_world(-1, false); empty_world(-1, false);
} })
void COMMAND(newmap, ARG_1INT, ^(int i) {
newmap(int i)
{
empty_world(i, false); empty_world(i, false);
} })
COMMAND(mapenlarge, ARG_NONE) COMMAND(recalc, ARG_NONE, ^{
COMMAND(newmap, ARG_1INT) calclight();
COMMANDN(recalc, calclight, ARG_NONE) })
COMMAND(delent, ARG_NONE)
COMMAND(entproperty, ARG_2INT)

View file

@ -2,6 +2,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "Entity.h" #import "Entity.h"
struct persistent_entity { struct persistent_entity {
@ -256,7 +257,10 @@ save_world(OFString *mname)
conoutf(@"wrote map file %@", cgzname); conoutf(@"wrote map file %@", cgzname);
settagareas(); settagareas();
} }
COMMANDN(savemap, save_world, ARG_1STR)
COMMAND(savemap, ARG_1STR, ^(OFString *mname) {
save_world(mname);
})
void void
load_world(OFString *mname) // still supports all map formats that have existed load_world(OFString *mname) // still supports all map formats that have existed

View file

@ -2,6 +2,7 @@
#include "cube.h" #include "cube.h"
#import "Command.h"
#import "DynamicEntity.h" #import "DynamicEntity.h"
#define NUMRAYS 512 #define NUMRAYS 512
@ -10,12 +11,9 @@ float rdist[NUMRAYS];
bool ocull = true; bool ocull = true;
float odist = 256; float odist = 256;
void COMMAND(toggleocull, ARG_NONE, ^{
toggleocull()
{
ocull = !ocull; ocull = !ocull;
} })
COMMAND(toggleocull, ARG_NONE)
// constructs occlusion map: cast rays in all directions on the 2d plane and // constructs occlusion map: cast rays in all directions on the 2d plane and
// record distance. done exactly once per frame. // record distance. done exactly once per frame.