Overview
Comment: | Improve clang-format |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
6f5dd506262655e5d3a6732794f955c8 |
User & Date: | js on 2025-03-08 02:38:40.221 |
Other Links: | manifest | tags |
Context
2025-03-08
| ||
03:05 | More style cleanup check-in: 753ff34122 user: js tags: trunk | |
02:38 | Improve clang-format check-in: 6f5dd50626 user: js tags: trunk | |
01:09 | Remove memory pool check-in: 0097baa3a7 user: js tags: trunk | |
Changes
Modified src/.clang-format
from [a045e80592]
to [2a796d79cc].
1 2 3 | IndentWidth: 8 TabWidth: 8 UseTab: ForIndentation | > > | > > > > > > > > > > > > > > > > > > > > > | 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 | IndentWidth: 8 TabWidth: 8 UseTab: ForIndentation ColumnLimit: 80 BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom BreakBeforeTernaryOperators: true BraceWrapping: AfterClass: false AfterControlStatement: false AfterEnum: false AfterFunction: true AfterNamespace: false AfterObjCDeclaration: true AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: false AlwaysBreakAfterReturnType: AllDefinitions AlignAfterOpenBracket: DontAlign AlignEscapedNewlines: Left AlignOperands: DontAlign ObjCBlockIndentWidth: 8 ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: true ObjCPropertyAttributeOrder: [ class, direct, readonly, readwrite, nullable, nonnull, null_resettable, null_unspecified, assign, retain, strong, copy, weak, unsafe_unretained, atomic, nonatomic, getter, setter ] SpaceBeforeInheritanceColon: false QualifierAlignment: Left #RemoveEmptyLinesInUnwrappedLines: true RemoveSemicolon: true CompactNamespaces: true SortIncludes: CaseSensitive IndentPPDirectives: AfterHash PPIndentWidth: 1 |
Modified src/Alias.h
from [257d20d71a]
to [6c97091132].
1 2 3 4 | #import "Identifier.h" OF_ASSUME_NONNULL_BEGIN | | | 1 2 3 4 5 6 7 8 9 10 11 12 | #import "Identifier.h" OF_ASSUME_NONNULL_BEGIN @interface Alias: Identifier @property (copy, nonatomic) OFString *action; @property (readonly, nonatomic) bool persisted; - (instancetype)initWithName:(OFString *)name OF_UNAVAILABLE; - (instancetype)initWithName:(OFString *)name action:(OFString *)action persisted:(bool)persisted; |
︙ | ︙ |
Modified src/Command.h
from [d308bef816]
to [e066e0d794].
1 2 3 4 | #import "Identifier.h" OF_ASSUME_NONNULL_BEGIN | | | 1 2 3 4 5 6 7 8 9 10 11 12 | #import "Identifier.h" OF_ASSUME_NONNULL_BEGIN @interface Command: Identifier @property (readonly, nonatomic) void (*function)(); @property (readonly, nonatomic) int argumentsTypes; - (instancetype)initWithName:(OFString *)name OF_UNAVAILABLE; - (instancetype)initWithName:(OFString *)name function:(void (*)())function argumentsTypes:(int)argumentsTypes; |
︙ | ︙ |
Modified src/Cube.mm
from [aeae4b6df1]
to [00b4da043c].
1 2 3 4 5 6 7 8 9 | // main.cpp: initialisation & main loop #include "cube.h" OF_APPLICATION_DELEGATE(Cube) VARF(gamespeed, 10, 100, 1000, if (multiplayer()) gamespeed = 100); VARP(minmillis, 0, 5, 1000); | | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // main.cpp: initialisation & main loop #include "cube.h" OF_APPLICATION_DELEGATE(Cube) VARF(gamespeed, 10, 100, 1000, if (multiplayer()) gamespeed = 100); VARP(minmillis, 0, 5, 1000); @implementation Cube { int _width, _height; } + (Cube *)sharedInstance { return (Cube *)OFApplication.sharedApplication.delegate; } |
︙ | ︙ |
Modified src/Identifier.h
from [9069c402ca]
to [f570e25a18].
1 2 3 4 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN | | | 1 2 3 4 5 6 7 8 9 10 11 12 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN @interface Identifier: OFObject @property (readonly, copy, nonatomic) OFString *name; - (instancetype)init OF_UNAVAILABLE; - (instancetype)initWithName:(OFString *)name; @end OF_ASSUME_NONNULL_END |
Modified src/KeyMapping.h
from [791a955c77]
to [995386e6ec].
1 2 3 4 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN | | | 1 2 3 4 5 6 7 8 9 10 11 12 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN @interface KeyMapping: OFObject @property (readonly) int code; @property (readonly, nonatomic) OFString *name; @property (copy, nonatomic) OFString *action; - (instancetype)initWithCode:(int)code name:(OFString *)name; @end |
︙ | ︙ |
Modified src/MD2.h
from [e16b607519]
to [3eecbab1e8].
1 2 3 4 5 6 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN @class MapModelInfo; | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN @class MapModelInfo; @interface MD2: OFObject @property (nonatomic) MapModelInfo *mmi; @property (copy, nonatomic) OFString *loadname; @property (nonatomic) int mdlnum; @property (nonatomic) bool loaded; - (bool)loadWithIRI:(OFIRI *)IRI; - (void)renderWithLight:(OFVector3D)light |
︙ | ︙ |
Modified src/MD2.mm
from [150ffcd79c]
to [074abf7ae2].
︙ | ︙ | |||
26 27 28 29 30 31 32 | static float snap(int sn, float f) { return sn ? (float)(((int)(f + sn * 0.5f)) & (~(sn - 1))) : f; } | | > | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | static float snap(int sn, float f) { return sn ? (float)(((int)(f + sn * 0.5f)) & (~(sn - 1))) : f; } @implementation MD2 { int _numGlCommands; int *_glCommands; int _numTriangles; int _frameSize; int _numFrames; int _numVerts; char *_frames; |
︙ | ︙ |
Modified src/MapModelInfo.h
from [340f29da11]
to [5ed60ec67c].
1 2 3 4 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN | | | 1 2 3 4 5 6 7 8 9 10 11 12 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN @interface MapModelInfo: OFObject @property (nonatomic) int rad, h, zoff, snap; @property (copy, nonatomic) OFString *name; - (instancetype)initWithRad:(int)rad h:(int)h zoff:(int)zoff snap:(int)snap |
︙ | ︙ |
Modified src/Menu.h
from [63596d2912]
to [5fa014f8d6].
1 2 3 4 5 6 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN @class MenuItem; | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #import <ObjFW/ObjFW.h> OF_ASSUME_NONNULL_BEGIN @class MenuItem; @interface Menu: OFObject @property (readonly, nonatomic) OFString *name; @property (readonly) OFMutableArray<MenuItem *> *items; @property (nonatomic) int mwidth; @property (nonatomic) int menusel; - (instancetype)initWithName:(OFString *)name; @end |
︙ | ︙ |
Modified src/MenuItem.h
from [58b3d87ceb]
to [3f56310839].
1 2 | #import <ObjFW/ObjFW.h> | | | 1 2 3 4 5 6 7 | #import <ObjFW/ObjFW.h> @interface MenuItem: OFObject @property (readonly, nonatomic) OFString *text, *action; - (instancetype)initWithText:(OFString *)text action:(OFString *)action; @end |
Modified src/Variable.h
from [d1b2d68346]
to [82779ddfda].
1 2 3 4 | #import "Identifier.h" OF_ASSUME_NONNULL_BEGIN | | | 1 2 3 4 5 6 7 8 9 10 11 12 | #import "Identifier.h" OF_ASSUME_NONNULL_BEGIN @interface Variable: Identifier @property (readonly, nonatomic) int min, max; @property (readonly, nonatomic) int *storage; @property (readonly, nonatomic) void (*__cdecl function)(); @property (readonly, nonatomic) bool persisted; - (instancetype)initWithName:(OFString *)name OF_UNAVAILABLE; - (instancetype)initWithName:(OFString *)name |
︙ | ︙ |
Modified src/client.mm
from [da4c60f968]
to [89ff04e5c2].
︙ | ︙ | |||
291 292 293 294 295 296 297 | putint(p, SV_MAPCHANGE); sendstring(toservermap, p); toservermap = @""; putint(p, nextmode); } else { putint(p, SV_POS); putint(p, clientnum); | | | | | | | | | | 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 | putint(p, SV_MAPCHANGE); sendstring(toservermap, p); toservermap = @""; putint(p, nextmode); } else { putint(p, SV_POS); putint(p, clientnum); putint(p, (int)(d->o.x * DMF)); // quantize coordinates to 1/16th // of a cube, between 1 and 3 bytes putint(p, (int)(d->o.y * DMF)); putint(p, (int)(d->o.z * DMF)); putint(p, (int)(d->yaw * DAF)); putint(p, (int)(d->pitch * DAF)); putint(p, (int)(d->roll * DAF)); putint( p, (int)(d->vel.x * DVF)); // quantize to 1/100, // almost always 1 byte putint(p, (int)(d->vel.y * DVF)); putint(p, (int)(d->vel.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); |
︙ | ︙ | |||
408 409 410 411 412 413 414 | case ENET_EVENT_TYPE_DISCONNECT: if (disconnecting) disconnect(); else server_err(); return; } | < > | 408 409 410 411 412 413 414 415 | case ENET_EVENT_TYPE_DISCONNECT: if (disconnecting) disconnect(); else server_err(); return; } } |
Modified src/clientextras.mm
from [45d297fe4b]
to [0e321e84f3].
︙ | ︙ | |||
74 75 76 77 78 79 80 | extern int democlientnum; void renderclients() { dynent *d; loopv(players) if ((d = players[i]) && | | | < | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | extern int democlientnum; void renderclients() { dynent *d; loopv(players) if ((d = players[i]) && (!demoplayback || i != democlientnum)) renderclient(d, isteam(player1->team, d->team), @"monster/ogro", false, 1.0f); } // creation of scoreboard pseudo-menu bool scoreson = false; void |
︙ | ︙ |
Modified src/clientgame.mm
from [2ddec801b6]
to [6689f47248].
︙ | ︙ | |||
37 38 39 40 41 42 43 | d->k_left = false; d->k_right = false; d->k_up = false; d->k_down = false; d->jumpnext = false; d->strafe = 0; d->move = 0; | < > | 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | d->k_left = false; d->k_right = false; d->k_up = false; d->k_down = false; d->jumpnext = false; d->strafe = 0; d->move = 0; } void spawnstate(dynent *d) // reset player state not persistent accross spawns { resetmovement(d); d->vel.x = d->vel.y = d->vel.z = 0; d->onfloor = false; |
︙ | ︙ | |||
91 92 93 94 95 96 97 | d->gunselect = GUN_CG; }; d->ammo[GUN_CG] /= 2; }; } else { d->ammo[GUN_SG] = 5; }; | < > | 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | d->gunselect = GUN_CG; }; d->ammo[GUN_CG] /= 2; }; } else { d->ammo[GUN_SG] = 5; }; } dynent * newdynent() // create a new blank player or monster { dynent *d = (dynent *)malloc(sizeof(dynent)); d->o.x = 0; d->o.y = 0; |
︙ | ︙ | |||
121 122 123 124 125 126 127 | d->monsterstate = 0; d->name[0] = d->team[0] = 0; d->blocked = false; d->lifesequence = 0; d->state = CS_ALIVE; spawnstate(d); return d; | < > < > < > | 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 | d->monsterstate = 0; d->name[0] = d->team[0] = 0; d->blocked = false; d->lifesequence = 0; d->state = CS_ALIVE; spawnstate(d); return d; } void respawnself() { spawnplayer(player1); showscores(false); } void arenacount(dynent *d, int &alive, int &dead, char *&lastteam, bool &oneteam) { if (d->state != CS_DEAD) { alive++; if (lastteam && strcmp(lastteam, d->team)) oneteam = false; lastteam = d->team; } else { dead++; }; } int arenarespawnwait = 0; int arenadetectwait = 0; void arenarespawn() { |
︙ | ︙ | |||
176 177 178 179 180 181 182 | else conoutf(@"everyone died!"); arenarespawnwait = lastmillis + 5000; arenadetectwait = lastmillis + 10000; player1->roll = 0; }; }; | < > < > < < > > | 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 206 207 208 209 210 211 212 213 214 215 216 217 218 | else conoutf(@"everyone died!"); arenarespawnwait = lastmillis + 5000; arenadetectwait = lastmillis + 10000; player1->roll = 0; }; }; } void zapdynent(dynent *&d) { if (d) free(d); d = NULL; } extern int democlientnum; void otherplayers() { loopv(players) if (players[i]) { const int lagtime = lastmillis - players[i]->lastupdate; if (lagtime > 1000 && players[i]->state == CS_ALIVE) { players[i]->state = CS_LAGGED; continue; }; if (lagtime && players[i]->state != CS_DEAD && (!demoplayback || i != democlientnum)) moveplayer( players[i], 2, false); // use physics to extrapolate // player position } } void respawn() { if (player1->state == CS_DEAD) { player1->attacking = false; if (m_arena) { |
︙ | ︙ | |||
264 265 266 267 268 269 270 | if (!demoplayback) { monsterthink(); if (player1->state == CS_DEAD) { if (lastmillis - player1->lastaction < 2000) { player1->move = player1->strafe = 0; moveplayer(player1, 10, false); } else if (!m_arena && !m_sp && | | < | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 | if (!demoplayback) { monsterthink(); if (player1->state == CS_DEAD) { if (lastmillis - player1->lastaction < 2000) { player1->move = player1->strafe = 0; moveplayer(player1, 10, false); } else if (!m_arena && !m_sp && lastmillis - player1->lastaction > 10000) respawn(); } else if (!intermission) { moveplayer(player1, 20, true); checkitems(); }; c2sinfo(player1); // do this last, to reduce the // effective frame lag |
︙ | ︙ | |||
296 297 298 299 300 301 302 | return; d->o.x -= dx; d->o.y -= dy; } conoutf(@"can't find entity spawn spot! (%d, %d)", (int)d->o.x, (int)d->o.y); // leave ent at original pos, possibly stuck | < > | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | return; d->o.x -= dx; d->o.y -= dy; } conoutf(@"can't find entity spawn spot! (%d, %d)", (int)d->o.x, (int)d->o.y); // leave ent at original pos, possibly stuck } int spawncycle = -1; int fixspawn = 2; void spawnplayer(dynent *d) // place at random spawn. also used by monsters! { |
︙ | ︙ | |||
320 321 322 323 324 325 326 | } else { d->o.x = d->o.y = (float)ssize / 2; d->o.z = 4; }; entinmap(d); spawnstate(d); d->state = CS_ALIVE; | < > | | | | | | < > < > < > | 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 | } else { d->o.x = d->o.y = (float)ssize / 2; d->o.z = 4; }; entinmap(d); spawnstate(d); d->state = CS_ALIVE; } // movement input code #define dir(name, v, d, s, os) \ void name(bool isdown) \ { \ player1->s = isdown; \ player1->v = isdown ? d : (player1->os ? -(d) : 0); \ player1->lastmove = lastmillis; \ } dir(backward, move, -1, k_down, k_up); dir(forward, move, 1, k_up, k_down); dir(left, strafe, 1, k_left, k_right); dir(right, strafe, -1, k_right, k_left); void attack(bool on) { if (intermission) return; if (editmode) editdrag(on); else if (player1->attacking = on) respawn(); } void jumpn(bool on) { if (!intermission && (player1->jumpnext = on)) respawn(); } COMMAND(backward, ARG_DOWN) COMMAND(forward, ARG_DOWN) COMMAND(left, ARG_DOWN) COMMAND(right, ARG_DOWN) COMMANDN(jump, jumpn, ARG_DOWN) COMMAND(attack, ARG_DOWN) |
︙ | ︙ | |||
375 376 377 378 379 380 381 | player1->pitch = MAXPITCH; if (player1->pitch < -MAXPITCH) player1->pitch = -MAXPITCH; while (player1->yaw < 0.0f) player1->yaw += 360.0f; while (player1->yaw >= 360.0f) player1->yaw -= 360.0f; | < > | < < > | | < | | | | | | | 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 | player1->pitch = MAXPITCH; if (player1->pitch < -MAXPITCH) player1->pitch = -MAXPITCH; while (player1->yaw < 0.0f) player1->yaw += 360.0f; while (player1->yaw >= 360.0f) player1->yaw -= 360.0f; } void mousemove(int dx, int dy) { if (player1->state == CS_DEAD || intermission) return; const float SENSF = 33.0f; // try match quake sens player1->yaw += (dx / SENSF) * (sensitivity / (float)sensitivityscale); player1->pitch -= (dy / SENSF) * (sensitivity / (float)sensitivityscale) * (invmouse ? -1 : 1); fixplayer1range(); } // damage arriving from the network, monsters, yourself, all ends up here. void selfdamage(int damage, int actor, dynent *act) { if (player1->state != CS_ALIVE || editmode || intermission) return; damageblend(damage); demoblend(damage); int ad = damage * (player1->armourtype + 1) * 20 / 100; // let armour absorb when possible if (ad > player1->armour) ad = player1->armour; player1->armour -= ad; damage -= ad; float droll = damage / 0.5f; player1->roll += player1->roll > 0 ? droll : (player1->roll < 0 ? -droll : (rnd(2) ? droll : -droll)); // give player a kick depending // on amount of damage if ((player1->health -= damage) <= 0) { if (actor == -2) { conoutf(@"you got killed by %s!", act->name); } else if (actor == -1) { actor = getclientnum(); conoutf(@"you suicided!"); addmsg(1, 2, SV_FRAGS, --player1->frags); |
︙ | ︙ |
Modified src/clients2c.mm
from [a511b2eec3]
to [15295b6bce].
︙ | ︙ | |||
48 49 50 51 52 53 54 | d->o.x += dx < 0 ? r - fx : -(r - fx); }; int lagtime = lastmillis - d->lastupdate; if (lagtime) { d->plag = (d->plag * 5 + lagtime) / 6; d->lastupdate = lastmillis; }; | < > | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | d->o.x += dx < 0 ? r - fx : -(r - fx); }; int lagtime = lastmillis - d->lastupdate; if (lagtime) { d->plag = (d->plag * 5 + lagtime) / 6; d->lastupdate = lastmillis; }; } void localservertoclient( uchar *buf, int len) // processes any updates from the server { if (ENET_NET_TO_HOST_16(*(ushort *)buf) != len) neterr(@"packet length"); |
︙ | ︙ |
Modified src/console.mm
from [de4b6af5c1]
to [54ce1aa50b].
︙ | ︙ | |||
74 75 76 77 78 79 80 | } void renderconsole() // render buffer taking into account time & scrolling { int nd = 0; char *refs[ndraw]; | | > | | < | | | > | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | } void renderconsole() // render buffer taking into account time & scrolling { int nd = 0; char *refs[ndraw]; loopv(conlines) { if (conskip ? i >= conskip - 1 || i >= conlines.length() - ndraw : lastmillis - conlines[i].outtime < 20000) { refs[nd++] = conlines[i].cref; if (nd == ndraw) break; } } @autoreleasepool { loopj(nd) { draw_text(@(refs[j]), FONTH / 3, (FONTH / 4 * 5) * (nd - j - 1) + FONTH / 3, 2); } |
︙ | ︙ |
Modified src/cube.h
from [d285e7fbb6]
to [4e3991eb16].
1 2 3 4 5 6 7 8 9 10 | // one big bad include file for the whole engine... nasty! #import <ObjFW/ObjFW.h> #define gamma gamma__ #include <SDL2/SDL.h> #undef gamma #include "tools.h" | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // one big bad include file for the whole engine... nasty! #import <ObjFW/ObjFW.h> #define gamma gamma__ #include <SDL2/SDL.h> #undef gamma #include "tools.h" @interface Cube: OFObject <OFApplicationDelegate> @property (class, readonly, nonatomic) Cube *sharedInstance; @property (readonly, nonatomic) SDL_Window *window; @property (readonly, nonatomic) OFIRI *gameDataIRI, *userDataIRI; @property (nonatomic) bool repeatsKeys; @property (nonatomic) int framesInMap; @end |
︙ | ︙ | |||
76 77 78 79 80 81 82 | { short x, y, z; // cube aligned position short attr1; uchar type; // type is one of the above uchar attr2, attr3, attr4; }; | | | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | { short x, y, z; // cube aligned position short attr1; uchar type; // type is one of the above uchar attr2, attr3, attr4; }; struct entity: public persistent_entity { bool spawned; // the only dynamic state of a map entity }; #define MAPVERSION 5 // bump if map format changes, see worldio.cpp struct header // map file format header { |
︙ | ︙ | |||
103 104 105 106 107 108 109 | #define SW(w, x, y) SWS(w, x, y, ssize) #define S(x, y) SW(world, x, y) // convenient lookup of a lowest mip cube #define SMALLEST_FACTOR 6 // determines number of mips there can be #define DEFAULT_FACTOR 8 #define LARGEST_FACTOR 11 // 10 is already insane #define SOLID(x) ((x)->type == SOLID) #define MINBORD 2 // 2 cubes from the edge of the world are always solid | | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | #define SW(w, x, y) SWS(w, x, y, ssize) #define S(x, y) SW(world, x, y) // convenient lookup of a lowest mip cube #define SMALLEST_FACTOR 6 // determines number of mips there can be #define DEFAULT_FACTOR 8 #define LARGEST_FACTOR 11 // 10 is already insane #define SOLID(x) ((x)->type == SOLID) #define MINBORD 2 // 2 cubes from the edge of the world are always solid #define OUTBORD(x, y) \ ((x) < MINBORD || (y) < MINBORD || (x) >= ssize - MINBORD || \ (y) >= ssize - MINBORD) struct block { int x, y, xs, ys; }; enum { |
︙ | ︙ | |||
157 158 159 160 161 162 163 | int trigger; // millis at which transition to another monsterstate takes // place OFVector3D attacktarget; // delayed attacks int anger; // how many times already hit by fellow monster string name, team; }; | | | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | int trigger; // millis at which transition to another monsterstate takes // place OFVector3D attacktarget; // delayed attacks int anger; // how many times already hit by fellow monster string name, team; }; #define SAVEGAMEVERSION \ 4 // bump if dynent/netprotocol changes or any other savegame/demo data enum { A_BLUE, A_GREEN, A_YELLOW }; // armour types... take 20/40/60 % off enum { M_NONE = 0, M_SEARCH, M_HOME, |
︙ | ︙ | |||
312 313 314 315 316 317 318 | #define PIXELTAB (VIRTW / 12) #define PI (3.1415927f) #define PI2 (2 * PI) // simplistic vector ops #define dotprod(u, v) ((u).x * (v).x + (u).y * (v).y + (u).z * (v).z) | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | #define PIXELTAB (VIRTW / 12) #define PI (3.1415927f) #define PI2 (2 * PI) // simplistic vector ops #define dotprod(u, v) ((u).x * (v).x + (u).y * (v).y + (u).z * (v).z) #define vmul(u, f) \ { \ (u).x *= (f); \ (u).y *= (f); \ (u).z *= (f); \ } #define vdiv(u, f) \ { \ (u).x /= (f); \ (u).y /= (f); \ (u).z /= (f); \ } #define vadd(u, v) \ { \ (u).x += (v).x; \ (u).y += (v).y; \ (u).z += (v).z; \ }; #define vsub(u, v) \ { \ (u).x -= (v).x; \ (u).y -= (v).y; \ (u).z -= (v).z; \ }; #define vdist(d, v, e, s) \ OFVector3D v = s; \ vsub(v, e); \ float d = (float)sqrt(dotprod(v, v)); #define vreject(v, u, max) \ ((v).x > (u).x + (max) || (v).x < (u).x - (max) || \ (v).y > (u).y + (max) || (v).y < (u).y - (max)) #define vlinterp(v, f, u, g) \ { \ (v).x = (v).x * f + (u).x * g; \ (v).y = (v).y * f + (u).y * g; \ (v).z = (v).z * f + (u).z * g; \ } #define sgetstr() \ { \ char *t = text; \ do { \ *t = getint(p); \ } while (*t++); \ } // used by networking #define m_noitems (gamemode >= 4) #define m_noitemsrail (gamemode <= 5) #define m_arena (gamemode >= 8) #define m_tarena (gamemode >= 10) #define m_teammode (gamemode & 1 && gamemode > 2) |
︙ | ︙ | |||
390 391 392 393 394 395 396 | ARG_1EST, ARG_2EST, ARG_VARI }; // nasty macros for registering script functions, abuses globals to avoid // excessive infrastructure | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 | ARG_1EST, ARG_2EST, ARG_VARI }; // nasty macros for registering script functions, abuses globals to avoid // excessive infrastructure #define COMMANDN(name, fun, nargs) \ OF_CONSTRUCTOR() \ { \ enqueueInit(^{ \ addcommand(@ #name, (void (*)())fun, nargs); \ }); \ } #define COMMAND(name, nargs) COMMANDN(name, name, nargs) #define VARP(name, min, cur, max) \ int name; \ OF_CONSTRUCTOR() \ { \ enqueueInit(^{ \ name = variable( \ @ #name, min, cur, max, &name, NULL, true); \ }); \ } #define VAR(name, min, cur, max) \ int name; \ OF_CONSTRUCTOR() \ { \ enqueueInit(^{ \ name = variable( \ @ #name, min, cur, max, &name, NULL, false); \ }); \ } #define VARF(name, min, cur, max, body) \ void var_##name(); \ static int name; \ OF_CONSTRUCTOR() \ { \ enqueueInit(^{ \ name = variable( \ @ #name, min, cur, max, &name, var_##name, false); \ }); \ } \ void var_##name() { body; } #define VARFP(name, min, cur, max, body) \ void var_##name(); \ static int name; \ OF_CONSTRUCTOR() \ { \ enqueueInit(^{ \ name = variable( \ @ #name, min, cur, max, &name, var_##name, true); \ }); \ } \ void var_##name() { body; } #define ATOI(s) strtol(s, NULL, 0) // supports hexadecimal numbers #ifdef WIN32 # define WIN32_LEAN_AND_MEAN # include "windows.h" |
︙ | ︙ |
Modified src/editing.mm
from [e060139dd3]
to [f5920b6aeb].
︙ | ︙ | |||
22 23 24 25 26 27 28 | }; }); } int selh = 0; bool selset = false; | | | | | | | | | | | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | }; }); } int selh = 0; bool selset = false; #define loopselxy(b) \ { \ makeundo(); \ loop(x, sel.xs) loop(y, sel.ys) \ { \ sqr *s = S(sel.x + x, sel.y + y); \ b; \ } \ remip(sel); \ } int cx, cy, ch; int curedittex[] = {-1, -1, -1}; bool dragging = false; |
︙ | ︙ | |||
82 83 84 85 86 87 88 | int bsize = ssize - MINBORD; if (sel.xs + sel.x > bsize) sel.xs = bsize - sel.x; if (sel.ys + sel.y > bsize) sel.ys = bsize - sel.y; if (sel.xs <= 0 || sel.ys <= 0) selset = false; | < > | | | | | | < > < > | < | < < > | 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 | int bsize = ssize - MINBORD; if (sel.xs + sel.x > bsize) sel.xs = bsize - sel.x; if (sel.ys + sel.y > bsize) sel.ys = bsize - sel.y; if (sel.xs <= 0 || sel.ys <= 0) selset = false; } bool noteditmode() { correctsel(); if (!editmode) conoutf(@"this function is only allowed in edit mode"); return !editmode; } bool noselection() { if (!selset) conoutf(@"no selection"); return !selset; } #define EDITSEL \ if (noteditmode() || noselection()) \ return; #define EDITSELMP \ if (noteditmode() || noselection() || multiplayer()) \ return; #define EDITMP \ if (noteditmode() || multiplayer()) \ return; void selectpos(int x, int y, int xs, int ys) { block s = {x, y, xs, ys}; sel = s; selh = 0; correctsel(); } void makesel() { block s = {min(lastx, cx), min(lasty, cy), abs(lastx - cx) + 1, abs(lasty - cy) + 1}; sel = s; selh = max(lasth, ch); correctsel(); if (selset) rtex = *S(sel.x, sel.y); } VAR(flrceil, 0, 0, 2); float sheight( sqr *s, sqr *t, float z) // finds out z height when cursor points at wall { return !flrceil // z-s->floor<s->ceil-z ? (s->type == FHF ? s->floor - t->vdelta / 4.0f : (float)s->floor) : (s->type == CHF ? s->ceil + t->vdelta / 4.0f : (float)s->ceil); } void cursorupdate() // called every frame from hud { flrceil = ((int)(player1->pitch >= 0)) * 2; volatile float x = |
︙ | ︙ | |||
231 232 233 234 235 236 237 | ch = (int)ih; }; if (selset) { linestyle(GRIDS, 0xFF, 0x40, 0x40); box(sel, (float)selh, (float)selh, (float)selh, (float)selh); }; | < > < < > > < > | 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 | ch = (int)ih; }; if (selset) { linestyle(GRIDS, 0xFF, 0x40, 0x40); box(sel, (float)selh, (float)selh, (float)selh, (float)selh); }; } vector<block *> undos; // unlimited undo VARP(undomegs, 0, 1, 10); // bounded by n megs void pruneundos(int maxremain) // bound memory { int t = 0; loopvrev(undos) { t += undos[i]->xs * undos[i]->ys * sizeof(sqr); if (t > maxremain) free(undos.remove(i)); } } void makeundo() { undos.add(blockcopy(sel)); pruneundos(undomegs << 20); } void editundo() { EDITMP; if (undos.empty()) { conoutf(@"nothing more to undo"); |
︙ | ︙ | |||
277 278 279 280 281 282 283 | void copy() { EDITSELMP; if (copybuf) free(copybuf); copybuf = blockcopy(sel); | < > | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | void copy() { EDITSELMP; if (copybuf) free(copybuf); copybuf = blockcopy(sel); } void paste() { EDITMP; if (!copybuf) { conoutf(@"nothing to paste"); |
︙ | ︙ | |||
315 316 317 318 319 320 321 | uchar *p = hdr.texlists[i]; int t = p[c]; for (int a = c - 1; a >= 0; a--) p[a + 1] = p[a]; p[0] = t; curedittex[i] = -1; }; | < < > > < > < > | 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 | uchar *p = hdr.texlists[i]; int t = p[c]; for (int a = c - 1; a >= 0; a--) p[a + 1] = p[a]; p[0] = t; curedittex[i] = -1; }; } } void editdrag(bool isdown) { if (dragging = isdown) { lastx = cx; lasty = cy; lasth = ch; selset = false; tofronttex(); }; makesel(); } // the core editing function. all the *xy functions perform the core operations // and are also called directly from the network, the function below it is // strictly triggered locally. They all have very similar structure. void editheightxy(bool isfloor, int amount, block &sel) { loopselxy( if (isfloor) { s->floor += amount; if (s->floor >= s->ceil) s->floor = s->ceil - 1; } else { s->ceil += amount; if (s->ceil <= s->floor) s->ceil = s->floor + 1; }); } void editheight(int flr, int amount) { EDITSEL; bool isfloor = flr == 0; editheightxy(isfloor, amount, sel); |
︙ | ︙ | |||
377 378 379 380 381 382 383 | case 2: s->ctex = t; break; case 3: s->utex = t; break; }); | < > < > | 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 | case 2: s->ctex = t; break; case 3: s->utex = t; break; }); } void edittex(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); } void replace() { EDITSELMP; loop(x, ssize) loop(y, ssize) { |
︙ | ︙ | |||
423 424 425 426 427 428 429 | s->ctex = lasttex; break; case 3: if (s->utex == rtex.utex) s->utex = lasttex; break; }; | < > < > < > | 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | s->ctex = lasttex; break; case 3: if (s->utex == rtex.utex) s->utex = lasttex; break; }; } block b = {0, 0, ssize, ssize}; remip(b); } void edittypexy(int type, block &sel) { loopselxy(s->type = type); } void edittype(int type) { EDITSEL; if (type == CORNER && (sel.xs != sel.ys || sel.xs == 3 || sel.xs > 4 && sel.xs != 8 || |
︙ | ︙ | |||
487 488 489 490 491 492 493 | if (isfloor) s->floor = low; else s->ceil = hi; if (s->floor >= s->ceil) s->floor = s->ceil - 1; }); | < > < > < > < > < | | | | | < > < > < > < > | 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 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 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 | if (isfloor) s->floor = low; else s->ceil = hi; if (s->floor >= s->ceil) s->floor = s->ceil - 1; }); } void equalize(int flr) { bool isfloor = flr == 0; EDITSEL; editequalisexy(isfloor, sel); addmsg(1, 6, SV_EDITE, sel.x, sel.y, sel.xs, sel.ys, isfloor); } COMMAND(equalize, ARG_1INT) void setvdeltaxy(int delta, block &sel) { loopselxy(s->vdelta = max(s->vdelta + delta, 0)); remipmore(sel); } void setvdelta(int delta) { EDITSEL; setvdeltaxy(delta, sel); addmsg(1, 6, SV_EDITD, sel.x, sel.y, sel.xs, sel.ys, delta); } const int MAXARCHVERT = 50; int archverts[MAXARCHVERT][MAXARCHVERT]; bool archvinit = false; void archvertex(int span, int vert, int delta) { if (!archvinit) { archvinit = true; loop(s, MAXARCHVERT) loop(v, MAXARCHVERT) archverts[s][v] = 0; }; if (span >= MAXARCHVERT || vert >= MAXARCHVERT || span < 0 || vert < 0) return; archverts[span][vert] = delta; } void arch(int sidedelta, int _a) { EDITSELMP; sel.xs++; sel.ys++; if (sel.xs > MAXARCHVERT) sel.xs = MAXARCHVERT; if (sel.ys > MAXARCHVERT) sel.ys = MAXARCHVERT; loopselxy(s->vdelta = sel.xs > sel.ys ? (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); } void slope(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++; loopselxy(s->vdelta = xd * x + yd * y + off); remipmore(sel); } void perlin(int scale, int seed, int psize) { EDITSELMP; sel.xs++; sel.ys++; makeundo(); sel.xs--; sel.ys--; perlinarea(sel, scale, seed, psize); sel.xs++; sel.ys++; remipmore(sel); sel.xs--; sel.ys--; } VARF( fullbright, 0, 0, 1, if (fullbright) { if (noteditmode()) return; loopi(mipsize) world[i].r = world[i].g = world[i].b = 176; };); void edittag(int tag) { EDITSELMP; loopselxy(s->tag = tag); } void newent(OFString *what, OFString *a1, OFString *a2, OFString *a3, OFString *a4) { EDITSEL; @autoreleasepool { newentity(sel.x, sel.y, (int)player1->o.z, what, |
︙ | ︙ |
Modified src/entities.mm
from [8e9438e362]
to [6e39a8fac1].
︙ | ︙ | |||
23 24 25 26 27 28 29 | void renderent(entity &e, OFString *mdlname, float z, float yaw, int frame = 0, int numf = 1, int basetime = 0, float speed = 10.0f) { rendermodel(mdlname, frame, numf, 0, 1.1f, e.x, z + S(e.x, e.y)->floor, e.y, yaw, 0, false, 1.0f, speed, 0, basetime); | < > | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | void renderent(entity &e, OFString *mdlname, float z, float yaw, int frame = 0, int numf = 1, int basetime = 0, float speed = 10.0f) { rendermodel(mdlname, frame, numf, 0, 1.1f, e.x, z + S(e.x, e.y)->floor, e.y, yaw, 0, false, 1.0f, speed, 0, basetime); } void renderentities() { if (lastmillis > triggertime + 1000) triggertime = 0; loopv(ents) |
︙ | ︙ | |||
55 56 57 58 59 60 61 | continue; if (e.type != CARROT) { if (!e.spawned && e.type != TELEPORT) continue; if (e.type < I_SHELLS || e.type > TELEPORT) continue; renderent(e, entmdlnames[e.type - I_SHELLS], | | | | > | | | | 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 | continue; if (e.type != CARROT) { if (!e.spawned && e.type != TELEPORT) continue; if (e.type < I_SHELLS || e.type > TELEPORT) continue; renderent(e, entmdlnames[e.type - I_SHELLS], (float)(1 + sin(lastmillis / 100.0 + e.x + e.y) / 20), lastmillis / 10.0f); } else switch (e.attr2) { case 1: case 3: continue; case 2: case 0: if (!e.spawned) continue; renderent(e, @"carrot", (float)(1 + sin(lastmillis / 100.0 + e.x + e.y) / 20), lastmillis / (e.attr2 ? 1.0f : 10.0f)); break; case 4: renderent(e, @"switch2", 3, (float)e.attr3 * 90, |
︙ | ︙ | |||
96 97 98 99 100 101 102 | : 0, (e.spawned || !triggertime) ? 1 : 30, triggertime, 35.0f); break; }; }; | < < > > | 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | : 0, (e.spawned || !triggertime) ? 1 : 30, triggertime, 35.0f); break; }; }; } } struct itemstat { int add, max, sound; } itemstats[] = { 10, 50, S_ITEMAMMO, |
︙ | ︙ | |||
135 136 137 138 139 140 141 | S_ITEMPUP, }; void baseammo(int gun) { player1->ammo[gun] = itemstats[gun - 1].add * 2; | < > < > | 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 | S_ITEMPUP, }; void baseammo(int gun) { player1->ammo[gun] = itemstats[gun - 1].add * 2; } // these two functions are called when the server acknowledges that you really // picked up the item (in multiplayer someone may grab it before you). void radditem(int i, int &v) { itemstat &is = itemstats[ents[i].type - I_SHELLS]; ents[i].spawned = false; v += is.add; if (v > is.max) v = is.max; playsoundc(is.sound); } void realpickup(int n, dynent *d) { switch (ents[n].type) { case I_SHELLS: radditem(n, d->ammo[1]); |
︙ | ︙ | |||
230 231 232 233 234 235 236 | d->pitch = 0; d->vel.x = d->vel.y = d->vel.z = 0; entinmap(d); playsoundc(S_TELEPORT); break; }; }; | < > | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | d->pitch = 0; d->vel.x = d->vel.y = d->vel.z = 0; entinmap(d); playsoundc(S_TELEPORT); break; }; }; } void pickup(int n, dynent *d) { int np = 1; loopv(players) if (players[i]) np++; np = np < 3 ? 4 : (np > 4 ? 2 : 3); // spawn times are dependent on |
︙ | ︙ | |||
342 343 344 345 346 347 348 | } } void putitems(uchar *&p) // puts items in network stream and also spawns them locally { loopv(ents) if ((ents[i].type >= I_SHELLS && ents[i].type <= I_QUAD) || | | < > < > | 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 | } } void putitems(uchar *&p) // puts items in network stream and also spawns them locally { loopv(ents) if ((ents[i].type >= I_SHELLS && ents[i].type <= I_QUAD) || ents[i].type == CARROT) { putint(p, i); ents[i].spawned = true; } } void resetspawns() { loopv(ents) ents[i].spawned = false; } void setspawn(uint i, bool on) { if (i < (uint)ents.length()) ents[i].spawned = on; } |
Modified src/monster.mm
from [6306bf3f2c]
to [9d16bae907].
︙ | ︙ | |||
80 81 82 83 84 85 86 | m->state = CS_ALIVE; m->anger = 0; @autoreleasepool { strcpy_s(m->name, t->name.UTF8String); } monsters.add(m); return m; | < > < > | 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 | m->state = CS_ALIVE; m->anger = 0; @autoreleasepool { strcpy_s(m->name, t->name.UTF8String); } monsters.add(m); return m; } void spawnmonster() // spawn a random monster according to freq distribution in DMSP { int n = rnd(TOTMFREQ), type; for (int i = 0;; i++) if ((n -= monstertypes[i].freq) < 0) { type = i; break; }; basicmonster(type, rnd(360), M_SEARCH, 1000, 1); } void monsterclear() // called after map start of when toggling edit mode to // reset/spawn all monsters to initial state { loopv(monsters) free(monsters[i]); monsters.setsize(0); |
︙ | ︙ | |||
117 118 119 120 121 122 123 | dynent *m = basicmonster( ents[i].attr2, ents[i].attr1, M_SLEEP, 100, 0); m->o.x = ents[i].x; m->o.y = ents[i].y; m->o.z = ents[i].z; entinmap(m); monstertotal++; | > | < < > | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | dynent *m = basicmonster( ents[i].attr2, ents[i].attr1, M_SLEEP, 100, 0); m->o.x = ents[i].x; m->o.y = ents[i].y; m->o.z = ents[i].z; entinmap(m); monstertotal++; } }; } bool los(float lx, float ly, float lz, float bx, float by, float bz, OFVector3D &v) // height-correct line of sight for monster shooting/seeing { if (OUTBORD((int)lx, (int)ly) || OUTBORD((int)bx, (int)by)) return false; |
︙ | ︙ | |||
156 157 158 159 160 161 162 | v.y = y; v.z = rz; x += dx / (float)steps; y += dy / (float)steps; i++; }; return i >= steps; | < > < > < > < > | 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 | v.y = y; v.z = rz; x += dx / (float)steps; y += dy / (float)steps; i++; }; return i >= steps; } bool enemylos(dynent *m, OFVector3D &v) { v = m->o; return los(m->o.x, m->o.y, m->o.z, m->enemy->o.x, m->enemy->o.y, m->enemy->o.z, v); } // monster AI is sequenced using transitions: they are in a particular state // 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. void transition(dynent *m, int state, int moving, int n, int r) // n = at skill 0, n/2 = at skill 10, r = added random factor { m->monsterstate = state; m->move = moving; n = n * 130 / 100; m->trigger = lastmillis + n - skill * (n / 16) + rnd(r + 1); } void normalise(dynent *m, float angle) { while (m->yaw < angle - 180.0f) m->yaw += 360.0f; while (m->yaw > angle + 180.0f) m->yaw -= 360.0f; } void monsteraction( dynent *m) // main AI thinking routine, called every frame for every monster { if (m->enemy->state == CS_DEAD) { m->enemy = player1; |
︙ | ︙ | |||
219 220 221 222 223 224 225 | vdist(disttoenemy, vectoenemy, m->o, m->enemy->o); m->pitch = atan2(m->enemy->o.z - m->o.z, disttoenemy) * 180 / PI; if (m->blocked) // special case: if we run into scenery { m->blocked = false; if (!rnd(20000 / | | | | | | 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | vdist(disttoenemy, vectoenemy, m->o, m->enemy->o); m->pitch = atan2(m->enemy->o.z - m->o.z, disttoenemy) * 180 / PI; if (m->blocked) // special case: if we run into scenery { m->blocked = false; if (!rnd(20000 / monstertypes[m->mtype] .speed)) // try to jump over obstackle (rare) { m->jumpnext = true; } else if (m->trigger < lastmillis && (m->monsterstate != M_HOME || !rnd(5))) // search for a way around (common) { m->targetyaw += 180 + rnd(180); // patented "random walk" AI // pathfinding (tm) ;) transition(m, M_SEARCH, 1, 400, 1000); }; }; |
︙ | ︙ | |||
308 309 310 311 312 313 314 | }; }; }; break; }; moveplayer(m, 1, false); // use physics to move monster | < > | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | }; }; }; break; }; moveplayer(m, 1, false); // use physics to move monster } void monsterpain(dynent *m, int damage, dynent *d) { if (d->monsterstate) // a monster hit us { if (m != d) // guard for RL guys shooting themselves :) |
︙ | ︙ | |||
343 344 345 346 347 348 349 | playsound(monstertypes[m->mtype].diesound, &m->o); int remain = monstertotal - numkilled; if (remain > 0 && remain <= 5) conoutf(@"only %d monster(s) remaining", remain); } else { playsound(monstertypes[m->mtype].painsound, &m->o); } | < > | 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 | playsound(monstertypes[m->mtype].diesound, &m->o); int remain = monstertotal - numkilled; if (remain > 0 && remain <= 5) conoutf(@"only %d monster(s) remaining", remain); } else { playsound(monstertypes[m->mtype].painsound, &m->o); } } void endsp(bool allkilled) { conoutf(allkilled ? @"you have cleared the map!" : @"you reached the exit!"); conoutf(@"score: %d kills in %d seconds", numkilled, |
︙ | ︙ | |||
393 394 395 396 397 398 399 | else { v.z += monsters[i]->eyeheight; vdist(dist, t, monsters[i]->o, v); v.z -= monsters[i]->eyeheight; if (dist < 4) teleport((int)(&e - &ents[0]), monsters[i]); | < < > > | 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 | else { v.z += monsters[i]->eyeheight; vdist(dist, t, monsters[i]->o, v); v.z -= monsters[i]->eyeheight; if (dist < 4) teleport((int)(&e - &ents[0]), monsters[i]); } } loopv(monsters) if (monsters[i]->state == CS_ALIVE) monsteraction(monsters[i]); } void monsterrender() { loopv(monsters) renderclient(monsters[i], false, monstertypes[monsters[i]->mtype].mdlname, monsters[i]->mtype == 5, monstertypes[monsters[i]->mtype].mscale / 10.0f); } |
Modified src/physics.mm
from [33d03da6be]
to [5d3f7bf679].
︙ | ︙ | |||
27 28 29 30 31 32 33 | if (d->monsterstate) return false; // hack headspace = d->o.z - o->o.z - o->aboveeye - d->eyeheight; if (headspace < 0) headspace = 10; }; return true; | < > < > | 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 | if (d->monsterstate) return false; // hack headspace = d->o.z - o->o.z - o->aboveeye - d->eyeheight; if (headspace < 0) headspace = 10; }; return true; } bool cornertest(int mip, int x, int y, int dx, int dy, int &bx, int &by, int &bs) // recursively collide with a mipmapped corner cube { sqr *w = wmip[mip]; int sz = ssize >> mip; bool stest = SOLID(SWS(w, x + dx, y, sz)) && SOLID(SWS(w, x, y + dy, sz)); mip++; x /= 2; y /= 2; if (SWS(wmip[mip], x, y, ssize >> mip)->type == CORNER) { bx = x << mip; by = y << mip; bs = 1 << mip; return cornertest(mip, x, y, dx, dy, bx, by, bs); }; return stest; } void mmcollide(dynent *d, float &hi, float &lo) // collide with a mapmodel { loopv(ents) { entity &e = ents[i]; |
︙ | ︙ | |||
93 94 95 96 97 98 99 | const float fy2 = d->o.y + d->radius; const int x1 = fast_f2nat(fx1); const int y1 = fast_f2nat(fy1); const int x2 = fast_f2nat(fx2); const int y2 = fast_f2nat(fy2); float hi = 127, lo = -128; float minfloor = (d->monsterstate && !spawn && d->health > 100) | | | | | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | const float fy2 = d->o.y + d->radius; const int x1 = fast_f2nat(fx1); const int y1 = fast_f2nat(fy1); const int x2 = fast_f2nat(fx2); const int y2 = fast_f2nat(fy2); float hi = 127, lo = -128; float minfloor = (d->monsterstate && !spawn && d->health > 100) ? d->o.z - d->eyeheight - 4.5f : -1000.0f; // big monsters are afraid of heights, // unless angry :) for (int x = x1; x <= x2; x++) for (int y = y1; y <= y2; y++) // collide with map { if (OUTBORD(x, y)) return false; sqr *s = S(x, y); |
︙ | ︙ | |||
135 136 137 138 139 140 141 | }; case FHF: // FIXME: too simplistic collision with // slopes, makes it feels like tiny stairs floor -= (s->vdelta + S(x + 1, y)->vdelta + S(x, y + 1)->vdelta + S(x + 1, y + 1)->vdelta) / | | | < > | | 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 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | }; case FHF: // FIXME: too simplistic collision with // slopes, makes it feels like tiny stairs floor -= (s->vdelta + S(x + 1, y)->vdelta + S(x, y + 1)->vdelta + S(x + 1, y + 1)->vdelta) / 16.0f; break; case CHF: ceil += (s->vdelta + S(x + 1, y)->vdelta + S(x, y + 1)->vdelta + S(x + 1, y + 1)->vdelta) / 16.0f; }; if (ceil < hi) hi = ceil; if (floor > lo) lo = floor; if (floor < minfloor) return false; }; if (hi - lo < d->eyeheight + d->aboveeye) return false; float headspace = 10; loopv(players) // collide with other players { dynent *o = players[i]; if (!o || o == d) continue; if (!plcollide(d, o, headspace, hi, lo)) return false; } if (d != player1) if (!plcollide(d, player1, headspace, hi, lo)) return false; dvector &v = getmonsters(); // this loop can be a performance bottleneck with many monster on a slow // cpu, should replace with a blockmap but seems mostly fast enough loopv(v) if (!vreject(d->o, v[i]->o, 7.0f) && d != v[i] && !plcollide(d, v[i], headspace, hi, lo)) return false; headspace -= 0.01f; mmcollide(d, hi, lo); // collide with map models if (spawn) { d->o.z = lo + d->eyeheight; // just drop to floor (sideeffect) d->onfloor = true; |
︙ | ︙ | |||
209 210 211 212 213 214 215 | return true; } float rad(float x) { return x * 3.14159f / 180; | < > < > | 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 | return true; } float rad(float x) { return x * 3.14159f / 180; } VARP(maxroll, 0, 3, 20); int physicsfraction = 0, physicsrepeat = 0; const int MINFRAMETIME = 20; // physics always simulated at 50fps or better void physicsframe() // optimally schedule physics frames inside the graphics frames { if (curtime >= MINFRAMETIME) { int faketime = curtime + physicsfraction; physicsrepeat = faketime / MINFRAMETIME; physicsfraction = faketime - physicsrepeat * MINFRAMETIME; } else { physicsrepeat = 1; }; } // main physics routine, moves a player/monster for a curtime step // moveres indicated the physics precision (which is lower for monsters and // multiplayer prediction) local is false for multiplayer prediction void moveplayer(dynent *pl, int moveres, bool local, int curtime) |
︙ | ︙ | |||
293 294 295 296 297 298 299 | }; // dampen velocity change even harder, gives // correct water feel if (local) playsoundc(S_JUMP); else if (pl->monsterstate) playsound(S_JUMP, &pl->o); } else if (pl->timeinair > | | | | < | < | | < | 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 | }; // dampen velocity change even harder, gives // correct water feel if (local) playsoundc(S_JUMP); else if (pl->monsterstate) playsound(S_JUMP, &pl->o); } 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->monsterstate) playsound(S_LAND, &pl->o); }; pl->timeinair = 0; } else { pl->timeinair += curtime; }; const float gravity = 20; const float f = 1.0f / moveres; float dropf = ((gravity - 1) + pl->timeinair / 15.0f); // incorrect, but works fine if (water) { dropf = 5; pl->timeinair = 0; }; // float slowly down in water const float drop = dropf * curtime / gravity / 100 / moveres; // at high fps, gravity kicks in too fast const float rise = speed / moveres / 1.2f; // extra smoothness when lifting up stairs loopi(moveres) // discrete steps collision detection & sliding { // try move forward pl->o.x += f * d.x; pl->o.y += f * d.y; |
︙ | ︙ | |||
355 356 357 358 359 360 361 | pl->o.y -= f * d.y; if (collide(pl, false, drop, rise)) { d.y = d.x = 0; continue; }; pl->o.z -= f * d.z; break; | < > | < | 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 | pl->o.y -= f * d.y; if (collide(pl, false, drop, rise)) { d.y = d.x = 0; continue; }; pl->o.z -= f * d.z; break; } }; // detect wether player is outside map, used for skipping zbuffer clear // mostly if (pl->o.x < 0 || pl->o.x >= ssize || pl->o.y < 0 || pl->o.y > ssize) { pl->outsidemap = true; } else { sqr *s = S((int)pl->o.x, (int)pl->o.y); pl->outsidemap = SOLID(s) || pl->o.z < s->floor - (s->type == FHF ? s->vdelta / 4 : 0) || pl->o.z > s->ceil + (s->type == CHF ? s->vdelta / 4 : 0); }; // automatically apply smooth roll when strafing if (pl->strafe == 0) { |
︙ | ︙ | |||
391 392 393 394 395 396 397 | if (!pl->inwater && water) { playsound(S_SPLASH2, &pl->o); pl->vel.z = 0; } else if (pl->inwater && !water) playsound(S_SPLASH1, &pl->o); pl->inwater = water; | < > < > | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 | if (!pl->inwater && water) { playsound(S_SPLASH2, &pl->o); pl->vel.z = 0; } else if (pl->inwater && !water) playsound(S_SPLASH1, &pl->o); pl->inwater = water; } void moveplayer(dynent *pl, int moveres, bool local) { loopi(physicsrepeat) moveplayer(pl, moveres, local, i ? curtime / physicsrepeat : curtime - curtime / physicsrepeat * (physicsrepeat - 1)); } |
Modified src/rendercubes.mm
from [3909c7f58d]
to [e0804e2cb2].
︙ | ︙ | |||
25 26 27 28 29 30 31 | setarraypointers(); } // generating the actual vertices is done dynamically every frame and sits at // the leaves of all these functions, and are part of the cpu bottleneck on // really slow machines, hence the macros. | | | | | | | | | | | | | | | | | | | | | 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 | setarraypointers(); } // generating the actual vertices is done dynamically every frame and sits at // the leaves of all these functions, and are part of the cpu bottleneck on // really slow machines, hence the macros. #define vertcheck() \ { \ if (curvert >= curmaxverts) \ reallocv(); \ } #define vertf(v1, v2, v3, ls, t1, t2) \ { \ vertex &v = verts[curvert++]; \ v.u = t1; \ v.v = t2; \ v.x = v1; \ v.y = v2; \ v.z = v3; \ v.r = ls->r; \ v.g = ls->g; \ v.b = ls->b; \ v.a = 255; \ }; #define vert(v1, v2, v3, ls, t1, t2) \ { \ vertf((float)(v1), (float)(v2), (float)(v3), ls, t1, t2); \ } int nquads; 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; |
︙ | ︙ | |||
72 73 74 75 76 77 78 | void mipstats(int a, int b, int c) { if (showm) conoutf(@"1x1/2x2/4x4: %d / %d / %d", a, b, c); } | | | | | | | < > | 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 | void mipstats(int a, int b, int c) { if (showm) conoutf(@"1x1/2x2/4x4: %d / %d / %d", a, b, c); } #define stripend() \ { \ if (floorstrip || deltastrip) { \ addstrip(ogltex, firstindex, curvert - firstindex); \ floorstrip = deltastrip = false; \ }; \ }; void finishstrips() { stripend(); } sqr sbright, sdark; VAR(lighterror, 1, 8, 100); void render_flat(int wtex, int x, int y, int size, int h, sqr *l1, sqr *l2, sqr *l3, sqr *l4, bool isceil) // floor/ceil quads |
︙ | ︙ | |||
108 109 110 111 112 113 114 | float yf = TEXTURESCALE / sy; float xs = size * xf; float ys = size * yf; float xo = xf * x; float yo = yf * y; bool first = !floorstrip || y != oy + size || ogltex != gltex || | | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | float yf = TEXTURESCALE / sy; float xs = size * xf; float ys = size * yf; float xo = xf * x; float yo = yf * y; bool first = !floorstrip || y != oy + size || ogltex != gltex || h != oh || x != ox; if (first) // start strip here { stripend(); firstindex = curvert; ogltex = gltex; oh = h; |
︙ | ︙ | |||
166 167 168 169 170 171 172 | } else { vert(x, h, y + size, l4, xo, yo + ys); vert(x + size, h, y + size, l3, xo + xs, yo + ys); }; oy = y; nquads++; | < > | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | } else { vert(x, h, y + size, l4, xo, yo + ys); vert(x + size, h, y + size, l3, xo + xs, yo + ys); }; oy = y; nquads++; } void render_flatdelta(int wtex, int x, int y, int size, float h1, float h2, float h3, float h4, sqr *l1, sqr *l2, sqr *l3, sqr *l4, bool isceil) // floor/ceil quads on a slope { vertcheck(); |
︙ | ︙ | |||
224 225 226 227 228 229 230 | vertf((float)x, h4, (float)y + size, l4, xo, yo + ys); vertf( (float)x + size, h3, (float)y + size, l3, xo + xs, yo + ys); }; oy = y; nquads++; | < > | 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | vertf((float)x, h4, (float)y + size, l4, xo, yo + ys); vertf( (float)x + size, h3, (float)y + size, l3, xo + xs, yo + ys); }; oy = y; nquads++; } void render_2tris(sqr *h, sqr *s, int x1, int y1, int x2, int y2, int x3, int y3, sqr *l1, sqr *l2, sqr *l3) // floor/ceil tris on a corner cube { stripend(); vertcheck(); |
︙ | ︙ | |||
252 253 254 255 256 257 258 | yf = TEXTURESCALE / sy; vertf((float)x3, h->ceil, (float)y3, l3, xf * x3, yf * y3); vertf((float)x2, h->ceil, (float)y2, l2, xf * x2, yf * y2); vertf((float)x1, h->ceil, (float)y1, l1, xf * x1, yf * y1); addstrip(gltex, curvert - 3, 3); nquads++; | < > < > | 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 | yf = TEXTURESCALE / sy; vertf((float)x3, h->ceil, (float)y3, l3, xf * x3, yf * y3); vertf((float)x2, h->ceil, (float)y2, l2, xf * x2, yf * y2); vertf((float)x1, h->ceil, (float)y1, l1, xf * x1, yf * y1); addstrip(gltex, curvert - 3, 3); nquads++; } void render_tris(int x, int y, int size, bool topleft, sqr *h1, sqr *h2, sqr *s, sqr *t, sqr *u, sqr *v) { if (topleft) { if (h1) render_2tris(h1, s, x + size, y + size, x, y + size, x, y, u, v, s); if (h2) render_2tris(h2, s, x, y, x + size, y, x + size, y + size, s, t, v); } else { if (h1) render_2tris( h1, s, x, y, x + size, y, x, y + size, s, t, u); if (h2) render_2tris(h2, s, x + size, y, x + size, y + size, x, y + size, t, u, v); }; } void render_square(int wtex, float floor1, float floor2, float ceil1, float ceil2, int x1, int y1, int x2, int y2, int size, sqr *l1, sqr *l2, bool flip) // wall quads { stripend(); |
︙ | ︙ | |||
308 309 310 311 312 313 314 | vertf((float)x2, ceil2, (float)y2, l2, xo + xs, -yf * ceil2); vertf((float)x1, floor1, (float)y1, l1, xo, -floor1 * yf); vertf((float)x2, floor2, (float)y2, l2, xo + xs, -floor2 * yf); }; nquads++; addstrip(gltex, curvert - 4, 4); | < > < > < > < > | 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 | vertf((float)x2, ceil2, (float)y2, l2, xo + xs, -yf * ceil2); vertf((float)x1, floor1, (float)y1, l1, xo, -floor1 * yf); vertf((float)x2, floor2, (float)y2, l2, xo + xs, -floor2 * yf); }; nquads++; addstrip(gltex, curvert - 4, 4); } int wx1, wy1, wx2, wy2; VAR(watersubdiv, 1, 4, 64); VARF(waterlevel, -128, -128, 127, if (!noteditmode()) hdr.waterlevel = waterlevel); inline void vertw(int v1, float v2, int v3, sqr *c, float t1, float t2, float t) { vertcheck(); vertf((float)v1, v2 - (float)sin(v1 * v3 * 0.1 + t) * 0.2f, (float)v3, c, t1, t2); } inline float dx(float x) { return x + (float)sin(x * 2 + lastmillis / 1000.0f) * 0.04f; } inline float dy(float x) { return x + (float)sin(x * 2 + lastmillis / 900.0f + PI / 5) * 0.05f; } // renders water for bounding rect area that contains water... simple but very // inefficient int renderwater(float hf) { |
︙ | ︙ | |||
387 388 389 390 391 392 393 | glDrawArrays(GL_TRIANGLE_STRIP, curvert -= n, n); }; glDisable(GL_BLEND); glDepthMask(GL_TRUE); return nquads; | < > | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | glDrawArrays(GL_TRIANGLE_STRIP, curvert -= n, n); }; glDisable(GL_BLEND); glDepthMask(GL_TRUE); return nquads; } void addwaterquad(int x, int y, int size) // update bounding rect that contains water { int x2 = x + size; int y2 = y + size; if (wx1 < 0) { |
︙ | ︙ | |||
409 410 411 412 413 414 415 | if (y < wy1) wy1 = y; if (x2 > wx2) wx2 = x2; if (y2 > wy2) wy2 = y2; }; | < > < > | 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | if (y < wy1) wy1 = y; if (x2 > wx2) wx2 = x2; if (y2 > wy2) wy2 = y2; }; } void resetcubes() { if (!verts) reallocv(); floorstrip = deltastrip = false; wx1 = -1; nquads = 0; sbright.r = sbright.g = sbright.b = 255; sdark.r = sdark.g = sdark.b = 0; } |
Modified src/renderextras.mm
from [2f71e0ae26]
to [0c686b4d39].
︙ | ︙ | |||
8 9 10 11 12 13 14 | glBegin(GL_POLYGON); glVertex3f((float)x1, z1, (float)y1); glVertex3f((float)x1, z1, y1 + 0.01f); glVertex3f((float)x2, z2, y2 + 0.01f); glVertex3f((float)x2, z2, (float)y2); glEnd(); xtraverts += 4; | < > < > < > < > | 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 | glBegin(GL_POLYGON); glVertex3f((float)x1, z1, (float)y1); glVertex3f((float)x1, z1, y1 + 0.01f); glVertex3f((float)x2, z2, y2 + 0.01f); glVertex3f((float)x2, z2, (float)y2); glEnd(); xtraverts += 4; } void linestyle(float width, int r, int g, int b) { glLineWidth(width); glColor3ub(r, g, b); } void box(block &b, float z1, float z2, float z3, float z4) { glBegin(GL_POLYGON); glVertex3f((float)b.x, z1, (float)b.y); glVertex3f((float)b.x + b.xs, z2, (float)b.y); glVertex3f((float)b.x + b.xs, z3, (float)b.y + b.ys); glVertex3f((float)b.x, z4, (float)b.y + b.ys); glEnd(); xtraverts += 4; } void dot(int x, int y, float z) { const float DOF = 0.1f; glBegin(GL_POLYGON); glVertex3f(x - DOF, (float)z, y - DOF); glVertex3f(x + DOF, (float)z, y - DOF); glVertex3f(x + DOF, (float)z, y + DOF); glVertex3f(x - DOF, (float)z, y + DOF); glEnd(); xtraverts += 4; } void 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); |
︙ | ︙ | |||
72 73 74 75 76 77 78 | glVertex2i(x1, y2); glEnd(); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); xtraverts += 8; glEnable(GL_BLEND); glEnable(GL_TEXTURE_2D); glDepthMask(GL_TRUE); | < > < > < > | 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 | glVertex2i(x1, y2); glEnd(); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); xtraverts += 8; glEnable(GL_BLEND); glEnable(GL_TEXTURE_2D); glDepthMask(GL_TRUE); } const int MAXSPHERES = 50; struct sphere { OFVector3D o; float size, max; int type; sphere *next; }; sphere spheres[MAXSPHERES], *slist = NULL, *sempty = NULL; bool sinit = false; void newsphere(OFVector3D &o, float max, int type) { if (!sinit) { loopi(MAXSPHERES) { spheres[i].next = sempty; sempty = &spheres[i]; } sinit = true; }; if (sempty) { sphere *p = sempty; sempty = p->next; p->o = o; p->max = max; p->size = 1; p->type = type; p->next = slist; slist = p; }; } void renderspheres(int time) { glDepthMask(GL_FALSE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); |
︙ | ︙ | |||
140 141 142 143 144 145 146 | p->size += time / 100.0f; pp = &p->next; }; }; glDisable(GL_BLEND); glDepthMask(GL_TRUE); | < > | 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | p->size += time / 100.0f; pp = &p->next; }; }; glDisable(GL_BLEND); glDepthMask(GL_TRUE); } string closeent; OFString *entnames[] = { @"none?", @"light", @"playerstart", @"shells", |
︙ | ︙ | |||
239 240 241 242 243 244 245 | void readmatrices() { glGetIntegerv(GL_VIEWPORT, viewport); glGetDoublev(GL_MODELVIEW_MATRIX, mm); glGetDoublev(GL_PROJECTION_MATRIX, pm); | < > < > | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | void readmatrices() { glGetIntegerv(GL_VIEWPORT, viewport); glGetDoublev(GL_MODELVIEW_MATRIX, mm); glGetDoublev(GL_PROJECTION_MATRIX, pm); } // stupid function to cater for stupid ATI linux drivers that return incorrect // depth values float depthcorrect(float d) { return (d <= 1 / 256.0f) ? d * 256 : d; } // find out the 3d target of the crosshair in the world easily and very // acurately. sadly many very old cards and drivers appear to fuck up on // glReadPixels() and give false coordinates, making shooting and such // impossible. also hits map entities which is unwanted. could be replaced by a // more acurate version of monster.cpp los() if needed |
︙ | ︙ | |||
270 271 272 273 274 275 276 | &worldx, &worldz, &worldy); worldpos.x = (float)worldx; worldpos.y = (float)worldy; worldpos.z = (float)worldz; OFVector3D r = OFMakeVector3D(mm[0], mm[4], mm[8]); OFVector3D u = OFMakeVector3D(mm[1], mm[5], mm[9]); setorient(r, u); | < > < > < > < > | 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 | &worldx, &worldz, &worldy); worldpos.x = (float)worldx; worldpos.y = (float)worldy; worldpos.z = (float)worldz; OFVector3D r = OFMakeVector3D(mm[0], mm[4], mm[8]); OFVector3D u = OFMakeVector3D(mm[1], mm[5], mm[9]); setorient(r, u); } void drawicon(float tx, float ty, int x, int y) { glBindTexture(GL_TEXTURE_2D, 5); glBegin(GL_QUADS); tx /= 192; ty /= 192; float o = 1 / 3.0f; int s = 120; glTexCoord2f(tx, ty); glVertex2i(x, y); glTexCoord2f(tx + o, ty); glVertex2i(x + s, y); glTexCoord2f(tx + o, ty + o); glVertex2i(x + s, y + s); glTexCoord2f(tx, ty + o); glVertex2i(x, y + s); glEnd(); xtraverts += 4; } void invertperspective() { // This only generates a valid inverse matrix for matrices generated by // gluPerspective() GLdouble inv[16]; memset(inv, 0, sizeof(inv)); inv[0 * 4 + 0] = 1.0 / pm[0 * 4 + 0]; inv[1 * 4 + 1] = 1.0 / pm[1 * 4 + 1]; inv[2 * 4 + 3] = 1.0 / pm[3 * 4 + 2]; inv[3 * 4 + 2] = -1.0; inv[3 * 4 + 3] = pm[2 * 4 + 2] / pm[3 * 4 + 2]; glLoadMatrixd(inv); } VARP(crosshairsize, 0, 15, 50); int dblend = 0; void damageblend(int n) { dblend += n; } VAR(hidestats, 0, 0, 1); VARP(crosshairfx, 0, 1, 1); void gl_drawhud(int w, int h, int curfps, int nquads, int curvert, bool underwater) { |
︙ | ︙ |
Modified src/rendergl.mm
from [7db200290d]
to [5b95ce281e].
︙ | ︙ | |||
59 60 61 62 63 64 65 | fatal(@"glu sphere"); gluQuadricDrawStyle(qsphere, GLU_FILL); gluQuadricOrientation(qsphere, GLU_INSIDE); gluQuadricTexture(qsphere, GL_TRUE); glNewList(1, GL_COMPILE); gluSphere(qsphere, 1, 12, 6); glEndList(); | < > | 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | fatal(@"glu sphere"); gluQuadricDrawStyle(qsphere, GLU_FILL); gluQuadricOrientation(qsphere, GLU_INSIDE); gluQuadricTexture(qsphere, GL_TRUE); glNewList(1, GL_COMPILE); gluSphere(qsphere, 1, 12, 6); glEndList(); } void cleangl() { if (qsphere) gluDeleteQuadric(qsphere); } |
︙ | ︙ | |||
170 171 172 173 174 175 176 | int mapping[256][MAXFRAMES]; // ( cube texture, frame ) -> ( opengl id, name ) string mapname[256][MAXFRAMES]; void purgetextures() { loopi(256) loop(j, MAXFRAMES) mapping[i][j] = 0; | < > | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | int mapping[256][MAXFRAMES]; // ( cube texture, frame ) -> ( opengl id, name ) string mapname[256][MAXFRAMES]; void purgetextures() { loopi(256) loop(j, MAXFRAMES) mapping[i][j] = 0; } int curtexnum = 0; void texturereset() { curtexnum = 0; |
︙ | ︙ | |||
261 262 263 264 265 266 267 | if (hasoverbright) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); }; | < > | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | if (hasoverbright) { glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); }; } int skyoglid; struct strip { int tex, start, num; }; vector<strip> strips; |
︙ | ︙ | |||
335 336 337 338 339 340 341 | glRotated(player1->pitch, -1.0, 0.0, 0.0); glRotated(player1->yaw, 0.0, 1.0, 0.0); glTranslated(-player1->o.x, (player1->state == CS_DEAD ? player1->eyeheight - 0.2f : 0) - player1->o.z, -player1->o.y); | < > | 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | glRotated(player1->pitch, -1.0, 0.0, 0.0); glRotated(player1->yaw, 0.0, 1.0, 0.0); glTranslated(-player1->o.x, (player1->state == CS_DEAD ? player1->eyeheight - 0.2f : 0) - player1->o.z, -player1->o.y); } VARP(fov, 10, 105, 120); int xtraverts; VAR(fog, 64, 180, 1024); VAR(fogcolour, 0, 0x8099B3, 0xFFFFFF); |
︙ | ︙ | |||
386 387 388 389 390 391 392 | glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(fovy, aspect, 0.15f, farplane); glMatrixMode(GL_MODELVIEW); glDisable(GL_CULL_FACE); | < > | 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(fovy, aspect, 0.15f, farplane); glMatrixMode(GL_MODELVIEW); glDisable(GL_CULL_FACE); } void gl_drawframe(int w, int h, float curfps) { float hf = hdr.waterlevel - 0.3f; float fovy = (float)fov * h / w; float aspect = w / (float)h; |
︙ | ︙ | |||
412 413 414 415 416 417 418 | fovy += (float)sin(lastmillis / 1000.0) * 2.0f; aspect += (float)sin(lastmillis / 1000.0 + PI) * 0.1f; glFogi(GL_FOG_START, 0); glFogi(GL_FOG_END, (fog + 96) / 8); }; glClear((player1->outsidemap ? GL_COLOR_BUFFER_BIT : 0) | | | | 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 | fovy += (float)sin(lastmillis / 1000.0) * 2.0f; aspect += (float)sin(lastmillis / 1000.0 + PI) * 0.1f; glFogi(GL_FOG_START, 0); glFogi(GL_FOG_END, (fog + 96) / 8); }; glClear((player1->outsidemap ? GL_COLOR_BUFFER_BIT : 0) | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); int farplane = fog * 5 / 2; gluPerspective(fovy, aspect, 0.15f, farplane); glMatrixMode(GL_MODELVIEW); |
︙ | ︙ | |||
486 487 488 489 490 491 492 | glDisable(GL_TEXTURE_2D); gl_drawhud(w, h, (int)curfps, nquads, curvert, underwater); glEnable(GL_CULL_FACE); glEnable(GL_FOG); | < > | 486 487 488 489 490 491 492 493 | glDisable(GL_TEXTURE_2D); gl_drawhud(w, h, (int)curfps, nquads, curvert, underwater); glEnable(GL_CULL_FACE); glEnable(GL_FOG); } |
Modified src/renderparticles.mm
from [d554171715]
to [9f00935137].
︙ | ︙ | |||
19 20 21 22 23 24 25 | newparticle(OFVector3D &o, OFVector3D &d, int fade, int type) { if (!parinit) { loopi(MAXPARTICLES) { particles[i].next = parempty; parempty = &particles[i]; | < > < > | 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 | newparticle(OFVector3D &o, OFVector3D &d, int fade, int type) { if (!parinit) { loopi(MAXPARTICLES) { particles[i].next = parempty; parempty = &particles[i]; } parinit = true; }; if (parempty) { particle *p = parempty; parempty = p->next; p->o = o; p->d = d; p->fade = fade; p->type = type; p->millis = lastmillis; p->next = parlist; parlist = p; }; } VAR(demotracking, 0, 0, 1); VARP(particlesize, 20, 100, 500); OFVector3D right, up; void |
︙ | ︙ | |||
113 114 115 116 117 118 119 | if (numrender++ > maxparticles || (p->fade -= time) < 0) { *pp = p->next; p->next = parempty; parempty = p; } else { if (pt->gr) p->o.z -= ((lastmillis - p->millis) / 3.0f) * | | < > | 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 | if (numrender++ > maxparticles || (p->fade -= time) < 0) { *pp = p->next; p->next = parempty; parempty = p; } else { if (pt->gr) p->o.z -= ((lastmillis - p->millis) / 3.0f) * curtime / (pt->gr * 10000); OFVector3D a = p->d; vmul(a, time); vdiv(a, 20000.0f); vadd(p->o, a); pp = &p->next; } } glEnable(GL_FOG); glDisable(GL_BLEND); glDepthMask(GL_TRUE); } void particle_splash(int type, int num, int fade, OFVector3D &p) { loopi(num) { const int radius = type == 5 ? 50 : 150; |
︙ | ︙ |
Modified src/rndmap.mm
from [b9a3803fd5]
to [db18b3b402].
1 2 3 4 5 6 7 8 9 10 11 | // rndmap.cpp: perlin noise landscape generation and some experimental random // map stuff, currently not used #include "cube.h" float noise(int x, int y, int seed) { int n = x + y * 57; n = (n << 13) ^ n; return 1.0f - | | | | | 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 | // rndmap.cpp: perlin noise landscape generation and some experimental random // map stuff, currently not used #include "cube.h" float noise(int x, int y, int seed) { int n = x + y * 57; n = (n << 13) ^ n; return 1.0f - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f; } float smoothednoise(int x, int y, int seed) { float corners = (noise(x - 1, y - 1, seed) + noise(x + 1, y - 1, seed) + noise(x - 1, y + 1, seed) + noise(x + 1, y + 1, seed)) / 16; float sides = (noise(x - 1, y, seed) + noise(x + 1, y, seed) + noise(x, y - 1, seed) + noise(x, y + 1, seed)) / 8; float center = noise(x, y, seed) / 4; return corners + sides + center; } float interpolate(float a, float b, float x) { |
︙ | ︙ | |||
56 57 58 59 60 61 62 | { float total = 0; int seed = 0; for (int i = 0; i < 7; i++) { float frequency = (float)(2 ^ i); float amplitude = (float)pow(pers, i); total += interpolatednoise(x * frequency, y * frequency, seed) * | | | | < > | 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 | { float total = 0; int seed = 0; for (int i = 0; i < 7; i++) { float frequency = (float)(2 ^ i); float amplitude = (float)pow(pers, i); total += interpolatednoise(x * frequency, y * frequency, seed) * amplitude; seed += seedstep; } return total; } void perlinarea(block &b, int scale, int seed, int psize) { srand(seed); seed = rnd(10000); if (!scale) scale = 10; for (int x = b.x; x <= b.x + b.xs; x++) for (int y = b.y; y <= b.y + b.ys; y++) { sqr *s = S(x, y); if (!SOLID(s) && x != b.x + b.xs && y != b.y + b.ys) s->type = FHF; s->vdelta = (int)(perlinnoise_2D(x / ((float)scale) + seed, y / ((float)scale) + seed, 1000, 0.01f) * 50 + 25); if (s->vdelta > 128) s->vdelta = 0; }; } |
Modified src/savegamedemo.mm
from [38fcd6b7f4]
to [d7af13e4bd].
︙ | ︙ | |||
211 212 213 214 215 216 217 | if (gzgeti() != ents.length()) return loadgameout(); loopv(ents) { ents[i].spawned = gzgetc(f) != 0; if (ents[i].type == CARROT && !ents[i].spawned) trigger(ents[i].attr1, ents[i].attr2, true); | < > | < < > < > | 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 | if (gzgeti() != ents.length()) return loadgameout(); loopv(ents) { ents[i].spawned = gzgetc(f) != 0; if (ents[i].type == CARROT && !ents[i].spawned) trigger(ents[i].attr1, ents[i].attr2, true); } restoreserverstate(ents); gzread(f, player1, sizeof(dynent)); player1->lastaction = lastmillis; int nmonsters = gzgeti(); dvector &monsters = getmonsters(); if (nmonsters != monsters.length()) return loadgameout(); loopv(monsters) { gzread(f, monsters[i], sizeof(dynent)); monsters[i]->enemy = player1; // lazy, could save id of enemy instead monsters[i]->lastaction = monsters[i]->trigger = lastmillis + 500; // also lazy, but no real noticable effect on game if (monsters[i]->state == CS_DEAD) monsters[i]->lastaction = 0; } restoremonsterstate(); int nplayers = gzgeti(); loopi(nplayers) if (!gzget()) { dynent *d = getclient(i); assert(d); gzread(f, d, sizeof(dynent)); } conoutf(@"savegame restored"); if (demoloading) startdemo(); else stop(); } |
︙ | ︙ | |||
288 289 290 291 292 293 294 | COMMAND(record, ARG_1STR) void demodamage(int damage, OFVector3D &o) { ddamage = damage; dorig = o; | < > < > | 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 | COMMAND(record, ARG_1STR) void demodamage(int damage, OFVector3D &o) { ddamage = damage; dorig = o; } void demoblend(int damage) { bdamage = damage; } void incomingdemodata(uchar *buf, int len, bool extras) { if (!demorecording) return; gzputi(lastmillis - starttime); |
︙ | ︙ | |||
405 406 407 408 409 410 411 | vmul(dest, 2 * s3 - 3 * s2 + 1); vmul(t, -2 * s3 + 3 * s2); vadd(dest, t); vmul(t1, s3 - 2 * s2 + s); vadd(dest, t1); vmul(t2, s3 - s2); vadd(dest, t2); | < > < > | 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 | vmul(dest, 2 * s3 - 3 * s2 + 1); vmul(t, -2 * s3 + 3 * s2); vadd(dest, t); vmul(t1, s3 - 2 * s2 + s); vadd(dest, t1); vmul(t2, s3 - s2); vadd(dest, t2); } void fixwrap(dynent *a, dynent *b) { while (b->yaw - a->yaw > 180) a->yaw += 360; while (b->yaw - a->yaw < -180) a->yaw -= 360; } void demoplaybackstep() { while (demoplayback && lastmillis >= playbacktime) { int len = gzgeti(); if (len < 1 || len > MAXTRANS) { |
︙ | ︙ | |||
477 478 479 480 481 482 483 | readdemotime(); } if (demoplayback) { int itime = lastmillis - demodelaymsec; loopvrev(playerhistory) if (playerhistory[i]->lastupdate < | | | | < | | 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 501 502 503 504 505 506 507 508 509 | readdemotime(); } if (demoplayback) { int itime = lastmillis - demodelaymsec; loopvrev(playerhistory) if (playerhistory[i]->lastupdate < itime) // find 2 positions in // history that surround // interpolation time point { dynent *a = playerhistory[i]; dynent *b = a; if (i + 1 < playerhistory.length()) b = playerhistory[i + 1]; *player1 = *b; if (a != b) // interpolate pos & angles { dynent *c = b; if (i + 2 < playerhistory.length()) c = playerhistory[i + 2]; dynent *z = a; if (i - 1 >= 0) z = playerhistory[i - 1]; // if(a==z || b==c) printf("* %d\n", // lastmillis); float bf = (itime - a->lastupdate) / (float)(b->lastupdate - a->lastupdate); fixwrap(a, player1); fixwrap(c, player1); fixwrap(z, player1); vdist(dist, v, z->o, c->o); if (dist < 16) // if teleport or spawn, dont't // interpolate |
︙ | ︙ |
Modified src/server.mm
from [133bbad38c]
to [2b7d5c9bfe].
︙ | ︙ | |||
36 37 38 39 40 41 42 | restoreserverstate( vector<entity> &ents) // hack: called from savegame code, only works in SP { loopv(sents) { sents[i].spawned = ents[i].spawned; sents[i].spawnsecs = 0; | < < > > | 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | restoreserverstate( vector<entity> &ents) // hack: called from savegame code, only works in SP { loopv(sents) { sents[i].spawned = ents[i].spawned; sents[i].spawnsecs = 0; } } int interm = 0, minremain = 0, mapend = 0; bool mapreload = false; static OFString *serverpassword = @""; bool isdedicated; |
︙ | ︙ | |||
70 71 72 73 74 75 76 | break; }; case ST_LOCAL: localservertoclient(packet->data, packet->dataLength); break; }; | < > < > | 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 | break; }; case ST_LOCAL: localservertoclient(packet->data, packet->dataLength); break; }; } void send2(bool rel, int cn, int a, int b) { ENetPacket *packet = enet_packet_create(NULL, 32, rel ? ENET_PACKET_FLAG_RELIABLE : 0); uchar *start = packet->data; uchar *p = start + 2; putint(p, a); putint(p, b); *(ushort *)start = ENET_HOST_TO_NET_16(p - start); enet_packet_resize(packet, p - start); if (cn < 0) process(packet, -1); else send(cn, packet); if (packet->referenceCount == 0) enet_packet_destroy(packet); } void sendservmsg(OFString *msg) { ENetPacket *packet = enet_packet_create( NULL, _MAXDEFSTR + 10, ENET_PACKET_FLAG_RELIABLE); uchar *start = packet->data; |
︙ | ︙ | |||
114 115 116 117 118 119 120 | void disconnect_client(int n, char *reason) { printf("disconnecting client (%s) [%s]\n", clients[n].hostname, reason); enet_peer_disconnect(clients[n].peer); clients[n].type = ST_EMPTY; send2(true, -1, SV_CDIS, n); | < > < > < > < > < > < > | 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 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 | void disconnect_client(int n, char *reason) { printf("disconnecting client (%s) [%s]\n", clients[n].hostname, reason); enet_peer_disconnect(clients[n].peer); clients[n].type = ST_EMPTY; send2(true, -1, SV_CDIS, n); } void resetitems() { sents.setsize(0); notgotitems = true; } void pickup(uint i, int sec, int sender) // server side item pickup, acknowledge // first client that gets it { if (i >= (uint)sents.length()) return; if (sents[i].spawned) { sents[i].spawned = false; sents[i].spawnsecs = sec; send2(true, sender, SV_ITEMACC, i); }; } void resetvotes() { loopv(clients) clients[i].mapvote[0] = 0; } bool vote(char *map, int reqmode, int sender) { strcpy_s(clients[sender].mapvote, map); clients[sender].modevote = reqmode; int yes = 0, no = 0; loopv(clients) if (clients[i].type != ST_EMPTY) { if (clients[i].mapvote[0]) { if (strcmp(clients[i].mapvote, map) == 0 && clients[i].modevote == reqmode) yes++; else no++; } else no++; } if (yes == 1 && no == 0) return true; // single player @autoreleasepool { OFString *msg = [OFString stringWithFormat: @"%s suggests %@ on map %s (set map to vote)", clients[sender].name, modestr(reqmode), map]; sendservmsg(msg); } if (yes / (float)(yes + no) <= 0.5f) return false; sendservmsg(@"vote passed"); resetvotes(); return true; } // server side processing of updates: does very little and most state is tracked // client only could be extended to move more gameplay to server (at expense of // lag) void process(ENetPacket *packet, int sender) // sender may be -1 |
︙ | ︙ | |||
299 300 301 302 303 304 305 | }; if (p > end) { disconnect_client(sender, "end of packet"); return; }; multicast(packet, sender); | < > | 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 | }; if (p > end) { disconnect_client(sender, "end of packet"); return; }; multicast(packet, sender); } void send_welcome(int n) { ENetPacket *packet = enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE); uchar *start = packet->data; |
︙ | ︙ | |||
337 338 339 340 341 342 343 | multicast(ENetPacket *packet, int sender) { loopv(clients) { if (i == sender) continue; send(i, packet); | < < > > < > < > < > < > | 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 | multicast(ENetPacket *packet, int sender) { loopv(clients) { if (i == sender) continue; send(i, packet); } } void localclienttoserver(ENetPacket *packet) { process(packet, 0); if (!packet->referenceCount) enet_packet_destroy(packet); } client & addclient() { loopv(clients) if (clients[i].type == ST_EMPTY) return clients[i]; return clients.add(); } void checkintermission() { if (!minremain) { interm = lastsec + 10; mapend = lastsec + 1000; }; send2(true, -1, SV_TIMEUP, minremain--); } void startintermission() { minremain = 0; checkintermission(); } void resetserverifempty() { loopv(clients) if (clients[i].type != ST_EMPTY) return; clients.setsize(0); smapname = @""; |
︙ | ︙ | |||
403 404 405 406 407 408 409 | { if (sents[i].spawnsecs && (sents[i].spawnsecs -= seconds - lastsec) <= 0) { sents[i].spawnsecs = 0; sents[i].spawned = true; send2(true, -1, SV_ITEMSPAWN, i); }; | < > < > | 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 | { if (sents[i].spawnsecs && (sents[i].spawnsecs -= seconds - lastsec) <= 0) { sents[i].spawnsecs = 0; sents[i].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; loopv(clients) if (clients[i].type != ST_EMPTY) { send2(true, i, SV_MAPRELOAD, 0); // ask a client to trigger map reload mapreload = true; break; } }; resetserverifempty(); if (!isdedicated) return; // below is network only |
︙ | ︙ | |||
455 456 457 458 459 460 461 | switch (event.type) { case ENET_EVENT_TYPE_CONNECT: { client &c = addclient(); c.type = ST_TCPIP; c.peer = event.peer; c.peer->data = (void *)(&c - &clients[0]); char hn[1024]; | | | | | | | 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 | switch (event.type) { case ENET_EVENT_TYPE_CONNECT: { client &c = addclient(); c.type = ST_TCPIP; c.peer = event.peer; c.peer->data = (void *)(&c - &clients[0]); char hn[1024]; strcpy_s(c.hostname, (enet_address_get_host( &c.peer->address, hn, sizeof(hn)) == 0) ? hn : "localhost"); printf("client connected (%s)\n", c.hostname); send_welcome(lastconnect = &c - &clients[0]); break; } case ENET_EVENT_TYPE_RECEIVE: brec += event.packet->dataLength; process(event.packet, (intptr_t)event.peer->data); |
︙ | ︙ | |||
489 490 491 492 493 494 495 | if (numplayers > maxclients) { disconnect_client(lastconnect, "maxclients reached"); }; }; #ifndef _WIN32 fflush(stdout); #endif | < > < > < > < > | 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 | if (numplayers > maxclients) { disconnect_client(lastconnect, "maxclients reached"); }; }; #ifndef _WIN32 fflush(stdout); #endif } void cleanupserver() { if (serverhost) enet_host_destroy(serverhost); } void localdisconnect() { loopv(clients) if (clients[i].type == ST_LOCAL) clients[i].type = ST_EMPTY; } void localconnect() { client &c = addclient(); c.type = ST_LOCAL; strcpy_s(c.hostname, "local"); send_welcome(&c - &clients[0]); } void initserver(bool dedicated, int uprate, OFString *sdesc, OFString *ip, OFString *master, OFString *passwd, int maxcl) { serverpassword = passwd; maxclients = maxcl; |
︙ | ︙ | |||
550 551 552 553 554 555 556 | printf("dedicated server started, waiting for " "clients...\nCtrl-C to exit\n\n"); atexit(cleanupserver); atexit(enet_deinitialize); for (;;) serverslice(/*enet_time_get_sec()*/ time(NULL), 5); }; | < > | 550 551 552 553 554 555 556 557 | printf("dedicated server started, waiting for " "clients...\nCtrl-C to exit\n\n"); atexit(cleanupserver); atexit(enet_deinitialize); for (;;) serverslice(/*enet_time_get_sec()*/ time(NULL), 5); }; } |
Modified src/serverbrowser.mm
from [c6e27aadf2]
to [4bf1a6646d].
︙ | ︙ | |||
43 44 45 46 47 48 49 | rr.query = rt->query; rr.address = address; rt->query = NULL; rt->starttime = 0; SDL_UnlockMutex(resolvermutex); }; return 0; | < > | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | rr.query = rt->query; rr.address = address; rt->query = NULL; rt->starttime = 0; SDL_UnlockMutex(resolvermutex); }; return 0; } void resolverinit(int threads, int limit) { resolverlimit = limit; resolversem = SDL_CreateSemaphore(0); resolvermutex = SDL_CreateMutex(); |
︙ | ︙ | |||
88 89 90 91 92 93 94 | resolverresults.setsize(0); while (SDL_SemTryWait(resolversem) == 0) ; loopv(resolverthreads) { resolverthread &rt = resolverthreads[i]; resolverstop(rt, true); | < > < > < > | 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 | resolverresults.setsize(0); while (SDL_SemTryWait(resolversem) == 0) ; loopv(resolverthreads) { resolverthread &rt = resolverthreads[i]; resolverstop(rt, true); } SDL_UnlockMutex(resolvermutex); } void resolverquery(char *name) { SDL_LockMutex(resolvermutex); resolverqueries.add(name); SDL_SemPost(resolversem); SDL_UnlockMutex(resolvermutex); } bool resolvercheck(char **name, ENetAddress *address) { SDL_LockMutex(resolvermutex); if (!resolverresults.empty()) { resolverresult &rr = resolverresults.pop(); |
︙ | ︙ | |||
123 124 125 126 127 128 129 | if (lastmillis - rt.starttime > resolverlimit) { resolverstop(rt, true); *name = rt.query; SDL_UnlockMutex(resolvermutex); return true; }; }; | < > < > | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | if (lastmillis - rt.starttime > resolverlimit) { resolverstop(rt, true); *name = rt.query; SDL_UnlockMutex(resolvermutex); return true; }; }; } SDL_UnlockMutex(resolvermutex); return false; } struct serverinfo { string name; string full; string map; string sdesc; int mode, numplayers, ping, protocol, minremain; |
︙ | ︙ | |||
155 156 157 158 159 160 161 | void addserver(OFString *servername_) { @autoreleasepool { const char *servername = servername_.UTF8String; loopv(servers) if (strcmp(servers[i].name, servername) == | | | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | void addserver(OFString *servername_) { @autoreleasepool { const char *servername = servername_.UTF8String; loopv(servers) if (strcmp(servers[i].name, servername) == 0) return; serverinfo &si = servers.insert(0, serverinfo()); strcpy_s(si.name, servername); si.full[0] = 0; si.mode = 0; si.numplayers = 0; si.ping = 9999; si.protocol = 0; |
︙ | ︙ | |||
187 188 189 190 191 192 193 | if (si.address.host == ENET_HOST_ANY) continue; p = ping; putint(p, lastmillis); buf.data = ping; buf.dataLength = p - ping; enet_socket_send(pingsock, &si.address, &buf, 1); | < > < > | 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | if (si.address.host == ENET_HOST_ANY) continue; p = ping; putint(p, lastmillis); buf.data = ping; buf.dataLength = p - ping; enet_socket_send(pingsock, &si.address, &buf, 1); } lastinfo = lastmillis; } void checkresolver() { char *name = NULL; ENetAddress addr = {ENET_HOST_ANY, CUBE_SERVINFO_PORT}; while (resolvercheck(&name, &addr)) { |
︙ | ︙ | |||
250 251 252 253 254 255 256 | } } int sicompare(const serverinfo *a, const serverinfo *b) { return a->ping > b->ping | | | | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | } } int sicompare(const serverinfo *a, const serverinfo *b) { return a->ping > b->ping ? 1 : (a->ping < b->ping ? -1 : strcmp(a->name, b->name)); } void refreshservers() { checkresolver(); checkpings(); |
︙ | ︙ | |||
281 282 283 284 285 286 287 | si.numplayers, si.map[0] ? si.map : "[unknown]", modestr(si.mode).UTF8String, si.name, si.sdesc); } } } else { | | < | 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | si.numplayers, si.map[0] ? si.map : "[unknown]", modestr(si.mode).UTF8String, si.name, si.sdesc); } } } else { sprintf_s(si.full)(si.address.host != ENET_HOST_ANY ? "%s [waiting for server response]" : "%s [unknown host]\t", si.name); } si.full[50] = 0; // cut off too long server descriptions @autoreleasepool { menumanual(1, i, @(si.full)); |
︙ | ︙ | |||
307 308 309 310 311 312 313 | pingsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, NULL); resolverinit(1, 1000); }; resolverclear(); loopv(servers) resolverquery(servers[i].name); refreshservers(); menuset(1); | < > | 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | pingsock = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, NULL); resolverinit(1, 1000); }; resolverclear(); loopv(servers) resolverquery(servers[i].name); refreshservers(); menuset(1); } void updatefrommaster() { const int MAXUPD = 32000; uchar buf[MAXUPD]; uchar *reply = retrieveservers(buf, MAXUPD); |
︙ | ︙ |
Modified src/serverms.mm
from [063897f679]
to [21c02ed323].
︙ | ︙ | |||
47 48 49 50 51 52 53 | mssock = ENET_SOCKET_NULL; return; }; buf.data = ((char *)buf.data) + len; ((char *)buf.data)[0] = 0; buf.dataLength -= len; }; | < > < > | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | mssock = ENET_SOCKET_NULL; return; }; buf.data = ((char *)buf.data) + len; ((char *)buf.data)[0] = 0; buf.dataLength -= len; }; } uchar * stripheader(uchar *b) { char *s = strstr((char *)b, "\n\r\n"); if (!s) s = strstr((char *)b, "\n\n"); return s ? (uchar *)s : b; } ENetAddress masterserver = {ENET_HOST_ANY, 80}; int updmaster = 0; string masterbase; string masterpath; uchar masterrep[MAXTRANS]; ENetBuffer masterb; |
︙ | ︙ | |||
79 80 81 82 83 84 85 | httpgetsend(masterserver, masterbase, path, "cubeserver", "Cube Server"); masterrep[0] = 0; masterb.data = masterrep; masterb.dataLength = MAXTRANS - 1; updmaster = seconds + 60 * 60; }; | < > < > < > | 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 | httpgetsend(masterserver, masterbase, path, "cubeserver", "Cube Server"); masterrep[0] = 0; masterb.data = masterrep; masterb.dataLength = MAXTRANS - 1; updmaster = seconds + 60 * 60; }; } void checkmasterreply() { bool busy = mssock != ENET_SOCKET_NULL; httpgetrecieve(masterb); if (busy && mssock == ENET_SOCKET_NULL) printf("masterserver reply: %s\n", stripheader(masterrep)); } uchar * retrieveservers(uchar *buf, int buflen) { sprintf_sd(path)("%sretrieve.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) httpgetrecieve(eb); return stripheader(buf); } ENetSocket pongsock = ENET_SOCKET_NULL; static OFString *serverdesc; void serverms(int mode, int numplayers, int minremain, OFString *smapname, int seconds, bool isfull) |
︙ | ︙ |
Modified src/serverutil.mm
from [e5f6cbf888]
to [9a3fdd3f13].
︙ | ︙ | |||
17 18 19 20 21 22 23 | } else { *p++ = 0x81; *p++ = n; *p++ = n >> 8; *p++ = n >> 16; *p++ = n >> 24; }; | < > | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | } else { *p++ = 0x81; *p++ = n; *p++ = n >> 8; *p++ = n >> 16; *p++ = n >> 24; }; } int getint(uchar *&p) { int c = *((char *)p); p++; if (c == -128) { |
︙ | ︙ | |||
89 90 91 92 93 94 95 | char msgsizelookup(int msg) { for (char *p = msgsizesl; *p >= 0; p += 2) if (*p == msg) return p[1]; return -1; | < > | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | char msgsizelookup(int msg) { for (char *p = msgsizesl; *p >= 0; p += 2) if (*p == msg) return p[1]; return -1; } // sending of maps between clients static OFString *copyname; int copysize; uchar *copydata = NULL; |
︙ | ︙ |
Modified src/sound.mm
from [2ceb58ac38]
to [af1eb7e101].
︙ | ︙ | |||
48 49 50 51 52 53 54 | }; if (stream) { #ifndef USE_MIXER FSOUND_Stream_Close(stream); #endif stream = NULL; }; | < > | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | }; if (stream) { #ifndef USE_MIXER FSOUND_Stream_Close(stream); #endif stream = NULL; }; } VAR(soundbufferlen, 128, 1024, 4096); void initsound() { memset(soundlocs, 0, sizeof(soundloc) * MAXCHAN); |
︙ | ︙ | |||
158 159 160 161 162 163 164 | return; stopsound(); #ifdef USE_MIXER Mix_CloseAudio(); #else FSOUND_Close(); #endif | < > | | | | | | | < > < > < < > > < > | 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 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 | return; stopsound(); #ifdef USE_MIXER Mix_CloseAudio(); #else FSOUND_Close(); #endif } VAR(stereo, 0, 1, 1); void updatechanvol(int chan, OFVector3D *loc) { int vol = soundvol, pan = 255 / 2; if (loc) { vdist(dist, v, *loc, player1->o); vol -= (int)(dist * 3 * soundvol / 255); // simple mono distance attenuation if (stereo && (v.x != 0 || v.y != 0)) { float yaw = -atan2(v.x, v.y) - player1->yaw * (PI / 180.0f); // relative angle of // sound along X-Y axis pan = int(255.9f * (0.5 * sin(yaw) + 0.5f)); // range is from 0 (left) // to 255 (right) }; }; vol = (vol * MAXVOL) / 255; #ifdef USE_MIXER Mix_Volume(chan, vol); Mix_SetPanning(chan, 255 - pan, pan); #else FSOUND_SetVolume(chan, vol); FSOUND_SetPan(chan, pan); #endif } void newsoundloc(int chan, OFVector3D *loc) { assert(chan >= 0 && chan < MAXCHAN); soundlocs[chan].loc = *loc; soundlocs[chan].inuse = true; } void updatevol() { if (nosound) return; loopi(MAXCHAN) if (soundlocs[i].inuse) { #ifdef USE_MIXER if (Mix_Playing(i)) #else if (FSOUND_IsPlaying(i)) #endif updatechanvol(i, &soundlocs[i].loc); else soundlocs[i].inuse = false; } } void playsoundc(int n) { addmsg(0, 2, SV_SOUND, n); playsound(n); } int soundsatonce = 0, lastsoundmillis = 0; void playsound(int n, OFVector3D *loc) { if (nosound) |
︙ | ︙ |
Modified src/tools.h
from [a99286d792]
to [fd4e5832e2].
︙ | ︙ | |||
34 35 36 37 38 39 40 | typedef unsigned short ushort; typedef unsigned int uint; #define max(a, b) (((a) > (b)) ? (a) : (b)) #define min(a, b) (((a) < (b)) ? (a) : (b)) #define rnd(max) (rand() % (max)) #define rndreset() (srand(1)) | | | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | typedef unsigned short ushort; typedef unsigned int uint; #define max(a, b) (((a) > (b)) ? (a) : (b)) #define min(a, b) (((a) < (b)) ? (a) : (b)) #define rnd(max) (rand() % (max)) #define rndreset() (srand(1)) #define rndtime() \ { \ loopi(lastmillis & 0xF) rnd(i + 1); \ } #define loop(v, m) for (int v = 0; v < (m); v++) #define loopi(m) loop(i, m) #define loopj(m) loop(j, m) #define loopk(m) loop(k, m) #define loopl(m) loop(l, m) |
︙ | ︙ | |||
98 99 100 101 102 103 104 | _vsnprintf(d, _MAXDEFSTR, fmt, v); va_end(v); d[_MAXDEFSTR - 1] = 0; } }; #define sprintf_s(d) sprintf_s_f((char *)d) | | | | | | | | | | | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | _vsnprintf(d, _MAXDEFSTR, fmt, v); va_end(v); d[_MAXDEFSTR - 1] = 0; } }; #define sprintf_s(d) sprintf_s_f((char *)d) #define sprintf_sd(d) \ string d; \ sprintf_s(d) #define sprintf_sdlv(d, last, fmt) \ string d; \ { \ va_list ap; \ va_start(ap, last); \ formatstring(d, fmt, ap); \ va_end(ap); \ } #define sprintf_sdv(d, fmt) sprintf_sdlv(d, fmt, fmt) #define fast_f2nat(val) ((int)(val)) extern void endianswap(void *, int, int); |
︙ | ︙ | |||
232 233 234 235 236 237 238 | for (int p = ulen - 1; p > i; p--) buf[p] = buf[p - 1]; buf[i] = e; return buf[i]; } }; | | | | | | | | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | for (int p = ulen - 1; p > i; p--) buf[p] = buf[p - 1]; buf[i] = e; return buf[i]; } }; #define loopv(v) \ if (false) { \ } else \ for (int i = 0; i < (v).length(); i++) #define loopvrev(v) \ if (false) { \ } else \ for (int i = (v).length() - 1; i >= 0; i--) #endif |
Modified src/tools.mm
from [d7e6269b15]
to [22d3464477].
︙ | ︙ | |||
13 14 15 16 17 18 19 | return; loop(w, length) loop(i, stride / 2) { uchar *p = (uchar *)memory + w * stride; uchar t = p[i]; p[i] = p[stride - i - 1]; p[stride - i - 1] = t; | < > | 13 14 15 16 17 18 19 20 21 | return; loop(w, length) loop(i, stride / 2) { uchar *p = (uchar *)memory + w * stride; uchar t = p[i]; p[i] = p[stride - i - 1]; p[stride - i - 1] = t; } } |
Modified src/weapon.mm
from [a7650f3ece]
to [93de7b2cbf].
︙ | ︙ | |||
103 104 105 106 107 108 109 | vmul(v, f); vadd(v, from); p = &v; } } return (p->x <= d->o.x + d->radius && p->x >= d->o.x - d->radius && | | | | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | vmul(v, f); vadd(v, from); p = &v; } } return (p->x <= d->o.x + d->radius && p->x >= d->o.x - d->radius && p->y <= d->o.y + d->radius && p->y >= d->o.y - d->radius && p->z <= d->o.z + d->aboveeye && p->z >= d->o.z - d->eyeheight); } OFString * playerincrosshair() { if (demoplayback) return NULL; |
︙ | ︙ | |||
265 266 267 268 269 270 271 | continue; projdamage(o, p, v, i, -1, qdam); } if (p->owner != player1) projdamage(player1, p, v, -1, -1, qdam); dvector &mv = getmonsters(); loopv(mv) if (!vreject(mv[i]->o, v, 10.0f) && | | | 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 | continue; projdamage(o, p, v, i, -1, qdam); } if (p->owner != player1) projdamage(player1, p, v, -1, -1, qdam); dvector &mv = getmonsters(); loopv(mv) if (!vreject(mv[i]->o, v, 10.0f) && mv[i] != p->owner) projdamage(mv[i], p, v, -1, i, qdam); } if (p->inuse) { if (time == dtime) splash(p, v, p->o, -1, -1, qdam); else { if (p->gun == GUN_RL) { |
︙ | ︙ |
Modified src/world.mm
from [cee211ba17]
to [50f4e28f8c].
︙ | ︙ | |||
31 32 33 34 35 36 37 | if (y > maxy) maxy = y; if (x < minx) minx = x; if (y < miny) miny = y; }; | < > < > | | | 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 | if (y > maxy) maxy = y; if (x < minx) minx = x; if (y < miny) miny = y; }; } block b = {minx, miny, maxx - minx + 1, maxy - miny + 1}; if (maxx) remip(b); // remip minimal area of changed geometry } void resettagareas() { settag(0, 0); } // reset for editing or map saving void settagareas() { settag(0, 1); loopv(ents) if (ents[i].type == CARROT) setspawn(i, true); } // set for playing void trigger(int tag, int type, bool savegame) { if (!tag) return; |
︙ | ︙ | |||
127 128 129 130 131 132 133 | { num++; int fh = o[i]->floor; int ch = o[i]->ceil; if (r->type == SEMISOLID) { if (o[i]->type == FHF) fh -= o[i]->vdelta / 4 + | | | | | | < | < > < > | < > | 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 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 | { num++; int fh = o[i]->floor; int ch = o[i]->ceil; if (r->type == SEMISOLID) { if (o[i]->type == FHF) fh -= o[i]->vdelta / 4 + 2; // crap hack, // needed for // rendering // large mips // next to hfs if (o[i]->type == CHF) ch += o[i]->vdelta / 4 + 2; // FIXME: needs // to somehow // take into // account middle // vertices on // higher mips }; if (fh < floor) floor = fh; // take lowest floor and // highest ceil, so we // never have to see // missing lower/upper // from the side if (ch > ceil) ceil = ch; } r->floor = floor; r->ceil = ceil; }; if (r->type == CORNER) goto mip; // special case: don't ever split even // if textures etc are different r->defer = 1; if (SOLID(r)) { loopi(3) { if (o[i]->wtex != o[3]->wtex) goto c; // on an all solid cube, // only thing that needs // to be equal for a // perfect mip is the // wall texture } } else { loopi(3) { if (o[i]->type != o[3]->type || o[i]->floor != o[3]->floor || o[i]->ceil != o[3]->ceil || o[i]->ftex != o[3]->ftex || o[i]->ctex != o[3]->ctex || abs(o[i + 1]->r - o[0]->r) > lighterr // perfect mip even if // light is not exactly // equal || abs(o[i + 1]->g - o[0]->g) > lighterr || abs(o[i + 1]->b - o[0]->b) > lighterr || o[i]->utex != o[3]->utex || o[i]->wtex != o[3]->wtex) goto c; } if (r->type == CHF || r->type == FHF) // can make a perfect mip out of a // hf if slopes lie on one line { if (o[0]->vdelta - o[1]->vdelta != o[1]->vdelta - |
︙ | ︙ | |||
230 231 232 233 234 235 236 | c:; }; s.x /= 2; s.y /= 2; s.xs /= 2; s.ys /= 2; remip(s, level + 1); | < > < > < > < > | 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 | c:; }; s.x /= 2; s.y /= 2; s.xs /= 2; s.ys /= 2; remip(s, level + 1); } void remipmore(block &b, int level) { block bb = b; if (bb.x > 1) bb.x--; if (bb.y > 1) bb.y--; if (bb.xs < ssize - 3) bb.xs++; if (bb.ys < ssize - 3) bb.ys++; remip(bb, level); } int closestent() // used for delent and edit mode ent display { if (noteditmode()) return -1; int best; float bdist = 99999; loopv(ents) { entity &e = ents[i]; if (e.type == NOTUSED) continue; OFVector3D v = OFMakeVector3D(e.x, e.y, e.z); vdist(dist, t, player1->o, v); if (dist < bdist) { best = i; bdist = dist; }; } return bdist == 99999 ? -1 : best; } void entproperty(int prop, int amount) { int e = closestent(); if (e < 0) return; |
︙ | ︙ | |||
289 290 291 292 293 294 295 | case 2: ents[e].attr3 += amount; break; case 3: ents[e].attr4 += amount; break; }; | < > | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | case 2: ents[e].attr3 += amount; break; case 3: ents[e].attr4 += amount; break; }; } void delent() { int e = closestent(); if (e < 0) { conoutf(@"no more entities"); |
︙ | ︙ | |||
351 352 353 354 355 356 357 | }; addmsg(1, 10, SV_EDITENT, ents.length(), type, e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4); ents.add(*((entity *)&e)); // unsafe! if (type == LIGHT) calclight(); return &ents.last(); | < > < > < > < > < > < < > > | 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 | }; addmsg(1, 10, SV_EDITENT, ents.length(), type, e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4); ents.add(*((entity *)&e)); // unsafe! if (type == LIGHT) calclight(); return &ents.last(); } void clearents(OFString *name) { int type = findtype(name); if (noteditmode() || multiplayer()) return; loopv(ents) { entity &e = ents[i]; if (e.type == type) e.type = NOTUSED; } if (type == LIGHT) calclight(); } COMMAND(clearents, ARG_1STR) void scalecomp(uchar &c, int intens) { int n = c * intens / 100; if (n > 255) n = 255; c = n; } void scalelights(int f, int intens) { loopv(ents) { entity &e = ents[i]; if (e.type != LIGHT) continue; e.attr1 = e.attr1 * f / 100; if (e.attr1 < 2) e.attr1 = 2; if (e.attr1 > 32) e.attr1 = 32; if (intens) { scalecomp(e.attr2, intens); scalecomp(e.attr3, intens); scalecomp(e.attr4, intens); }; } calclight(); } COMMAND(scalelights, ARG_2INT) int findentity(int type, int index) { for (int i = index; i < ents.length(); i++) if (ents[i].type == type) return i; loopj(index) if (ents[j].type == type) return j; return -1; } sqr *wmip[LARGEST_FACTOR * 2]; void setupworld(int factor) { ssize = 1 << (sfactor = factor); cubicsize = ssize * ssize; mipsize = cubicsize * 134 / 100; sqr *w = world = (sqr *)alloc(mipsize * sizeof(sqr)); loopi(LARGEST_FACTOR * 2) { wmip[i] = w; w += cubicsize >> (i * 2); } } void empty_world( int factor, bool force) // main empty world creation routine, if passed // factor -1 will enlarge old world by 1 { if (!force && noteditmode()) |
︙ | ︙ |
Modified src/worldio.mm
from [fcad2200c2]
to [09e55787b5].
︙ | ︙ | |||
181 182 183 184 185 186 187 | entity tmp = ents[i]; endianswap(&tmp, sizeof(short), 4); gzwrite(f, &tmp, sizeof(persistent_entity)); } } sqr *t = NULL; int sc = 0; | | | | | | | | | | | | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | entity tmp = ents[i]; endianswap(&tmp, sizeof(short), 4); gzwrite(f, &tmp, sizeof(persistent_entity)); } } sqr *t = NULL; int sc = 0; #define spurge \ while (sc) { \ gzputc(f, 255); \ if (sc > 255) { \ gzputc(f, 255); \ sc -= 255; \ } else { \ gzputc(f, sc); \ sc = 0; \ } \ } loopk(cubicsize) { sqr *s = &world[k]; #define c(f) (s->f == t->f) // 4 types of blocks, to compress a bit: // 255 (2): same as previous block + count |
︙ | ︙ |
Modified src/worldlight.mm
from [93b7010f75]
to [3bb65afc34].
︙ | ︙ | |||
15 16 17 18 19 20 21 | float dx = bx - lx; float dy = by - ly; float dist = (float)sqrt(dx * dx + dy * dy); if (dist < 1.0f) return; int reach = light.attr1; int steps = (int)(reach * reach * 1.6f / | | | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | float dx = bx - lx; float dy = by - ly; float dist = (float)sqrt(dx * dx + dy * dy); if (dist < 1.0f) return; int reach = light.attr1; int steps = (int)(reach * reach * 1.6f / dist); // can change this for speedup/quality? const int PRECBITS = 12; const float PRECF = 4096.0f; int x = (int)(lx * PRECF); int y = (int)(ly * PRECF); int l = light.attr2 << PRECBITS; int stepx = (int)(dx / (float)steps * PRECF); int stepy = (int)(dy / (float)steps * PRECF); |
︙ | ︙ | |||
73 74 75 76 77 78 79 | y += stepy; l -= stepl; g -= stepg; b -= stepb; stepl -= 25; stepg -= 25; stepb -= 25; | < > < > > | < < > | 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 | y += stepy; l -= stepl; g -= stepg; b -= stepb; stepl -= 25; stepg -= 25; stepb -= 25; } } else // white light, special optimized version { int dimness = rnd((255 - light.attr2) / 16 + 1); x += stepx * dimness; y += stepy * dimness; if (OUTBORD(x >> PRECBITS, y >> PRECBITS)) return; loopi(steps) { sqr *s = S(x >> PRECBITS, y >> PRECBITS); int tl = (l >> PRECBITS) + s->r; s->r = s->g = s->b = tl > 255 ? 255 : tl; if (SOLID(s)) return; x += stepx; y += stepy; l -= stepl; stepl -= 25; } }; } else // the old (white) light code, here for the few people with old // video cards that don't support overbright { loopi(steps) { sqr *s = S(x >> PRECBITS, y >> PRECBITS); int light = l >> PRECBITS; if (light > s->r) s->r = s->g = s->b = (uchar)light; if (SOLID(s)) return; x += stepx; y += stepy; l -= stepl; } }; } void calclightsource(persistent_entity &l) { int reach = l.attr1; int sx = l.x - reach; int ex = l.x + reach; |
︙ | ︙ | |||
137 138 139 140 141 142 143 | }; for (float sy2 = sy + s; sy2 <= ey - s; sy2 += s * 2) { lightray((float)sx, sy2, l); lightray((float)ex, sy2, l); }; rndtime(); | < > | | | | | < | > < > | 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 | }; for (float sy2 = sy + s; sy2 <= ey - s; sy2 += s * 2) { lightray((float)sx, sy2, l); lightray((float)ex, sy2, l); }; rndtime(); } void postlightarea(block &a) // median filter, smooths out random noise in light and // makes it more mipable { loop(x, a.xs) loop(y, a.ys) // assumes area not on edge of world { sqr *s = S(x + a.x, y + a.y); #define median(m) \ s->m = \ (s->m * 2 + SW(s, 1, 0)->m * 2 + SW(s, 0, 1)->m * 2 + \ SW(s, -1, 0)->m * 2 + SW(s, 0, -1)->m * 2 + SW(s, 1, 1)->m + \ SW(s, 1, -1)->m + SW(s, -1, 1)->m + SW(s, -1, -1)->m) / \ 14; // median is 4/2/1 instead median(r); median(g); median(b); } remip(a); } void calclight() { loop(x, ssize) loop(y, ssize) { sqr *s = S(x, y); |
︙ | ︙ |
Modified src/worldocull.mm
from [8bad2cc9f5]
to [7b61604ca1].
︙ | ︙ | |||
65 66 67 68 69 70 71 | sy += dy; if (SOLID(S(fast_f2nat(sx), fast_f2nat( sy)))) // 90% of time spend in this // function is on this line { rdist[i] = (float)(fabs(sx - vx) + | | < < > > < > < > | 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 | sy += dy; if (SOLID(S(fast_f2nat(sx), fast_f2nat( sy)))) // 90% of time spend in this // function is on this line { rdist[i] = (float)(fabs(sx - vx) + fabs(sy - vy)); break; }; }; } else { rdist[i] = 2; }; } } // test occlusion for a cube... one of the most computationally expensive // functions in the engine as its done for every cube and entity, but its effect // is more than worth it! inline float ca(float x, float y) { return x > y ? y / x : 2 - x / y; } inline float ma(float x, float y) { return x == 0 ? (y > 0 ? 2 : -2) : y / x; } int isoccluded(float vx, float vy, float cx, float cy, float csize) // v = viewer, c = cube to test { if (!ocull) return 0; |
︙ | ︙ | |||
183 184 185 186 187 188 189 | }; // E } else { h = ca(cx + csize - vx, cy - vy); l = ca(cx - vx, cy + csize - vy); }; // H }; int si = fast_f2nat(h * (NUMRAYS / 8)) + | | < > | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | }; // E } else { h = ca(cx + csize - vx, cy - vy); l = ca(cx - vx, cy + csize - vy); }; // H }; int si = fast_f2nat(h * (NUMRAYS / 8)) + NUMRAYS; // get indexes into occlusion map from angles int ei = fast_f2nat(l * (NUMRAYS / 8)) + NUMRAYS + 1; if (ei <= si) ei += NUMRAYS; for (int i = si; i <= ei; i++) { if (dist < rdist[i & (NUMRAYS - 1)]) return 0; // if any value in this segment of the // occlusion map is further away then cube is // not occluded }; return 1; // cube is entirely occluded } |
Modified src/worldrender.mm
from [a8374cc3dc]
to [5690f47554].
︙ | ︙ | |||
57 58 59 60 61 62 63 | c2 += d2->vdelta / 4.0f; } if (c1 <= f1 && c2 <= f2) return; render_square(o->utex, f1, f2, c1, c2, x1 << mip, y1 << mip, x2 << mip, y2 << mip, 1 << mip, d1, d2, topleft); }; | < > | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | c2 += d2->vdelta / 4.0f; } if (c1 <= f1 && c2 <= f2) return; render_square(o->utex, f1, f2, c1, c2, x1 << mip, y1 << mip, x2 << mip, y2 << mip, 1 << mip, d1, d2, topleft); }; } const int MAX_MIP = 5; // 32x32 unit blocks const int MIN_LOD = 2; const int LOW_LOD = 25; const int MAX_LOD = 1000; int lod = 40, lodtop, lodbot, lodleft, lodright; |
︙ | ︙ | |||
102 103 104 105 106 107 108 | case CORNER: case SOLID: break; default: return true; }; return false; | < > | 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | case CORNER: case SOLID: break; default: return true; }; return false; } bool render_floor, render_ceil; // the core recursive function, renders a rect of cubes at a certain mip level // from a viewer perspective call itself for lower mip levels, on most modern // machines however this function will use the higher mip levels only for // perfect mips. |
︙ | ︙ | |||
154 155 156 157 158 159 160 | // loop through the rect 3 times (for floor/ceil/walls seperately, to // facilitate dynamic stripify) for each we skip occluded cubes // (occlusion at higher mip levels is a big time saver!). during the // first loop (ceil) we collect cubes that lie within the lower mip rect // and are also deferred, and render them recursively. Anything left // (perfect mips and higher lods) we render here. | | | | | | | | | | | | | | < > | 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 | // loop through the rect 3 times (for floor/ceil/walls seperately, to // facilitate dynamic stripify) for each we skip occluded cubes // (occlusion at higher mip levels is a big time saver!). during the // first loop (ceil) we collect cubes that lie within the lower mip rect // and are also deferred, and render them recursively. Anything left // (perfect mips and higher lods) we render here. #define LOOPH \ { \ for (int xx = x; xx < xs; xx++) \ for (int yy = y; yy < ys; yy++) { \ sqr *s = SWS(w, xx, yy, sz); \ if (s->occluded == 1) \ continue; \ if (s->defer && !s->occluded && mip && \ xx >= lx && xx < rx && yy >= ly && \ yy < ry) #define LOOPD \ sqr *t = SWS(s, 1, 0, sz); \ sqr *u = SWS(s, 1, 1, sz); \ sqr *v = SWS(s, 0, 1, sz); LOOPH // ceils { int start = yy; sqr *next; while (yy < ys - 1 && (next = SWS(w, xx, yy + 1, sz))->defer && !next->occluded) yy++; // collect 2xN rect of lower mip render_seg_new(vx, vy, vh, mip - 1, xx * 2, start * 2, xx * 2 + 2, yy * 2 + 2); continue; } stats[mip]++; LOOPD if ((s->type == SPACE || s->type == FHF) && s->ceil >= vh && render_ceil) render_flat(s->ctex, xx << mip, yy << mip, 1 << mip, s->ceil, s, t, u, v, true); if (s->type == CHF) // if(s->ceil>=vh) |
︙ | ︙ | |||
307 308 309 310 311 312 313 | float f = 90.0f / lod / widef; low = (int)((90 - angle) / f); high = (int)(angle / f); if (low < min_lod) low = min_lod; if (high < min_lod) high = min_lod; | < > | > | | 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 | float f = 90.0f / lod / widef; low = (int)((90 - angle) / f); high = (int)(angle / f); if (low < min_lod) low = min_lod; if (high < min_lod) high = min_lod; } // does some out of date view frustrum optimisation that doesn't contribute much // anymore void render_world( float vx, float vy, float vh, int yaw, int pitch, float fov, int w, int h) { loopi(LARGEST_FACTOR) stats[i] = 0; min_lod = MIN_LOD + abs(pitch) / 12; yaw = 360 - yaw; float widef = fov / 75.0f; int cdist = abs(yaw % 90 - 45); if (cdist < 7) // hack to avoid popup at high fovs at 45 yaw { min_lod = max(min_lod, (int)(MIN_LOD + (10 - cdist) / 1.0f * widef)); // less if lod worked better widef = 1.0f; }; lod = MAX_LOD; lodtop = lodbot = lodleft = lodright = min_lod; if (yaw > 45 && yaw <= 135) { lodleft = lod; distlod(lodtop, lodbot, yaw - 45, widef); |
︙ | ︙ | |||
351 352 353 354 355 356 357 | float hyfov = fov * h / w / 2; render_floor = pitch < hyfov; render_ceil = -pitch < hyfov; render_seg_new( vx, vy, vh, MAX_MIP, 0, 0, ssize >> MAX_MIP, ssize >> MAX_MIP); mipstats(stats[0], stats[1], stats[2]); | < > | 352 353 354 355 356 357 358 359 | float hyfov = fov * h / w / 2; render_floor = pitch < hyfov; render_ceil = -pitch < hyfov; render_seg_new( vx, vy, vh, MAX_MIP, 0, 0, ssize >> MAX_MIP, ssize >> MAX_MIP); mipstats(stats[0], stats[1], stats[2]); } |