Initial sauer
[SauerbratenRemote.git] / src / fpsgame / movable.h
blob1331a34e28c88f440242d9b7d24752763be79093
1 // movable.h: implements physics for inanimate models
3 struct movableset
5 fpsclient &cl;
7 enum
9 BOXWEIGHT = 25,
10 BARRELHEALTH = 50,
11 BARRELWEIGHT = 25,
12 PLATFORMWEIGHT = 1000,
13 PLATFORMSPEED = 8,
14 EXPLODEDELAY = 200
17 struct movable : dynent
19 int etype, mapmodel, health, weight, explode, tag, dir;
20 movableset *ms;
22 movable(const entity &e, movableset *ms) :
23 etype(e.type),
24 mapmodel(e.attr2),
25 health(e.type==BARREL ? (e.attr4 ? e.attr4 : BARRELHEALTH) : 0),
26 weight(e.type==PLATFORM || e.type==ELEVATOR ? PLATFORMWEIGHT : (e.type==e.attr3 ? e.attr3 : (e.type==BARREL ? BARRELWEIGHT : BOXWEIGHT))),
27 explode(0),
28 tag(e.type==PLATFORM || e.type==ELEVATOR ? e.attr3 : 0),
29 dir(e.type==PLATFORM || e.type==ELEVATOR ? (e.attr4 < 0 ? -1 : 1) : 0),
30 ms(ms)
32 state = CS_ALIVE;
33 type = ENT_INANIMATE;
34 yaw = float((e.attr1+7)-(e.attr1+7)%15);
35 if(e.type==PLATFORM || e.type==ELEVATOR)
37 maxspeed = e.attr4 ? fabs(float(e.attr4)) : PLATFORMSPEED;
38 if(tag) vel = vec(0, 0, 0);
39 else if(e.type==PLATFORM) { vecfromyawpitch(yaw, 0, 1, 0, vel); vel.mul(dir*maxspeed); }
40 else vel = vec(0, 0, dir*maxspeed);
43 const char *mdlname = mapmodelname(e.attr2);
44 if(mdlname) setbbfrommodel(this, mdlname);
47 void hitpush(int damage, const vec &dir, fpsent *actor, int gun)
49 if(etype!=BOX && etype!=BARREL) return;
50 vec push(dir);
51 push.mul(80*damage/weight);
52 vel.add(push);
53 moving = true;
56 void damaged(int damage, fpsent *at, int gun = -1)
58 if(etype!=BARREL || state!=CS_ALIVE || explode) return;
59 health -= damage;
60 if(health>0) return;
61 if(gun==GUN_BARREL) explode = ms->cl.lastmillis + EXPLODEDELAY;
62 else
64 state = CS_DEAD;
65 ms->cl.ws.explode(true, at, o, this, guns[GUN_BARREL].damage, GUN_BARREL);
69 void suicide()
71 state = CS_DEAD;
72 if(etype==BARREL) ms->cl.ws.explode(true, ms->cl.player1, o, this, guns[GUN_BARREL].damage, GUN_BARREL);
76 movableset(fpsclient &cl) : cl(cl)
78 CCOMMAND(platform, "ii", (movableset *self, int *tag, int *newdir), self->triggerplatform(*tag, *newdir));
81 vector<movable *> movables;
83 void clear(int gamemode)
85 if(movables.length())
87 cleardynentcache();
88 movables.deletecontentsp();
90 if(!m_dmsp && !m_classicsp) return;
91 loopv(cl.et.ents)
93 const entity &e = *cl.et.ents[i];
94 if(e.type!=BOX && e.type!=BARREL && e.type!=PLATFORM && e.type!=ELEVATOR) continue;
95 movable *m = new movable(e, this);
96 movables.add(m);
97 m->o = e.o;
98 entinmap(m, true);
102 void triggerplatform(int tag, int newdir)
104 newdir = max(-1, min(1, newdir));
105 loopv(movables)
107 movable *m = movables[i];
108 if(m->state!=CS_ALIVE || (m->etype!=PLATFORM && m->etype!=ELEVATOR) || m->tag!=tag) continue;
109 if(!newdir)
111 if(m->tag) m->vel = vec(0, 0, 0);
112 else m->vel.neg();
114 else
116 if(m->etype==PLATFORM) { vecfromyawpitch(m->yaw, 0, 1, 0, m->vel); m->vel.mul(newdir*m->dir*m->maxspeed); }
117 else m->vel = vec(0, 0, newdir*m->dir*m->maxspeed);
122 void update(int curtime)
124 if(!curtime) return;
125 loopv(movables)
127 movable *m = movables[i];
128 if(m->state!=CS_ALIVE) continue;
129 if(m->etype==PLATFORM || m->etype==ELEVATOR)
131 if(m->vel.iszero() || !insideworld(m->o)) continue;
132 for(int remaining = curtime; remaining>0;)
134 int step = min(remaining, 20);
135 remaining -= step;
136 if(!moveplatform(m, vec(m->vel).mul(step/1000.0f)))
138 if(m->tag) { m->vel = vec(0, 0, 0); break; }
139 else m->vel.neg();
143 else if(m->explode && cl.lastmillis >= m->explode)
145 m->state = CS_DEAD;
146 m->explode = 0;
147 cl.ws.explode(true, (fpsent *)m, m->o, m, guns[GUN_BARREL].damage, GUN_BARREL);
149 else if(m->moving || (m->onplayer && (m->onplayer->state!=CS_ALIVE || m->lastmoveattempt <= m->onplayer->lastmove))) moveplayer(m, 2, false);
153 void render()
155 loopv(movables)
157 movable &m = *movables[i];
158 if(m.state!=CS_ALIVE) continue;
159 vec o(m.o), color, dir;
160 o.z -= m.eyeheight;
161 const char *mdlname = mapmodelname(m.mapmodel);
162 if(!mdlname) continue;
163 rendermodel(color, dir, mdlname, ANIM_MAPMODEL|ANIM_LOOP, 0, 0, o, m.yaw, 0, 0, 0, &m, MDL_SHADOW | MDL_CULL_VFC | MDL_CULL_DIST | MDL_CULL_OCCLUDED, NULL);