Comment: | Switch from clang-format to manual formatting
clang-format does too many weird things. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
75e920ae307d96d6ce0141652617959f |
User & Date: | js on 2025-03-29 14:25:43 |
Other Links: | manifest | tags |
2025-03-29
| ||
17:13 | More style fixes check-in: c634a689e7 user: js tags: trunk | |
14:25 | Switch from clang-format to manual formatting check-in: 75e920ae30 user: js tags: trunk | |
13:01 | Make more use of OFColor check-in: 932a90c261 user: js tags: trunk | |
Deleted src/.clang-format version [0d630f9489].
Modified src/Alias.h from [9b91901d8c] to [0fb6418ce5].
1 2 3 4 5 6 7 8 | #import "Identifier.h" OF_ASSUME_NONNULL_BEGIN @interface Alias: Identifier @property (direct, copy, nonatomic) OFString *action; @property (readonly, nonatomic) bool persisted; | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #import "Identifier.h" OF_ASSUME_NONNULL_BEGIN @interface Alias: Identifier @property (direct, copy, nonatomic) OFString *action; @property (readonly, nonatomic) bool persisted; + (instancetype)aliasWithName: (OFString *)name action: (OFString *)action persisted: (bool)persisted OF_DIRECT; - (instancetype)initWithName: (OFString *)name OF_UNAVAILABLE; - (instancetype)initWithName: (OFString *)name action: (OFString *)action persisted: (bool)persisted OF_DESIGNATED_INITIALIZER OF_DIRECT; @end OF_ASSUME_NONNULL_END |
Modified src/Alias.m from [dce3b067a2] to [fe2a009013].
1 2 3 | #import "Alias.h" @implementation Alias | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #import "Alias.h" @implementation Alias + (instancetype)aliasWithName: (OFString *)name action: (OFString *)action persisted: (bool)persisted; { return [[self alloc] initWithName: name action: action persisted: persisted]; } - (instancetype)initWithName: (OFString *)name action: (OFString *)action persisted: (bool)persisted { self = [super initWithName: name]; _action = [action copy]; _persisted = persisted; return self; } @end |
Modified src/Command.h from [710ad3a2bf] to [f6eb8c644d].
1 2 3 4 | #import "Identifier.h" OF_ASSUME_NONNULL_BEGIN | | | | | | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #import "Identifier.h" OF_ASSUME_NONNULL_BEGIN #define COMMAND(name, nargs, block_) \ OF_CONSTRUCTOR() \ { \ enqueueInit(^ { \ Identifier.identifiers[@#name] = \ [Command commandWithName: @#name \ argumentsTypes: nargs \ block: block_]; \ }); \ } OF_DIRECT_MEMBERS @interface Command: Identifier @property (readonly, nonatomic) int argumentsTypes; + (instancetype)commandWithName: (OFString *)name argumentsTypes: (int)argumentsTypes block: (id)block; - (instancetype)initWithName: (OFString *)name OF_UNAVAILABLE; - (instancetype)initWithName: (OFString *)name argumentsTypes: (int)argumentsTypes block: (id)block OF_DESIGNATED_INITIALIZER; - (int)callWithArguments: (OFArray<OFString *> *)arguments isDown: (bool)isDown; @end OF_ASSUME_NONNULL_END |
Modified src/Command.m from [1956763843] to [254356cb16].
︙ | ︙ | |||
9 10 11 12 13 14 15 | OFMutableArray<OFString *> *copy; if (arguments.count >= count) return arguments; copy = [arguments mutableCopy]; while (copy.count < count) | | | | | | | | | | | | | | | | | | | | | | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | OFMutableArray<OFString *> *copy; if (arguments.count >= count) return arguments; copy = [arguments mutableCopy]; while (copy.count < count) [copy addObject: @""]; [copy makeImmutable]; return copy; } @implementation Command { id _block; } + (instancetype)commandWithName: (OFString *)name argumentsTypes: (int)argumentsTypes block: (id)block { return [[self alloc] initWithName: name argumentsTypes: argumentsTypes block: block]; } - (instancetype)initWithName: (OFString *)name argumentsTypes: (int)argumentsTypes block: (id)block { self = [super initWithName: name]; _argumentsTypes = argumentsTypes; _block = block; return self; } - (int)callWithArguments: (OFArray<OFString *> *)arguments isDown: (bool)isDown { switch (_argumentsTypes) { case ARG_1INT: if (isDown) { arguments = padArguments(arguments, 2); ((void (^)(int))_block)( [arguments[1] cube_intValueWithBase: 0]); } break; case ARG_2INT: if (isDown) { arguments = padArguments(arguments, 3); ((void (^)(int, int))_block)( [arguments[1] cube_intValueWithBase: 0], [arguments[2] cube_intValueWithBase: 0]); } break; case ARG_3INT: if (isDown) { arguments = padArguments(arguments, 4); ((void (^)(int, int, int))_block)( [arguments[1] cube_intValueWithBase: 0], [arguments[2] cube_intValueWithBase: 0], [arguments[3] cube_intValueWithBase: 0]); } break; case ARG_4INT: if (isDown) { arguments = padArguments(arguments, 5); ((void (^)(int, int, int, int))_block)( [arguments[1] cube_intValueWithBase: 0], [arguments[2] cube_intValueWithBase: 0], [arguments[3] cube_intValueWithBase: 0], [arguments[4] cube_intValueWithBase: 0]); } break; case ARG_NONE: if (isDown) ((void (^)())_block)(); break; case ARG_1STR: |
︙ | ︙ | |||
150 151 152 153 154 155 156 | arguments[1], arguments[2]); } break; case ARG_VARI: if (isDown) // limit, remove ((void (^)(OFString *))_block)([[arguments | | | | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | arguments[1], arguments[2]); } break; case ARG_VARI: if (isDown) // limit, remove ((void (^)(OFString *))_block)([[arguments objectsInRange: OFMakeRange(1, arguments.count - 1)] componentsJoinedByString: @" "]); break; } return 0; } @end |
Modified src/ConsoleLine.h from [3048f3e388] to [7afa80390f].
1 2 3 4 5 6 7 | #import <ObjFW/ObjFW.h> OF_DIRECT_MEMBERS @interface ConsoleLine: OFObject @property (readonly, copy) OFString *text; @property (readonly) int outtime; | | | | 1 2 3 4 5 6 7 8 9 10 | #import <ObjFW/ObjFW.h> OF_DIRECT_MEMBERS @interface ConsoleLine: OFObject @property (readonly, copy) OFString *text; @property (readonly) int outtime; + (instancetype)lineWithText: (OFString *)text outtime: (int)outtime; - (instancetype)initWithText: (OFString *)text outtime: (int)outtime; @end |
Modified src/ConsoleLine.m from [8c83ebcd46] to [558d4dd328].
1 2 3 | #import "ConsoleLine.h" @implementation ConsoleLine | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #import "ConsoleLine.h" @implementation ConsoleLine + (instancetype)lineWithText: (OFString *)text outtime: (int)outtime { return [[self alloc] initWithText: text outtime: outtime]; } - (instancetype)initWithText: (OFString *)text outtime: (int)outtime { self = [super init]; _text = [text copy]; _outtime = outtime; return self; |
︙ | ︙ |
Modified src/Cube.m from [37d676edf6] to [67dd855e73].
︙ | ︙ | |||
17 18 19 20 21 22 23 | } + (Cube *)sharedInstance { return (Cube *)OFApplication.sharedApplication.delegate; } | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | } + (Cube *)sharedInstance { return (Cube *)OFApplication.sharedApplication.delegate; } - (void)applicationDidFinishLaunching: (OFNotification *)notification { @autoreleasepool { bool dedicated, windowed; int par = 0, uprate = 0, maxcl = 4; OFString *__autoreleasing sdesc, *__autoreleasing ip; OFString *__autoreleasing master, *__autoreleasing passwd; |
︙ | ︙ | |||
44 45 46 47 48 49 50 | { 'i', @"ip", 1, NULL, &ip }, { 'm', @"master", 1, NULL, &master }, { 'p', @"password", 1, NULL, &passwd }, { 'c', @"max-clients", 1, NULL, NULL }, { '\0', nil, 0, NULL, NULL } }; OFOptionsParser *optionsParser = | | | | | | | | 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | { 'i', @"ip", 1, NULL, &ip }, { 'm', @"master", 1, NULL, &master }, { 'p', @"password", 1, NULL, &passwd }, { 'c', @"max-clients", 1, NULL, NULL }, { '\0', nil, 0, NULL, NULL } }; OFOptionsParser *optionsParser = [OFOptionsParser parserWithOptions: options]; OFUnichar option; while ((option = [optionsParser nextOption]) != '\0') { switch (option) { case 'w': _width = optionsParser.argument.intValue; break; case 'h': _height = optionsParser.argument.intValue; break; case 'u': uprate = optionsParser.argument.intValue; break; case 'c': maxcl = optionsParser.argument.intValue; break; case ':': case '=': case '?': conoutf(@"unknown commandline option"); [OFApplication terminateWithStatus: 1]; } } if (sdesc == nil) sdesc = @""; if (ip == nil) ip = @""; if (passwd == nil) passwd = @""; _gameDataIRI = [OFFileManager.defaultManager currentDirectoryIRI]; _userDataIRI = [OFFileManager.defaultManager currentDirectoryIRI]; [OFFileManager.defaultManager createDirectoryAtIRI: [_userDataIRI IRIByAppendingPathComponent: @"demos"] createParents: true]; [OFFileManager.defaultManager createDirectoryAtIRI: [_userDataIRI IRIByAppendingPathComponent: @"savegames"] createParents: true]; if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | par) < 0) fatal(@"Unable to initialize SDL"); initEntities(); initPlayers(); |
︙ | ︙ | |||
141 142 143 144 145 146 147 | SDL_ShowCursor(0); log(@"gl"); gl_init(_width, _height); log(@"basetex"); int xs, ys; | | < < | < | | < < | | < < | | < < | | < < | | < | < < | | < < | | < < | | | | | | 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | SDL_ShowCursor(0); log(@"gl"); gl_init(_width, _height); log(@"basetex"); int xs, ys; if (!installtex(2, [_gameDataIRI IRIByAppendingPathComponent: @"data/newchars.png"], &xs, &ys, false) || !installtex(3, [_gameDataIRI IRIByAppendingPathComponent: @"data/martin/base.png"], &xs, &ys, false) || !installtex(6, [_gameDataIRI IRIByAppendingPathComponent: @"data/martin/ball1.png"], &xs, &ys, false) || !installtex(7, [_gameDataIRI IRIByAppendingPathComponent: @"data/martin/smoke.png"], &xs, &ys, false) || !installtex(8, [_gameDataIRI IRIByAppendingPathComponent: @"data/martin/ball2.png"], &xs, &ys, false) || !installtex(9, [_gameDataIRI IRIByAppendingPathComponent: @"data/martin/ball3.png"], &xs, &ys, false) || !installtex(4, [_gameDataIRI IRIByAppendingPathComponent: @"data/explosion.jpg"], &xs, &ys, false) || !installtex(5, [_gameDataIRI IRIByAppendingPathComponent: @"data/items.png"], &xs, &ys, false) || !installtex(1, [_gameDataIRI IRIByAppendingPathComponent: @"data/crosshair.png"], &xs, &ys, false)) fatal(@"could not find core textures (hint: run cube " @"from the parent of the bin directory)"); log(@"sound"); initsound(); log(@"cfg"); newmenu(@"frags\tpj\tping\tteam\tname"); newmenu(@"ping\tplr\tserver"); exec(@"data/keymap.cfg"); exec(@"data/menus.cfg"); exec(@"data/prefabs.cfg"); exec(@"data/sounds.cfg"); exec(@"servers.cfg"); if (!execfile([_userDataIRI IRIByAppendingPathComponent: @"config.cfg"])) execfile([_gameDataIRI IRIByAppendingPathComponent: @"data/defaults.cfg"]); exec(@"autoexec.cfg"); log(@"localconnect"); localconnect(); // if this map is changed, also change depthcorrect() changemap(@"metl3"); log(@"mainloop"); } OFDate *past = [OFDate date]; int ignore = 5; for (;;) { @autoreleasepool { [OFRunLoop.mainRunLoop runUntilDate: past]; Player *player1 = Player.player1; int millis = SDL_GetTicks() * gamespeed / 100; if (millis - lastmillis > 200) lastmillis = millis - 200; else if (millis - lastmillis < 1) |
︙ | ︙ | |||
291 292 293 294 295 296 297 | break; } } } } } | | | | | 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | break; } } } } } - (void)applicationWillTerminate: (OFNotification *)notification { stop(); disconnect(true, false); writecfg(); cleangl(); cleansound(); cleanupserver(); SDL_ShowCursor(1); SDL_Quit(); } - (void)showMessage: (OFString *)msg { #ifdef _WIN32 MessageBoxW( NULL, msg.UTF16String, L"cube fatal error", MB_OK | MB_SYSTEMMODAL); #else [OFStdOut writeString: msg]; #endif } - (void)screenshot { SDL_Surface *image; SDL_Surface *temp; |
︙ | ︙ | |||
335 336 337 338 339 340 341 | memcpy(dest, (char *)image->pixels + 3 * _width * (_height - 1 - idx), 3 * _width); endianswap(dest, 3, _width); } | | | < | | | | | | | | | | | 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | memcpy(dest, (char *)image->pixels + 3 * _width * (_height - 1 - idx), 3 * _width); endianswap(dest, 3, _width); } OFString *path = [OFString stringWithFormat: @"screenshots/screenshot_%d.bmp", lastmillis]; SDL_SaveBMP(temp, [_userDataIRI IRIByAppendingPathComponent: path] .fileSystemRepresentation.UTF8String); SDL_FreeSurface(temp); } SDL_FreeSurface(image); } } - (void)quit { writeservercfg(); [OFApplication terminateWithStatus: 0]; } @end // failure exit void fatal(OFConstantString *s, ...) { va_list args; va_start(args, s); OFMutableString *msg = [[OFMutableString alloc] initWithFormat: s arguments: args]; va_end(args); [msg appendFormat: @" (%s)\n", SDL_GetError()]; [Cube.sharedInstance showMessage: msg]; [OFApplication terminateWithStatus: 1]; } // normal exit COMMAND(quit, ARG_NONE, ^ { [Cube.sharedInstance quit]; }) COMMAND(screenshot, ARG_NONE, ^ { [Cube.sharedInstance screenshot]; }) |
Modified src/DynamicEntity.h from [0ee26a40fb] to [0008508591].
︙ | ︙ | |||
29 30 31 32 33 34 35 | @property (direct, readonly, nonatomic) int *ammo; @property (direct, nonatomic) bool attacking; // used by physics to signal ai @property (direct, nonatomic) bool blocked, moving; @property (direct, copy, nonatomic) OFString *name; - (OFData *)dataBySerializing; | | | 29 30 31 32 33 34 35 36 37 38 39 40 | @property (direct, readonly, nonatomic) int *ammo; @property (direct, nonatomic) bool attacking; // used by physics to signal ai @property (direct, nonatomic) bool blocked, moving; @property (direct, copy, nonatomic) OFString *name; - (OFData *)dataBySerializing; - (void)setFromSerializedData: (OFData *)data; - (void)resetMovement; // reset player state not persistent accross spawns - (void)resetToSpawnState; @end |
Modified src/DynamicEntity.m from [7a1598ea36] to [ba58eb8bdf].
︙ | ︙ | |||
163 164 165 166 167 168 169 | .moving = _moving }; for (int i = 0; i < NUMGUNS; i++) data.ammo[i] = _ammo[i]; memcpy(data.name, _name.UTF8String, min(_name.UTF8StringLength, 259)); | | | | | | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | .moving = _moving }; for (int i = 0; i < NUMGUNS; i++) data.ammo[i] = _ammo[i]; memcpy(data.name, _name.UTF8String, min(_name.UTF8StringLength, 259)); if ([self isKindOfClass: Player.class]) { Player *player = (Player *)self; data.lifeSequence = player.lifeSequence, data.frags = player.frags; memcpy(data.team, player.team.UTF8String, min(player.team.UTF8StringLength, 259)); } if ([self isKindOfClass: Monster.class]) { Monster *monster = (Monster *)self; data.monsterState = monster.monsterState; data.monsterType = monster.monsterType; data.targetYaw = monster.targetYaw; data.trigger = monster.trigger; data.attackTarget = monster.attackTarget; data.anger = monster.anger; } return [OFData dataWithItems: &data count: sizeof(data)]; } - (void)setFromSerializedData: (OFData *)data { struct dynent d; if (data.count != sizeof(struct dynent)) @throw [OFOutOfRangeException exception]; memcpy(&d, data.items, data.count); |
︙ | ︙ | |||
235 236 237 238 239 240 241 | for (int i = 0; i < NUMGUNS; i++) _ammo[i] = d.ammo[i]; _blocked = d.blocked; _moving = d.moving; | | | | | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | for (int i = 0; i < NUMGUNS; i++) _ammo[i] = d.ammo[i]; _blocked = d.blocked; _moving = d.moving; _name = [[OFString alloc] initWithUTF8String: d.name]; if ([self isKindOfClass: Player.class]) { Player *player = (Player *)self; player.lifeSequence = d.lifeSequence; player.frags = d.frags; player.team = @(d.team); } if ([self isKindOfClass: Monster.class]) { Monster *monster = (Monster *)self; monster.monsterState = d.monsterState; monster.monsterType = d.monsterType; monster.targetYaw = d.targetYaw; monster.trigger = d.trigger; monster.attackTarget = d.attackTarget; monster.anger = d.anger; |
︙ | ︙ |
Modified src/Identifier.h from [79fe1b6b9a] to [91de4ded4b].
1 2 3 4 5 6 7 8 9 10 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN @interface Identifier: OFObject @property (direct, readonly, copy, nonatomic) OFString *name; @property (class, direct, readonly, nonatomic) OFMutableDictionary<OFString *, __kindof Identifier *> *identifiers; - (instancetype)init OF_UNAVAILABLE; | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN @interface Identifier: OFObject @property (direct, readonly, copy, nonatomic) OFString *name; @property (class, direct, readonly, nonatomic) OFMutableDictionary<OFString *, __kindof Identifier *> *identifiers; - (instancetype)init OF_UNAVAILABLE; - (instancetype)initWithName: (OFString *)name; @end OF_ASSUME_NONNULL_END |
Modified src/Identifier.m from [9cd9c4b220] to [eff0175544].
︙ | ︙ | |||
11 12 13 14 15 16 17 | } + (OFMutableDictionary<OFString *, __kindof Identifier *> *)identifiers { return identifiers; } | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | } + (OFMutableDictionary<OFString *, __kindof Identifier *> *)identifiers { return identifiers; } - (instancetype)initWithName: (OFString *)name { self = [super init]; _name = [name copy]; return self; } |
︙ | ︙ |
Modified src/KeyMapping.h from [3b8ccce865] to [7e5483fe4c].
1 2 3 4 5 6 7 8 9 10 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN OF_DIRECT_MEMBERS @interface KeyMapping: OFObject @property (readonly) int code; @property (readonly, nonatomic) OFString *name; @property (copy, nonatomic) OFString *action; | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN OF_DIRECT_MEMBERS @interface KeyMapping: OFObject @property (readonly) int code; @property (readonly, nonatomic) OFString *name; @property (copy, nonatomic) OFString *action; + (instancetype)mappingWithCode: (int)code name: (OFString *)name; - (instancetype)init OF_UNAVAILABLE; - (instancetype)initWithCode: (int)code name: (OFString *)name; @end OF_ASSUME_NONNULL_END |
Modified src/KeyMapping.m from [49eed66821] to [962ce788ca].
1 2 3 | #import "KeyMapping.h" @implementation KeyMapping | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #import "KeyMapping.h" @implementation KeyMapping + (instancetype)mappingWithCode: (int)code name: (OFString *)name { return [[self alloc] initWithCode: code name: name]; } - (instancetype)initWithCode: (int)code name: (OFString *)name { self = [super init]; _code = code; _name = [name copy]; return self; |
︙ | ︙ |
Modified src/MD2.h from [738081230a] to [25323c6c56].
︙ | ︙ | |||
8 9 10 11 12 13 14 | @interface MD2: OFObject @property (nonatomic) MapModelInfo *mmi; @property (copy, nonatomic) OFString *loadname; @property (nonatomic) int mdlnum; @property (nonatomic) bool loaded; + (instancetype)md2; | | | | | | | | | | | | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | @interface MD2: OFObject @property (nonatomic) MapModelInfo *mmi; @property (copy, nonatomic) OFString *loadname; @property (nonatomic) int mdlnum; @property (nonatomic) bool loaded; + (instancetype)md2; - (bool)loadWithIRI: (OFIRI *)IRI; - (void)renderWithLight: (OFColor *)light frame: (int)frame range: (int)range position: (OFVector3D)position yaw: (float)yaw pitch: (float)pitch scale: (float)scale speed: (float)speed snap: (int)snap basetime: (int)basetime; - (void)scaleWithFrame: (int)frame scale: (float)scale snap: (int)snap; @end OF_ASSUME_NONNULL_END |
Modified src/MD2.m from [eb988e3999] to [64d68c27a0].
︙ | ︙ | |||
59 60 61 62 63 64 65 | if (_mverts != NULL) for (size_t i = 0; i < _numFrames; i++) OFFreeMemory(_mverts[i]); OFFreeMemory(_mverts); } | | | | | | | | | | | | | | | | | | | | | | | | | | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | if (_mverts != NULL) for (size_t i = 0; i < _numFrames; i++) OFFreeMemory(_mverts[i]); OFFreeMemory(_mverts); } - (bool)loadWithIRI: (OFIRI *)IRI { OFSeekableStream *stream; @try { stream = (OFSeekableStream *)[[OFIRIHandler handlerForIRI: IRI] openItemAtIRI: IRI mode: @"r"]; } @catch (id e) { return false; } if (![stream isKindOfClass: OFSeekableStream.class]) return false; struct md2_header header; [stream readIntoBuffer: &header exactLength: sizeof(header)]; endianswap(&header, sizeof(int), sizeof(header) / sizeof(int)); if (header.magic != 844121161 || header.version != 8) return false; @try { _frames = OFAllocMemory(header.numFrames, header.frameSize); } @catch (OFOutOfMemoryException *e) { return false; } [stream seekToOffset: header.offsetFrames whence: OFSeekSet]; [stream readIntoBuffer: _frames exactLength: header.frameSize * header.numFrames]; for (int i = 0; i < header.numFrames; ++i) endianswap(_frames + i * header.frameSize, sizeof(float), 6); @try { _glCommands = OFAllocMemory(header.numGlCommands, sizeof(int)); } @catch (OFOutOfMemoryException *e) { return false; } [stream seekToOffset: header.offsetGlCommands whence: OFSeekSet]; [stream readIntoBuffer: _glCommands exactLength: header.numGlCommands * sizeof(int)]; endianswap(_glCommands, sizeof(int), header.numGlCommands); _numFrames = header.numFrames; _numGlCommands = header.numGlCommands; _frameSize = header.frameSize; _numTriangles = header.numTriangles; _numVerts = header.numVertices; [stream close]; _mverts = OFAllocZeroedMemory(_numFrames, sizeof(OFVector3D *)); return true; } - (void)scaleWithFrame: (int)frame scale: (float)scale snap: (int)sn { OFAssert(_mverts[frame] == NULL); _mverts[frame] = OFAllocMemory(_numVerts, sizeof(OFVector3D)); struct md2_frame *cf = (struct md2_frame *)((char *)_frames + _frameSize * frame); float sc = 16.0f / scale; for (int vi = 0; vi < _numVerts; vi++) { unsigned char *cv = (unsigned char *)&cf->vertices[vi].vertex; OFVector3D *v = &(_mverts[frame])[vi]; v->x = (snap(sn, cv[0] * cf->scale[0]) + cf->translate[0]) / sc; v->y = -(snap(sn, cv[1] * cf->scale[1]) + cf->translate[1]) / sc; v->z = (snap(sn, cv[2] * cf->scale[2]) + cf->translate[2]) / sc; } } - (void)renderWithLight: (OFColor *)light frame: (int)frame range: (int)range position: (OFVector3D)position yaw: (float)yaw pitch: (float)pitch scale: (float)sc speed: (float)speed snap: (int)sn basetime: (int)basetime { for (int i = 0; i < range; i++) if (!_mverts[frame + i]) [self scaleWithFrame: frame + i scale: sc snap: sn]; glPushMatrix(); glTranslatef(position.x, position.y, position.z); glRotatef(yaw + 180, 0, -1, 0); glRotatef(pitch, 0, 0, 1); [light cube_setAsGLColor]; |
︙ | ︙ |
Modified src/MapModelInfo.h from [3aab1dec04] to [9966a1ab68].
1 2 3 4 5 6 7 8 9 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN OF_DIRECT_MEMBERS @interface MapModelInfo: OFObject @property (nonatomic) int rad, h, zoff, snap; @property (copy, nonatomic) OFString *name; | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN OF_DIRECT_MEMBERS @interface MapModelInfo: OFObject @property (nonatomic) int rad, h, zoff, snap; @property (copy, nonatomic) OFString *name; + (instancetype)infoWithRad: (int)rad h: (int)h zoff: (int)zoff snap: (int)snap name: (OFString *)name; - (instancetype)init OF_UNAVAILABLE; - (instancetype)initWithRad: (int)rad h: (int)h zoff: (int)zoff snap: (int)snap name: (OFString *)name; @end OF_ASSUME_NONNULL_END |
Modified src/MapModelInfo.m from [d506409929] to [19135ee4c2].
1 2 3 | #import "MapModelInfo.h" @implementation MapModelInfo | | | | | | | > > > > | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #import "MapModelInfo.h" @implementation MapModelInfo + (instancetype)infoWithRad: (int)rad h: (int)h zoff: (int)zoff snap: (int)snap name: (OFString *)name { return [[self alloc] initWithRad: rad h: h zoff: zoff snap: snap name: name]; } - (instancetype)initWithRad: (int)rad h: (int)h zoff: (int)zoff snap: (int)snap name: (OFString *)name { self = [super init]; _rad = rad; _h = h; _zoff = zoff; _snap = snap; |
︙ | ︙ |
Modified src/Menu.h from [213d149aa4] to [fddccab06a].
1 2 3 4 5 6 7 8 9 10 11 12 13 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN @class MenuItem; OF_DIRECT_MEMBERS @interface Menu: OFObject @property (readonly, nonatomic) OFString *name; @property (readonly) OFMutableArray<MenuItem *> *items; @property (nonatomic) int mwidth; @property (nonatomic) int menusel; | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN @class MenuItem; OF_DIRECT_MEMBERS @interface Menu: OFObject @property (readonly, nonatomic) OFString *name; @property (readonly) OFMutableArray<MenuItem *> *items; @property (nonatomic) int mwidth; @property (nonatomic) int menusel; + (instancetype)menuWithName: (OFString *)name; - (instancetype)init OF_UNAVAILABLE; - (instancetype)initWithName: (OFString *)name; @end OF_ASSUME_NONNULL_END |
Modified src/Menu.m from [e5fbce3936] to [106bd88ce2].
1 2 3 | #import "Menu.h" @implementation Menu | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #import "Menu.h" @implementation Menu + (instancetype)menuWithName: (OFString *)name { return [[self alloc] initWithName: name]; } - (instancetype)initWithName: (OFString *)name { self = [super init]; _name = [name copy]; _items = [[OFMutableArray alloc] init]; return self; |
︙ | ︙ |
Modified src/MenuItem.h from [969de9221d] to [d2df5485ed].
1 2 3 4 5 6 | #import <ObjFW/ObjFW.h> OF_DIRECT_MEMBERS @interface MenuItem: OFObject @property (readonly, nonatomic) OFString *text, *action; | | | | 1 2 3 4 5 6 7 8 9 10 | #import <ObjFW/ObjFW.h> OF_DIRECT_MEMBERS @interface MenuItem: OFObject @property (readonly, nonatomic) OFString *text, *action; + (instancetype)itemWithText: (OFString *)text action: (OFString *)action; - (instancetype)init OF_UNAVAILABLE; - (instancetype)initWithText: (OFString *)text action: (OFString *)action; @end |
Modified src/MenuItem.m from [5ee318d452] to [c51eda1a22].
1 2 3 | #import "MenuItem.h" @implementation MenuItem | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #import "MenuItem.h" @implementation MenuItem + (instancetype)itemWithText: (OFString *)text action: (OFString *)action { return [[self alloc] initWithText: text action: action]; } - (instancetype)initWithText: (OFString *)text action: (OFString *)action { self = [super init]; _text = [text copy]; _action = [action copy]; return self; } - (OFComparisonResult)compare: (id)otherObject { MenuItem *otherItem; if (![otherObject isKindOfClass: MenuItem.class]) @throw [OFInvalidArgumentException exception]; int x, y; @try { x = _text.intValue; } @catch (OFInvalidFormatException *e) { x = 0; |
︙ | ︙ |
Modified src/Monster.h from [f02a70099a] to [ecb02516a6].
︙ | ︙ | |||
21 22 23 24 25 26 27 | // called after map start of when toggling edit mode to reset/spawn all // monsters to initial state + (void)restoreAll; + (void)resetAll; + (void)thinkAll; + (void)renderAll; // TODO: Move this somewhere else | | | | | | | | | | | | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | // called after map start of when toggling edit mode to reset/spawn all // monsters to initial state + (void)restoreAll; + (void)resetAll; + (void)thinkAll; + (void)renderAll; // TODO: Move this somewhere else + (void)endSinglePlayerWithAllKilled: (bool)allKilled; + (instancetype)monsterWithType: (int)type yaw: (int)yaw state: (int)state trigger: (int)trigger move: (int)move; - (instancetype)initWithType: (int)type yaw: (int)yaw state: (int)state trigger: (int)trigger move: (int)move; - (void)incurDamage: (int)damage fromEntity: (__kindof DynamicEntity *)d; @end |
Modified src/Monster.m from [96bb3308b2] to [911d4fb855].
︙ | ︙ | |||
18 19 20 21 22 23 24 | } + (OFMutableArray<Monster *> *)monsters { return monsters; } | | | | | | | | | | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | } + (OFMutableArray<Monster *> *)monsters { return monsters; } + (instancetype)monsterWithType: (int)type yaw: (int)yaw state: (int)state trigger: (int)trigger move: (int)move { return [[self alloc] initWithType: type yaw: yaw state: state trigger: trigger move: move]; } VARF(skill, 1, 3, 10, conoutf(@"skill is now %d", skill)); // for savegames + (void)restoreAll { |
︙ | ︙ | |||
71 72 73 74 75 76 77 | @"a hellpig", @"monster/hellpig" }, { GUN_ICEBALL, 12, 250, 1, 0, 10, 400, 6, 18, 18, S_PAINH, S_DEATHH, @"a knight", @"monster/knight" }, { GUN_SLIMEBALL, 15, 100, 1, 0, 200, 400, 2, 13, 10, S_PAIND, S_DEATHD, @"a goblin", @"monster/goblin" }, }; | | | | | | | 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | @"a hellpig", @"monster/hellpig" }, { GUN_ICEBALL, 12, 250, 1, 0, 10, 400, 6, 18, 18, S_PAINH, S_DEATHH, @"a knight", @"monster/knight" }, { GUN_SLIMEBALL, 15, 100, 1, 0, 200, 400, 2, 13, 10, S_PAIND, S_DEATHD, @"a goblin", @"monster/goblin" }, }; - (instancetype)initWithType: (int)type yaw: (int)yaw state: (int)state trigger: (int)trigger move: (int)move { self = [super init]; if (type >= NUMMONSTERTYPES) { conoutf(@"warning: unknown monster in spawn: %d", type); type = 0; } |
︙ | ︙ | |||
142 143 144 145 146 147 148 | for (int i = 0;; i++) { if ((n -= monstertypes[i].freq) < 0) { type = i; break; } } | | | | | | | | | | | | | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | for (int i = 0;; i++) { if ((n -= monstertypes[i].freq) < 0) { type = i; break; } } [monsters addObject: [Monster monsterWithType: type yaw: rnd(360) state: M_SEARCH trigger: 1000 move: 1]]; } + (void)resetAll { [monsters removeAllObjects]; numkilled = 0; monstertotal = 0; spawnremain = 0; if (m_dmsp) { nextmonster = mtimestart = lastmillis + 10000; monstertotal = spawnremain = gamemode < 0 ? skill * 10 : 0; } else if (m_classicsp) { mtimestart = lastmillis; for (Entity *e in ents) { if (e.type != MONSTER) continue; Monster *m = [Monster monsterWithType: e.attr2 yaw: e.attr1 state: M_SLEEP trigger: 100 move: 0]; m.origin = OFMakeVector3D(e.x, e.y, e.z); [monsters addObject: m]; entinmap(m); monstertotal++; } } } // height-correct line of sight for monster shooting/seeing |
︙ | ︙ | |||
233 234 235 236 237 238 239 | // where they execute a particular behaviour until the trigger time is hit, and // then they reevaluate their situation based on the current state, the // environment etc., and transition to the next state. Transition timeframes are // parametrized by difficulty level (skill), faster transitions means quicker // decision making means tougher AI. // n = at skill 0, n/2 = at skill 10, r = added random factor | | | | | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | // where they execute a particular behaviour until the trigger time is hit, and // then they reevaluate their situation based on the current state, the // environment etc., and transition to the next state. Transition timeframes are // parametrized by difficulty level (skill), faster transitions means quicker // decision making means tougher AI. // n = at skill 0, n/2 = at skill 10, r = added random factor - (void)transitionWithState: (int)state moving: (int)moving n: (int)n r: (int)r { self.monsterState = state; self.move = moving; n = n * 130 / 100; self.trigger = lastmillis + n - skill * (n / 16) + rnd(r + 1); } - (void)normalizeWithAngle: (float)angle { while (self.yaw < angle - 180.0f) self.yaw += 360.0f; while (self.yaw > angle + 180.0f) self.yaw -= 360.0f; } // main AI thinking routine, called every frame for every monster - (void)performAction { if (self.enemy.state == CS_DEAD) { self.enemy = Player.player1; self.anger = 0; } [self normalizeWithAngle: self.targetYaw]; // slowly turn monster towards his target if (self.targetYaw > self.yaw) { self.yaw += curtime * 0.5f; if (self.targetYaw < self.yaw) self.yaw = self.targetYaw; } else { self.yaw -= curtime * 0.5f; |
︙ | ︙ | |||
284 285 286 287 288 289 290 | if (!rnd(20000 / monstertypes[self.monsterType].speed)) self.jumpNext = true; // search for a way around (common) else if (self.trigger < lastmillis && (self.monsterState != M_HOME || !rnd(5))) { // patented "random walk" AI pathfinding (tm) ;) self.targetYaw += 180 + rnd(180); | | | | | | > > > | | > > > | | | | | | | | | | | | | | | | | | | | | | | | | | 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 | if (!rnd(20000 / monstertypes[self.monsterType].speed)) self.jumpNext = true; // search for a way around (common) else if (self.trigger < lastmillis && (self.monsterState != M_HOME || !rnd(5))) { // patented "random walk" AI pathfinding (tm) ;) self.targetYaw += 180 + rnd(180); [self transitionWithState: M_SEARCH moving: 1 n: 400 r: 1000]; } } float enemyYaw = -(float)atan2(self.enemy.origin.x - self.origin.x, self.enemy.origin.y - self.origin.y) / PI * 180 + 180; switch (self.monsterState) { case M_PAIN: case M_ATTACKING: case M_SEARCH: if (self.trigger < lastmillis) [self transitionWithState: M_HOME moving: 1 n: 100 r: 200]; break; case M_SLEEP: // state classic sp monster start in, wait for visual // contact { OFVector3D target; if (editmode || !enemylos(self, &target)) return; // skip running physics [self normalizeWithAngle: enemyYaw]; float angle = (float)fabs(enemyYaw - self.yaw); if (disttoenemy < 8 // the better the angle to the player, the // further the monster can see/hear || (disttoenemy < 16 && angle < 135) || (disttoenemy < 32 && angle < 90) || (disttoenemy < 64 && angle < 45) || angle < 10) { [self transitionWithState: M_HOME moving: 1 n: 500 r: 200]; OFVector3D loc = self.origin; playsound(S_GRUNT1 + rnd(2), &loc); } break; } case M_AIMING: // this state is the delay between wanting to shoot and actually // firing if (self.trigger < lastmillis) { self.lastAction = 0; self.attacking = true; shoot(self, self.attackTarget); [self transitionWithState: M_ATTACKING moving: 0 n: 600 r: 0]; } break; case M_HOME: // monster has visual contact, heads straight for player and // may want to shoot at any time self.targetYaw = enemyYaw; if (self.trigger < lastmillis) { OFVector3D target; if (!enemylos(self, &target)) { // no visual contact anymore, let monster get // as close as possible then search for player [self transitionWithState: M_HOME moving: 1 n: 800 r: 500]; } else { // the closer the monster is the more likely he // wants to shoot if (!rnd((int)disttoenemy / 3 + 1) && self.enemy.state == CS_ALIVE) { // get ready to fire self.attackTarget = target; int n = monstertypes[self.monsterType].lag; [self transitionWithState: M_AIMING moving: 0 n: n r: 10]; } else { // track player some more int n = monstertypes[self.monsterType].rate; [self transitionWithState: M_HOME moving: 1 n: n r: 0]; } } } break; } moveplayer(self, 1, false); // use physics to move monster } - (void)incurDamage: (int)damage fromEntity: (__kindof DynamicEntity *)d { // a monster hit us if ([d isKindOfClass: Monster.class]) { Monster *m = (Monster *)d; // guard for RL guys shooting themselves :) if (self != m) { // don't attack straight away, first get angry self.anger++; int anger = (self.monsterType == m.monsterType ? self.anger / 2 : self.anger); if (anger >= monstertypes[self.monsterType].loyalty) // monster infight if very angry self.enemy = m; } } else { // player hit us self.anger = 0; self.enemy = d; } // in this state monster won't attack [self transitionWithState: M_PAIN moving: 0 n: monstertypes[self.monsterType].pain r: 200]; if ((self.health -= damage) <= 0) { self.state = CS_DEAD; self.lastAction = lastmillis; numkilled++; Player.player1.frags = numkilled; OFVector3D loc = self.origin; playsound(monstertypes[self.monsterType].diesound, &loc); int remain = monstertotal - numkilled; if (remain > 0 && remain <= 5) conoutf(@"only %d monster(s) remaining", remain); } else { OFVector3D loc = self.origin; playsound(monstertypes[self.monsterType].painsound, &loc); } } + (void)endSinglePlayerWithAllKilled: (bool)allKilled { conoutf(allKilled ? @"you have cleared the map!" : @"you reached the exit!"); conoutf(@"score: %d kills in %d seconds", numkilled, (lastmillis - mtimestart) / 1000); monstertotal = 0; startintermission(); } + (void)thinkAll { if (m_dmsp && spawnremain && lastmillis > nextmonster) { if (spawnremain-- == monstertotal) conoutf(@"The invasion has begun!"); nextmonster = lastmillis + 1000; spawnmonster(); } if (monstertotal && !spawnremain && numkilled == monstertotal) [self endSinglePlayerWithAllKilled: true]; // equivalent of player entity touch, but only teleports are used [ents enumerateObjectsUsingBlock: ^ (Entity *e, size_t i, bool *stop) { if (e.type != TELEPORT) return; if (OUTBORD(e.x, e.y)) return; OFVector3D v = |
︙ | ︙ |
Modified src/OFColor+Cube.m from [830e6212b6] to [a418a3dce6].
1 2 3 4 5 6 7 8 | #include "cube.h" #import "OFColor+Cube.h" @implementation OFColor (Cube) - (void)cube_setAsGLColor { float red, green, blue, alpha; | | | 1 2 3 4 5 6 7 8 9 10 11 12 | #include "cube.h" #import "OFColor+Cube.h" @implementation OFColor (Cube) - (void)cube_setAsGLColor { float red, green, blue, alpha; [self getRed: &red green: &green blue: &blue alpha: &alpha]; glColor4f(red, green, blue, alpha); } @end |
Modified src/OFString+Cube.h from [521e5eedaf] to [4053523497].
1 2 3 4 5 | #import <ObjFW/ObjFW.h> @interface OFString (Cube) @property (readonly, nonatomic) int cube_intValue; | | | 1 2 3 4 5 6 7 | #import <ObjFW/ObjFW.h> @interface OFString (Cube) @property (readonly, nonatomic) int cube_intValue; - (int)cube_intValueWithBase: (unsigned char)base; @end |
Modified src/OFString+Cube.m from [fe77741148] to [fa8b89b835].
︙ | ︙ | |||
12 13 14 15 16 17 18 | return 0; } @catch (OFOutOfRangeException *e) { conoutf(@"invalid value: %@", self); return 0; } } | | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | return 0; } @catch (OFOutOfRangeException *e) { conoutf(@"invalid value: %@", self); return 0; } } - (int)cube_intValueWithBase: (unsigned char)base { @try { return [self intValueWithBase: base]; } @catch (OFInvalidFormatException *e) { conoutf(@"invalid value: %@", self); return 0; } @catch (OFOutOfRangeException *e) { conoutf(@"invalid value: %@", self); return 0; } |
︙ | ︙ |
Modified src/Player.m from [0c9f736137] to [312fff2095].
︙ | ︙ | |||
10 11 12 13 14 15 16 | } + (instancetype)player { return [[self alloc] init]; } | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | } + (instancetype)player { return [[self alloc] init]; } + (void)setPlayer1: (Player *)player1_ { player1 = player1_; } + (Player *)player1 { return player1; |
︙ | ︙ |
Modified src/ResolverResult.h from [48e906dbd2] to [97bc46e6ab].
1 2 3 4 5 6 7 8 9 | #import <ObjFW/ObjFW.h> #import "cube.h" OF_DIRECT_MEMBERS @interface ResolverResult: OFObject @property (readonly, nonatomic) OFString *query; @property (readonly, nonatomic) ENetAddress address; | | > | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #import <ObjFW/ObjFW.h> #import "cube.h" OF_DIRECT_MEMBERS @interface ResolverResult: OFObject @property (readonly, nonatomic) OFString *query; @property (readonly, nonatomic) ENetAddress address; + (instancetype)resultWithQuery: (OFString *)query address: (ENetAddress)address; - (instancetype)init OF_UNAVAILABLE; - (instancetype)initWithQuery: (OFString *)query address: (ENetAddress)address OF_DESIGNATED_INITIALIZER; @end |
Modified src/ResolverResult.m from [36dcd5aa96] to [2be4a1c685].
1 2 3 | #import "ResolverResult.h" @implementation ResolverResult | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #import "ResolverResult.h" @implementation ResolverResult + (instancetype)resultWithQuery: (OFString *)query address: (ENetAddress)address { return [[self alloc] initWithQuery: query address: address]; } - (instancetype)initWithQuery: (OFString *)query address: (ENetAddress)address { self = [super init]; _query = query; _address = address; return self; |
︙ | ︙ |
Modified src/ResolverThread.m from [5a480794ce] to [c6ab30f422].
︙ | ︙ | |||
21 22 23 24 25 26 27 | _starttime = lastmillis; } ENetAddress address = { ENET_HOST_ANY, CUBE_SERVINFO_PORT }; enet_address_set_host(&address, _query.UTF8String); @synchronized(ResolverThread.class) { | | | | | 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | _starttime = lastmillis; } ENetAddress address = { ENET_HOST_ANY, CUBE_SERVINFO_PORT }; enet_address_set_host(&address, _query.UTF8String); @synchronized(ResolverThread.class) { [resolverresults addObject: [ResolverResult resultWithQuery: _query address: address]]; _query = NULL; _starttime = 0; } } return nil; |
︙ | ︙ |
Modified src/ServerInfo.h from [8949d4cc02] to [688d346abd].
1 2 3 4 5 6 7 8 9 10 11 12 13 | #import <ObjFW/ObjFW.h> #include <enet/enet.h> OF_DIRECT_MEMBERS @interface ServerInfo: OFObject <OFComparing> @property (readonly, nonatomic) OFString *name; @property (copy, nonatomic) OFString *full; @property (copy, nonatomic) OFString *map; @property (copy, nonatomic) OFString *sdesc; @property (nonatomic) int mode, numplayers, ping, protocol, minremain; @property (nonatomic) ENetAddress address; | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #import <ObjFW/ObjFW.h> #include <enet/enet.h> OF_DIRECT_MEMBERS @interface ServerInfo: OFObject <OFComparing> @property (readonly, nonatomic) OFString *name; @property (copy, nonatomic) OFString *full; @property (copy, nonatomic) OFString *map; @property (copy, nonatomic) OFString *sdesc; @property (nonatomic) int mode, numplayers, ping, protocol, minremain; @property (nonatomic) ENetAddress address; + (instancetype)infoWithName: (OFString *)name; - (instancetype)init OF_UNAVAILABLE; - (instancetype)initWithName: (OFString *)name; @end |
Modified src/ServerInfo.m from [77aa772923] to [774d015eb0].
1 2 3 4 5 | #import "ServerInfo.h" #include "cube.h" @implementation ServerInfo | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #import "ServerInfo.h" #include "cube.h" @implementation ServerInfo + (instancetype)infoWithName: (OFString *)name; { return [[self alloc] initWithName: name]; } - (instancetype)initWithName: (OFString *)name { self = [super init]; _name = [name copy]; _full = @""; _mode = 0; _numplayers = 0; _ping = 9999; _protocol = 0; _minremain = 0; _map = @""; _sdesc = @""; _address.host = ENET_HOST_ANY; _address.port = CUBE_SERVINFO_PORT; return self; } - (OFComparisonResult)compare: (ServerInfo *)otherObject { if (![otherObject isKindOfClass: ServerInfo.class]) @throw [OFInvalidArgumentException exception]; if (_ping > otherObject.ping) return OFOrderedDescending; if (_ping < otherObject.ping) return OFOrderedAscending; return [_name compare: otherObject.name]; } @end |
Modified src/Variable.h from [b06c507597] to [780b5706d6].
1 2 3 4 | #import "Identifier.h" OF_ASSUME_NONNULL_BEGIN | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | > > > > | | | | | < > | | | | | | | | | < < > > | | > > > > | | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | #import "Identifier.h" OF_ASSUME_NONNULL_BEGIN #define VARP(name, min_, cur, max_) \ int name = cur; \ \ OF_CONSTRUCTOR() \ { \ enqueueInit(^ { \ Variable *variable = \ [Variable variableWithName: @#name \ min: min_ \ max: max_ \ storage: &name \ function: NULL \ persisted: true]; \ Identifier.identifiers[@#name] = variable; \ }); \ } #define VAR(name, min_, cur, max_) \ int name = cur; \ \ OF_CONSTRUCTOR() \ { \ enqueueInit(^ { \ Variable *variable = \ [Variable variableWithName: @#name \ min: min_ \ max: max_ \ storage: &name \ function: NULL \ persisted: false]; \ Identifier.identifiers[@#name] = variable; \ }); \ } #define VARF(name, min_, cur, max_, body) \ static void var_##name(void); \ static int name = cur; \ \ OF_CONSTRUCTOR() \ { \ enqueueInit(^ { \ Variable *variable = \ [Variable variableWithName: @#name \ min: min_ \ max: max_ \ storage: &name \ function: var_##name \ persisted: false]; \ Identifier.identifiers[@#name] = variable; \ }); \ } \ \ static void \ var_##name(void) \ { \ body; \ } #define VARFP(name, min_, cur, max_, body) \ static void var_##name(void); \ static int name = cur; \ \ OF_CONSTRUCTOR() \ { \ enqueueInit(^ { \ Variable *variable = \ [Variable variableWithName: @#name \ min: min_ \ max: max_ \ storage: &name \ function: var_##name \ persisted: true]; \ Identifier.identifiers[@#name] = variable; \ }); \ } \ \ static void \ var_##name(void) \ { \ body; \ } @interface Variable: Identifier @property (direct, readonly, nonatomic) int min, max; @property (direct, readonly, nonatomic) int *storage; @property (direct, readonly, nullable, nonatomic) void (*function)(); @property (readonly, nonatomic) bool persisted; + (instancetype)variableWithName: (OFString *)name min: (int)min max: (int)max storage: (int *)storage function: (void (*_Nullable)())function persisted: (bool)persisted OF_DIRECT; - (instancetype)initWithName: (OFString *)name OF_UNAVAILABLE; - (instancetype)initWithName: (OFString *)name min: (int)min max: (int)max storage: (int *)storage function: (void (*_Nullable)())function persisted: (bool)persisted OF_DESIGNATED_INITIALIZER OF_DIRECT; - (void)printValue OF_DIRECT; - (void)setValue: (int)value OF_DIRECT; @end OF_ASSUME_NONNULL_END |
Modified src/Variable.m from [eb5893de54] to [60a145c003].
1 2 3 4 5 | #import "Variable.h" #include "cube.h" @implementation Variable | | | | | | | | | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #import "Variable.h" #include "cube.h" @implementation Variable + (instancetype)variableWithName: (OFString *)name min: (int)min max: (int)max storage: (int *)storage function: (void (*__cdecl)())function persisted: (bool)persisted { return [[self alloc] initWithName: name min: min max: max storage: storage function: function persisted: persisted]; } - (instancetype)initWithName: (OFString *)name min: (int)min max: (int)max storage: (int *)storage function: (void (*__cdecl)())function persisted: (bool)persisted { self = [super initWithName: name]; _min = min; _max = max; _storage = storage; _function = function; _persisted = persisted; return self; } - (void)printValue { conoutf(@"%@ = %d", self.name, *_storage); } - (void)setValue: (int)value { bool outOfRange = false; if (_min > _max) { conoutf(@"variable is read-only"); return; } |
︙ | ︙ |
Modified src/clientextras.m from [89ccbf227a] to [d459541c88].
︙ | ︙ | |||
47 48 49 50 51 52 53 | } } if (mz < -1000) return; // mdl = (((int)d>>6)&1)+1; // mz = d.o.z-d.eyeHeight+0.2f; // scale = 1.2f; | | | | | | | | | | | | | | | < | | | | | | | | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | } } if (mz < -1000) return; // mdl = (((int)d>>6)&1)+1; // mz = d.o.z-d.eyeHeight+0.2f; // scale = 1.2f; } else if (d.state == CS_EDITING) n = 16; else if (d.state == CS_LAGGED) n = 17; else if ([d isKindOfClass: Monster.class] && ((Monster *)d).monsterState == M_ATTACKING) n = 8; else if ([d isKindOfClass: Monster.class] && ((Monster *)d).monsterState == M_PAIN) n = 10; else if ((!d.move && !d.strafe) || !d.moving) n = 12; else if (!d.onFloor && d.timeInAir > 100) n = 18; else { n = 14; speed = 1200 / d.maxSpeed * scale; if (hellpig) speed = 300 / d.maxSpeed; } if (hellpig) { n++; scale *= 32; mz -= 1.9f; } rendermodel(mdlname, frame[n], range[n], 0, 1.5f, OFMakeVector3D(d.origin.x, mz, d.origin.y), d.yaw + 90, d.pitch / 2, team, scale, speed, 0, basetime); } extern int democlientnum; void renderclients() { [players enumerateObjectsUsingBlock: ^ (Player *player, size_t i, bool *stop) { if ([player isKindOfClass: Player.class] && (!demoplayback || i != democlientnum)) renderclient(player, isteam(Player.player1.team, [player team]), @"monster/ogro", false, 1.0f); }]; } // creation of scoreboard pseudo-menu bool scoreson = false; void showscores(bool on) { scoreson = on; menuset(((int)on) - 1); } static OFMutableArray<OFString *> *scoreLines; static void renderscore(Player *d) { OFString *lag = [OFString stringWithFormat: @"%d", d.lag]; OFString *name = [OFString stringWithFormat: @"(%@)", d.name]; OFString *line = [OFString stringWithFormat: @"%d\t%@\t%d\t%@\t%@", d.frags, (d.state == CS_LAGGED ? @"LAG" : lag), d.ping, d.team, (d.state == CS_DEAD ? name : d.name)]; if (scoreLines == nil) scoreLines = [[OFMutableArray alloc] init]; [scoreLines addObject: line]; menumanual(0, scoreLines.count - 1, line); } #define maxTeams 4 static OFString *teamName[maxTeams]; static int teamScore[maxTeams]; static size_t teamsUsed; static void addteamscore(Player *d) { for (size_t i = 0; i < teamsUsed; i++) { if ([teamName[i] isEqual: d.team]) { teamScore[i] += d.frags; return; } } if (teamsUsed == maxTeams) return; |
︙ | ︙ | |||
153 154 155 156 157 158 159 | { if (!scoreson) return; [scoreLines removeAllObjects]; if (!demoplayback) renderscore(Player.player1); for (Player *player in players) | | | | | | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | { if (!scoreson) return; [scoreLines removeAllObjects]; if (!demoplayback) renderscore(Player.player1); for (Player *player in players) if ([player isKindOfClass: Player.class]) renderscore(player); sortmenu(); if (m_teammode) { teamsUsed = 0; for (Player *player in players) if ([player isKindOfClass: Player.class]) addteamscore(player); if (!demoplayback) addteamscore(Player.player1); OFMutableString *teamScores = [OFMutableString string]; for (size_t j = 0; j < teamsUsed; j++) [teamScores appendFormat: @"[ %@: %d ]", teamName[j], teamScore[j]]; menumanual(0, scoreLines.count, @""); menumanual(0, scoreLines.count + 1, teamScores); } } // sendmap/getmap commands, should be replaced by more intuitive map downloading COMMAND(sendmap, ARG_1STR, (^ (OFString *mapname) { if (mapname.length > 0) save_world(mapname); changemap(mapname); mapname = getclientmap(); OFData *mapdata = readmap(mapname); if (mapdata == nil) return; |
︙ | ︙ | |||
200 201 202 203 204 205 206 | } memcpy(p, mapdata.items, mapdata.count); p += mapdata.count; *(unsigned short *)start = ENET_HOST_TO_NET_16(p - start); enet_packet_resize(packet, p - start); sendpackettoserv(packet); conoutf(@"sending map %@ to server...", mapname); | | < | < | | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | } memcpy(p, mapdata.items, mapdata.count); p += mapdata.count; *(unsigned short *)start = ENET_HOST_TO_NET_16(p - start); enet_packet_resize(packet, p - start); sendpackettoserv(packet); conoutf(@"sending map %@ to server...", mapname); OFString *msg = [OFString stringWithFormat: @"[map %@ uploaded to server, \"getmap\" to receive it]", mapname]; toserver(msg); })) COMMAND(getmap, ARG_NONE, ^ { ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); unsigned char *start = packet->data; unsigned char *p = start + 2; putint(&p, SV_RECVMAP); *(unsigned short *)start = ENET_HOST_TO_NET_16(p - start); enet_packet_resize(packet, p - start); sendpackettoserv(packet); conoutf(@"requesting map from server..."); }) |
Modified src/clientgame.m from [591f2f2799] to [0b8b0d202d].
︙ | ︙ | |||
9 10 11 12 13 14 15 | #import "OFString+Cube.h" #import "Player.h" #import "Variable.h" int nextmode = 0; // nextmode becomes gamemode after next map load VAR(gamemode, 1, 0, 0); | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #import "OFString+Cube.h" #import "Player.h" #import "Variable.h" int nextmode = 0; // nextmode becomes gamemode after next map load VAR(gamemode, 1, 0, 0); COMMAND(mode, ARG_1INT, ^ (int n) { addmsg(1, 2, SV_GAMEMODE, nextmode = n); }) bool intermission = false; OFMutableArray *players; // other clients |
︙ | ︙ | |||
49 50 51 52 53 54 55 | } static void arenacount(Player *d, int *alive, int *dead, OFString **lastteam, bool *oneteam) { if (d.state != CS_DEAD) { (*alive)++; | | | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | } static void arenacount(Player *d, int *alive, int *dead, OFString **lastteam, bool *oneteam) { if (d.state != CS_DEAD) { (*alive)++; if (![*lastteam isEqual: d.team]) *oneteam = false; *lastteam = d.team; } else (*dead)++; } int arenarespawnwait = 0; |
︙ | ︙ | |||
98 99 100 101 102 103 104 | } extern int democlientnum; void otherplayers() { | | | | | | | | | | | | | | | | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | } extern int democlientnum; void otherplayers() { [players enumerateObjectsUsingBlock: ^ (Player *player, size_t i, bool *stop) { if ([player isKindOfClass: Player.class]) return; const int lagtime = lastmillis - player.lastUpdate; if (lagtime > 1000 && player.state == CS_ALIVE) { player.state = CS_LAGGED; return; } if (lagtime && player.state != CS_DEAD && (!demoplayback || i != democlientnum)) // use physics to extrapolate player position moveplayer(player, 2, false); }]; } void respawn() { if (Player.player1.state == CS_DEAD) { Player.player1.attacking = false; |
︙ | ︙ | |||
136 137 138 139 140 141 142 | } // if we die in SP we try the same map again respawnself(); } } int sleepwait = 0; static OFString *sleepcmd = nil; | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | } // if we die in SP we try the same map again respawnself(); } } int sleepwait = 0; static OFString *sleepcmd = nil; COMMAND(sleep, ARG_2STR, ^ (OFString *msec, OFString *cmd) { sleepwait = msec.cube_intValue + lastmillis; sleepcmd = cmd; }) void updateworld(int millis) // main game update loop { |
︙ | ︙ | |||
233 234 235 236 237 238 239 | entinmap(d); [d resetToSpawnState]; d.state = CS_ALIVE; } // movement input code | | | | | | | | | | | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | entinmap(d); [d resetToSpawnState]; d.state = CS_ALIVE; } // movement input code #define dir(name, v, d, s, os) \ COMMAND(name, ARG_DOWN, ^ (bool isDown) { \ Player *player1 = Player.player1; \ 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); COMMAND(attack, ARG_DOWN, ^ (bool on) { if (intermission) return; if (editmode) editdrag(on); else if ((Player.player1.attacking = on)) respawn(); }) COMMAND(jump, ARG_DOWN, ^ (bool on) { if (!intermission && (Player.player1.jumpNext = on)) respawn(); }) COMMAND(showscores, ARG_DOWN, ^ (bool isDown) { showscores(isDown); }) void fixplayer1range() { const float MAXPITCH = 90.0f; |
︙ | ︙ | |||
372 373 374 375 376 377 378 | { if (cn < 0 || cn >= MAXCLIENTS) { neterr(@"clientnum"); return nil; } while (cn >= players.count) | | | | 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | { if (cn < 0 || cn >= MAXCLIENTS) { neterr(@"clientnum"); return nil; } while (cn >= players.count) [players addObject: [OFNull null]]; id player = players[cn]; if (player == [OFNull null]) { player = [Player player]; players[cn] = player; } return player; } void setclient(int cn, id client) { if (cn < 0 || cn >= MAXCLIENTS) neterr(@"clientnum"); while (cn >= players.count) [players addObject: [OFNull null]]; players[cn] = client; } void initclient() { clientmap = @""; |
︙ | ︙ | |||
414 415 416 417 418 419 420 | sleepwait = 0; [Monster resetAll]; projreset(); spawncycle = -1; spawnplayer(Player.player1); Player.player1.frags = 0; for (Player *player in players) | | | | 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 | sleepwait = 0; [Monster resetAll]; projreset(); spawncycle = -1; spawnplayer(Player.player1); Player.player1.frags = 0; for (Player *player in players) if ([player isKindOfClass: Player.class]) player.frags = 0; resetspawns(); clientmap = name; if (editmode) toggleedit(); setvar(@"gamespeed", 100); setvar(@"fog", 180); setvar(@"fogcolour", 0x8099B3); showscores(false); intermission = false; Cube.sharedInstance.framesInMap = 0; conoutf(@"game mode is %@", modestr(gamemode)); } COMMAND(map, ARG_1STR, ^ (OFString *name) { changemap(name); }) |
Modified src/clients.m from [0204d78717] to [0b6e5b2153].
︙ | ︙ | |||
64 65 66 67 68 69 70 | static void newname(OFString *name) { c2sinit = false; if (name.length > 16) | | | | | | | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | static void newname(OFString *name) { c2sinit = false; if (name.length > 16) name = [name substringToIndex: 16]; Player.player1.name = name; } COMMAND(name, ARG_1STR, ^ (OFString *name) { newname(name); }) static void newteam(OFString *name) { c2sinit = false; if (name.length > 5) name = [name substringToIndex: 5]; Player.player1.team = name; } COMMAND(team, ARG_1STR, ^ (OFString *name) { newteam(name); }) void writeclientinfo(OFStream *stream) { [stream writeFormat: @"name \"%@\"\nteam \"%@\"\n", Player.player1.name, Player.player1.team]; } void connects(OFString *servername) { disconnect(true, false); // reset state addserver(servername); |
︙ | ︙ | |||
181 182 183 184 185 186 187 | void toserver(OFString *text) { conoutf(@"%@:\f %@", Player.player1.name, text); ctext = text; } | | | | | | | | | | | | | | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | void toserver(OFString *text) { conoutf(@"%@:\f %@", Player.player1.name, text); ctext = text; } COMMAND(echo, ARG_VARI, ^ (OFString *text) { conoutf(@"%@", text); }) 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 static OFMutableArray<OFData *> *messages; void addmsg(int rel, int num, int type, ...) { if (demoplayback) return; if (num != msgsizelookup(type)) fatal(@"inconsistant msg size for %d (%d != %d)", type, num, msgsizelookup(type)); if (messages.count == 100) { conoutf(@"command flood protection (type %d)", type); return; } OFMutableData *msg = [OFMutableData dataWithItemSize: sizeof(int) capacity: num + 2]; [msg addItem: &num]; [msg addItem: &rel]; [msg addItem: &type]; va_list marker; va_start(marker, type); for (int i = 0; i < num - 1; i++) { int tmp = va_arg(marker, int); [msg addItem: &tmp]; } va_end(marker); [msg makeImmutable]; if (messages == nil) messages = [[OFMutableArray alloc] init]; [messages addObject: msg]; } void server_err() { conoutf(@"server network error, disconnecting..."); disconnect(false, false); } int lastupdate = 0, lastping = 0; OFString *toservermap; bool senditemstoserver = false; // after a map change, since server doesn't have map data OFString *clientpassword; COMMAND(password, ARG_1STR, ^ (OFString *p) { clientpassword = p; }) bool netmapstart() { senditemstoserver = true; |
︙ | ︙ | |||
313 314 315 316 317 318 319 | putint(&p, (int)(d.pitch * DAF)); putint(&p, (int)(d.roll * DAF)); // quantize to 1/100, almost always 1 byte putint(&p, (int)(d.velocity.x * DVF)); putint(&p, (int)(d.velocity.y * DVF)); putint(&p, (int)(d.velocity.z * DVF)); // pack rest in 1 byte: strafe:2, move:2, onFloor:1, state:3 | < | | | | 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 | putint(&p, (int)(d.pitch * DAF)); putint(&p, (int)(d.roll * DAF)); // quantize to 1/100, almost always 1 byte putint(&p, (int)(d.velocity.x * DVF)); putint(&p, (int)(d.velocity.y * DVF)); putint(&p, (int)(d.velocity.z * DVF)); // pack rest in 1 byte: strafe:2, move:2, onFloor:1, state:3 putint(&p, (d.strafe & 3) | ((d.move & 3) << 2) | (((int)d.onFloor) << 4) | ((editmode ? CS_EDITING : d.state) << 5)); if (senditemstoserver) { packet->flags = ENET_PACKET_FLAG_RELIABLE; putint(&p, SV_ITEMLIST); if (!m_noitems) putitems(&p); putint(&p, -1); |
︙ | ︙ | |||
345 346 347 348 349 350 351 | putint(&p, SV_INITC2S); sendstring(Player.player1.name, &p); sendstring(Player.player1.team, &p); putint(&p, Player.player1.lifeSequence); } for (OFData *msg in messages) { // send messages collected during the previous frames | | | | | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 | putint(&p, SV_INITC2S); sendstring(Player.player1.name, &p); sendstring(Player.player1.team, &p); putint(&p, Player.player1.lifeSequence); } for (OFData *msg in messages) { // send messages collected during the previous frames if (*(int *)[msg itemAtIndex: 1]) packet->flags = ENET_PACKET_FLAG_RELIABLE; for (int i = 0; i < *(int *)[msg itemAtIndex: 0]; i++) putint(&p, *(int *)[msg itemAtIndex: i + 2]); } [messages removeAllObjects]; if (lastmillis - lastping > 250) { putint(&p, SV_PING); putint(&p, lastmillis); lastping = lastmillis; } |
︙ | ︙ |
Modified src/clients2c.m from [476557dd41] to [11f87c82e6].
︙ | ︙ | |||
170 171 172 173 174 175 176 | if (mapchanged) setspawn(n, true); break; } // server requests next map case SV_MAPRELOAD: { getint(&p); | | | > | < | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | if (mapchanged) setspawn(n, true); break; } // server requests next map case SV_MAPRELOAD: { getint(&p); OFString *nextmapalias = [OFString stringWithFormat: @"nextmap_%@", getclientmap()]; // look up map in the cycle OFString *map = getalias(nextmapalias); changemap(map != nil ? map : getclientmap()); break; } // another client either connected or changed name/team case SV_INITC2S: { Player *d_ = (Player *)d; sgetstr(); if (d_.name.length > 0) { // already connected if (![d_.name isEqual: @(text)]) conoutf(@"%@ is now known as %s", d_.name, text); } else { // new client // send new players my info again c2sinit = false; |
︙ | ︙ | |||
275 276 277 278 279 280 281 | OFVector3D loc = d_.origin; playsound(S_DIE1 + rnd(2), &loc); d_.lifeSequence++; break; } case SV_FRAGS: | | | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | OFVector3D loc = d_.origin; playsound(S_DIE1 + rnd(2), &loc); d_.lifeSequence++; break; } case SV_FRAGS: OFAssert([players[cn] isKindOfClass: Player.class]); ((Player *)players[cn]).frags = getint(&p); break; case SV_ITEMPICKUP: setspawn(getint(&p), false); getint(&p); break; |
︙ | ︙ | |||
338 339 340 341 342 343 344 | case SV_EDITENT: // coop edit of ent { unsigned int i = getint(&p); while (ents.count <= i) { Entity *e = [Entity entity]; e.type = NOTUSED; | | | 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 | case SV_EDITENT: // coop edit of ent { unsigned int i = getint(&p); while (ents.count <= i) { Entity *e = [Entity entity]; e.type = NOTUSED; [ents addObject: e]; } int to = ents[i].type; ents[i].type = getint(&p); ents[i].x = getint(&p); ents[i].y = getint(&p); ents[i].z = getint(&p); |
︙ | ︙ | |||
368 369 370 371 372 373 374 | addmsg(0, 2, SV_CLIENTPING, Player.player1.ping = (Player.player1.ping * 5 + lastmillis - getint(&p)) / 6); break; case SV_CLIENTPING: | | | 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 | addmsg(0, 2, SV_CLIENTPING, Player.player1.ping = (Player.player1.ping * 5 + lastmillis - getint(&p)) / 6); break; case SV_CLIENTPING: OFAssert([players[cn] isKindOfClass: Player.class]); ((Player *)players[cn]).ping = getint(&p); break; case SV_GAMEMODE: nextmode = getint(&p); break; |
︙ | ︙ |
Modified src/commands.m from [45f7f8cf15] to [e072f98aae].
︙ | ︙ | |||
17 18 19 20 21 22 23 | void alias(OFString *name, OFString *action) { Alias *alias = Identifier.identifiers[name]; if (alias == nil) | | | | | | | | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | void alias(OFString *name, OFString *action) { Alias *alias = Identifier.identifiers[name]; if (alias == nil) Identifier.identifiers[name] = [Alias aliasWithName: name action: action persisted: true]; else { if ([alias isKindOfClass: Alias.class]) alias.action = action; else conoutf( @"cannot redefine builtin %@ with an alias", name); } } COMMAND(alias, ARG_2STR, ^ (OFString *name, OFString *action) { alias(name, action); }) void setvar(OFString *name, int i) { Variable *variable = Identifier.identifiers[name]; if ([variable isKindOfClass: Variable.class]) *variable.storage = i; } int getvar(OFString *name) { Variable *variable = Identifier.identifiers[name]; if ([variable isKindOfClass: Variable.class]) return *variable.storage; return 0; } bool identexists(OFString *name) { return (Identifier.identifiers[name] != nil); } OFString * getalias(OFString *name) { Alias *alias = Identifier.identifiers[name]; if ([alias isKindOfClass: Alias.class]) return alias.action; return nil; } // parse any nested set of () or [] static char * |
︙ | ︙ | |||
94 95 96 97 98 99 100 | return NULL; } } char *s = strndup(word, *p - word - 1); if (left == '(') { OFString *t; @try { | | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | return NULL; } } char *s = strndup(word, *p - word - 1); if (left == '(') { OFString *t; @try { t = [OFString stringWithFormat: @"%d", execute(@(s), true)]; } @finally { free(s); } s = strdup(t.UTF8String); } return s; } |
︙ | ︙ | |||
136 137 138 139 140 141 142 | } // find value of ident referenced with $ in exp OFString * lookup(OFString *n) { __kindof Identifier *identifier = | | | | > | | | | | | | | | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | } // find value of ident referenced with $ in exp OFString * lookup(OFString *n) { __kindof Identifier *identifier = Identifier.identifiers[[n substringFromIndex: 1]]; if ([identifier isKindOfClass: Variable.class]) { return [OFString stringWithFormat: @"%d", *[identifier storage]]; } else if ([identifier isKindOfClass: Alias.class]) return [identifier action]; conoutf(@"unknown alias lookup: %@", [n substringFromIndex: 1]); return n; } int executeIdentifier(__kindof Identifier *identifier, OFArray<OFString *> *arguments, bool isDown) { if (identifier == nil) { @try { return [arguments[0] intValueWithBase: 0]; } @catch (OFInvalidFormatException *e) { conoutf(@"unknown command: %@", arguments[0]); return 0; } @catch (OFOutOfRangeException *e) { conoutf(@"invalid value: %@", arguments[0]); return 0; } } if ([identifier isKindOfClass: Command.class]) // game defined commands use very ad-hoc function signature, // and just call it return [identifier callWithArguments: arguments isDown: isDown]; if ([identifier isKindOfClass: Variable.class]) { if (!isDown) return 0; // game defined variables if (arguments.count < 2 || arguments[1].length == 0) [identifier printValue]; else [identifier setValue: [arguments[1] cube_intValueWithBase: 0]]; } if ([identifier isKindOfClass: Alias.class]) { // alias, also used as functions and (global) variables for (int i = 1; i < arguments.count; i++) { // set any arguments as (global) arg values so // functions can access them OFString *t = [OFString stringWithFormat: @"arg%d", i]; alias(t, arguments[i]); } return execute([identifier action], isDown); } return 0; |
︙ | ︙ | |||
235 236 237 238 239 240 241 | } p += strcspn(p, ";\n\0"); // more statements if this isn't the end of the string cont = *p++ != 0; OFString *c = w[0]; // strip irc-style command prefix | | | | | | | | | < | > | | | | | | | > | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 | } p += strcspn(p, ";\n\0"); // more statements if this isn't the end of the string cont = *p++ != 0; OFString *c = w[0]; // strip irc-style command prefix if ([c hasPrefix: @"/"]) { c = [c substringFromIndex: 1]; w[0] = c; } // empty statement if (c.length == 0) continue; val = executeIdentifier(Identifier.identifiers[c], [OFArray arrayWithObjects: w count: numargs], isDown); } return val; } // tab-completion of all identifiers int completesize = 0, completeidx = 0; void resetcomplete() { completesize = 0; } void complete(OFMutableString *s) { if (![s hasPrefix: @"/"]) [s insertString: @"/" atIndex: 0]; if (s.length == 1) return; if (!completesize) { completesize = s.length - 1; completeidx = 0; } __block int idx = 0; [Identifier.identifiers enumerateKeysAndObjectsUsingBlock: ^ (OFString *name, __kindof Identifier *identifier, bool *stop) { if (strncmp(identifier.name.UTF8String, s.UTF8String + 1, completesize) == 0 && idx++ == completeidx) [s replaceCharactersInRange: OFMakeRange( 1, s.length - 1) withString: identifier.name]; }]; completeidx++; if (completeidx >= idx) completeidx = 0; } bool execfile(OFIRI *cfgfile) { OFString *command; @try { command = [OFString stringWithContentsOfIRI: cfgfile]; } @catch (OFOpenItemFailedException *e) { return false; } @catch (OFReadFailedException *e) { return false; } execute(command, true); return true; } void exec(OFString *cfgfile) { if (!execfile([Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent: cfgfile]) && !execfile([Cube.sharedInstance.gameDataIRI IRIByAppendingPathComponent: cfgfile])) conoutf(@"could not read \"%@\"", cfgfile); } COMMAND(exec, ARG_1STR, ^ (OFString *cfgfile) { exec(cfgfile); }) void writecfg() { OFStream *stream; @try { OFIRI *IRI = [Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent: @"config.cfg"]; stream = [[OFIRIHandler handlerForIRI: IRI] openItemAtIRI: IRI mode: @"w"]; } @catch (id e) { return; } [stream writeString: @"// automatically written on exit, do not modify\n" @"// delete this file to have defaults.cfg overwrite these " @"settings\n" @"// modify settings in game, or put settings in autoexec.cfg to " @"override anything\n" @"\n"]; writeclientinfo(stream); [stream writeString: @"\n"]; [Identifier.identifiers enumerateKeysAndObjectsUsingBlock: ^ (OFString *name, __kindof Identifier *identifier, bool *stop) { if (![identifier isKindOfClass: Variable.class] || ![identifier persisted]) return; [stream writeFormat: @"%@ %d\n", identifier.name, *[identifier storage]]; }]; [stream writeString: @"\n"]; writebinds(stream); [stream writeString: @"\n"]; [Identifier.identifiers enumerateKeysAndObjectsUsingBlock: ^ (OFString *name, Alias *alias, bool *stop) { if (![alias isKindOfClass: Alias.class] || [alias.name hasPrefix: @"nextmap_"]) return; [stream writeFormat: @"alias \"%@\" [%@]\n", alias.name, alias.action]; }]; [stream close]; } 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 // trivially. void intset(OFString *name, int v) { alias(name, [OFString stringWithFormat: @"%d", v]); } COMMAND(if, ARG_3STR, ^ (OFString *cond, OFString *thenp, OFString *elsep) { execute((![cond hasPrefix: @"0"] ? thenp : elsep), true); }) 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); } }) COMMAND(while, ARG_2STR, ^ (OFString *cond, OFString *body) { while (execute(cond, true)) execute(body, true); }) COMMAND(onrelease, ARG_DWN1, ^ (bool on, OFString *body) { if (!on) execute(body, true); }) void concat(OFString *s) { alias(@"s", s); } COMMAND(concat, ARG_VARI, ^ (OFString *s) { concat(s); }) COMMAND(concatword, ARG_VARI, ^ (OFString *s) { concat([s stringByReplacingOccurrencesOfString: @" " withString: @""]); }) COMMAND(listlen, ARG_1EST, ^ (OFString *a_) { const char *a = a_.UTF8String; if (!*a) return 0; int n = 0; while (*a) if (*a++ == ' ') n++; return n + 1; }) COMMAND(at, ARG_2STR, ^ (OFString *s_, OFString *pos) { int n = pos.cube_intValue; char *copy __attribute__((__cleanup__(cleanup))) = strdup(s_.UTF8String); char *s = copy; for (int i = 0; i < n; i++) { s += strcspn(s, " \0"); s += strspn(s, " "); } s[strcspn(s, " \0")] = 0; concat(@(s)); }) COMMAND(+, ARG_2EXP, ^ (int a, int b) { return a + b; }) COMMAND(*, ARG_2EXP, ^ (int a, int b) { return a * b; }) COMMAND(-, ARG_2EXP, ^ (int a, int b) { return a - b; }) COMMAND(div, ARG_2EXP, ^ (int a, int b) { return b ? a / b : 0; }) COMMAND(mod, ARG_2EXP, ^ (int a, int b) { return b ? a % b : 0; }) COMMAND(=, ARG_2EXP, ^ (int a, int b) { return (int)(a == b); }) COMMAND(<, ARG_2EXP, ^ (int a, int b) { return (int)(a < b); }) COMMAND(>, ARG_2EXP, ^ (int a, int b) { return (int)(a > b); }) COMMAND(strcmp, ARG_2EST, ^ (OFString *a, OFString *b) { return [a isEqual: b]; }) COMMAND(rnd, ARG_1EXP, ^ (int a) { return (a > 0 ? rnd(a) : 0); }) COMMAND(millis, ARG_1EXP, ^ (int unused) { return lastmillis; }) |
Modified src/console.m from [a83084fb6c] to [1d463d8f9f].
︙ | ︙ | |||
14 15 16 17 18 19 20 | const int ndraw = 5; const int WORDWRAP = 80; int conskip = 0; bool saycommandon = false; static OFMutableString *commandbuf; | | | | | | | | | | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | const int ndraw = 5; const int WORDWRAP = 80; int conskip = 0; bool saycommandon = false; static OFMutableString *commandbuf; COMMAND(conskip, ARG_1INT, ^ (int n) { conskip += n; if (conskip < 0) conskip = 0; }) static void conline(OFString *sf, bool highlight) // add a line to the console buffer { OFMutableString *text; // constrain the buffer size if (conlines.count > 100) { text = [conlines.lastObject.text mutableCopy]; [conlines removeLastObject]; } else text = [OFMutableString string]; if (highlight) // show line in a different colour, for chat etc. [text appendString: @"\f"]; [text appendString: sf]; if (conlines == nil) conlines = [[OFMutableArray alloc] init]; [conlines insertObject: [ConsoleLine lineWithText: text outtime: lastmillis] atIndex: 0]; puts(text.UTF8String); #ifndef OF_WINDOWS fflush(stdout); #endif } void conoutf(OFConstantString *format, ...) { va_list arguments; va_start(arguments, format); OFString *string = [[OFString alloc] initWithFormat: format arguments: arguments]; va_end(arguments); int n = 0; while (string.length > WORDWRAP) { conline([string substringToIndex: WORDWRAP], n++ != 0); string = [string substringFromIndex: WORDWRAP]; } conline(string, n != 0); } // render buffer taking into account time & scrolling void renderconsole() |
︙ | ︙ | |||
98 99 100 101 102 103 104 | (FONTH / 4 * 5) * (nd - j - 1) + FONTH / 3, 2); } // keymap is defined externally in keymap.cfg static OFMutableArray<KeyMapping *> *keyMappings = nil; | | | | | | | | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | (FONTH / 4 * 5) * (nd - j - 1) + FONTH / 3, 2); } // keymap is defined externally in keymap.cfg static OFMutableArray<KeyMapping *> *keyMappings = nil; COMMAND(keymap, ARG_3STR, ^ (OFString *code, OFString *key, OFString *action) { if (keyMappings == nil) keyMappings = [[OFMutableArray alloc] init]; KeyMapping *mapping = [KeyMapping mappingWithCode: code.cube_intValue name: key]; mapping.action = action; [keyMappings addObject: mapping]; }) COMMAND(bind, ARG_2STR, ^ (OFString *key, OFString *action) { for (KeyMapping *mapping in keyMappings) { if ([mapping.name caseInsensitiveCompare: key] == OFOrderedSame) { mapping.action = action; return; } } conoutf(@"unknown key \"%@\"", key); |
︙ | ︙ | |||
139 140 141 142 143 144 145 | if (init == nil) init = @""; commandbuf = [init mutableCopy]; } | | | | | | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | if (init == nil) init = @""; commandbuf = [init mutableCopy]; } 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); }) void pasteconsole() { [commandbuf appendString: @(SDL_GetClipboardText())]; } static OFMutableArray<OFString *> *vhistory; static int histpos = 0; COMMAND(history, ARG_1INT, ^ (int n) { static bool rec = false; if (!rec && n >= 0 && n < vhistory.count) { rec = true; execute(vhistory[vhistory.count - n - 1], true); rec = false; } |
︙ | ︙ | |||
222 223 224 225 226 227 228 | if (commandbuf.length > 0) { if (vhistory == nil) vhistory = [[OFMutableArray alloc] init]; if (vhistory.count == 0 || | | | | | | | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | if (commandbuf.length > 0) { if (vhistory == nil) vhistory = [[OFMutableArray alloc] init]; if (vhistory.count == 0 || ![vhistory.lastObject isEqual: commandbuf]) { // cap this? [vhistory addObject: [commandbuf copy]]; } histpos = vhistory.count; if ([commandbuf hasPrefix: @"/"]) execute(commandbuf, true); else toserver(commandbuf); } saycommand(NULL); } else if (code == SDLK_ESCAPE) { saycommand(NULL); |
︙ | ︙ | |||
257 258 259 260 261 262 263 | } } void input(OFString *text) { if (saycommandon) | | | | | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | } } void input(OFString *text) { if (saycommandon) [commandbuf appendString: text]; } OFString * getcurcommand() { return saycommandon ? commandbuf : NULL; } void writebinds(OFStream *stream) { for (KeyMapping *mapping in keyMappings) if (mapping.action.length > 0) [stream writeFormat: @"bind \"%@\" [%@]\n", mapping.name, mapping.action]; } |
Modified src/cube.h from [8e48390c7e] to [e6d07ee71e].
︙ | ︙ | |||
306 307 308 309 310 311 312 | #define m_noitemsrail (gamemode <= 5) #define m_arena (gamemode >= 8) #define m_tarena (gamemode >= 10) #define m_teammode (gamemode & 1 && gamemode > 2) #define m_sp (gamemode < 0) #define m_dmsp (gamemode == -1) #define m_classicsp (gamemode == -2) | | | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | #define m_noitemsrail (gamemode <= 5) #define m_arena (gamemode >= 8) #define m_tarena (gamemode >= 10) #define m_teammode (gamemode & 1 && gamemode > 2) #define m_sp (gamemode < 0) #define m_dmsp (gamemode == -1) #define m_classicsp (gamemode == -2) #define isteam(a, b) (m_teammode && [a isEqual: b]) // function signatures for script functions, see command.mm enum { ARG_1INT, ARG_2INT, ARG_3INT, ARG_4INT, |
︙ | ︙ |
Modified src/editing.m from [bc0b6a3e18] to [1510ae8332].
︙ | ︙ | |||
16 17 18 19 20 21 22 | // invariant: all code assumes that these are kept inside MINBORD distance of // the edge of the map struct block sel = { 0, 0, 0, 0 }; OF_CONSTRUCTOR() { | | | | | | | | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | // invariant: all code assumes that these are kept inside MINBORD distance of // the edge of the map struct block sel = { 0, 0, 0, 0 }; OF_CONSTRUCTOR() { enqueueInit(^ { static const struct { OFString *name; int *storage; } vars[4] = { { @"selx", &sel.x }, { @"sely", &sel.y }, { @"selxs", &sel.xs }, { @"selys", &sel.ys } }; for (size_t i = 0; i < 4; i++) { Variable *variable = [Variable variableWithName: vars[i].name min: 0 max: 4096 storage: vars[i].storage function: NULL persisted: false]; Identifier.identifiers[vars[i].name] = variable; } }); } int selh = 0; bool selset = false; |
︙ | ︙ | |||
89 90 91 92 93 94 95 | projreset(); } Cube.sharedInstance.repeatsKeys = editmode; selset = false; editing = editmode; } | | | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | projreset(); } Cube.sharedInstance.repeatsKeys = editmode; selset = false; editing = editmode; } COMMAND(edittoggle, ARG_NONE, ^ { toggleedit(); }) void correctsel() // ensures above invariant { selset = !OUTBORD(sel.x, sel.y); |
︙ | ︙ | |||
133 134 135 136 137 138 139 | #define EDITSELMP \ if (noteditmode() || noselection() || multiplayer()) \ return; #define EDITMP \ if (noteditmode() || multiplayer()) \ return; | | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | #define EDITSELMP \ if (noteditmode() || noselection() || multiplayer()) \ return; #define EDITMP \ if (noteditmode() || multiplayer()) \ return; 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 |
︙ | ︙ | |||
217 218 219 220 221 222 223 | if (SOLID(s)) continue; float h1 = sheight(s, s, z); float h2 = sheight(s, SWS(s, 1, 0, ssize), z); float h3 = sheight(s, SWS(s, 1, 1, ssize), z); float h4 = sheight(s, SWS(s, 0, 1, ssize), z); if (s->tag) | | | | | | | | | | | | | | 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | if (SOLID(s)) continue; float h1 = sheight(s, s, z); float h2 = sheight(s, SWS(s, 1, 0, ssize), z); float h3 = sheight(s, SWS(s, 1, 1, ssize), z); float h4 = sheight(s, SWS(s, 0, 1, ssize), z); if (s->tag) linestyle(GRIDW, [OFColor colorWithRed: 1.0f green: 0.25f blue: 0.25f alpha: 1.0f]); else if (s->type == FHF || s->type == CHF) linestyle(GRIDW, [OFColor colorWithRed: 0.5f green: 1.0f blue: 0.5f alpha: 1.0f]); else linestyle(GRIDW, OFColor.gray); struct block b = { ix, iy, 1, 1 }; box(&b, h1, h2, h3, h4); linestyle(GRID8, [OFColor colorWithRed: 0.25f green: 0.25f blue: 1.0f alpha: 1.0f]); if (!(ix & GRIDM)) line(ix, iy, h1, ix, iy + 1, h4); if (!(ix + 1 & GRIDM)) line(ix + 1, iy, h2, ix + 1, iy + 1, h3); if (!(iy & GRIDM)) line(ix, iy, h1, ix + 1, iy, h2); if (!(iy + 1 & GRIDM)) |
︙ | ︙ | |||
258 259 260 261 262 263 264 | sheight(s, SWS(s, 0, 1, ssize), z)); linestyle(GRIDS, OFColor.red); dot(cx, cy, ih); ch = (int)ih; } if (selset) { | | | | | | | | | | | | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | sheight(s, SWS(s, 0, 1, ssize), z)); linestyle(GRIDS, OFColor.red); dot(cx, cy, ih); ch = (int)ih; } if (selset) { linestyle(GRIDS, [OFColor colorWithRed: 1.0f green: 0.25f blue: 0.25f alpha: 1.0f]); box(&sel, (float)selh, (float)selh, (float)selh, (float)selh); } } static OFMutableData *undos; // unlimited undo VARP(undomegs, 0, 1, 10); // bounded by n megs void pruneundos(int maxremain) // bound memory { int t = 0; for (ssize_t i = (ssize_t)undos.count - 1; i >= 0; i--) { struct block *undo = [undos mutableItemAtIndex: i]; t += undo->xs * undo->ys * sizeof(struct sqr); if (t > maxremain) { OFFreeMemory(undo); [undos removeItemAtIndex: i]; } } } void makeundo() { if (undos == nil) undos = [[OFMutableData alloc] initWithItemSize: sizeof(struct block *)]; struct block *copy = blockcopy(&sel); [undos addItem: ©]; pruneundos(undomegs << 20); } COMMAND(undo, ARG_NONE, ^ { EDITMP; if (undos.count == 0) { conoutf(@"nothing more to undo"); return; } struct block *p = undos.mutableLastItem; [undos removeLastItem]; blockpaste(p); OFFreeMemory(p); }) static struct block *copybuf = NULL; COMMAND(copy, ARG_NONE, ^ { EDITSELMP; if (copybuf) OFFreeMemory(copybuf); copybuf = blockcopy(&sel); }) COMMAND(paste, ARG_NONE, ^ { EDITMP; if (!copybuf) { conoutf(@"nothing to paste"); return; } sel.xs = copybuf->xs; sel.ys = copybuf->ys; |
︙ | ︙ | |||
397 398 399 400 401 402 403 | EDITSEL; bool isfloor = flr == 0; editheightxy(isfloor, amount, &sel); addmsg(1, 7, SV_EDITH, sel.x, sel.y, sel.xs, sel.ys, isfloor, amount); } | | | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 | EDITSEL; bool isfloor = flr == 0; editheightxy(isfloor, amount, &sel); addmsg(1, 7, SV_EDITH, sel.x, sel.y, sel.xs, sel.ys, isfloor, amount); } COMMAND(editheight, ARG_2INT, ^ (int flr, int amount) { editheight(flr, amount); }) void edittexxy(int type, int t, const struct block *sel) { loopselxy(switch (type) { |
︙ | ︙ | |||
420 421 422 423 424 425 426 | break; case 3: s->utex = t; break; }); } | | | | 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | break; case 3: s->utex = t; break; }); } COMMAND(edittex, ARG_2INT, ^ (int type, int dir) { EDITSEL; if (type < 0 || type > 3) return; if (type != lasttype) { tofronttex(); lasttype = type; } int atype = type == 3 ? 1 : type; int i = curedittex[atype]; i = i < 0 ? 0 : i + dir; curedittex[atype] = i = min(max(i, 0), 255); 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); }) COMMAND(replace, ARG_NONE, (^ { EDITSELMP; for (int x = 0; x < ssize; x++) { for (int y = 0; y < ssize; y++) { struct sqr *s = S(x, y); switch (lasttype) { case 0: |
︙ | ︙ | |||
493 494 495 496 497 498 499 | return; } edittypexy(type, &sel); addmsg(1, 6, SV_EDITS, sel.x, sel.y, sel.xs, sel.ys, type); } | | | | | 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 | return; } edittypexy(type, &sel); addmsg(1, 6, SV_EDITS, sel.x, sel.y, sel.xs, sel.ys, type); } COMMAND(heightfield, ARG_1INT, ^ (int t) { edittype(t == 0 ? FHF : CHF); }) COMMAND(solid, ARG_1INT, ^ (int t) { edittype(t == 0 ? SPACE : SOLID); }) COMMAND(corner, ARG_NONE, ^ { edittype(CORNER); }) void editequalisexy(bool isfloor, const struct block *sel) { int low = 127, hi = -128; |
︙ | ︙ | |||
525 526 527 528 529 530 531 | else s->ceil = hi; if (s->floor >= s->ceil) s->floor = s->ceil - 1; }); } | | | | | | 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 | else s->ceil = hi; if (s->floor >= s->ceil) s->floor = s->ceil - 1; }); } 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); }) void setvdeltaxy(int delta, const struct block *sel) { loopselxy(s->vdelta = max(s->vdelta + delta, 0)); remipmore(sel, 0); } 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; COMMAND(archvertex, ARG_3INT, ^ (int span, int vert, int delta) { if (!archvinit) { archvinit = true; for (int s = 0; s < MAXARCHVERT; s++) for (int v = 0; v < MAXARCHVERT; v++) archverts[s][v] = 0; } if (span >= MAXARCHVERT || vert >= MAXARCHVERT || span < 0 || vert < 0) return; archverts[span][vert] = delta; }) COMMAND(arch, ARG_2INT, ^ (int sidedelta, int _a) { EDITSELMP; sel.xs++; sel.ys++; if (sel.xs > MAXARCHVERT) sel.xs = MAXARCHVERT; |
︙ | ︙ | |||
586 587 588 589 590 591 592 | ? (archverts[sel->xs - 1][x] + (y == 0 || y == sel->ys - 1 ? sidedelta : 0)) : (archverts[sel->ys - 1][y] + (x == 0 || x == sel->xs - 1 ? sidedelta : 0))); remipmore(sel, 0); }) | | | | 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 | ? (archverts[sel->xs - 1][x] + (y == 0 || y == sel->ys - 1 ? sidedelta : 0)) : (archverts[sel->ys - 1][y] + (x == 0 || x == sel->xs - 1 ? sidedelta : 0))); remipmore(sel, 0); }) COMMAND(slope, ARG_2INT, ^ (int xd, int yd) { EDITSELMP; int off = 0; if (xd < 0) off -= xd * sel.xs; if (yd < 0) off -= yd * sel.ys; sel.xs++; sel.ys++; struct block *sel_ = &sel; // Ugly hack to make the macro work. struct block *sel = sel_; loopselxy(s->vdelta = xd * x + yd * y + off); remipmore(sel, 0); }) COMMAND(perlin, ARG_3INT, ^ (int scale, int seed, int psize) { EDITSELMP; sel.xs++; sel.ys++; makeundo(); |
︙ | ︙ | |||
635 636 637 638 639 640 641 | fullbright, 0, 0, 1, if (fullbright) { if (noteditmode()) return; for (int i = 0; i < mipsize; i++) world[i].r = world[i].g = world[i].b = 176; }); | | | | | | | | | 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 | fullbright, 0, 0, 1, if (fullbright) { if (noteditmode()) return; for (int i = 0; i < mipsize; i++) world[i].r = world[i].g = world[i].b = 176; }); 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); }) COMMAND(newent, ARG_5STR, ^ (OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4) { EDITSEL; newentity(sel.x, sel.y, (int)Player.player1.origin.z, what, [a1 cube_intValueWithBase: 0], [a2 cube_intValueWithBase: 0], [a3 cube_intValueWithBase: 0], [a4 cube_intValueWithBase: 0]); }) |
Modified src/entities.m from [e376d54115] to [945da2b6da].
︙ | ︙ | |||
309 310 311 312 313 314 315 | checkitems() { Player *player1 = Player.player1; if (editmode) return; | | | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | checkitems() { Player *player1 = Player.player1; if (editmode) return; [ents enumerateObjectsUsingBlock: ^ (Entity *e, size_t i, bool *stop) { if (e.type == NOTUSED) return; if (!e.spawned && e.type != TELEPORT && e.type != JUMPPAD) return; if (OUTBORD(e.x, e.y)) |
︙ | ︙ | |||
344 345 346 347 348 349 350 | } } // puts items in network stream and also spawns them locally void putitems(unsigned char **p) { | | | 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 | } } // puts items in network stream and also spawns them locally void putitems(unsigned char **p) { [ents enumerateObjectsUsingBlock: ^ (Entity *e, size_t i, bool *stop) { if ((e.type >= I_SHELLS && e.type <= I_QUAD) || e.type == CARROT) { putint(p, i); e.spawned = true; } }]; } |
︙ | ︙ |
Modified src/menus.m from [c38d6c5a56] to [abea91099d].
︙ | ︙ | |||
17 18 19 20 21 22 23 | { if ((vmenu = menu) >= 1) [Player.player1 resetMovement]; if (vmenu == 1) menus[1].menusel = 0; } | | | | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | { if ((vmenu = menu) >= 1) [Player.player1 resetMovement]; if (vmenu == 1) menus[1].menusel = 0; } COMMAND(showmenu, ARG_1STR, ^ (OFString *name) { int i = 0; for (Menu *menu in menus) { if (i > 1 && [menu.name isEqual: name]) { menuset(i); return; } i++; } }) |
︙ | ︙ | |||
50 51 52 53 54 55 56 | if (vmenu == 1) refreshservers(); Menu *m = menus[vmenu]; OFString *title; if (vmenu > 1) | | | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | if (vmenu == 1) refreshservers(); Menu *m = menus[vmenu]; OFString *title; if (vmenu > 1) title = [OFString stringWithFormat: @"[ %@ menu ]", m.name]; else title = m.name; int mdisp = m.items.count; int w = 0; for (int i = 0; i < mdisp; i++) { int x = text_width(m.items[i].text); if (x > w) |
︙ | ︙ | |||
89 90 91 92 93 94 95 | void newmenu(OFString *name) { if (menus == nil) menus = [[OFMutableArray alloc] init]; | | | | | | | | | | | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | void newmenu(OFString *name) { if (menus == nil) menus = [[OFMutableArray alloc] init]; [menus addObject: [Menu menuWithName: name]]; } COMMAND(newmenu, ARG_1STR, ^ (OFString *name) { newmenu(name); }) void menumanual(int m, int n, OFString *text) { if (n == 0) [menus[m].items removeAllObjects]; MenuItem *item = [MenuItem itemWithText: text action: @""]; [menus[m].items addObject: item]; } 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]; }) bool menukey(int code, bool isdown) { if (vmenu <= 0) return false; |
︙ | ︙ | |||
151 152 153 154 155 156 157 | OFString *action = menus[vmenu].items[menusel].action; if (vmenu == 1) connects(getservername(menusel)); if (menuStack == nil) menuStack = [[OFMutableArray alloc] init]; | | | 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | OFString *action = menus[vmenu].items[menusel].action; if (vmenu == 1) connects(getservername(menusel)); if (menuStack == nil) menuStack = [[OFMutableArray alloc] init]; [menuStack addObject: @(vmenu)]; menuset(-1); execute(action, true); } } return true; } |
Modified src/physics.m from [8500b9ce45] to [95d4c13f64].
︙ | ︙ | |||
28 29 30 31 32 33 34 | if (o.origin.z - o.eyeHeight < *hi) *hi = o.origin.z - o.eyeHeight - 1; } else if (o.origin.z + o.aboveEye > *lo) *lo = o.origin.z + o.aboveEye + 1; if (fabs(o.origin.z - d.origin.z) < o.aboveEye + d.eyeHeight) return false; | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | if (o.origin.z - o.eyeHeight < *hi) *hi = o.origin.z - o.eyeHeight - 1; } else if (o.origin.z + o.aboveEye > *lo) *lo = o.origin.z + o.aboveEye + 1; if (fabs(o.origin.z - d.origin.z) < o.aboveEye + d.eyeHeight) return false; if ([d isKindOfClass: Monster.class]) return false; // hack *headspace = d.origin.z - o.origin.z - o.aboveEye - d.eyeHeight; if (*headspace < 0) *headspace = 10; } |
︙ | ︙ | |||
104 105 106 107 108 109 110 | const float fy2 = d.origin.y + d.radius; const int x1 = fx1; const int y1 = fy1; const int x2 = fx2; const int y2 = fy2; float hi = 127, lo = -128; // big monsters are afraid of heights, unless angry :) | | < | < | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | const float fy2 = d.origin.y + d.radius; const int x1 = fx1; const int y1 = fy1; const int x2 = fx2; const int y2 = fy2; float hi = 127, lo = -128; // big monsters are afraid of heights, unless angry :) float minfloor = ([d isKindOfClass: Monster.class] && !spawn && d.health > 100 ? d.origin.z - d.eyeHeight - 4.5f : -1000.0f); for (int x = x1; x <= x2; x++) { for (int y = y1; y <= y2; y++) { // collide with map if (OUTBORD(x, y)) return false; struct sqr *s = S(x, y); |
︙ | ︙ | |||
324 325 326 327 328 329 330 | // correct water feel if (water) pl.velocity = OFMakeVector3D( pl.velocity.x / 8, pl.velocity.y / 8, pl.velocity.z); if (local) playsoundc(S_JUMP); | | | | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 | // correct water feel if (water) pl.velocity = OFMakeVector3D( pl.velocity.x / 8, pl.velocity.y / 8, pl.velocity.z); if (local) playsoundc(S_JUMP); else if ([pl isKindOfClass: Monster.class]) { OFVector3D loc = pl.origin; playsound(S_JUMP, &loc); } } else if (pl.timeInAir > 800) { // if we land after long time must have been a // high jump, make thud sound if (local) playsoundc(S_LAND); else if ([pl isKindOfClass: Monster.class]) { OFVector3D loc = pl.origin; playsound(S_LAND, &loc); } } pl.timeInAir = 0; } else |
︙ | ︙ |
Modified src/rendercubes.m from [4e2c5682e1] to [d20e5d1984].
︙ | ︙ | |||
60 61 62 63 64 65 66 | const float TEXTURESCALE = 32.0f; bool floorstrip = false, deltastrip = false; int oh, oy, ox, ogltex; // the o* vars are used by the stripification int ol3r, ol3g, ol3b, ol4r, ol4g, ol4b; int firstindex; bool showm = false; | | | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | const float TEXTURESCALE = 32.0f; bool floorstrip = false, deltastrip = false; int oh, oy, ox, ogltex; // the o* vars are used by the stripification int ol3r, ol3g, ol3b, ol4r, ol4g, ol4b; int firstindex; bool showm = false; COMMAND(showmip, ARG_NONE, ^ { showm = !showm; }) void mipstats(int a, int b, int c) { if (showm) |
︙ | ︙ |
Modified src/renderextras.m from [efc1c2688d] to [f1478ac26e].
︙ | ︙ | |||
56 57 58 59 60 61 62 | blendbox(int x1, int y1, int x2, int y2, bool border) { glDepthMask(GL_FALSE); glDisable(GL_TEXTURE_2D); glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); glBegin(GL_QUADS); if (border) | | | | | | | | | | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | blendbox(int x1, int y1, int x2, int y2, bool border) { glDepthMask(GL_FALSE); glDisable(GL_TEXTURE_2D); glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); glBegin(GL_QUADS); if (border) [[OFColor colorWithRed: 0.5f green: 0.3f blue: 0.4f alpha: 1.0f] cube_setAsGLColor]; else [OFColor.white cube_setAsGLColor]; glVertex2i(x1, y1); glVertex2i(x2, y1); glVertex2i(x2, y2); glVertex2i(x1, y2); glEnd(); glDisable(GL_BLEND); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glBegin(GL_POLYGON); [[OFColor colorWithRed: 0.2f green: 0.7f blue: 0.4f alpha: 1.0f] cube_setAsGLColor]; glVertex2i(x1, y1); glVertex2i(x2, y1); glVertex2i(x2, y2); glVertex2i(x1, y2); glEnd(); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); xtraverts += 8; |
︙ | ︙ | |||
129 130 131 132 133 134 135 | glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBindTexture(GL_TEXTURE_2D, 4); for (struct sphere *p, **pp = &slist; (p = *pp) != NULL;) { glPushMatrix(); float size = p->size / p->max; | | | | | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBindTexture(GL_TEXTURE_2D, 4); for (struct sphere *p, **pp = &slist; (p = *pp) != NULL;) { glPushMatrix(); float size = p->size / p->max; [[OFColor colorWithRed: 1.0f green: 1.0f blue: 1.0f alpha: 1.0f - size] cube_setAsGLColor]; glTranslatef(p->o.x, p->o.z, p->o.y); glRotatef(lastmillis / 5.0f, 1, 1, 1); glScalef(p->size, p->size, p->size); glCallList(1); glScalef(0.8f, 0.8f, 0.8f); glCallList(1); glPopMatrix(); |
︙ | ︙ | |||
203 204 205 206 207 208 209 | particle_splash(2, 2, 40, OFMakeVector3D(e.x, e.y, e.z)); } int e = closestent(); if (e >= 0) { Entity *c = ents[e]; closeent = | | > | | | | | | | | < | < | 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | particle_splash(2, 2, 40, OFMakeVector3D(e.x, e.y, e.z)); } int e = closestent(); if (e >= 0) { Entity *c = ents[e]; closeent = [OFString stringWithFormat: @"closest entity = %@ (%d, %d, %d, %d), " @"selection = (%d, %d)", entnames[c.type], c.attr1, c.attr2, c.attr3, c.attr4, getvar(@"selxs"), getvar(@"selys")]; } } COMMAND(loadsky, ARG_1STR, (^ (OFString *basename) { static OFString *lastsky = @""; basename = [basename stringByReplacingOccurrencesOfString: @"\\" withString: @"/"]; if ([lastsky isEqual: basename]) return; static const OFString *side[] = { @"ft", @"bk", @"lf", @"rt", @"dn", @"up" }; int texnum = 14; for (int i = 0; i < 6; i++) { OFString *path = [OFString stringWithFormat: @"packages/%@_%@.jpg", basename, side[i]]; int xs, ys; if (!installtex(texnum + i, [Cube.sharedInstance.gameDataIRI IRIByAppendingPathComponent: path], &xs, &ys, true)) conoutf(@"could not load sky textures"); } lastsky = basename; })) float cursordepth = 0.9f; |
︙ | ︙ | |||
357 358 359 360 361 362 363 | glDepthMask(GL_FALSE); if (dblend || underwater) { glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); glBegin(GL_QUADS); if (dblend) | | | | | | | | | | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | glDepthMask(GL_FALSE); if (dblend || underwater) { glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); glBegin(GL_QUADS); if (dblend) [[OFColor colorWithRed: 0.0f green: 0.9f blue: 0.9f alpha: 1.0f] cube_setAsGLColor]; else [[OFColor colorWithRed: 0.9f green: 0.5f blue: 0.0f alpha: 1.0f] cube_setAsGLColor]; glVertex2i(0, 0); glVertex2i(VIRTW, 0); glVertex2i(VIRTW, VIRTH); glVertex2i(0, VIRTH); glEnd(); dblend -= curtime / 3; if (dblend < 0) |
︙ | ︙ | |||
400 401 402 403 404 405 406 | [OFColor.white cube_setAsGLColor]; if (crosshairfx) { if (player1.gunWait) [OFColor.gray cube_setAsGLColor]; else if (player1.health <= 25) [OFColor.red cube_setAsGLColor]; else if (player1.health <= 50) | | | | > | | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 | [OFColor.white cube_setAsGLColor]; if (crosshairfx) { if (player1.gunWait) [OFColor.gray cube_setAsGLColor]; else if (player1.health <= 25) [OFColor.red cube_setAsGLColor]; else if (player1.health <= 50) [[OFColor colorWithRed: 1.0f green: 0.5f blue: 0.0f alpha: 1.0f] cube_setAsGLColor]; } float chsize = (float)crosshairsize; glTexCoord2d(0.0, 0.0); glVertex2f(VIRTW / 2 - chsize, VIRTH / 2 - chsize); glTexCoord2d(1.0, 0.0); glVertex2f(VIRTW / 2 + chsize, VIRTH / 2 - chsize); glTexCoord2d(1.0, 1.0); |
︙ | ︙ |
Modified src/rendergl.m from [a52bf36780] to [8875dffa42].
︙ | ︙ | |||
186 187 188 189 190 191 192 | for (int i = 0; i < 256; i++) for (int j = 0; j < MAXFRAMES; j++) mapping[i][j] = 0; } int curtexnum = 0; | | | | | | | | | < | < | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 | for (int i = 0; i < 256; i++) for (int j = 0; j < MAXFRAMES; j++) mapping[i][j] = 0; } int curtexnum = 0; COMMAND(texturereset, ARG_NONE, ^ { curtexnum = 0; }) COMMAND(texture, ARG_2STR, (^ (OFString *aframe, OFString *name) { int num = curtexnum++, frame = aframe.cube_intValue; if (num < 0 || num >= 256 || frame < 0 || frame >= MAXFRAMES) return; mapping[num][frame] = 1; mapname[num][frame] = [name stringByReplacingOccurrencesOfString: @"\\" withString: @"/"]; })) int lookuptexture(int tex, int *xs, int *ys) { int frame = 0; // other frames? int tid = mapping[tex][frame]; if (tid >= FIRSTTEX) { *xs = texx[tid - FIRSTTEX]; *ys = texy[tid - FIRSTTEX]; return tid; } *xs = *ys = 16; if (tid == 0) return 1; // crosshair :) // lazily happens once per "texture" command, basically for (int i = 0; i < curtex; i++) { if ([mapname[tex][frame] isEqual: texname[i]]) { mapping[tex][frame] = tid = i + FIRSTTEX; *xs = texx[i]; *ys = texy[i]; return tid; } } if (curtex == MAXTEX) fatal(@"loaded too many textures"); int tnum = curtex + FIRSTTEX; texname[curtex] = mapname[tex][frame]; OFString *path = [OFString stringWithFormat: @"packages/%@", texname[curtex]]; if (installtex(tnum, [Cube.sharedInstance.gameDataIRI IRIByAppendingPathComponent: path], xs, ys, false)) { mapping[tex][frame] = tnum; texx[curtex] = *xs; texy[curtex] = *ys; curtex++; return tnum; } else { return mapping[tex][frame] = FIRSTTEX; // temp fix |
︙ | ︙ | |||
318 319 320 321 322 323 324 | } void addstrip(int tex, int start, int n) { if (strips == nil) strips = [[OFMutableData alloc] | | | | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 | } void addstrip(int tex, int start, int n) { if (strips == nil) strips = [[OFMutableData alloc] initWithItemSize: sizeof(struct strip)]; struct strip s = { .tex = tex, .start = start, .num = n }; [strips addItem: &s]; } #undef gamma VARFP(gamma, 30, 100, 300, { float f = gamma / 100.0f; Uint16 ramp[256]; |
︙ | ︙ |
Modified src/rendermd2.m from [c6c4c06ab4] to [923fa1d88f].
︙ | ︙ | |||
13 14 15 16 17 18 19 | static const int FIRSTMDL = 20; void delayedload(MD2 *m) { if (!m.loaded) { | | | | | > | | > | | < | < | | | | | | | | | | | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | static const int FIRSTMDL = 20; void delayedload(MD2 *m) { if (!m.loaded) { OFString *path = [OFString stringWithFormat: @"packages/models/%@", m.loadname]; OFIRI *baseIRI = [Cube.sharedInstance.gameDataIRI IRIByAppendingPathComponent: path]; OFIRI *IRI1 = [baseIRI IRIByAppendingPathComponent: @"tris.md2"]; if (![m loadWithIRI: IRI1]) fatal(@"loadmodel: %@", IRI1.string); OFIRI *IRI2 = [baseIRI IRIByAppendingPathComponent: @"skin.jpg"]; int xs, ys; installtex(FIRSTMDL + m.mdlnum, IRI2, &xs, &ys, false); m.loaded = true; } } MD2 * loadmodel(OFString *name) { static int modelnum = 0; MD2 *m = mdllookup[name]; if (m != nil) return m; m = [MD2 md2]; m.mdlnum = modelnum++; m.mmi = [MapModelInfo infoWithRad: 2 h: 2 zoff: 0 snap: 0 name: @""]; m.loadname = name; if (mdllookup == nil) mdllookup = [[OFMutableDictionary alloc] init]; mdllookup[name] = m; return m; } 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]; [mapmodels addObject: m]; }) COMMAND(mapmodelreset, ARG_NONE, ^ { [mapmodels removeAllObjects]; }) MapModelInfo * getmminfo(int i) { return i < mapmodels.count ? mapmodels[i].mmi : nil; |
︙ | ︙ | |||
98 99 100 101 102 103 104 | int xs, ys; glBindTexture(GL_TEXTURE_2D, tex ? lookuptexture(tex, &xs, &ys) : FIRSTMDL + m.mdlnum); int ix = (int)position.x; int iy = (int)position.z; | | | | | | | | | | | | | | | | | | | | | | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | int xs, ys; glBindTexture(GL_TEXTURE_2D, tex ? lookuptexture(tex, &xs, &ys) : FIRSTMDL + m.mdlnum); int ix = (int)position.x; int iy = (int)position.z; OFColor *light = OFColor.white; if (!OUTBORD(ix, iy)) { struct sqr *s = S(ix, iy); float ll = 256.0f; // 0.96f; float of = 0.0f; // 0.1f; light = [OFColor colorWithRed: s->r / ll + of green: s->g / ll + of blue: s->b / ll + of alpha: 1]; } if (teammate) { float red, green, blue; [light getRed: &red green: &green blue: &blue alpha: NULL]; light = [OFColor colorWithRed: red * 0.6f green: green * 0.7f blue: blue * 1.2f alpha: 1]; } [m renderWithLight: light frame: frame range: range position: position yaw: yaw pitch: pitch scale: scale speed: speed snap: snap basetime: basetime]; } |
Modified src/rendertext.m from [da461b7a90] to [656fe9791c].
︙ | ︙ | |||
135 136 137 138 139 140 141 | } void draw_textf(OFConstantString *format, int left, int top, int gl_num, ...) { va_list arguments; va_start(arguments, gl_num); | | | | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | } void draw_textf(OFConstantString *format, int left, int top, int gl_num, ...) { va_list arguments; va_start(arguments, gl_num); OFString *str = [[OFString alloc] initWithFormat: format arguments: arguments]; va_end(arguments); draw_text(str, left, top, gl_num); } void draw_text(OFString *string, int left, int top, int gl_num) { |
︙ | ︙ | |||
166 167 168 169 170 171 172 | if (c == '\t') { x = (x - left + PIXELTAB) / PIXELTAB * PIXELTAB + left; continue; } if (c == '\f') { | | | | | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | if (c == '\t') { x = (x - left + PIXELTAB) / PIXELTAB * PIXELTAB + left; continue; } if (c == '\f') { [[OFColor colorWithRed: 0.25f green: 1.0f blue: 0.5f alpha: 1.0f] cube_setAsGLColor]; continue; } if (c == ' ') { x += FONTH / 2; continue; } |
︙ | ︙ |
Modified src/savegamedemo.m from [fe0624b79b] to [94bda1495e].
︙ | ︙ | |||
93 94 95 96 97 98 99 | } void savestate(OFIRI *IRI) { stop(); f = gzopen([IRI.fileSystemRepresentation | | < | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | } void savestate(OFIRI *IRI) { stop(); f = gzopen([IRI.fileSystemRepresentation cStringWithEncoding: OFLocale.encoding], "wb9"); if (!f) { conoutf(@"could not write %@", IRI.string); return; } gzwrite(f, (void *)"CUBESAVE", 8); gzputc(f, islittleendian); gzputi(SAVEGAMEVERSION); |
︙ | ︙ | |||
127 128 129 130 131 132 133 | for (id player in players) { gzput(player == [OFNull null]); data = [player dataBySerializing]; gzwrite(f, data.items, data.count); } } | | | > | | | < | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | for (id player in players) { gzput(player == [OFNull null]); data = [player dataBySerializing]; gzwrite(f, data.items, data.count); } } COMMAND(savegame, ARG_1STR, (^ (OFString *name) { if (!m_classicsp) { conoutf(@"can only save classic sp games"); return; } OFString *path = [OFString stringWithFormat: @"savegames/%@.csgz", name]; OFIRI *IRI = [Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent: path]; savestate(IRI); stop(); conoutf(@"wrote %@", IRI.string); })) void loadstate(OFIRI *IRI) { stop(); if (multiplayer()) return; f = gzopen([IRI.fileSystemRepresentation cStringWithEncoding: OFLocale.encoding], "rb9"); if (!f) { conoutf(@"could not open %@", IRI.string); return; } char mapname[_MAXDEFSTR] = { 0 }; char buf[8]; |
︙ | ︙ | |||
179 180 181 182 183 184 185 | return; out: conoutf(@"aborting: savegame/demo from a different version of " @"cube or cpu architecture"); stop(); } | | | > | | | 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 | return; out: conoutf(@"aborting: savegame/demo from a different version of " @"cube or cpu architecture"); stop(); } COMMAND(loadgame, ARG_1STR, (^ (OFString *name) { OFString *path = [OFString stringWithFormat: @"savegames/%@.csgz", name]; OFIRI *IRI = [Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent: path]; loadstate(IRI); })) void loadgameout() { stop(); |
︙ | ︙ | |||
213 214 215 216 217 218 219 | if (e.type == CARROT && !e.spawned) trigger(e.attr1, e.attr2, true); } restoreserverstate(ents); OFMutableData *data = | | | | | | | | | | | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | if (e.type == CARROT && !e.spawned) trigger(e.attr1, e.attr2, true); } restoreserverstate(ents); OFMutableData *data = [OFMutableData dataWithCapacity: DynamicEntity.serializedSize]; [data increaseCountBy: DynamicEntity.serializedSize]; gzread(f, data.mutableItems, data.count); [Player.player1 setFromSerializedData: data]; Player.player1.lastAction = lastmillis; int nmonsters = gzgeti(); OFArray<Monster *> *monsters = Monster.monsters; if (nmonsters != monsters.count) return loadgameout(); for (Monster *monster in monsters) { gzread(f, data.mutableItems, data.count); [monster setFromSerializedData: data]; // lazy, could save id of enemy instead monster.enemy = Player.player1; // also lazy, but no real noticable effect on game monster.lastAction = monster.trigger = lastmillis + 500; if (monster.state == CS_DEAD) monster.lastAction = 0; } [Monster restoreAll]; int nplayers = gzgeti(); for (int i = 0; i < nplayers; i++) { if (!gzget()) { Player *d = getclient(i); assert(d); gzread(f, data.mutableItems, data.count); [d setFromSerializedData: data]; } } conoutf(@"savegame restored"); if (demoloading) startdemo(); else stop(); } // demo functions int starttime = 0; int playbacktime = 0; int ddamage, bdamage; OFVector3D dorig; COMMAND(record, ARG_1STR, (^ (OFString *name) { if (m_sp) { conoutf(@"cannot record singleplayer games"); return; } int cn = getclientnum(); if (cn < 0) return; OFString *path = [OFString stringWithFormat: @"demos/%@.cdgz", name]; OFIRI *IRI = [Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent: path]; savestate(IRI); gzputi(cn); conoutf(@"started recording demo to %@", IRI.string); demorecording = true; starttime = lastmillis; ddamage = bdamage = 0; })) |
︙ | ︙ | |||
329 330 331 332 333 334 335 | ddamage = 0; } // FIXME: add all other client state which is not send through // the network } } | | | | | | 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | ddamage = 0; } // FIXME: add all other client state which is not send through // the network } } COMMAND(demo, ARG_1STR, (^ (OFString *name) { OFString *path = [OFString stringWithFormat: @"demos/%@.cdgz", name]; OFIRI *IRI = [Cube.sharedInstance.userDataIRI IRIByAppendingPathComponent: path]; loadstate(IRI); demoloading = true; })) void stopreset() { |
︙ | ︙ | |||
458 459 460 461 462 463 464 | playerhistory.lastObject.lastUpdate != playbacktime)) { Player *d = [target copy]; d.lastUpdate = playbacktime; if (playerhistory == nil) playerhistory = [[OFMutableArray alloc] init]; | | | | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 | playerhistory.lastObject.lastUpdate != playbacktime)) { Player *d = [target copy]; d.lastUpdate = playbacktime; if (playerhistory == nil) playerhistory = [[OFMutableArray alloc] init]; [playerhistory addObject: d]; if (playerhistory.count > 20) [playerhistory removeObjectAtIndex: 0]; } readdemotime(); } if (!demoplayback) return; |
︙ | ︙ | |||
538 539 540 541 542 543 544 | } break; } } // if(player1->state!=CS_DEAD) showscores(false); } | | | 538 539 540 541 542 543 544 545 546 547 548 549 550 551 | } break; } } // if(player1->state!=CS_DEAD) showscores(false); } COMMAND(stop, ARG_NONE, ^ { if (demoplayback) stopreset(); else stop(); conoutf(@"demo stopped"); }) |
Modified src/server.m from [853a6dbe34] to [95faadaf28].
︙ | ︙ | |||
20 21 22 23 24 25 26 | bool notgotitems = true; int mode = 0; // hack: called from savegame code, only works in SP void restoreserverstate(OFArray<Entity *> *ents) { | | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | bool notgotitems = true; int mode = 0; // hack: called from savegame code, only works in SP void restoreserverstate(OFArray<Entity *> *ents) { [sents enumerateObjectsUsingBlock: ^ (ServerEntity *e, size_t i, bool *stop) { e.spawned = ents[i].spawned; e.spawnsecs = 0; }]; } int interm = 0, minremain = 0, mapend = 0; bool mapreload = false; |
︙ | ︙ | |||
97 98 99 100 101 102 103 | if (packet->referenceCount == 0) enet_packet_destroy(packet); } void disconnect_client(int n, OFString *reason) { | | | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | if (packet->referenceCount == 0) enet_packet_destroy(packet); } void disconnect_client(int n, OFString *reason) { [OFStdOut writeFormat: @"disconnecting client (%@) [%@]\n", clients[n].hostname, reason]; enet_peer_disconnect(clients[n].peer); clients[n].type = ST_EMPTY; send2(true, -1, SV_CDIS, n); } void resetitems() |
︙ | ︙ | |||
142 143 144 145 146 147 148 | clients[sender].mapvote = map; clients[sender].modevote = reqmode; int yes = 0, no = 0; for (Client *client in clients) { if (client.type != ST_EMPTY) { if (client.mapvote.length > 0) { | | | | | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | clients[sender].mapvote = map; clients[sender].modevote = reqmode; int yes = 0, no = 0; for (Client *client in clients) { if (client.type != ST_EMPTY) { if (client.mapvote.length > 0) { if ([client.mapvote isEqual: map] && client.modevote == reqmode) yes++; else no++; } else no++; } } if (yes == 1 && no == 0) return true; // single player OFString *msg = [OFString stringWithFormat: @"%@ suggests %@ on map %@ (set map to vote)", clients[sender].name, modestr(reqmode), map]; sendservmsg(msg); if (yes / (float)(yes + no) <= 0.5f) return false; sendservmsg(@"vote passed"); |
︙ | ︙ | |||
223 224 225 226 227 228 229 | } case SV_ITEMLIST: { int n; while ((n = getint(&p)) != -1) if (notgotitems) { while (sents.count <= n) | | | | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | } case SV_ITEMLIST: { int n; while ((n = getint(&p)) != -1) if (notgotitems) { while (sents.count <= n) [sents addObject: [ServerEntity entity]]; sents[n].spawned = true; } notgotitems = false; break; } case SV_ITEMPICKUP: { |
︙ | ︙ | |||
310 311 312 313 314 315 316 | sendstring(serverpassword, &p); putint(&p, clients.count > maxclients); if (smapname.length > 0) { putint(&p, SV_MAPCHANGE); sendstring(smapname, &p); putint(&p, mode); putint(&p, SV_ITEMLIST); | | | | 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 | sendstring(serverpassword, &p); putint(&p, clients.count > maxclients); if (smapname.length > 0) { putint(&p, SV_MAPCHANGE); sendstring(smapname, &p); putint(&p, mode); putint(&p, SV_ITEMLIST); [sents enumerateObjectsUsingBlock: ^ (ServerEntity *e, size_t i, bool *stop) { if (e.spawned) putint(&p, i); }]; putint(&p, -1); } *(unsigned short *)start = ENET_HOST_TO_NET_16(p - start); enet_packet_resize(packet, p - start); |
︙ | ︙ | |||
352 353 354 355 356 357 358 | return client; Client *client = [Client client]; if (clients == nil) clients = [[OFMutableArray alloc] init]; | | | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | return client; Client *client = [Client client]; if (clients == nil) clients = [[OFMutableArray alloc] init]; [clients addObject: client]; return client; } void checkintermission() { |
︙ | ︙ | |||
401 402 403 404 405 406 407 | void serverslice(int seconds, unsigned int timeout) // main server update, called from cube main loop in // sp, or dedicated server loop { // spawn entities when timer reached | | | | | | 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 | void serverslice(int seconds, unsigned int timeout) // main server update, called from cube main loop in // sp, or dedicated server loop { // spawn entities when timer reached [sents enumerateObjectsUsingBlock: ^ (ServerEntity *e, size_t i, bool *stop) { if (e.spawnsecs && (e.spawnsecs -= seconds - lastsec) <= 0) { e.spawnsecs = 0; e.spawned = true; send2(true, -1, SV_ITEMSPAWN, i); } }]; lastsec = seconds; if ((mode > 1 || (mode == 0 && nonlocalclients)) && seconds > mapend - minremain * 60) checkintermission(); if (interm && seconds > interm) { interm = 0; [clients enumerateObjectsUsingBlock: ^ (Client *client, size_t i, bool *stop) { if (client.type != ST_EMPTY) { // ask a client to trigger map reload send2(true, i, SV_MAPRELOAD, 0); mapreload = true; *stop = true; return; } |
︙ | ︙ | |||
471 472 473 474 475 476 477 | c.peer = event.peer; c.peer->data = (void *)(clients.count - 1); char hn[1024]; c.hostname = (enet_address_get_host( &c.peer->address, hn, sizeof(hn)) == 0 ? @(hn) : @"localhost"); | | | | > | 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 | c.peer = event.peer; c.peer->data = (void *)(clients.count - 1); char hn[1024]; c.hostname = (enet_address_get_host( &c.peer->address, hn, sizeof(hn)) == 0 ? @(hn) : @"localhost"); [OFStdOut writeFormat: @"client connected (%@)\n", c.hostname]; send_welcome(lastconnect = clients.count - 1); break; } case ENET_EVENT_TYPE_RECEIVE: brec += event.packet->dataLength; process(event.packet, (intptr_t)event.peer->data); if (event.packet->referenceCount == 0) enet_packet_destroy(event.packet); break; case ENET_EVENT_TYPE_DISCONNECT: if ((intptr_t)event.peer->data < 0) break; [OFStdOut writeFormat: @"disconnected client (%@)\n", clients[(size_t)event.peer->data].hostname]; clients[(size_t)event.peer->data].type = ST_EMPTY; send2(true, -1, SV_CDIS, (intptr_t)event.peer->data); event.peer->data = (void *)-1; break; case ENET_EVENT_TYPE_NONE: break; |
︙ | ︙ |
Modified src/serverbrowser.m from [738828d34a] to [8678daf863].
︙ | ︙ | |||
23 24 25 26 27 28 29 | resolverresults = [[OFMutableArray alloc] init]; resolverlimit = limit; resolversem = SDL_CreateSemaphore(0); while (threads > 0) { ResolverThread *rt = [ResolverThread thread]; rt.name = @"resolverthread"; | | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | resolverresults = [[OFMutableArray alloc] init]; resolverlimit = limit; resolversem = SDL_CreateSemaphore(0); while (threads > 0) { ResolverThread *rt = [ResolverThread thread]; rt.name = @"resolverthread"; [resolverthreads addObject: rt]; [rt start]; --threads; } } void resolverstop(size_t i, bool restart) { @synchronized(ResolverThread.class) { ResolverThread *rt = resolverthreads[i]; [rt stop]; if (restart) { rt = [ResolverThread thread]; rt.name = @"resolverthread"; resolverthreads[i] = rt; [rt start]; } else [resolverthreads removeObjectAtIndex: i]; } } void resolverclear() { @synchronized(ResolverThread.class) { |
︙ | ︙ | |||
67 68 69 70 71 72 73 | } } void resolverquery(OFString *name) { @synchronized(ResolverThread.class) { | | | 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | } } void resolverquery(OFString *name) { @synchronized(ResolverThread.class) { [resolverqueries addObject: name]; SDL_SemPost(resolversem); } } bool resolvercheck(OFString **name, ENetAddress *address) { |
︙ | ︙ | |||
114 115 116 117 118 119 120 | return servers[n].name; } void addserver(OFString *servername) { for (ServerInfo *si in servers) | | | | | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | return servers[n].name; } void addserver(OFString *servername) { for (ServerInfo *si in servers) if ([si.name isEqual: servername]) return; if (servers == nil) servers = [[OFMutableArray alloc] init]; [servers addObject: [ServerInfo infoWithName: servername]]; } COMMAND(addserver, ARG_1STR, ^ (OFString *servername) { addserver(servername); }) void pingservers() { ENetBuffer buf; |
︙ | ︙ | |||
159 160 161 162 163 164 165 | OFString *name = nil; ENetAddress addr = { ENET_HOST_ANY, CUBE_SERVINFO_PORT }; while (resolvercheck(&name, &addr)) { if (addr.host == ENET_HOST_ANY) continue; for (ServerInfo *si in servers) { | | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | OFString *name = nil; ENetAddress addr = { ENET_HOST_ANY, CUBE_SERVINFO_PORT }; while (resolvercheck(&name, &addr)) { if (addr.host == ENET_HOST_ANY) continue; for (ServerInfo *si in servers) { if ([name isEqual: si.name]) { si.address = addr; addr.host = ENET_HOST_ANY; break; } } } } |
︙ | ︙ | |||
213 214 215 216 217 218 219 | checkresolver(); checkpings(); if (lastmillis - lastinfo >= 5000) pingservers(); [servers sort]; __block int maxmenu = 16; | | | | < | | | | | | | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | checkresolver(); checkpings(); if (lastmillis - lastinfo >= 5000) pingservers(); [servers sort]; __block int maxmenu = 16; [servers enumerateObjectsUsingBlock: ^ (ServerInfo *si, size_t i, bool *stop) { if (si.address.host != ENET_HOST_ANY && si.ping != 9999) { if (si.protocol != PROTOCOL_VERSION) si.full = [OFString stringWithFormat: @"%@ [different cube protocol]", si.name]; else si.full = [OFString stringWithFormat: @"%d\t%d\t%@, %@: %@ %@", si.ping, si.numplayers, si.map.length > 0 ? si.map : @"[unknown]", modestr(si.mode), si.name, si.sdesc]; } else si.full = [OFString stringWithFormat: (si.address.host != ENET_HOST_ANY ? @"%@ [waiting for server response]" : @"%@ [unknown host]\t"), si.name]; // cut off too long server descriptions if (si.full.length > 50) si.full = [si.full substringToIndex: 50]; menumanual(1, i, si.full); if (!--maxmenu) return; }]; } |
︙ | ︙ | |||
261 262 263 264 265 266 267 | for (ServerInfo *si in servers) resolverquery(si.name); refreshservers(); menuset(1); } | | | | 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | for (ServerInfo *si in servers) resolverquery(si.name); refreshservers(); menuset(1); } COMMAND(servermenu, ARG_NONE, ^ { servermenu(); }) COMMAND(updatefrommaster, ARG_NONE, ^ { const int MAXUPD = 32000; unsigned char buf[MAXUPD]; unsigned char *reply = retrieveservers(buf, MAXUPD); if (!*reply || strstr((char *)reply, "<html>") || strstr((char *)reply, "<HTML>")) conoutf(@"master server not replying"); else { |
︙ | ︙ |
Modified src/serverms.m from [3e3cb4cc55] to [86b7b53d7e].
1 2 3 4 5 6 7 8 9 10 11 | // all server side masterserver and pinging functionality #include "cube.h" static ENetSocket mssock = ENET_SOCKET_NULL; static void httpgetsend(ENetAddress *ad, OFString *hostname, OFString *req, OFString *ref, OFString *agent) { if (ad->host == ENET_HOST_ANY) { | | | > | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | // all server side masterserver and pinging functionality #include "cube.h" static ENetSocket mssock = ENET_SOCKET_NULL; static void httpgetsend(ENetAddress *ad, OFString *hostname, OFString *req, OFString *ref, OFString *agent) { if (ad->host == ENET_HOST_ANY) { [OFStdOut writeFormat: @"looking up %@...\n", hostname]; enet_address_set_host(ad, hostname.UTF8String); if (ad->host == ENET_HOST_ANY) return; } if (mssock != ENET_SOCKET_NULL) enet_socket_destroy(mssock); mssock = enet_socket_create(ENET_SOCKET_TYPE_STREAM, NULL); if (mssock == ENET_SOCKET_NULL) { printf("could not open socket\n"); return; } if (enet_socket_connect(mssock, ad) < 0) { printf("could not connect\n"); return; } ENetBuffer buf; OFString *httpget = [OFString stringWithFormat: @"GET %@ HTTP/1.0\n" @"Host: %@\n" @"Referer: %@\n" @"User-Agent: %@\n\n", req, hostname, ref, agent]; buf.data = (void *)httpget.UTF8String; buf.dataLength = httpget.UTF8StringLength; [OFStdOut writeFormat: @"sending request to %@...\n", hostname]; enet_socket_send(mssock, NULL, &buf, 1); } static void httpgetrecieve(ENetBuffer *buf) { if (mssock == ENET_SOCKET_NULL) |
︙ | ︙ | |||
73 74 75 76 77 78 79 | static ENetBuffer masterb; static void updatemasterserver(int seconds) { // send alive signal to masterserver every hour of uptime if (seconds > updmaster) { | | | | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | static ENetBuffer masterb; static void updatemasterserver(int seconds) { // send alive signal to masterserver every hour of uptime if (seconds > updmaster) { OFString *path = [OFString stringWithFormat: @"%@register.do?action=add", masterpath]; httpgetsend(&masterserver, masterbase, path, @"cubeserver", @"Cube Server"); masterrep[0] = 0; masterb.data = masterrep; masterb.dataLength = MAXTRANS - 1; updmaster = seconds + 60 * 60; } |
︙ | ︙ | |||
96 97 98 99 100 101 102 | if (busy && mssock == ENET_SOCKET_NULL) printf("masterserver reply: %s\n", stripheader(masterrep)); } unsigned char * retrieveservers(unsigned char *buf, int buflen) { | | | | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | if (busy && mssock == ENET_SOCKET_NULL) printf("masterserver reply: %s\n", stripheader(masterrep)); } unsigned char * retrieveservers(unsigned char *buf, int buflen) { OFString *path = [OFString stringWithFormat: @"%@retrieve.do?item=list", masterpath]; httpgetsend( &masterserver, masterbase, path, @"cubeserver", @"Cube Server"); ENetBuffer eb; buf[0] = 0; eb.data = buf; eb.dataLength = buflen - 1; while (mssock != ENET_SOCKET_NULL) |
︙ | ︙ | |||
136 137 138 139 140 141 142 | if (len < 0) return; p = &pong[len]; putint(&p, PROTOCOL_VERSION); putint(&p, mode); putint(&p, numplayers); putint(&p, minremain); | | | | > | 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | if (len < 0) return; p = &pong[len]; putint(&p, PROTOCOL_VERSION); putint(&p, mode); putint(&p, numplayers); putint(&p, minremain); OFString *mname = [OFString stringWithFormat: @"%@%@", (isfull ? @"[FULL] " : @""), smapname]; sendstring(mname, &p); sendstring(serverdesc, &p); buf.dataLength = p - pong; enet_socket_send(pongsock, &addr, &buf, 1); } } void servermsinit(OFString *master_, OFString *sdesc, bool listen) { const char *master = master_.UTF8String; const char *mid = strstr(master, "/"); if (!mid) mid = master; masterpath = @(mid); masterbase = [OFString stringWithUTF8String: master length: mid - master]; serverdesc = sdesc; if (listen) { ENetAddress address = { ENET_HOST_ANY, CUBE_SERVINFO_PORT }; pongsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, &address); if (pongsock == ENET_SOCKET_NULL) fatal(@"could not create server info socket\n"); } } |
Modified src/serverutil.m from [25b79fa395] to [da87a5e2ce].
︙ | ︙ | |||
142 143 144 145 146 147 148 | void fatal(OFConstantString *s, ...) { cleanupserver(); va_list args; va_start(args, s); | | | | 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | void fatal(OFConstantString *s, ...) { cleanupserver(); va_list args; va_start(args, s); OFString *msg = [[OFString alloc] initWithFormat: s arguments: args]; va_end(args); [OFStdOut writeFormat: @"servererror: %@\n", msg]; exit(1); } void * alloc(int s) { |
︙ | ︙ |
Modified src/sound.m from [0732f14714] to [78a898d2ad].
︙ | ︙ | |||
45 46 47 48 49 50 51 | conoutf(@"sound init failed (SDL_mixer): %s", (size_t)Mix_GetError()); nosound = true; } Mix_AllocateChannels(MAXCHAN); } | | | | | | | | | | | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | conoutf(@"sound init failed (SDL_mixer): %s", (size_t)Mix_GetError()); nosound = true; } Mix_AllocateChannels(MAXCHAN); } COMMAND(music, ARG_1STR, (^ (OFString *name) { if (nosound) return; stopsound(); if (soundvol && musicvol) { name = [name stringByReplacingOccurrencesOfString: @"\\" withString: @"/"]; OFString *path = [OFString stringWithFormat: @"packages/%@", name]; OFIRI *IRI = [Cube.sharedInstance.gameDataIRI IRIByAppendingPathComponent: path]; if ((mod = Mix_LoadMUS( IRI.fileSystemRepresentation.UTF8String)) != NULL) { Mix_PlayMusic(mod, -1); Mix_VolumeMusic((musicvol * MAXVOL) / 255); } } })) static OFMutableData *samples; static OFMutableArray<OFString *> *snames; COMMAND(registersound, ARG_1EST, ^int(OFString *name) { int i = 0; for (OFString *iter in snames) { if ([iter isEqual: name]) return i; i++; } if (snames == nil) snames = [[OFMutableArray alloc] init]; if (samples == nil) samples = [[OFMutableData alloc] initWithItemSize: sizeof(Mix_Chunk *)]; [snames addObject: [name stringByReplacingOccurrencesOfString: @"\\" withString: @"/"]]; Mix_Chunk *sample = NULL; [samples addItem: &sample]; return samples.count - 1; }) void cleansound() { |
︙ | ︙ | |||
189 190 191 192 193 194 195 | return; if (n < 0 || n >= samples.count) { conoutf(@"unregistered sound: %d", n); return; } | | | | | | | 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | return; if (n < 0 || n >= samples.count) { conoutf(@"unregistered sound: %d", n); return; } Mix_Chunk **sample = (Mix_Chunk **)[samples mutableItemAtIndex: n]; if (*sample == NULL) { OFString *path = [OFString stringWithFormat: @"packages/sounds/%@.wav", snames[n]]; OFIRI *IRI = [Cube.sharedInstance.gameDataIRI IRIByAppendingPathComponent: path]; *sample = Mix_LoadWAV(IRI.fileSystemRepresentation.UTF8String); if (*sample == NULL) { conoutf(@"failed to load sample: %@", IRI.string); return; } } int chan = Mix_PlayChannel(-1, *sample, 0); if (chan < 0) return; if (loc) newsoundloc(chan, loc); updatechanvol(chan, loc); } COMMAND(sound, ARG_1INT, ^ (int n) { playsound(n, NULL); }) |
Modified src/weapon.m from [48ff54c543] to [6c8b962c81].
︙ | ︙ | |||
62 63 64 65 66 67 68 | int reloadtime(int gun) { return guns[gun].attackdelay; } | | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | int reloadtime(int gun) { return guns[gun].attackdelay; } 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)); }) // create random spread of rays for the shotgun void |
︙ | ︙ | |||
113 114 115 116 117 118 119 | playerincrosshair() { if (demoplayback) return NULL; OFVector3D o = Player.player1.origin; for (Player *player in players) { | | | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | playerincrosshair() { if (demoplayback) return NULL; OFVector3D o = Player.player1.origin; for (Player *player in players) { if (![Player isKindOfClass: Player.class]) continue; if (intersect(player, o, worldpos)) return [player name]; } return nil; |
︙ | ︙ | |||
163 164 165 166 167 168 169 | static void hit(int target, int damage, __kindof DynamicEntity *d, DynamicEntity *at) { OFVector3D o = d.origin; if (d == Player.player1) selfdamage(damage, (at == Player.player1) ? -1 : -2, at); | | | | | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | static void hit(int target, int damage, __kindof DynamicEntity *d, DynamicEntity *at) { OFVector3D o = d.origin; if (d == Player.player1) selfdamage(damage, (at == Player.player1) ? -1 : -2, at); else if ([d isKindOfClass: Monster.class]) [d incurDamage: damage fromEntity: at]; else if ([d isKindOfClass: Player.class]) { addmsg(1, 4, SV_DAMAGE, target, damage, ((Player *)d).lifeSequence); playsound(S_PAIN1 + rnd(5), &o); } particle_splash(3, damage, 1000, o); demodamage(damage, o); } |
︙ | ︙ | |||
221 222 223 224 225 226 227 | dodynlight(vold, v, 0, 0, p.owner); if (!p.local) return; radialeffect(Player.player1, v, -1, qdam, p.owner); | | | | | | 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | dodynlight(vold, v, 0, 0, p.owner); if (!p.local) return; radialeffect(Player.player1, v, -1, qdam, p.owner); [players enumerateObjectsUsingBlock: ^ (id player, size_t i, bool *stop) { if (i == notthisplayer) return; if (player == [OFNull null]) return; radialeffect(player, v, i, qdam, p.owner); }]; [Monster.monsters enumerateObjectsUsingBlock: ^ (Monster *monster, size_t i, bool *stop) { if (i != notthismonster) radialeffect(monster, v, i, qdam, p.owner); }]; } } static inline void |
︙ | ︙ | |||
264 265 266 267 268 269 270 | for (size_t i = 0; i < MAXPROJ; i++) { Projectile *p = projs[i]; if (!p.inuse) continue; int qdam = guns[p.gun].damage * (p.owner.quadMillis ? 4 : 1); | | | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | for (size_t i = 0; i < MAXPROJ; i++) { Projectile *p = projs[i]; if (!p.inuse) continue; int qdam = guns[p.gun].damage * (p.owner.quadMillis ? 4 : 1); if ([p.owner isKindOfClass: Monster.class]) qdam /= MONSTERDAMAGEFACTOR; OFVector3D po = p.o, pto = p.to; float dist = OFDistanceOfVectors3D(pto, po); OFVector3D v = OFSubtractVectors3D(pto, po); float dtime = dist * 1000 / p.speed; if (time > dtime) dtime = time; |
︙ | ︙ | |||
332 333 334 335 336 337 338 | break; case GUN_RL: case GUN_FIREBALL: case GUN_ICEBALL: case GUN_SLIMEBALL: pspeed = guns[gun].projspeed; | | | 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | break; case GUN_RL: case GUN_FIREBALL: case GUN_ICEBALL: case GUN_SLIMEBALL: pspeed = guns[gun].projspeed; if ([d isKindOfClass: Monster.class]) pspeed /= 2; newprojectile(from, to, (float)pspeed, local, d, gun); break; case GUN_RIFLE: particle_splash(0, 50, 200, to); particle_trail(1, 500, from, to); |
︙ | ︙ | |||
364 365 366 367 368 369 370 | DynamicEntity *o, OFVector3D from, OFVector3D to, DynamicEntity *d, int i) { if (o.state != CS_ALIVE) return; int qdam = guns[d.gunSelect].damage; if (d.quadMillis) qdam *= 4; | | | 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | DynamicEntity *o, OFVector3D from, OFVector3D to, DynamicEntity *d, int i) { if (o.state != CS_ALIVE) return; int qdam = guns[d.gunSelect].damage; if (d.quadMillis) qdam *= 4; if ([d isKindOfClass: Monster.class]) qdam /= MONSTERDAMAGEFACTOR; if (d.gunSelect == GUN_SG) { int damage = 0; for (int r = 0; r < SGRAYS; r++) if (intersect(o, from, sg[r])) damage += qdam; if (damage) |
︙ | ︙ | |||
419 420 421 422 423 424 425 | } if (d.gunSelect == GUN_SG) createrays(from, to); if (d.quadMillis && attacktime > 200) playsoundc(S_ITEMPUP); shootv(d.gunSelect, from, to, d, true); | | | > | | 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | } if (d.gunSelect == GUN_SG) createrays(from, to); if (d.quadMillis && attacktime > 200) playsoundc(S_ITEMPUP); shootv(d.gunSelect, from, to, d, true); if (![d isKindOfClass: Monster.class]) addmsg(1, 8, SV_SHOT, d.gunSelect, (int)(from.x * DMF), (int)(from.y * DMF), (int)(from.z * DMF), (int)(to.x * DMF), (int)(to.y * DMF), (int)(to.z * DMF)); d.gunWait = guns[d.gunSelect].attackdelay; if (guns[d.gunSelect].projspeed) return; [players enumerateObjectsUsingBlock: ^ (id player, size_t i, bool *stop) { if (player != [OFNull null]) raydamage(player, from, to, d, i); }]; for (Monster *monster in Monster.monsters) if (monster != d) raydamage(monster, from, to, d, -2); if ([d isKindOfClass: Monster.class]) raydamage(Player.player1, from, to, d, -1); } |
Modified src/world.m from [1c22ea0614] to [a8feb3f63c].
︙ | ︙ | |||
62 63 64 65 66 67 68 | // set for playing void settagareas() { settag(0, 1); | | | | | | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | // set for playing void settagareas() { settag(0, 1); [ents enumerateObjectsUsingBlock: ^ (Entity *e, size_t i, bool *stop) { if (ents[i].type == CARROT) setspawn(i, true); }]; } void trigger(int tag, int type, bool savegame) { if (!tag) return; settag(tag, type); if (!savegame && type != 3) playsound(S_RUMBLE, NULL); OFString *aliasname = [OFString stringWithFormat: @"level_trigger_%d", tag]; if (identexists(aliasname)) execute(aliasname, true); if (type == 2) [Monster endSinglePlayerWithAllKilled: false]; } 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 // defer to 0 if mipped cube is a perfect mip, i.e. can be rendered at this mip // level indistinguishable from its constituent cubes (saves considerable |
︙ | ︙ | |||
289 290 291 292 293 294 295 | closestent() // used for delent and edit mode ent display { if (noteditmode()) return -1; __block int best; __block float bdist = 99999; | | | | | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | closestent() // used for delent and edit mode ent display { if (noteditmode()) return -1; __block int best; __block float bdist = 99999; [ents enumerateObjectsUsingBlock: ^ (Entity *e, size_t i, bool *stop) { if (e.type == NOTUSED) return; OFVector3D v = OFMakeVector3D(e.x, e.y, e.z); float dist = OFDistanceOfVectors3D(v, Player.player1.origin); if (dist < bdist) { best = i; bdist = dist; } }]; return (bdist == 99999 ? -1 : best); } COMMAND(entproperty, ARG_2INT, ^ (int prop, int amount) { int e = closestent(); if (e < 0) return; switch (prop) { case 0: ents[e].attr1 += amount; break; case 1: ents[e].attr2 += amount; break; case 2: ents[e].attr3 += amount; break; case 3: ents[e].attr4 += amount; break; } }) COMMAND(delent, ARG_NONE, ^ { int e = closestent(); if (e < 0) { conoutf(@"no more entities"); return; } int t = ents[e].type; conoutf(@"%@ entity deleted", entnames[t]); ents[e].type = NOTUSED; addmsg(1, 10, SV_EDITENT, e, NOTUSED, 0, 0, 0, 0, 0, 0, 0); if (t == LIGHT) calclight(); }) int findtype(OFString *what) { for (int i = 0; i < MAXENTTYPES; i++) if ([what isEqual: entnames[i]]) return i; conoutf(@"unknown entity type \"%@\"", what); return NOTUSED; } Entity * newentity(int x, int y, int z, OFString *what, int v1, int v2, int v3, int v4) |
︙ | ︙ | |||
385 386 387 388 389 390 391 | case PLAYERSTART: e.attr1 = (int)Player.player1.yaw; break; } addmsg(1, 10, SV_EDITENT, ents.count, type, e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4); | | | | 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | case PLAYERSTART: e.attr1 = (int)Player.player1.yaw; break; } addmsg(1, 10, SV_EDITENT, ents.count, type, e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4); [ents addObject: e]; if (type == LIGHT) calclight(); return e; } COMMAND(clearents, ARG_1STR, ^ (OFString *name) { int type = findtype(name); if (noteditmode() || multiplayer()) return; for (Entity *e in ents) if (e.type == type) |
︙ | ︙ | |||
416 417 418 419 420 421 422 | { int n = c * intens / 100; if (n > 255) n = 255; return n; } | | | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 | { int n = c * intens / 100; if (n > 255) n = 255; return n; } COMMAND(scalelights, ARG_2INT, ^ (int f, int intens) { for (Entity *e in ents) { if (e.type != LIGHT) continue; e.attr1 = e.attr1 * f / 100; if (e.attr1 < 2) e.attr1 = 2; |
︙ | ︙ | |||
541 542 543 544 545 546 547 | if (oldworld) { OFFreeMemory(oldworld); toggleedit(); execute(@"fullbright 1", true); } } | | | | | 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 | if (oldworld) { OFFreeMemory(oldworld); toggleedit(); execute(@"fullbright 1", true); } } COMMAND(mapenlarge, ARG_NONE, ^ { empty_world(-1, false); }) COMMAND(newmap, ARG_1INT, ^ (int i) { empty_world(i, false); }) COMMAND(recalc, ARG_NONE, ^ { calclight(); }) |
Modified src/worldio.m from [d379fda5be] to [f35a650122].
︙ | ︙ | |||
11 12 13 14 15 16 17 | unsigned char type; // type is one of the above unsigned char attr2, attr3, attr4; }; void backup(OFString *name, OFString *backupname) { | | | | | | | | | | | | | | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | unsigned char type; // type is one of the above unsigned char attr2, attr3, attr4; }; void backup(OFString *name, OFString *backupname) { [OFFileManager.defaultManager removeItemAtPath: backupname]; [OFFileManager.defaultManager moveItemAtPath: name toPath: backupname]; } static OFString *cgzname, *bakname, *pcfname, *mcfname; static void setnames(OFString *name) { OFCharacterSet *cs = [OFCharacterSet characterSetWithCharactersInString: @"/\\"]; OFRange range = [name rangeOfCharacterFromSet: cs]; OFString *pakname, *mapname; if (range.location != OFNotFound) { pakname = [name substringToIndex: range.location]; mapname = [name substringFromIndex: range.location + 1]; } else { pakname = @"base"; mapname = name; } cgzname = [[OFString alloc] initWithFormat: @"packages/%@/%@.cgz", pakname, mapname]; bakname = [[OFString alloc] initWithFormat: @"packages/%@/%@_%d.BAK", pakname, mapname, lastmillis]; pcfname = [[OFString alloc] initWithFormat: @"packages/%@/package.cfg", pakname]; mcfname = [[OFString alloc] initWithFormat: @"packages/%@/%@.cfg", pakname, mapname]; } // the optimize routines below are here to reduce the detrimental effects of // messy mapping by setting certain properties (vdeltas and textures) to // neighbouring values wherever there is no visible difference. This allows the // mipmapper to generate more efficient mips. the reason it is done on save is // to reduce the amount spend in the mipmapper (as that is done in realtime). |
︙ | ︙ | |||
141 142 143 144 145 146 147 | void writemap(OFString *mname, int msize, unsigned char *mdata) { setnames(mname); backup(cgzname, bakname); | | | | | | 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | void writemap(OFString *mname, int msize, unsigned char *mdata) { setnames(mname); backup(cgzname, bakname); FILE *f = fopen([cgzname cStringWithEncoding: OFLocale.encoding], "wb"); if (!f) { conoutf(@"could not write map to %@", cgzname); return; } fwrite(mdata, 1, msize, f); fclose(f); conoutf(@"wrote map %@ as file %@", mname, cgzname); } OFData * readmap(OFString *mname) { setnames(mname); return [OFData dataWithContentsOfFile: mname]; } // save map as .cgz file. uses 2 layers of compression: first does simple // run-length encoding and leaves out data for certain kinds of cubes, then zlib // removes the last bits of redundancy. Both passes contribute greatly to the // miniscule map sizes. void save_world(OFString *mname) { resettagareas(); // wouldn't be able to reproduce tagged areas // otherwise voptimize(); toptimize(); if (mname.length == 0) mname = getclientmap(); setnames(mname); backup(cgzname, bakname); gzFile f = gzopen([cgzname cStringWithEncoding: OFLocale.encoding], "wb9"); if (!f) { conoutf(@"could not write map to %@", cgzname); return; } hdr.version = MAPVERSION; hdr.numents = 0; for (Entity *e in ents) |
︙ | ︙ | |||
254 255 256 257 258 259 260 | } spurge; gzclose(f); conoutf(@"wrote map file %@", cgzname); settagareas(); } | | | | | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 | } spurge; gzclose(f); conoutf(@"wrote map file %@", cgzname); settagareas(); } COMMAND(savemap, ARG_1STR, ^ (OFString *mname) { save_world(mname); }) void load_world(OFString *mname) // still supports all map formats that have existed // since the earliest cube betas! { stopifrecording(); cleardlights(); pruneundos(0); setnames(mname); gzFile f = gzopen([cgzname cStringWithEncoding: OFLocale.encoding], "rb9"); if (!f) { conoutf(@"could not read map %@", cgzname); return; } gzread(f, &hdr, sizeof(struct header) - sizeof(int) * 16); endianswap(&hdr.version, sizeof(int), 4); if (strncmp(hdr.head, "CUBE", 4) != 0) |
︙ | ︙ | |||
301 302 303 304 305 306 307 | e.y = tmp.y; e.z = tmp.z; e.attr1 = tmp.attr1; e.type = tmp.type; e.attr2 = tmp.attr2; e.attr3 = tmp.attr3; e.attr4 = tmp.attr4; | | | 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 | e.y = tmp.y; e.z = tmp.z; e.attr1 = tmp.attr1; e.type = tmp.type; e.attr2 = tmp.attr2; e.attr3 = tmp.attr3; e.attr4 = tmp.attr4; [ents addObject: e]; if (e.type == LIGHT) { if (!e.attr2) e.attr2 = 255; // needed for MAPVERSION<=2 if (e.attr1 > 32) e.attr1 = 32; // 12_03 and below } |
︙ | ︙ | |||
392 393 394 395 396 397 398 | lookuptexture(i, &xs, &ys); conoutf(@"read map %@ (%d milliseconds)", cgzname, SDL_GetTicks() - lastmillis); conoutf(@"%s", hdr.maptitle); startmap(mname); for (int l = 0; l < 256; l++) { // can this be done smarter? | | | | | | | 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | lookuptexture(i, &xs, &ys); conoutf(@"read map %@ (%d milliseconds)", cgzname, SDL_GetTicks() - lastmillis); conoutf(@"%s", hdr.maptitle); startmap(mname); for (int l = 0; l < 256; l++) { // can this be done smarter? OFString *aliasname = [OFString stringWithFormat: @"level_trigger_%d", l]; if (identexists(aliasname)) alias(aliasname, @""); } OFIRI *gameDataIRI = Cube.sharedInstance.gameDataIRI; execfile([gameDataIRI IRIByAppendingPathComponent: @"data/default_map_settings.cfg"]); execfile([gameDataIRI IRIByAppendingPathComponent: pcfname]); execfile([gameDataIRI IRIByAppendingPathComponent: mcfname]); } |
Modified src/worldlight.m from [279400f849] to [38a360a277].
︙ | ︙ | |||
201 202 203 204 205 206 207 | void dodynlight(OFVector3D vold, OFVector3D v, int reach, int strength, DynamicEntity *owner) { if (!reach) reach = dynlight; | | | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | void dodynlight(OFVector3D vold, OFVector3D v, int reach, int strength, DynamicEntity *owner) { if (!reach) reach = dynlight; if ([owner isKindOfClass: Monster.class]) reach = reach / 2; if (!reach) return; if (v.x < 0 || v.y < 0 || v.x > ssize || v.y > ssize) return; int creach = reach + 16; // dependant on lightray random offsets! |
︙ | ︙ | |||
223 224 225 226 227 228 229 | if (b.xs + b.x > ssize - 2) b.xs = ssize - 2 - b.x; if (b.ys + b.y > ssize - 2) b.ys = ssize - 2 - b.y; if (dlights == nil) dlights = [[OFMutableData alloc] | | | | 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | if (b.xs + b.x > ssize - 2) b.xs = ssize - 2 - b.x; if (b.ys + b.y > ssize - 2) b.ys = ssize - 2 - b.y; if (dlights == nil) dlights = [[OFMutableData alloc] initWithItemSize: sizeof(struct block *)]; // backup area before rendering in dynlight struct block *copy = blockcopy(&b); [dlights addItem: ©]; Entity *l = [Entity entity]; l.x = v.x; l.y = v.y; l.z = v.z; l.attr1 = reach; l.type = LIGHT; |
︙ | ︙ |
Modified src/worldocull.m from [201c3dd9c9] to [a7de71ad12].
1 2 3 4 5 6 7 8 9 10 11 12 13 | // worldocull.cpp: occlusion map and occlusion test #include "cube.h" #import "Command.h" #import "Player.h" #define NUMRAYS 512 float rdist[NUMRAYS]; bool ocull = true; float odist = 256; | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // worldocull.cpp: occlusion map and occlusion test #include "cube.h" #import "Command.h" #import "Player.h" #define NUMRAYS 512 float rdist[NUMRAYS]; bool ocull = true; float odist = 256; COMMAND(toggleocull, ARG_NONE, ^ { ocull = !ocull; }) // constructs occlusion map: cast rays in all directions on the 2d plane and // record distance. done exactly once per frame. void |
︙ | ︙ |