1 // movable.h: implements physics for inanimate models
12 PLATFORMWEIGHT
= 1000,
17 struct movable
: dynent
19 int etype
, mapmodel
, health
, weight
, explode
, tag
, dir
;
22 movable(const entity
&e
, movableset
*ms
) :
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
))),
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),
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;
51 push
.mul(80*damage
/weight
);
56 void damaged(int damage
, fpsent
*at
, int gun
= -1)
58 if(etype
!=BARREL
|| state
!=CS_ALIVE
|| explode
) return;
61 if(gun
==GUN_BARREL
) explode
= ms
->cl
.lastmillis
+ EXPLODEDELAY
;
65 ms
->cl
.ws
.explode(true, at
, o
, this, guns
[GUN_BARREL
].damage
, GUN_BARREL
);
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
)
88 movables
.deletecontentsp();
90 if(!m_dmsp
&& !m_classicsp
) return;
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);
102 void triggerplatform(int tag
, int newdir
)
104 newdir
= max(-1, min(1, newdir
));
107 movable
*m
= movables
[i
];
108 if(m
->state
!=CS_ALIVE
|| (m
->etype
!=PLATFORM
&& m
->etype
!=ELEVATOR
) || m
->tag
!=tag
) continue;
111 if(m
->tag
) m
->vel
= vec(0, 0, 0);
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
)
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);
136 if(!moveplatform(m
, vec(m
->vel
).mul(step
/1000.0f
)))
138 if(m
->tag
) { m
->vel
= vec(0, 0, 0); break; }
143 else if(m
->explode
&& cl
.lastmillis
>= m
->explode
)
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);
157 movable
&m
= *movables
[i
];
158 if(m
.state
!=CS_ALIVE
) continue;
159 vec
o(m
.o
), color
, dir
;
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
);