Index: src/Cube.mm ================================================================== --- src/Cube.mm +++ src/Cube.mm @@ -92,10 +92,11 @@ createParents:true]; if (SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO | par) < 0) fatal(@"Unable to initialize SDL"); + initEntities(); initPlayers(); log(@"net"); if (enet_initialize() < 0) fatal(@"Unable to initialise network module"); ADDED src/Entity.h Index: src/Entity.h ================================================================== --- /dev/null +++ src/Entity.h @@ -0,0 +1,5 @@ +#import "PersistentEntity.h" + +@interface Entity: PersistentEntity +@property (nonatomic) bool spawned; // the only dynamic state of a map entity +@end ADDED src/Entity.m Index: src/Entity.m ================================================================== --- /dev/null +++ src/Entity.m @@ -0,0 +1,4 @@ +#import "Entity.h" + +@implementation Entity +@end ADDED src/PersistentEntity.h Index: src/PersistentEntity.h ================================================================== --- /dev/null +++ src/PersistentEntity.h @@ -0,0 +1,11 @@ +#import + +// map entity +@interface PersistentEntity: OFObject +@property (nonatomic) short x, y, z; // cube aligned position +@property (nonatomic) short attr1; +@property (nonatomic) unsigned char type; // type is one of the above +@property (nonatomic) unsigned char attr2, attr3, attr4; + ++ (instancetype)entity; +@end ADDED src/PersistentEntity.m Index: src/PersistentEntity.m ================================================================== --- /dev/null +++ src/PersistentEntity.m @@ -0,0 +1,8 @@ +#import "PersistentEntity.h" + +@implementation PersistentEntity ++ (instancetype)entity +{ + return [[self alloc] init]; +} +@end Index: src/clientgame.mm ================================================================== --- src/clientgame.mm +++ src/clientgame.mm @@ -1,10 +1,11 @@ // clientgame.cpp: core game related stuff #include "cube.h" #import "DynamicEntity.h" +#import "Entity.h" #import "OFString+Cube.h" int nextmode = 0; // nextmode becomes gamemode after next map load VAR(gamemode, 1, 0, 0); Index: src/clients2c.mm ================================================================== --- src/clients2c.mm +++ src/clients2c.mm @@ -1,10 +1,11 @@ // client processing of the incoming network stream #include "cube.h" #import "DynamicEntity.h" +#import "Entity.h" extern int clientnum; extern bool c2sinit, senditemstoserver; extern OFString *toservermap; extern OFString *clientpassword; @@ -278,11 +279,11 @@ break; case SV_ITEMSPAWN: { uint i = getint(p); setspawn(i, true); - if (i >= (uint)ents.length()) + if (i >= (uint)ents.count) break; OFVector3D v = OFMakeVector3D(ents[i].x, ents[i].y, ents[i].z); playsound(S_ITEMSPAWN, &v); break; @@ -326,12 +327,17 @@ } case SV_EDITENT: // coop edit of ent { uint i = getint(p); - while ((uint)ents.length() <= i) - ents.add().type = NOTUSED; + + while ((uint)ents.count <= i) { + Entity *e = [Entity entity]; + e.type = NOTUSED; + [ents addObject:e]; + } + int to = ents[i].type; ents[i].type = getint(p); ents[i].x = getint(p); ents[i].y = getint(p); ents[i].z = getint(p); Index: src/cube.h ================================================================== --- src/cube.h +++ src/cube.h @@ -8,10 +8,11 @@ #include "tools.h" #define _MAXDEFSTR 260 +@class Entity; @class DynamicEntity; @interface Cube: OFObject @property (class, readonly, nonatomic) Cube *sharedInstance; @property (readonly, nonatomic) SDL_Window *window; @@ -74,22 +75,10 @@ CARROT, // attr1 = tag, attr2 = type JUMPPAD, // attr1 = zpush, attr2 = ypush, attr3 = xpush MAXENTTYPES }; -// map entity -struct persistent_entity { - 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 // map file format header struct header { char head[4]; // "CUBE" @@ -262,11 +251,11 @@ // special client ent that receives input and acts as camera extern DynamicEntity *player1; // all the other clients (in multiplayer) extern OFMutableArray *players; extern bool editmode; -extern vector ents; // map entities +extern OFMutableArray *ents; // map entities extern OFVector3D worldpos; // current target of the crosshair in the world extern int lastmillis; // last time extern int curtime; // current frame time extern int gamemode, nextmode; extern int xtraverts; Index: src/entities.mm ================================================================== --- src/entities.mm +++ src/entities.mm @@ -1,13 +1,14 @@ // entities.cpp: map entity related functions (pickup etc.) #include "cube.h" #import "DynamicEntity.h" +#import "Entity.h" #import "MapModelInfo.h" -vector ents; +OFMutableArray *ents; static OFString *entmdlnames[] = { @"shells", @"bullets", @"rockets", @@ -21,11 +22,17 @@ }; int triggertime = 0; void -renderent(entity &e, OFString *mdlname, float z, float yaw, int frame = 0, +initEntities() +{ + ents = [[OFMutableArray alloc] init]; +} + +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, OFMakeVector3D(e.x, z + S(e.x, e.y)->floor, e.y), yaw, 0, false, 1.0f, speed, 0, basetime); @@ -34,13 +41,12 @@ void renderentities() { if (lastmillis > triggertime + 1000) triggertime = 0; - loopv(ents) - { - entity &e = ents[i]; + + for (Entity *e in ents) { if (e.type == MAPMODEL) { MapModelInfo *mmi = getmminfo(e.attr2); if (mmi == nil) continue; rendermodel(mmi.name, 0, 1, e.attr4, (float)mmi.rad, @@ -297,25 +303,28 @@ void checkitems() { if (editmode) return; - loopv(ents) - { - entity &e = ents[i]; + + [ents enumerateObjectsUsingBlock:^(Entity *e, size_t i, bool *stop) { if (e.type == NOTUSED) - continue; - if (!ents[i].spawned && e.type != TELEPORT && e.type != JUMPPAD) - continue; + return; + + if (!e.spawned && e.type != TELEPORT && e.type != JUMPPAD) + return; + if (OUTBORD(e.x, e.y)) - continue; + return; + OFVector3D v = OFMakeVector3D( e.x, e.y, (float)S(e.x, e.y)->floor + player1.eyeheight); vdist(dist, t, player1.o, v); + if (dist < (e.type == TELEPORT ? 4 : 2.5)) pickup(i, player1); - } + }]; } void checkquad(int time) { @@ -327,24 +336,26 @@ } 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; - } + [ents enumerateObjectsUsingBlock:^(Entity *e, size_t i, bool *stop) { + if ((e.type >= I_SHELLS && e.type <= I_QUAD) || + e.type == CARROT) { + putint(p, i); + e.spawned = true; + } + }]; } void resetspawns() { - loopv(ents) ents[i].spawned = false; + for (Entity *e in ents) + e.spawned = false; } void setspawn(uint i, bool on) { - if (i < (uint)ents.length()) + if (i < (uint)ents.count) ents[i].spawned = on; } Index: src/meson.build ================================================================== --- src/meson.build +++ src/meson.build @@ -4,17 +4,19 @@ 'Client.mm', 'Command.mm', 'ConsoleLine.m', 'Cube.mm', 'DynamicEntity.mm', + 'Entity.m', 'Identifier.m', 'KeyMapping.m', 'MD2.mm', 'MapModelInfo.m', 'Menu.m', 'MenuItem.m', 'OFString+Cube.mm', + 'PersistentEntity.m', 'Projectile.m', 'ResolverResult.mm', 'ResolverThread.mm', 'ServerInfo.mm', 'Variable.mm', Index: src/monster.mm ================================================================== --- src/monster.mm +++ src/monster.mm @@ -1,10 +1,11 @@ // monster.cpp: implements AI for single player monsters, currently client only #include "cube.h" #import "DynamicEntity.h" +#import "Entity.h" static OFMutableArray *monsters; static int nextmonster, spawnremain, numkilled, monstertotal, mtimestart; VARF(skill, 1, 3, 10, conoutf(@"skill is now %d", skill)); @@ -119,15 +120,18 @@ if (m_dmsp) { nextmonster = mtimestart = lastmillis + 10000; monstertotal = spawnremain = gamemode < 0 ? skill * 10 : 0; } else if (m_classicsp) { mtimestart = lastmillis; - loopv(ents) if (ents[i].type == MONSTER) - { - DynamicEntity *m = basicmonster( - ents[i].attr2, ents[i].attr1, M_SLEEP, 100, 0); - m.o = OFMakeVector3D(ents[i].x, ents[i].y, ents[i].z); + + for (Entity *e in ents) { + if (e.type != MONSTER) + continue; + + DynamicEntity *m = + basicmonster(e.attr2, e.attr1, M_SLEEP, 100, 0); + m.o = OFMakeVector3D(e.x, e.y, e.z); entinmap(m); monstertotal++; } } } @@ -375,17 +379,17 @@ if (monstertotal && !spawnremain && numkilled == monstertotal) endsp(true); // equivalent of player entity touch, but only teleports are used - loopv(ents) - { - entity &e = ents[i]; + [ents enumerateObjectsUsingBlock:^(Entity *e, size_t i, bool *stop) { if (e.type != TELEPORT) - continue; + return; + if (OUTBORD(e.x, e.y)) - continue; + return; + OFVector3D v = OFMakeVector3D(e.x, e.y, (float)S(e.x, e.y)->floor); for (DynamicEntity *monster in monsters) { if (monster.state == CS_DEAD) { if (lastmillis - monster.lastaction < 2000) { @@ -394,15 +398,16 @@ } } else { v.z += monster.eyeheight; vdist(dist, t, monster.o, v); v.z -= monster.eyeheight; + if (dist < 4) - teleport((int)(&e - &ents[0]), monster); + teleport(i, monster); } } - } + }]; for (DynamicEntity *monster in monsters) if (monster.state == CS_ALIVE) monsteraction(monster); } Index: src/physics.mm ================================================================== --- src/physics.mm +++ src/physics.mm @@ -5,10 +5,11 @@ // fixed fps). #include "cube.h" #import "DynamicEntity.h" +#import "Entity.h" #import "MapModelInfo.h" // collide with player or monster bool plcollide( @@ -56,22 +57,23 @@ } void mmcollide(DynamicEntity *d, float &hi, float &lo) // collide with a mapmodel { - loopv(ents) - { - entity &e = ents[i]; + for (Entity *e in ents) { if (e.type != MAPMODEL) continue; + MapModelInfo *mmi = getmminfo(e.attr2); if (mmi == nil || !mmi.h) continue; + const float r = mmi.rad + d.radius; if (fabs(e.x - d.o.x) < r && fabs(e.y - d.o.y) < r) { float mmz = (float)(S(e.x, e.y)->floor + mmi.zoff + e.attr3); + if (d.o.z - d.eyeheight < mmz) { if (mmz < hi) hi = mmz; } else if (mmz + mmi.h > lo) lo = mmz + mmi.h; Index: src/protos.h ================================================================== --- src/protos.h +++ src/protos.h @@ -119,11 +119,11 @@ extern int closestent(); extern int findentity(int type, int index = 0); extern void trigger(int tag, int type, bool savegame); extern void resettagareas(); extern void settagareas(); -extern entity *newentity( +extern Entity *newentity( int x, int y, int z, OFString *what, int v1, int v2, int v3, int v4); // worldlight extern void calclight(); extern void dodynlight(const OFVector3D &vold, const OFVector3D &v, int reach, @@ -225,11 +225,11 @@ extern void serverslice(int seconds, unsigned int timeout); extern void putint(uchar *&p, int n); extern int getint(uchar *&p); extern void sendstring(OFString *t, uchar *&p); extern void startintermission(); -extern void restoreserverstate(vector &ents); +extern void restoreserverstate(OFArray *ents); extern uchar *retrieveservers(uchar *buf, int buflen); extern char msgsizelookup(int msg); extern void serverms(int mode, int numplayers, int minremain, OFString *smapname, int seconds, bool isfull); extern void servermsinit(OFString *master, OFString *sdesc, bool listen); @@ -255,10 +255,11 @@ extern OFArray *getmonsters(); extern void monsterpain(DynamicEntity *m, int damage, DynamicEntity *d); extern void endsp(bool allkilled); // entities +extern void initEntities(); extern void renderents(); extern void putitems(uchar *&p); extern void checkquad(int time); extern void checkitems(); extern void realpickup(int n, DynamicEntity *d); Index: src/renderextras.mm ================================================================== --- src/renderextras.mm +++ src/renderextras.mm @@ -1,10 +1,11 @@ // renderextras.cpp: misc gl render code and the HUD #include "cube.h" #import "DynamicEntity.h" +#import "Entity.h" void line(int x1, int y1, float z1, int x2, int y2, float z2) { glBegin(GL_POLYGON); @@ -173,27 +174,30 @@ @"?", @"?", @"?", }; +// show sparkly thingies for map entities in edit mode void -renderents() // show sparkly thingies for map entities in edit mode +renderents() { closeent = @""; + if (!editmode) return; - loopv(ents) - { - entity &e = ents[i]; + + for (Entity *e in ents) { if (e.type == NOTUSED) continue; + OFVector3D v = OFMakeVector3D(e.x, e.y, e.z); particle_splash(2, 2, 40, v); } + int e = closestent(); if (e >= 0) { - entity &c = ents[e]; + Entity *c = ents[e]; closeent = [OFString stringWithFormat:@"closest entity = %@ (%d, %d, " @"%d, %d), selection = (%d, %d)", entnames[c.type], c.attr1, c.attr2, c.attr3, c.attr4, getvar(@"selxs"), getvar(@"selys")]; Index: src/savegamedemo.mm ================================================================== --- src/savegamedemo.mm +++ src/savegamedemo.mm @@ -2,10 +2,11 @@ // mapents, the full state of all dynents (monsters + player) #include "cube.h" #import "DynamicEntity.h" +#import "Entity.h" #ifdef OF_BIG_ENDIAN static const int islittleendian = 0; #else static const int islittleendian = 1; @@ -107,12 +108,13 @@ char map[_MAXDEFSTR] = { 0 }; memcpy(map, getclientmap().UTF8String, min(getclientmap().UTF8StringLength, _MAXDEFSTR - 1)); gzwrite(f, map, _MAXDEFSTR); gzputi(gamemode); - gzputi(ents.length()); - loopv(ents) gzputc(f, ents[i].spawned); + gzputi(ents.count); + for (Entity *e in ents) + gzputc(f, e.spawned); gzwrite(f, data.items, data.count); OFArray *monsters = getmonsters(); gzputi(monsters.count); for (DynamicEntity *monster in monsters) { data = [monster dataBySerializing]; @@ -203,18 +205,20 @@ loadgamerest() { if (demoplayback || !f) return; - if (gzgeti() != ents.length()) + if (gzgeti() != ents.count) 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); + + for (Entity *e in ents) { + e.spawned = (gzgetc(f) != 0); + + if (e.type == CARROT && !e.spawned) + trigger(e.attr1, e.attr2, true); } + restoreserverstate(ents); OFMutableData *data = [OFMutableData dataWithCapacity:DynamicEntity.serializedSize]; [data increaseCountBy:DynamicEntity.serializedSize]; Index: src/server.mm ================================================================== --- src/server.mm +++ src/server.mm @@ -2,10 +2,11 @@ // runs dedicated or as client coroutine #include "cube.h" #import "Client.h" +#import "Entity.h" enum { ST_EMPTY, ST_LOCAL, ST_TCPIP }; static OFMutableArray *clients; @@ -22,13 +23,13 @@ // true when map has changed and waiting for clients to send item bool notgotitems = true; int mode = 0; +// hack: called from savegame code, only works in SP void -restoreserverstate( - vector &ents) // hack: called from savegame code, only works in SP +restoreserverstate(OFArray *ents) { loopv(sents) { sents[i].spawned = ents[i].spawned; sents[i].spawnsecs = 0; Index: src/world.mm ================================================================== --- src/world.mm +++ src/world.mm @@ -1,10 +1,11 @@ // world.cpp: core map management stuff #include "cube.h" #import "DynamicEntity.h" +#import "Entity.h" extern OFString *entnames[]; // lookup from map entities above to strings sqr *world = NULL; int sfactor, ssize, cubicsize, mipsize; @@ -51,11 +52,15 @@ } // reset for editing or map saving void settagareas() { settag(0, 1); - loopv(ents) if (ents[i].type == CARROT) setspawn(i, true); + + [ents enumerateObjectsUsingBlock:^(Entity *e, size_t i, bool *stop) { + if (ents[i].type == CARROT) + setspawn(i, true); + }]; } // set for playing void trigger(int tag, int type, bool savegame) { @@ -254,25 +259,26 @@ 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]; + + __block int best; + __block float bdist = 99999; + [ents enumerateObjectsUsingBlock:^(Entity *e, size_t i, bool *stop) { if (e.type == NOTUSED) - continue; + return; + 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; + }]; + + return (bdist == 99999 ? -1 : best); } void entproperty(int prop, int amount) { @@ -317,16 +323,25 @@ loopi(MAXENTTYPES) if ([what isEqual:entnames[i]]) return i; conoutf(@"unknown entity type \"%@\"", what); return NOTUSED; } -entity * +Entity * newentity(int x, int y, int z, OFString *what, int v1, int v2, int v3, int v4) { int type = findtype(what); - persistent_entity e = { (short)x, (short)y, (short)z, (short)v1, - (uchar)type, (uchar)v2, (uchar)v3, (uchar)v4 }; + + PersistentEntity *e = [PersistentEntity entity]; + e.x = x; + e.y = y; + e.z = z; + e.attr1 = v1; + e.type = type; + e.attr2 = v2; + e.attr3 = v3; + e.attr4 = v4; + switch (type) { case LIGHT: if (v1 > 32) v1 = 32; if (!v1) @@ -343,71 +358,75 @@ e.attr2 = (uchar)e.attr1; case PLAYERSTART: e.attr1 = (int)player1.yaw; break; } - addmsg(1, 10, SV_EDITENT, ents.length(), type, e.x, e.y, e.z, e.attr1, + addmsg(1, 10, SV_EDITENT, ents.count, type, e.x, e.y, e.z, e.attr1, e.attr2, e.attr3, e.attr4); - ents.add(*((entity *)&e)); // unsafe! + + [ents addObject:e]; // unsafe! + if (type == LIGHT) calclight(); - return &ents.last(); + + return e; } void clearents(OFString *name) { int type = findtype(name); + if (noteditmode() || multiplayer()) return; - loopv(ents) - { - entity &e = ents[i]; + + for (Entity *e in ents) if (e.type == type) e.type = NOTUSED; - } + if (type == LIGHT) calclight(); } COMMAND(clearents, ARG_1STR) -void -scalecomp(uchar &c, int intens) +static uchar +scalecomp(uchar c, int intens) { int n = c * intens / 100; if (n > 255) n = 255; - c = n; + return n; } void scalelights(int f, int intens) { - loopv(ents) - { - entity &e = ents[i]; + for (Entity *e in ents) { 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); + e.attr2 = scalecomp(e.attr2, intens); + e.attr3 = scalecomp(e.attr3, intens); + e.attr4 = scalecomp(e.attr4, intens); } } + calclight(); } COMMAND(scalelights, ARG_2INT) int findentity(int type, int index) { - for (int i = index; i < ents.length(); i++) + for (int i = index; i < ents.count; i++) if (ents[i].type == type) return i; loopj(index) if (ents[j].type == type) return j; return -1; } @@ -472,22 +491,22 @@ loop(x, ssize / 2) loop(y, ssize / 2) { *S(x + ssize / 4, y + ssize / 4) = *SWS(oldworld, x, y, ssize / 2); } - loopv(ents) - { - ents[i].x += ssize / 4; - ents[i].y += ssize / 4; + + for (Entity *e in ents) { + e.x += ssize / 4; + e.y += ssize / 4; } } else { char buffer[128] = "Untitled Map by Unknown"; memcpy(hdr.maptitle, buffer, 128); hdr.waterlevel = -100000; loopi(15) hdr.reserved[i] = 0; loopk(3) loopi(256) hdr.texlists[k][i] = i; - ents.setsize(0); + [ents removeAllObjects]; block b = { 8, 8, ssize - 16, ssize - 16 }; edittypexy(SPACE, b); } calclight(); Index: src/worldio.mm ================================================================== --- src/worldio.mm +++ src/worldio.mm @@ -1,8 +1,17 @@ // worldio.cpp: loading & saving of maps and savegames #include "cube.h" + +#import "Entity.h" + +struct persistent_entity { + short x, y, z; // cube aligned position + short attr1; + uchar type; // type is one of the above + uchar attr2, attr3, attr4; +}; void backup(OFString *name, OFString *backupname) { [OFFileManager.defaultManager removeItemAtPath:backupname]; @@ -171,19 +180,21 @@ conoutf(@"could not write map to %@", cgzname); return; } hdr.version = MAPVERSION; hdr.numents = 0; - loopv(ents) if (ents[i].type != NOTUSED) hdr.numents++; + for (Entity *e in ents) + if (e.type != NOTUSED) + hdr.numents++; header tmp = hdr; endianswap(&tmp.version, sizeof(int), 4); endianswap(&tmp.waterlevel, sizeof(int), 16); gzwrite(f, &tmp, sizeof(header)); - loopv(ents) - { - if (ents[i].type != NOTUSED) { - entity tmp = ents[i]; + for (Entity *e in ents) { + if (e.type != NOTUSED) { + struct persistent_entity tmp = { e.x, e.y, e.z, e.attr1, + e.type, e.attr2, e.attr3, e.attr4 }; endianswap(&tmp, sizeof(short), 4); gzwrite(f, &tmp, sizeof(persistent_entity)); } } sqr *t = NULL; @@ -271,17 +282,28 @@ gzread(f, &hdr.waterlevel, sizeof(int) * 16); endianswap(&hdr.waterlevel, sizeof(int), 16); } else { hdr.waterlevel = -100000; } - ents.setsize(0); + [ents removeAllObjects]; loopi(hdr.numents) { - entity &e = ents.add(); - gzread(f, &e, sizeof(persistent_entity)); - endianswap(&e, sizeof(short), 4); - e.spawned = false; + struct persistent_entity tmp; + gzread(f, &tmp, sizeof(persistent_entity)); + endianswap(&tmp, sizeof(short), 4); + + Entity *e = [Entity entity]; + e.x = tmp.x; + e.y = tmp.y; + e.z = tmp.z; + e.attr1 = tmp.attr1; + e.type = tmp.type; + e.attr2 = tmp.attr2; + e.attr3 = tmp.attr3; + e.attr4 = tmp.attr4; + [ents addObject:e]; + if (e.type == LIGHT) { if (!e.attr2) e.attr2 = 255; // needed for MAPVERSION<=2 if (e.attr1 > 32) e.attr1 = 32; // 12_03 and below Index: src/worldlight.mm ================================================================== --- src/worldlight.mm +++ src/worldlight.mm @@ -1,18 +1,20 @@ // worldlight.cpp #include "cube.h" #import "DynamicEntity.h" +#import "Entity.h" +#import "PersistentEntity.h" extern bool hasoverbright; VAR(lightscale, 1, 4, 100); +// done in realtime, needs to be fast void -lightray(float bx, float by, - persistent_entity &light) // done in realtime, needs to be fast +lightray(float bx, float by, PersistentEntity *light) { float lx = light.x + (rnd(21) - 10) * 0.1f; float ly = light.y + (rnd(21) - 10) * 0.1f; float dx = bx - lx; float dy = by - ly; @@ -119,11 +121,11 @@ } } } void -calclightsource(persistent_entity &l) +calclightsource(PersistentEntity *l) { int reach = l.attr1; int sx = l.x - reach; int ex = l.x + reach; int sy = l.y - reach; @@ -173,16 +175,13 @@ { sqr *s = S(x, y); s->r = s->g = s->b = 10; } - loopv(ents) - { - entity &e = ents[i]; + for (Entity *e in ents) if (e.type == LIGHT) calclightsource(e); - } block b = { 1, 1, ssize - 2, ssize - 2 }; postlightarea(b); setvar(@"fullbright", 0); } @@ -234,12 +233,17 @@ // backup area before rendering in dynlight block *copy = blockcopy(b); [dlights addItem:©]; - persistent_entity l = { (short)v.x, (short)v.y, (short)v.z, - (short)reach, LIGHT, (uchar)strength, 0, 0 }; + PersistentEntity *l = [Entity entity]; + l.x = v.x; + l.y = v.y; + l.z = v.z; + l.attr1 = reach; + l.type = LIGHT; + l.attr2 = strength; calclightsource(l); postlightarea(b); } // utility functions also used by editing code