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
#define COMMAND(name, nargs, block_) \
OF_CONSTRUCTOR() \
{ \
enqueueInit(^{ \
[Identifier \
addIdentifier:[Command commandWithName:@ #name \
argumentsTypes:nargs \
block:block_]]; \
}); \
}
@interface Command: Identifier
@property (readonly, nonatomic) void (*function)();
@property (readonly, nonatomic) int argumentsTypes;
+ (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
function:(void (*)())function
argumentsTypes:(int)argumentsTypes;
argumentsTypes:(int)argumentsTypes
block:(id)block;
- (int)callWithArguments:(OFArray<OFString *> *)arguments isDown:(bool)isDown;
@end

View file

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

View file

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

View file

@ -5,6 +5,9 @@ OF_ASSUME_NONNULL_BEGIN
@interface Identifier: OFObject
@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)initWithName:(OFString *)name;
@end

View file

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

View file

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

View file

@ -2,6 +2,7 @@
#include "cube.h"
#import "Command.h"
#import "DynamicEntity.h"
#import "Entity.h"
#import "Monster.h"
@ -10,12 +11,9 @@
int nextmode = 0; // nextmode becomes gamemode after next map load
VAR(gamemode, 1, 0, 0);
static void
mode(int n)
{
COMMAND(mode, ARG_1INT, ^(int n) {
addmsg(1, 2, SV_GAMEMODE, nextmode = n);
}
COMMAND(mode, ARG_1INT)
})
bool intermission = false;
@ -142,13 +140,10 @@ respawn()
int sleepwait = 0;
static OFString *sleepcmd = nil;
void
sleepf(OFString *msec, OFString *cmd)
{
COMMAND(sleep, ARG_2STR, ^(OFString *msec, OFString *cmd) {
sleepwait = msec.cube_intValue + lastmillis;
sleepcmd = cmd;
}
COMMANDN(sleep, sleepf, ARG_2STR)
})
void
updateworld(int millis) // main game update loop
@ -240,43 +235,34 @@ spawnplayer(DynamicEntity *d)
// movement input code
#define dir(name, v, d, s, os) \
static void name(bool isdown) \
{ \
player1.s = isdown; \
player1.v = isdown ? d : (player1.os ? -(d) : 0); \
COMMAND(name, ARG_DOWN, ^(bool isDown) { \
player1.s = isDown; \
player1.v = isDown ? d : (player1.os ? -(d) : 0); \
player1.lastMove = lastmillis; \
}
})
dir(backward, move, -1, k_down, k_up);
dir(forward, move, 1, k_up, k_down);
dir(left, strafe, 1, k_left, k_right);
dir(right, strafe, -1, k_right, k_left);
void
attack(bool on)
{
COMMAND(attack, ARG_DOWN, ^(bool on) {
if (intermission)
return;
if (editmode)
editdrag(on);
else if ((player1.attacking = on))
respawn();
}
})
void
jumpn(bool on)
{
COMMAND(jump, ARG_DOWN, ^(bool on) {
if (!intermission && (player1.jumpNext = on))
respawn();
}
})
COMMAND(backward, ARG_DOWN)
COMMAND(forward, ARG_DOWN)
COMMAND(left, ARG_DOWN)
COMMAND(right, ARG_DOWN)
COMMANDN(jump, jumpn, ARG_DOWN)
COMMAND(attack, ARG_DOWN)
COMMAND(showscores, ARG_DOWN)
COMMAND(showscores, ARG_DOWN, ^(bool isDown) {
showscores(isDown);
})
void
fixplayer1range()
@ -440,4 +426,6 @@ startmap(OFString *name) // called just after a map load
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"
#import "Command.h"
#import "DynamicEntity.h"
static ENetHost *clienthost = NULL;
@ -60,7 +61,7 @@ throttle()
throttle_interval * 1000, throttle_accel, throttle_decel);
}
void
static void
newname(OFString *name)
{
c2sinit = false;
@ -70,9 +71,12 @@ newname(OFString *name)
player1.name = name;
}
COMMANDN(name, newname, ARG_1STR)
void
COMMAND(name, ARG_1STR, ^(OFString *name) {
newname(name);
})
static void
newteam(OFString *name)
{
c2sinit = false;
@ -82,7 +86,10 @@ newteam(OFString *name)
player1.team = name;
}
COMMANDN(team, newteam, ARG_1STR)
COMMAND(team, ARG_1STR, ^(OFString *name) {
newteam(name);
})
void
writeclientinfo(OFStream *stream)
@ -177,16 +184,18 @@ toserver(OFString *text)
ctext = text;
}
void
echo(OFString *text)
{
COMMAND(echo, ARG_VARI, ^(OFString *text) {
conoutf(@"%@", text);
}
COMMAND(echo, ARG_VARI)
COMMANDN(say, toserver, ARG_VARI)
COMMANDN(connect, connects, ARG_1STR)
COMMANDN(disconnect, trydisconnect, ARG_NONE)
})
COMMAND(say, ARG_VARI, ^(OFString *text) {
toserver(text);
})
COMMAND(connect, ARG_1STR, ^(OFString *servername) {
connects(servername);
})
COMMAND(disconnect, ARG_NONE, ^{
trydisconnect();
})
// collect c2s messages conveniently
@ -239,12 +248,9 @@ bool senditemstoserver =
false; // after a map change, since server doesn't have map data
OFString *clientpassword;
void
password(OFString *p)
{
COMMAND(password, ARG_1STR, ^(OFString *p) {
clientpassword = p;
}
COMMAND(password, ARG_1STR)
})
bool
netmapstart()

View file

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

View file

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

View file

@ -340,14 +340,6 @@ enum {
// nasty macros for registering script functions, abuses globals to avoid
// 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) \
int name; \
OF_CONSTRUCTOR() \

View file

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

View file

@ -4,6 +4,7 @@
#import "Menu.h"
#import "Command.h"
#import "DynamicEntity.h"
#import "MenuItem.h"
@ -20,9 +21,7 @@ menuset(int menu)
menus[1].menusel = 0;
}
void
showmenu(OFString *name)
{
COMMAND(showmenu, ARG_1STR, ^(OFString *name) {
int i = 0;
for (Menu *menu in menus) {
if (i > 1 && [menu.name isEqual:name]) {
@ -31,8 +30,7 @@ showmenu(OFString *name)
}
i++;
}
}
COMMAND(showmenu, ARG_1STR)
})
void
sortmenu()
@ -97,7 +95,10 @@ newmenu(OFString *name)
[menus addObject:[Menu menuWithName:name]];
}
COMMAND(newmenu, ARG_1STR)
COMMAND(newmenu, ARG_1STR, ^(OFString *name) {
newmenu(name);
})
void
menumanual(int m, int n, OFString *text)
@ -109,17 +110,14 @@ menumanual(int m, int n, OFString *text)
[menus[m].items addObject:item];
}
void
menuitem(OFString *text, OFString *action)
{
COMMAND(menuitem, ARG_2STR, ^(OFString *text, OFString *action) {
Menu *menu = menus.lastObject;
MenuItem *item =
[MenuItem itemWithText:text
action:(action.length > 0 ? action : text)];
[menu.items addObject:item];
}
COMMAND(menuitem, ARG_2STR)
})
bool
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 int getvar(OFString *name);
extern bool identexists(OFString *name);
extern bool addcommand(OFString *name, void (*fun)(), int narg);
extern int execute(OFString *p, bool down);
extern void exec(OFString *cfgfile);
extern bool execfile(OFIRI *cfgfile);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,6 +2,7 @@
#include "cube.h"
#import "Command.h"
#import "DynamicEntity.h"
#import "Entity.h"
#import "Monster.h"
@ -91,7 +92,10 @@ trigger(int tag, int type, bool savegame)
if (type == 2)
[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
// 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);
}
void
entproperty(int prop, int amount)
{
COMMAND(entproperty, ARG_2INT, ^(int prop, int amount) {
int e = closestent();
if (e < 0)
return;
@ -324,11 +326,9 @@ entproperty(int prop, int amount)
ents[e].attr4 += amount;
break;
}
}
})
void
delent()
{
COMMAND(delent, ARG_NONE, ^{
int e = closestent();
if (e < 0) {
conoutf(@"no more entities");
@ -340,7 +340,7 @@ delent()
addmsg(1, 10, SV_EDITENT, e, NOTUSED, 0, 0, 0, 0, 0, 0, 0);
if (t == LIGHT)
calclight();
}
})
int
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;
}
void
clearents(OFString *name)
{
COMMAND(clearents, ARG_1STR, ^(OFString *name) {
int type = findtype(name);
if (noteditmode() || multiplayer())
@ -411,8 +409,7 @@ clearents(OFString *name)
if (type == LIGHT)
calclight();
}
COMMAND(clearents, ARG_1STR)
})
static unsigned char
scalecomp(unsigned char c, int intens)
@ -423,9 +420,7 @@ scalecomp(unsigned char c, int intens)
return n;
}
void
scalelights(int f, int intens)
{
COMMAND(scalelights, ARG_2INT, ^(int f, int intens) {
for (Entity *e in ents) {
if (e.type != LIGHT)
continue;
@ -444,8 +439,7 @@ scalelights(int f, int intens)
}
calclight();
}
COMMAND(scalelights, ARG_2INT)
})
int
findentity(int type, int index)
@ -551,20 +545,14 @@ empty_world(int factor, bool force)
}
}
void
mapenlarge()
{
COMMAND(mapenlarge, ARG_NONE, ^{
empty_world(-1, false);
}
})
void
newmap(int i)
{
COMMAND(newmap, ARG_1INT, ^(int i) {
empty_world(i, false);
}
})
COMMAND(mapenlarge, ARG_NONE)
COMMAND(newmap, ARG_1INT)
COMMANDN(recalc, calclight, ARG_NONE)
COMMAND(delent, ARG_NONE)
COMMAND(entproperty, ARG_2INT)
COMMAND(recalc, ARG_NONE, ^{
calclight();
})

View file

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

View file

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