diff options
| author | xolatile | 2025-07-16 23:07:43 +0200 |
|---|---|---|
| committer | xolatile | 2025-07-16 23:07:43 +0200 |
| commit | 7256502afa0babe60fcafbd2888cd3e33c3f9b6b (patch) | |
| tree | 8a8495662a69bdadc4b5d9152656b9f02a44d668 /src/fpsgame/entities.cpp | |
| parent | bc596ac9d4cdd00abf537b88d3c544be161330cc (diff) | |
| download | xolatile-badassbug-7256502afa0babe60fcafbd2888cd3e33c3f9b6b.tar.xz xolatile-badassbug-7256502afa0babe60fcafbd2888cd3e33c3f9b6b.tar.zst | |
Source code, broken...
Diffstat (limited to 'src/fpsgame/entities.cpp')
| -rw-r--r-- | src/fpsgame/entities.cpp | 709 |
1 files changed, 709 insertions, 0 deletions
diff --git a/src/fpsgame/entities.cpp b/src/fpsgame/entities.cpp new file mode 100644 index 0000000..c35a0d1 --- /dev/null +++ b/src/fpsgame/entities.cpp @@ -0,0 +1,709 @@ +#include "game.h" + +namespace entities +{ + 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 + + 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 FLAG: + case MONSTER: + case TELEDEST: + case RESPAWNPOINT: + case BOX: + case BARREL: + case PLATFORM: + case ELEVATOR: + e.attr1 = (int(e.attr1)+180)%360; + break; + } + if(ver <= 31) switch(e.type) + { + case BOX: + case BARREL: + case PLATFORM: + case ELEVATOR: + int yaw = (int(e.attr1)%360 + 360)%360 + 7; + e.attr1 = yaw - yaw%15; + 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", "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: case I_BULLETS: case I_ROCKETS: case I_ROUNDS: case I_GRENADES: case I_CARTRIDGES: + if(m_noammo) continue; + break; + case I_HEALTH: case I_BOOST: case I_GREENARMOUR: case I_YELLOWARMOUR: case I_QUAD: + if(m_noitems) continue; + break; + case CARROT: case RESPAWNPOINT: + if(!m_classicsp) 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)); + 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 CARROT: + case RESPAWNPOINT: + if(e.attr2) revs = 1; + break; + 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); + 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 RESPAWNPOINT: + if(!m_classicsp || d!=player1 || n==respawnent) break; + respawnent = n; + conoutf(CON_GAMEINFO, "\f2respawn point set!"); + playsound(S_V_RESPAWNPOINT); + 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 && e.type!=RESPAWNPOINT) 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 || m_sp || !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 fpsentity(); } + void deleteentity(extentity *e) { delete (fpsentity *)e; } + + void clearents() + { + while(ents.length()) deleteentity(ents.pop()); + } + + enum + { + TRIG_COLLIDE = 1<<0, + TRIG_TOGGLE = 1<<1, + TRIG_ONCE = 0<<2, + TRIG_MANY = 1<<2, + TRIG_DISAPPEAR = 1<<3, + TRIG_AUTO_RESET = 1<<4, + TRIG_RUMBLE = 1<<5, + TRIG_LOCKED = 1<<6, + TRIG_ENDSP = 1<<7 + }; + + static const int NUMTRIGGERTYPES = 32; + + static const int triggertypes[NUMTRIGGERTYPES] = + { + -1, + TRIG_ONCE, // 1 + TRIG_RUMBLE, // 2 + TRIG_TOGGLE, // 3 + TRIG_TOGGLE | TRIG_RUMBLE, // 4 + TRIG_MANY, // 5 + TRIG_MANY | TRIG_RUMBLE, // 6 + TRIG_MANY | TRIG_TOGGLE, // 7 + TRIG_MANY | TRIG_TOGGLE | TRIG_RUMBLE, // 8 + TRIG_COLLIDE | TRIG_TOGGLE | TRIG_RUMBLE, // 9 + TRIG_COLLIDE | TRIG_TOGGLE | TRIG_AUTO_RESET | TRIG_RUMBLE, // 10 + TRIG_COLLIDE | TRIG_TOGGLE | TRIG_LOCKED | TRIG_RUMBLE, // 11 + TRIG_DISAPPEAR, // 12 + TRIG_DISAPPEAR | TRIG_RUMBLE, // 13 + TRIG_DISAPPEAR | TRIG_COLLIDE | TRIG_LOCKED, // 14 + -1 /* reserved 15 */, + -1 /* reserved 16 */, + -1 /* reserved 17 */, + -1 /* reserved 18 */, + -1 /* reserved 19 */, + -1 /* reserved 20 */, + -1 /* reserved 21 */, + -1 /* reserved 22 */, + -1 /* reserved 23 */, + -1 /* reserved 24 */, + -1 /* reserved 25 */, + -1 /* reserved 26 */, + -1 /* reserved 27 */, + -1 /* reserved 28 */, + TRIG_DISAPPEAR | TRIG_RUMBLE | TRIG_ENDSP, // 29 + -1 /* reserved 30 */, + -1 /* reserved 31 */, + }; + + #define validtrigger(type) (triggertypes[(type) & (NUMTRIGGERTYPES-1)]>=0) + #define checktriggertype(type, flag) (triggertypes[(type) & (NUMTRIGGERTYPES-1)] & (flag)) + + static inline void cleartriggerflags(extentity &e) + { + e.flags &= ~(EF_ANIM | EF_NOVIS | EF_NOSHADOW | EF_NOCOLLIDE); + } + + static inline void setuptriggerflags(fpsentity &e) + { + cleartriggerflags(e); + e.flags |= EF_ANIM; + if(checktriggertype(e.attr3, TRIG_COLLIDE|TRIG_DISAPPEAR)) e.flags |= EF_NOSHADOW; + if(!checktriggertype(e.attr3, TRIG_COLLIDE)) e.flags |= EF_NOCOLLIDE; + switch(e.triggerstate) + { + case TRIGGERING: + if(checktriggertype(e.attr3, TRIG_COLLIDE) && lastmillis-e.lasttrigger >= 500) e.flags |= EF_NOCOLLIDE; + break; + case TRIGGERED: + if(checktriggertype(e.attr3, TRIG_COLLIDE)) e.flags |= EF_NOCOLLIDE; + break; + case TRIGGER_DISAPPEARED: + e.flags |= EF_NOVIS | EF_NOCOLLIDE; + break; + } + } + + void resettriggers() + { + loopv(ents) + { + fpsentity &e = *(fpsentity *)ents[i]; + if(e.type != ET_MAPMODEL || !validtrigger(e.attr3)) continue; + e.triggerstate = TRIGGER_RESET; + e.lasttrigger = 0; + setuptriggerflags(e); + } + } + + void unlocktriggers(int tag, int oldstate = TRIGGER_RESET, int newstate = TRIGGERING) + { + loopv(ents) + { + fpsentity &e = *(fpsentity *)ents[i]; + if(e.type != ET_MAPMODEL || !validtrigger(e.attr3)) continue; + if(e.attr4 == tag && e.triggerstate == oldstate && checktriggertype(e.attr3, TRIG_LOCKED)) + { + if(newstate == TRIGGER_RESETTING && checktriggertype(e.attr3, TRIG_COLLIDE) && overlapsdynent(e.o, 20)) continue; + e.triggerstate = newstate; + e.lasttrigger = lastmillis; + if(checktriggertype(e.attr3, TRIG_RUMBLE)) playsound(S_RUMBLE, &e.o); + } + } + } + + ICOMMAND(trigger, "ii", (int *tag, int *state), + { + if(*state) unlocktriggers(*tag); + else unlocktriggers(*tag, TRIGGERED, TRIGGER_RESETTING); + }); + + VAR(triggerstate, -1, 0, 1); + + void doleveltrigger(int trigger, int state) + { + defformatstring(aliasname, "level_trigger_%d", trigger); + if(identexists(aliasname)) + { + triggerstate = state; + execident(aliasname); + } + } + + void checktriggers() + { + if(player1->state != CS_ALIVE) return; + vec o = player1->feetpos(); + loopv(ents) + { + fpsentity &e = *(fpsentity *)ents[i]; + if(e.type != ET_MAPMODEL || !validtrigger(e.attr3)) continue; + switch(e.triggerstate) + { + case TRIGGERING: + case TRIGGER_RESETTING: + if(lastmillis-e.lasttrigger>=1000) + { + if(e.attr4) + { + if(e.triggerstate == TRIGGERING) unlocktriggers(e.attr4); + else unlocktriggers(e.attr4, TRIGGERED, TRIGGER_RESETTING); + } + if(checktriggertype(e.attr3, TRIG_DISAPPEAR)) e.triggerstate = TRIGGER_DISAPPEARED; + else if(e.triggerstate==TRIGGERING && checktriggertype(e.attr3, TRIG_TOGGLE)) e.triggerstate = TRIGGERED; + else e.triggerstate = TRIGGER_RESET; + } + setuptriggerflags(e); + break; + case TRIGGER_RESET: + if(e.lasttrigger) + { + if(checktriggertype(e.attr3, TRIG_AUTO_RESET|TRIG_MANY|TRIG_LOCKED) && e.o.dist(o)-player1->radius>=(checktriggertype(e.attr3, TRIG_COLLIDE) ? 20 : 12)) + e.lasttrigger = 0; + break; + } + else if(e.o.dist(o)-player1->radius>=(checktriggertype(e.attr3, TRIG_COLLIDE) ? 20 : 12)) break; + else if(checktriggertype(e.attr3, TRIG_LOCKED)) + { + if(!e.attr4) break; + doleveltrigger(e.attr4, -1); + e.lasttrigger = lastmillis; + break; + } + e.triggerstate = TRIGGERING; + e.lasttrigger = lastmillis; + setuptriggerflags(e); + if(checktriggertype(e.attr3, TRIG_RUMBLE)) playsound(S_RUMBLE, &e.o); + if(checktriggertype(e.attr3, TRIG_ENDSP)) endsp(false); + if(e.attr4) doleveltrigger(e.attr4, 1); + break; + case TRIGGERED: + if(e.o.dist(o)-player1->radius<(checktriggertype(e.attr3, TRIG_COLLIDE) ? 20 : 12)) + { + if(e.lasttrigger) break; + } + else if(checktriggertype(e.attr3, TRIG_AUTO_RESET)) + { + if(lastmillis-e.lasttrigger<6000) break; + } + else if(checktriggertype(e.attr3, TRIG_MANY)) + { + e.lasttrigger = 0; + break; + } + else break; + if(checktriggertype(e.attr3, TRIG_COLLIDE) && overlapsdynent(e.o, 20)) break; + e.triggerstate = TRIGGER_RESETTING; + e.lasttrigger = lastmillis; + setuptriggerflags(e); + if(checktriggertype(e.attr3, TRIG_RUMBLE)) playsound(S_RUMBLE, &e.o); + if(checktriggertype(e.attr3, TRIG_ENDSP)) endsp(false); + if(e.attr4) doleveltrigger(e.attr4, 0); + break; + } + } + } + + void animatemapmodel(const extentity &e, int &anim, int &basetime) + { + const fpsentity &f = (const fpsentity &)e; + if(validtrigger(f.attr3)) switch(f.triggerstate) + { + case TRIGGER_RESET: anim = ANIM_TRIGGER|ANIM_START; break; + case TRIGGERING: anim = ANIM_TRIGGER; basetime = f.lasttrigger; break; + case TRIGGERED: anim = ANIM_TRIGGER|ANIM_END; break; + case TRIGGER_RESETTING: anim = ANIM_TRIGGER|ANIM_REVERSE; basetime = f.lasttrigger; break; + } + } + + void fixentity(extentity &e) + { + switch(e.type) + { + case FLAG: + case BOX: + case BARREL: + case PLATFORM: + case ELEVATOR: + e.attr5 = e.attr4; + e.attr4 = e.attr3; + case TELEDEST: + e.attr3 = e.attr2; + case MONSTER: + e.attr2 = e.attr1; + case RESPAWNPOINT: + e.attr1 = (int)player1->yaw; + break; + } + } + + void entradius(extentity &e, bool color) + { + switch(e.type) + { + 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; + + case FLAG: + case MONSTER: + case TELEDEST: + case RESPAWNPOINT: + case BOX: + case BARREL: + case PLATFORM: + case ELEVATOR: + { + vec dir; + vecfromyawpitch(e.attr1, 0, 1, 0, dir); + renderentarrow(e, dir, 4); + break; + } + case MAPMODEL: + if(validtrigger(e.attr3)) renderentring(e, checktriggertype(e.attr3, TRIG_COLLIDE) ? 20 : 12); + 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", "greenarmour", "yellowarmour", "quaddamage", + "teleport", "teledest", + "monster", "carrot", "jumppad", + "base", "respawnpoint", + "box", "barrel", + "platform", "elevator", + "flag", + "", "", "", "", + }; + return i>=0 && size_t(i)<sizeof(entnames)/sizeof(entnames[0]) ? entnames[i] : ""; + } + + void editent(int i, bool local) + { + extentity &e = *ents[i]; + if(e.type == ET_MAPMODEL && validtrigger(e.attr3)) + { + fpsentity &f = (fpsentity &)e; + f.triggerstate = TRIGGER_RESET; + f.lasttrigger = 0; + setuptriggerflags(f); + } + else cleartriggerflags(e); + 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); + } + + float dropheight(entity &e) + { + if(e.type==BASE || e.type==FLAG) return 0.0f; + return 4.0f; + } +#endif +} + |
