diff options
| author | xolatile | 2025-08-04 22:53:42 +0200 |
|---|---|---|
| committer | xolatile | 2025-08-04 22:53:42 +0200 |
| commit | d309df4ce4d8ad0ed995a8e1c4267412a7782021 (patch) | |
| tree | 999ca8d785ecc1681e5eb7538ce2e6a18d244fa5 /src/fpsgame/entities.cpp | |
| parent | 29d613d9cb65a0faa7e3f80e75bea0b6d910cb9a (diff) | |
| download | xolatile-badassbug-d309df4ce4d8ad0ed995a8e1c4267412a7782021.tar.xz xolatile-badassbug-d309df4ce4d8ad0ed995a8e1c4267412a7782021.tar.zst | |
Bunch of small changes...
Diffstat (limited to 'src/fpsgame/entities.cpp')
| -rw-r--r-- | src/fpsgame/entities.cpp | 886 |
1 files changed, 443 insertions, 443 deletions
diff --git a/src/fpsgame/entities.cpp b/src/fpsgame/entities.cpp index 4676ca8..dc0e175 100644 --- a/src/fpsgame/entities.cpp +++ b/src/fpsgame/entities.cpp @@ -4,456 +4,456 @@ int pwitemspicked[7] = { 0 }; namespace entities { - using namespace game; + using namespace game; - int extraentinfosize() { return 0; } // size in bytes of what the 2 methods below read/write... so it can be skipped by other games + int extraentinfosize() { return 0; } // size in bytes of what the 2 methods below read/write... so it can be skipped by other games - void writeent(entity &e, char *buf) // write any additional data to disk (except for ET_ ents) - { - } + void writeent(entity &e, char *buf) // write any additional data to disk (except for ET_ ents) + { + } - void readent(entity &e, char *buf, int ver) // read from disk, and init - { - if(ver <= 30) switch(e.type) - { - case TELEDEST: - e.attr1 = (int(e.attr1)+180)%360; - break; - } - } + void readent(entity &e, char *buf, int ver) // read from disk, and init + { + if(ver <= 30) switch(e.type) + { + case TELEDEST: + e.attr1 = (int(e.attr1)+180)%360; + break; + } + } #ifndef STANDALONE - vector<extentity *> ents; - - vector<extentity *> &getents() { return ents; } - - bool mayattach(extentity &e) { return false; } - bool attachent(extentity &e, extentity &a) { return false; } - - const char *itemname(int i) - { - int t = ents[i]->type; - if(t<I_SHELLS || t>I_QUAD) return NULL; - return itemstats[t-I_SHELLS].name; - } - - int itemicon(int i) - { - int t = ents[i]->type; - if(t<I_SHELLS || t>I_QUAD) return -1; - return itemstats[t-I_SHELLS].icon; - } - - const char *entmdlname(int type) - { - static const char * const entmdlnames[] = - { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - "ammo/shells", "ammo/bullets", "ammo/rockets", "ammo/rrounds", "ammo/grenades", "ammo/cartridges", - "health", "boost", "tinyhealth", "tinyarmour", "armor/green", "armor/yellow", "quad", "teleporter", - NULL, NULL, - "carrot", - NULL, NULL, - "checkpoint", - NULL, NULL, - NULL, NULL, - NULL - }; - return entmdlnames[type]; - } - - const char *entmodel(const entity &e) - { - if(e.type == TELEPORT) - { - if(e.attr2 > 0) return mapmodelname(e.attr2); - if(e.attr2 < 0) return NULL; - } - return e.type < MAXENTTYPES ? entmdlname(e.type) : NULL; - } - - void preloadentities() - { - loopi(MAXENTTYPES) - { - switch(i) - { - case I_SHELLS: - [[fallthrough]]; - case I_BULLETS: - [[fallthrough]]; - case I_ROCKETS: - [[fallthrough]]; - case I_ROUNDS: - [[fallthrough]]; - case I_GRENADES: - [[fallthrough]]; - case I_CARTRIDGES: - if(m_noammo) continue; - break; - case I_HEALTH: - [[fallthrough]]; - case I_BOOST: - [[fallthrough]]; - case I_TINYHEALTH: - [[fallthrough]]; - case I_TINYARMOUR: - [[fallthrough]]; - case I_GREENARMOUR: - [[fallthrough]]; - case I_YELLOWARMOUR: - [[fallthrough]]; - case I_QUAD: - if(m_noitems) continue; - break; - } - const char *mdl = entmdlname(i); - if(!mdl) continue; - preloadmodel(mdl); - } - loopv(ents) - { - extentity &e = *ents[i]; - switch(e.type) - { - case TELEPORT: - if(e.attr2 > 0) preloadmodel(mapmodelname(e.attr2)); - [[fallthrough]]; - - case JUMPPAD: - if(e.attr4 > 0) preloadmapsound(e.attr4); - break; - } - } - } - - void renderentities() - { - loopv(ents) - { - extentity &e = *ents[i]; - int revs = 10; - switch(e.type) - { - case TELEPORT: - if(e.attr2 < 0) continue; - break; - default: - if(!e.spawned() || e.type < I_SHELLS || e.type > I_QUAD) continue; - } - const char *mdlname = entmodel(e); - if(mdlname) - { - vec p = e.o; - p.z += 1+sinf(lastmillis/100.0+e.o.x+e.o.y)/20; - rendermodel(&e.light, mdlname, ANIM_MAPMODEL|ANIM_LOOP, p, lastmillis/(float)revs, 0, MDL_SHADOW | MDL_CULL_VFC | MDL_CULL_DIST | MDL_CULL_OCCLUDED); - } - } - } - - void addammo(int type, int &v, bool local) - { - itemstat &is = itemstats[type-I_SHELLS]; - v += is.add; - if(v>is.max) v = is.max; - if(local) msgsound(is.sound); - } - - void repammo(fpsent *d, int type, bool local) - { - addammo(type, d->ammo[type-I_SHELLS+GUN_SG], local); - } - - // 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 pickupeffects(int n, fpsent *d) - { - if(!ents.inrange(n)) return; - extentity *e = ents[n]; - int type = e->type; - if(type<I_SHELLS || type>I_QUAD) return; - e->clearspawned(); - e->clearnopickup(); - if(!d) return; - itemstat &is = itemstats[type-I_SHELLS]; - fpsent *h = followingplayer(player1); - if(d!=h || isthirdperson()) - { - //particle_text(d->abovehead(), is.name, PART_TEXT, 2000, 0xFFC864, 4.0f, -8); - particle_icon(d->abovehead(), is.icon%4, is.icon/4, PART_HUD_ICON_GREY, 2000, 0xFFFFFF, 2.0f, -8); - } - playsound(itemstats[type-I_SHELLS].sound, d!=h ? &d->o : NULL, NULL, 0, 0, 0, -1, 0, 1500); - d->pickup(type); - switch(type) { - case I_TINYARMOUR: pwitemspicked[0]++; break; - case I_GREENARMOUR: pwitemspicked[1]++; break; - case I_YELLOWARMOUR: pwitemspicked[2]++; break; - case I_TINYHEALTH: pwitemspicked[3]++; break; - case I_HEALTH: pwitemspicked[4]++; break; - case I_BOOST: pwitemspicked[5]++; break; - case I_QUAD: pwitemspicked[6]++; break; - } - if(d==h) switch(type) - { - case I_BOOST: - conoutf(CON_GAMEINFO, "\f2you got the health boost!"); - playsound(S_V_BOOST, NULL, NULL, 0, 0, 0, -1, 0, 3000); - break; - - case I_QUAD: - conoutf(CON_GAMEINFO, "\f2you got the quad!"); - playsound(S_V_QUAD, NULL, NULL, 0, 0, 0, -1, 0, 3000); - break; - } - } - - // these functions are called when the client touches the item - - void teleporteffects(fpsent *d, int tp, int td, bool local) - { - if(ents.inrange(tp) && ents[tp]->type == TELEPORT) - { - extentity &e = *ents[tp]; - if(e.attr4 >= 0) - { - int snd = S_TELEPORT, flags = 0; - if(e.attr4 > 0) { snd = e.attr4; flags = SND_MAP; } - fpsent *h = followingplayer(player1); - playsound(snd, d==h ? NULL : &e.o, NULL, flags); - if(d!=h && ents.inrange(td) && ents[td]->type == TELEDEST) playsound(snd, &ents[td]->o, NULL, flags); - } - } - if(local && d->clientnum >= 0) - { - sendposition(d); - packetbuf p(32, ENET_PACKET_FLAG_RELIABLE); - putint(p, N_TELEPORT); - putint(p, d->clientnum); - putint(p, tp); - putint(p, td); - sendclientpacket(p.finalize(), 0); - flushclient(); - } - } - - void jumppadeffects(fpsent *d, int jp, bool local) - { - if(ents.inrange(jp) && ents[jp]->type == JUMPPAD) - { - extentity &e = *ents[jp]; - if(e.attr4 >= 0) - { - int snd = S_JUMPPAD, flags = 0; - if(e.attr4 > 0) { snd = e.attr4; flags = SND_MAP; } - playsound(snd, d == followingplayer(player1) ? NULL : &e.o, NULL, flags); - } - } - if(local && d->clientnum >= 0) - { - sendposition(d); - packetbuf p(16, ENET_PACKET_FLAG_RELIABLE); - putint(p, N_JUMPPAD); - putint(p, d->clientnum); - putint(p, jp); - sendclientpacket(p.finalize(), 0); - flushclient(); - } - } - - void teleport(int n, fpsent *d) // also used by monsters - { - int e = -1, tag = ents[n]->attr1, beenhere = -1; - for(;;) - { - e = findentity(TELEDEST, e+1); - if(e==beenhere || e<0) { conoutf(CON_WARN, "no teleport destination for tag %d", tag); return; } - if(beenhere<0) beenhere = e; - if(ents[e]->attr2==tag) - { - teleporteffects(d, n, e, true); - d->o = ents[e]->o; - d->yaw = ents[e]->attr1; - if(ents[e]->attr3 > 0) - { - vec dir; - vecfromyawpitch(d->yaw, 0, 1, 0, dir); - float speed = d->vel.magnitude2(); - d->vel.x = dir.x*speed; - d->vel.y = dir.y*speed; - } - else d->vel = vec(0, 0, 0); - entinmap(d); - updatedynentcache(d); - ai::inferwaypoints(d, ents[n]->o, ents[e]->o, 16.f); - break; - } - } - } - - void trypickup(int n, fpsent *d) - { - extentity *e = ents[n]; - switch(e->type) - { - default: - if(d->canpickup(e->type)) - { - addmsg(N_ITEMPICKUP, "rci", d, n); - e->setnopickup(); // even if someone else gets it first - } - break; - - case TELEPORT: - { - if(d->lastpickup==e->type && lastmillis-d->lastpickupmillis<500) break; - if(e->attr3 > 0) - { - defformatstring(hookname, "can_teleport_%d", e->attr3); - if(!execidentbool(hookname, true)) break; - } - d->lastpickup = e->type; - d->lastpickupmillis = lastmillis; - teleport(n, d); - break; - } - - case JUMPPAD: - { - if(d->lastpickup==e->type && lastmillis-d->lastpickupmillis<300) break; - d->lastpickup = e->type; - d->lastpickupmillis = lastmillis; - jumppadeffects(d, n, true); - vec v((int)(char)e->attr3*10.0f, (int)(char)e->attr2*10.0f, e->attr1*12.5f); - if(d->ai) d->ai->becareful = true; + vector<extentity *> ents; + + vector<extentity *> &getents() { return ents; } + + bool mayattach(extentity &e) { return false; } + bool attachent(extentity &e, extentity &a) { return false; } + + const char *itemname(int i) + { + int t = ents[i]->type; + if(t<I_SHELLS || t>I_QUAD) return NULL; + return itemstats[t-I_SHELLS].name; + } + + int itemicon(int i) + { + int t = ents[i]->type; + if(t<I_SHELLS || t>I_QUAD) return -1; + return itemstats[t-I_SHELLS].icon; + } + + const char *entmdlname(int type) + { + static const char * const entmdlnames[] = + { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + "ammo/shells", "ammo/bullets", "ammo/rockets", "ammo/rrounds", "ammo/grenades", "ammo/cartridges", + "health", "boost", "tinyhealth", "tinyarmour", "armor/green", "armor/yellow", "quad", "teleporter", + NULL, NULL, + "carrot", + NULL, NULL, + "checkpoint", + NULL, NULL, + NULL, NULL, + NULL + }; + return entmdlnames[type]; + } + + const char *entmodel(const entity &e) + { + if(e.type == TELEPORT) + { + if(e.attr2 > 0) return mapmodelname(e.attr2); + if(e.attr2 < 0) return NULL; + } + return e.type < MAXENTTYPES ? entmdlname(e.type) : NULL; + } + + void preloadentities() + { + loopi(MAXENTTYPES) + { + switch(i) + { + case I_SHELLS: + [[fallthrough]]; + case I_BULLETS: + [[fallthrough]]; + case I_ROCKETS: + [[fallthrough]]; + case I_ROUNDS: + [[fallthrough]]; + case I_GRENADES: + [[fallthrough]]; + case I_CARTRIDGES: + if(m_noammo) continue; + break; + case I_HEALTH: + [[fallthrough]]; + case I_BOOST: + [[fallthrough]]; + case I_TINYHEALTH: + [[fallthrough]]; + case I_TINYARMOUR: + [[fallthrough]]; + case I_GREENARMOUR: + [[fallthrough]]; + case I_YELLOWARMOUR: + [[fallthrough]]; + case I_QUAD: + if(m_noitems) continue; + break; + } + const char *mdl = entmdlname(i); + if(!mdl) continue; + preloadmodel(mdl); + } + loopv(ents) + { + extentity &e = *ents[i]; + switch(e.type) + { + case TELEPORT: + if(e.attr2 > 0) preloadmodel(mapmodelname(e.attr2)); + [[fallthrough]]; + + case JUMPPAD: + if(e.attr4 > 0) preloadmapsound(e.attr4); + break; + } + } + } + + void renderentities() + { + loopv(ents) + { + extentity &e = *ents[i]; + int revs = 10; + switch(e.type) + { + case TELEPORT: + if(e.attr2 < 0) continue; + break; + default: + if(!e.spawned() || e.type < I_SHELLS || e.type > I_QUAD) continue; + } + const char *mdlname = entmodel(e); + if(mdlname) + { + vec p = e.o; + p.z += 1+sinf(lastmillis/100.0+e.o.x+e.o.y)/20; + rendermodel(&e.light, mdlname, ANIM_MAPMODEL|ANIM_LOOP, p, lastmillis/(float)revs, 0, MDL_SHADOW | MDL_CULL_VFC | MDL_CULL_DIST | MDL_CULL_OCCLUDED); + } + } + } + + void addammo(int type, int &v, bool local) + { + itemstat &is = itemstats[type-I_SHELLS]; + v += is.add; + if(v>is.max) v = is.max; + if(local) msgsound(is.sound); + } + + void repammo(fpsent *d, int type, bool local) + { + addammo(type, d->ammo[type-I_SHELLS+GUN_SG], local); + } + + // 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 pickupeffects(int n, fpsent *d) + { + if(!ents.inrange(n)) return; + extentity *e = ents[n]; + int type = e->type; + if(type<I_SHELLS || type>I_QUAD) return; + e->clearspawned(); + e->clearnopickup(); + if(!d) return; + itemstat &is = itemstats[type-I_SHELLS]; + fpsent *h = followingplayer(player1); + if(d!=h || isthirdperson()) + { + //particle_text(d->abovehead(), is.name, PART_TEXT, 2000, 0xFFC864, 4.0f, -8); + particle_icon(d->abovehead(), is.icon%4, is.icon/4, PART_HUD_ICON_GREY, 2000, 0xFFFFFF, 2.0f, -8); + } + playsound(itemstats[type-I_SHELLS].sound, d!=h ? &d->o : NULL, NULL, 0, 0, 0, -1, 0, 1500); + d->pickup(type); + switch(type) { + case I_TINYARMOUR: pwitemspicked[0]++; break; + case I_GREENARMOUR: pwitemspicked[1]++; break; + case I_YELLOWARMOUR: pwitemspicked[2]++; break; + case I_TINYHEALTH: pwitemspicked[3]++; break; + case I_HEALTH: pwitemspicked[4]++; break; + case I_BOOST: pwitemspicked[5]++; break; + case I_QUAD: pwitemspicked[6]++; break; + } + if(d==h) switch(type) + { + case I_BOOST: + conoutf(CON_GAMEINFO, "\f2you got the health boost!"); + playsound(S_V_BOOST, NULL, NULL, 0, 0, 0, -1, 0, 3000); + break; + + case I_QUAD: + conoutf(CON_GAMEINFO, "\f2you got the quad!"); + playsound(S_V_QUAD, NULL, NULL, 0, 0, 0, -1, 0, 3000); + break; + } + } + + // these functions are called when the client touches the item + + void teleporteffects(fpsent *d, int tp, int td, bool local) + { + if(ents.inrange(tp) && ents[tp]->type == TELEPORT) + { + extentity &e = *ents[tp]; + if(e.attr4 >= 0) + { + int snd = S_TELEPORT, flags = 0; + if(e.attr4 > 0) { snd = e.attr4; flags = SND_MAP; } + fpsent *h = followingplayer(player1); + playsound(snd, d==h ? NULL : &e.o, NULL, flags); + if(d!=h && ents.inrange(td) && ents[td]->type == TELEDEST) playsound(snd, &ents[td]->o, NULL, flags); + } + } + if(local && d->clientnum >= 0) + { + sendposition(d); + packetbuf p(32, ENET_PACKET_FLAG_RELIABLE); + putint(p, N_TELEPORT); + putint(p, d->clientnum); + putint(p, tp); + putint(p, td); + sendclientpacket(p.finalize(), 0); + flushclient(); + } + } + + void jumppadeffects(fpsent *d, int jp, bool local) + { + if(ents.inrange(jp) && ents[jp]->type == JUMPPAD) + { + extentity &e = *ents[jp]; + if(e.attr4 >= 0) + { + int snd = S_JUMPPAD, flags = 0; + if(e.attr4 > 0) { snd = e.attr4; flags = SND_MAP; } + playsound(snd, d == followingplayer(player1) ? NULL : &e.o, NULL, flags); + } + } + if(local && d->clientnum >= 0) + { + sendposition(d); + packetbuf p(16, ENET_PACKET_FLAG_RELIABLE); + putint(p, N_JUMPPAD); + putint(p, d->clientnum); + putint(p, jp); + sendclientpacket(p.finalize(), 0); + flushclient(); + } + } + + void teleport(int n, fpsent *d) // also used by monsters + { + int e = -1, tag = ents[n]->attr1, beenhere = -1; + for(;;) + { + e = findentity(TELEDEST, e+1); + if(e==beenhere || e<0) { conoutf(CON_WARN, "no teleport destination for tag %d", tag); return; } + if(beenhere<0) beenhere = e; + if(ents[e]->attr2==tag) + { + teleporteffects(d, n, e, true); + d->o = ents[e]->o; + d->yaw = ents[e]->attr1; + if(ents[e]->attr3 > 0) + { + vec dir; + vecfromyawpitch(d->yaw, 0, 1, 0, dir); + float speed = d->vel.magnitude2(); + d->vel.x = dir.x*speed; + d->vel.y = dir.y*speed; + } + else d->vel = vec(0, 0, 0); + entinmap(d); + updatedynentcache(d); + ai::inferwaypoints(d, ents[n]->o, ents[e]->o, 16.f); + break; + } + } + } + + void trypickup(int n, fpsent *d) + { + extentity *e = ents[n]; + switch(e->type) + { + default: + if(d->canpickup(e->type)) + { + addmsg(N_ITEMPICKUP, "rci", d, n); + e->setnopickup(); // even if someone else gets it first + } + break; + + case TELEPORT: + { + if(d->lastpickup==e->type && lastmillis-d->lastpickupmillis<500) break; + if(e->attr3 > 0) + { + defformatstring(hookname, "can_teleport_%d", e->attr3); + if(!execidentbool(hookname, true)) break; + } + d->lastpickup = e->type; + d->lastpickupmillis = lastmillis; + teleport(n, d); + break; + } + + case JUMPPAD: + { + if(d->lastpickup==e->type && lastmillis-d->lastpickupmillis<300) break; + d->lastpickup = e->type; + d->lastpickupmillis = lastmillis; + jumppadeffects(d, n, true); + vec v((int)(char)e->attr3*10.0f, (int)(char)e->attr2*10.0f, e->attr1*12.5f); + if(d->ai) d->ai->becareful = true; d->falling = vec(0, 0, 0); d->physstate = PHYS_FALL; - d->timeinair = 1; - d->vel = v; - break; - } - } - } - - void checkitems(fpsent *d) - { - if(d->state!=CS_ALIVE) return; - vec o = d->feetpos(); - loopv(ents) - { - extentity &e = *ents[i]; - if(e.type==NOTUSED) continue; - if((!e.spawned() || e.nopickup()) && e.type!=TELEPORT && e.type!=JUMPPAD) continue; - float dist = e.o.dist(o); - if(dist<(e.type==TELEPORT ? 16 : 12)) trypickup(i, d); - } - } - - void checkquad(int time, fpsent *d) - { - if(d->quadmillis && (d->quadmillis -= time)<=0) - { - d->quadmillis = 0; - fpsent *h = followingplayer(player1); - playsound(S_PUPOUT, d==h ? NULL : &d->o); - if(d==h) conoutf(CON_GAMEINFO, "\f2quad damage is over"); - } - } - - void putitems(packetbuf &p) // puts items in network stream and also spawns them locally - { - putint(p, N_ITEMLIST); - loopv(ents) if(ents[i]->type>=I_SHELLS && ents[i]->type<=I_QUAD && (!m_noammo || ents[i]->type<I_SHELLS || ents[i]->type>I_CARTRIDGES)) - { - putint(p, i); - putint(p, ents[i]->type); - } - putint(p, -1); - } - - void resetspawns() { loopv(ents) { extentity *e = ents[i]; e->clearspawned(); e->clearnopickup(); } } - - void spawnitems(bool force) - { - if(m_noitems) return; - loopv(ents) - { - extentity *e = ents[i]; - if(e->type>=I_SHELLS && e->type<=I_QUAD && (!m_noammo || e->type<I_SHELLS || e->type>I_CARTRIDGES)) - { - e->setspawned(force || !server::delayspawn(e->type)); - e->clearnopickup(); - } - } - } - - void setspawn(int i, bool on) { if(ents.inrange(i)) { extentity *e = ents[i]; e->setspawned(on); e->clearnopickup(); } } - - extentity *newentity() { return new extentity(); } - void deleteentity(extentity *e) { delete e; } - - void clearents() - { - while(ents.length()) deleteentity(ents.pop()); - } - - void fixentity(extentity &e) - { - if(e.type == TELEDEST) e.attr3 = e.attr2; - } - - void entradius(extentity &e, bool color) - { - switch(e.type) - { - case TELEDEST: - { - vec dir; - vecfromyawpitch(e.attr1, 0, 1, 0, dir); - renderentarrow(e, dir, 4); - break; - } - case TELEPORT: - loopv(ents) if(ents[i]->type == TELEDEST && e.attr1==ents[i]->attr2) - { - renderentarrow(e, vec(ents[i]->o).sub(e.o).normalize(), e.o.dist(ents[i]->o)); - break; - } - break; - - case JUMPPAD: - renderentarrow(e, vec((int)(char)e.attr3*10.0f, (int)(char)e.attr2*10.0f, e.attr1*12.5f).normalize(), 4); - break; - - default: break; - } - } - - bool printent(extentity &e, char *buf, int len) - { - return false; - } - - const char *entnameinfo(entity &e) { return ""; } - const char *entname(int i) - { - static const char * const entnames[] = - { - "none?", "light", "mapmodel", "playerstart", "envmap", "particles", "sound", "spotlight", - "shells", "bullets", "rockets", "riflerounds", "grenades", "cartridges", - "health", "healthboost", "tinyhealth", "tinyarmour", "greenarmour", "yellowarmour", "quaddamage", - "teleport", "teledest", - "jumppad", - "", "", "", "", - }; - return i>=0 && size_t(i)<sizeof(entnames)/sizeof(entnames[0]) ? entnames[i] : ""; - } - - void editent(int i, bool local) - { - extentity &e = *ents[i]; - if(local) addmsg(N_EDITENT, "rii3ii5", i, (int)(e.o.x*DMF), (int)(e.o.y*DMF), (int)(e.o.z*DMF), e.type, e.attr1, e.attr2, e.attr3, e.attr4, e.attr5); - } + d->timeinair = 1; + d->vel = v; + break; + } + } + } + + void checkitems(fpsent *d) + { + if(d->state!=CS_ALIVE) return; + vec o = d->feetpos(); + loopv(ents) + { + extentity &e = *ents[i]; + if(e.type==NOTUSED) continue; + if((!e.spawned() || e.nopickup()) && e.type!=TELEPORT && e.type!=JUMPPAD) continue; + float dist = e.o.dist(o); + if(dist<(e.type==TELEPORT ? 16 : 12)) trypickup(i, d); + } + } + + void checkquad(int time, fpsent *d) + { + if(d->quadmillis && (d->quadmillis -= time)<=0) + { + d->quadmillis = 0; + fpsent *h = followingplayer(player1); + playsound(S_PUPOUT, d==h ? NULL : &d->o); + if(d==h) conoutf(CON_GAMEINFO, "\f2quad damage is over"); + } + } + + void putitems(packetbuf &p) // puts items in network stream and also spawns them locally + { + putint(p, N_ITEMLIST); + loopv(ents) if(ents[i]->type>=I_SHELLS && ents[i]->type<=I_QUAD && (!m_noammo || ents[i]->type<I_SHELLS || ents[i]->type>I_CARTRIDGES)) + { + putint(p, i); + putint(p, ents[i]->type); + } + putint(p, -1); + } + + void resetspawns() { loopv(ents) { extentity *e = ents[i]; e->clearspawned(); e->clearnopickup(); } } + + void spawnitems(bool force) + { + if(m_noitems) return; + loopv(ents) + { + extentity *e = ents[i]; + if(e->type>=I_SHELLS && e->type<=I_QUAD && (!m_noammo || e->type<I_SHELLS || e->type>I_CARTRIDGES)) + { + e->setspawned(force || !server::delayspawn(e->type)); + e->clearnopickup(); + } + } + } + + void setspawn(int i, bool on) { if(ents.inrange(i)) { extentity *e = ents[i]; e->setspawned(on); e->clearnopickup(); } } + + extentity *newentity() { return new extentity(); } + void deleteentity(extentity *e) { delete e; } + + void clearents() + { + while(ents.length()) deleteentity(ents.pop()); + } + + void fixentity(extentity &e) + { + if(e.type == TELEDEST) e.attr3 = e.attr2; + } + + void entradius(extentity &e, bool color) + { + switch(e.type) + { + case TELEDEST: + { + vec dir; + vecfromyawpitch(e.attr1, 0, 1, 0, dir); + renderentarrow(e, dir, 4); + break; + } + case TELEPORT: + loopv(ents) if(ents[i]->type == TELEDEST && e.attr1==ents[i]->attr2) + { + renderentarrow(e, vec(ents[i]->o).sub(e.o).normalize(), e.o.dist(ents[i]->o)); + break; + } + break; + + case JUMPPAD: + renderentarrow(e, vec((int)(char)e.attr3*10.0f, (int)(char)e.attr2*10.0f, e.attr1*12.5f).normalize(), 4); + break; + + default: break; + } + } + + bool printent(extentity &e, char *buf, int len) + { + return false; + } + + const char *entnameinfo(entity &e) { return ""; } + const char *entname(int i) + { + static const char * const entnames[] = + { + "none?", "light", "mapmodel", "playerstart", "envmap", "particles", "sound", "spotlight", + "shells", "bullets", "rockets", "riflerounds", "grenades", "cartridges", + "health", "healthboost", "tinyhealth", "tinyarmour", "greenarmour", "yellowarmour", "quaddamage", + "teleport", "teledest", + "jumppad", + "", "", "", "", + }; + return i>=0 && size_t(i)<sizeof(entnames)/sizeof(entnames[0]) ? entnames[i] : ""; + } + + void editent(int i, bool local) + { + extentity &e = *ents[i]; + if(local) addmsg(N_EDITENT, "rii3ii5", i, (int)(e.o.x*DMF), (int)(e.o.y*DMF), (int)(e.o.z*DMF), e.type, e.attr1, e.attr2, e.attr3, e.attr4, e.attr5); + } #endif } |
