4 #include <client/csqcmodel_hooks.qh>
8 #include <common/constants.qh>
9 #include <common/mapobjects/bgmscript.qh>
10 #include <common/mapobjects/subs.qh>
11 #include <common/mapobjects/triggers.qh>
12 #include <common/net_linked.qh>
13 #include <common/stats.qh>
14 #include <common/weapons/_all.qh>
15 #include <lib/csqcmodel/sv_model.qh>
17 void g_model_setcolormaptoactivator(entity this, entity actor, entity trigger)
22 this.colormap = (actor.team - 1) * 0x11;
27 this.colormap = floor(random() * 256);
28 this.colormap |= BIT(10); // RENDER_COLORMAPPED
31 void g_clientmodel_setcolormaptoactivator(entity this, entity actor, entity trigger)
33 g_model_setcolormaptoactivator(this, actor, trigger);
34 this.SendFlags |= (BIT(3) | BIT(0));
37 void g_clientmodel_use(entity this, entity actor, entity trigger)
39 // Flag to set func_clientwall state
40 // 1 == deactivate, 2 == activate, 0 == do nothing
41 if(this.classname == "func_clientwall" || this.classname == "func_clientillusionary")
42 this.antiwall_flag = trigger.antiwall_flag;
44 if (this.antiwall_flag == 1)
47 if (this.solid != SOLID_NOT)
49 this.solid = SOLID_NOT;
50 setorigin(this, this.origin); // unlink
53 else if (this.antiwall_flag == 2)
56 if (this.solid != this.default_solid)
58 this.solid = this.default_solid;
59 setorigin(this, this.origin); // link
62 g_clientmodel_setcolormaptoactivator(this, actor, trigger);
65 void g_model_dropbyspawnflags(entity this)
67 if((this.spawnflags & 3) == 1) // ALIGN_ORIGIN
69 traceline(this.origin, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
70 setorigin(this, trace_endpos);
72 else if((this.spawnflags & 3) == 2) // ALIGN_BOTTOM
74 tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
75 setorigin(this, trace_endpos);
77 else if((this.spawnflags & 3) == 3) // ALIGN_ORIGIN | ALIGN_BOTTOM
79 traceline(this.origin, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
80 setorigin(this, trace_endpos - '0 0 1' * this.mins.z);
84 void g_clientmodel_think(entity this)
86 this.nextthink = time;
87 if(this.oldorigin != this.origin)
88 this.SendFlags |= BIT(1);
89 this.oldorigin = this.origin;
92 void g_clientmodel_dropbyspawnflags(entity this)
96 g_model_dropbyspawnflags(this);
98 this.SendFlags |= BIT(1);
101 bool g_clientmodel_genericsendentity(entity this, entity to, int sf)
104 if(this.angles != '0 0 0')
106 if(this.mins != '0 0 0' || this.maxs != '0 0 0')
108 if(this.colormap != 0)
110 if(this.lodmodelindex1)
113 WriteHeader(MSG_ENTITY, ENT_CLIENT_WALL);
114 WriteByte(MSG_ENTITY, sf);
119 WriteShort(MSG_ENTITY, this.colormap);
120 WriteByte(MSG_ENTITY, this.skin);
125 WriteVector(MSG_ENTITY, this.origin);
131 WriteAngleVector(MSG_ENTITY, this.angles);
138 WriteShort(MSG_ENTITY, this.lodmodelindex0);
139 WriteShort(MSG_ENTITY, bound(0, this.loddistance1, 32767));
140 WriteShort(MSG_ENTITY, this.lodmodelindex1);
141 WriteShort(MSG_ENTITY, bound(0, this.loddistance2, 32767));
142 WriteShort(MSG_ENTITY, this.lodmodelindex2);
145 WriteShort(MSG_ENTITY, this.modelindex);
146 WriteByte(MSG_ENTITY, this.solid);
147 WriteShort(MSG_ENTITY, floor(this.scale * 256));
150 WriteVector(MSG_ENTITY, this.mins);
151 WriteVector(MSG_ENTITY, this.maxs);
153 WriteString(MSG_ENTITY, this.bgmscript);
154 if(this.bgmscript != "")
156 WriteByte(MSG_ENTITY, floor(this.bgmscriptattack * 64));
157 WriteByte(MSG_ENTITY, floor(this.bgmscriptdecay * 64));
158 WriteByte(MSG_ENTITY, floor(this.bgmscriptsustain * 255));
159 WriteByte(MSG_ENTITY, floor(this.bgmscriptrelease * 64));
160 WriteVector(MSG_ENTITY, this.movedir);
161 WriteByte(MSG_ENTITY, floor(this.lip * 255));
163 WriteShort(MSG_ENTITY, bound(0, this.fade_start, 32767));
164 WriteShort(MSG_ENTITY, bound(0, this.fade_end, 32767));
165 WriteByte(MSG_ENTITY, floor(this.alpha_max * 256));
166 WriteByte(MSG_ENTITY, floor(this.alpha_min * 256));
167 WriteByte(MSG_ENTITY, this.inactive);
168 WriteShort(MSG_ENTITY, this.fade_vertical_offset);
174 void g_model_init(entity ent, float sol)
176 if(ent.geomtype && autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) set_movetype(ent, MOVETYPE_PHYSICS);
177 if(!ent.scale) ent.scale = ent.modelscale;
179 if(!ent.solid) ent.solid = (sol);
180 else if(ent.solid < 0) ent.solid = SOLID_NOT;
181 SetBrushEntityModel(ent,true); // called after setting .solid to ensure correct area grid linking/unlinking
183 ent.use = g_model_setcolormaptoactivator;
184 InitializeEntity(ent, g_model_dropbyspawnflags, INITPRIO_DROPTOFLOOR);
187 void g_clientmodel_init(entity ent, float sol)
189 if(ent.geomtype && autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) set_movetype(ent, MOVETYPE_PHYSICS);
190 if(!ent.scale) ent.scale = ent.modelscale;
192 if(!ent.solid) ent.solid = (sol);
193 else if(ent.solid < 0) ent.solid = SOLID_NOT;
194 SetBrushEntityModel(ent,true); // called after setting .solid to ensure correct area grid linking/unlinking
196 ent.use = g_clientmodel_use;
197 setthink(ent, g_clientmodel_think);
198 ent.nextthink = time;
199 ent.oldorigin = ent.origin; // don't run an initial double update
200 InitializeEntity(ent, g_clientmodel_dropbyspawnflags, INITPRIO_DROPTOFLOOR);
201 if(!ent.bgmscriptsustain) ent.bgmscriptsustain = 1;
202 else if(ent.bgmscriptsustain < 0) ent.bgmscriptsustain = 0;
203 Net_LinkEntity(ent, true, 0, g_clientmodel_genericsendentity);
204 ent.default_solid = sol;
207 // non-solid model entities:
208 spawnfunc(misc_gamemodel) { this.angles_x = -this.angles.x; g_model_init(this, SOLID_NOT); } // model entity
209 spawnfunc(misc_clientmodel) { this.angles_x = -this.angles.x; g_clientmodel_init(this, SOLID_NOT); } // model entity
210 spawnfunc(misc_models) { this.angles_x = -this.angles.x; g_model_init(this, SOLID_NOT); } // DEPRECATED old compat entity with confusing name, do not use
212 // non-solid brush entities:
213 spawnfunc(func_illusionary) { g_model_init(this, SOLID_NOT); } // Q1 name (WARNING: MISPREDICTED)
214 spawnfunc(func_clientillusionary) { g_clientmodel_init(this, SOLID_NOT); } // brush entity
216 // solid brush entities
217 spawnfunc(func_wall) { g_model_init(this, SOLID_BSP); } // Q1 name
218 spawnfunc(func_clientwall) { g_clientmodel_init(this, SOLID_BSP); } // brush entity (WARNING: MISPREDICTED)
219 spawnfunc(func_static) { g_model_init(this, SOLID_BSP); } // DEPRECATED old alias name from some other game
225 void Ent_Wall_PreDraw(entity this)
227 float alph = this.alpha;
234 vector org = getpropertyvec(VF_ORIGIN);
235 if(!checkpvs(org, this))
237 else if(this.fade_start || this.fade_end) {
238 vector offset = '0 0 0';
239 offset_z = this.fade_vertical_offset;
240 vector player_dist_math = org - this.origin - 0.5 * (this.mins + this.maxs) + offset;
241 if (this.fade_end == this.fade_start)
243 if (vdist(player_dist_math, >=, this.fade_start))
250 float player_dist = vlen(player_dist_math);
251 alph = (this.alpha_min + this.alpha_max * bound(0,
252 (this.fade_end - player_dist)
253 / (this.fade_end - this.fade_start), 1)) / 100.0;
262 this.drawmask = (alph <= 0) ? 0 : MASK_NORMAL;
265 void Ent_Wall_Draw(entity this)
270 if(this.bgmscriptangular)
274 this.(fld) = this.saved;
276 CSQCModel_LOD_Apply(this, false);
278 InterpolateOrigin_Do(this);
280 this.saved = this.(fld);
282 f = doBGMScript(this);
285 if(this.lip < 0) // < 0: alpha goes from 1 to 1-|lip| when toggled (toggling subtracts lip)
286 this.alpha = 1 + this.lip * f;
287 else // > 0: alpha goes from 1-|lip| to 1 when toggled (toggling adds lip)
288 this.alpha = 1 - this.lip * (1 - f);
289 this.(fld) = this.(fld) + this.movedir * f;
294 if(this.alpha >= ALPHA_MIN_VISIBLE)
295 this.drawmask = MASK_NORMAL;
300 void Ent_Wall_Remove(entity this)
302 strfree(this.bgmscript);
305 NET_HANDLE(ENT_CLIENT_WALL, bool isnew)
310 InterpolateOrigin_Undo(this);
311 this.iflags = IFLAG_ANGLES | IFLAG_ORIGIN;
313 if(this.bgmscriptangular)
317 this.(fld) = this.saved;
324 this.colormap = ReadShort();
327 this.skin = ReadByte();
332 this.origin = ReadVector();
333 setorigin(this, this.origin);
339 this.angles = ReadAngleVector();
341 this.angles = '0 0 0';
348 this.lodmodelindex0 = ReadShort();
349 this.loddistance1 = ReadShort();
350 this.lodmodelindex1 = ReadShort();
351 this.loddistance2 = ReadShort();
352 this.lodmodelindex2 = ReadShort();
353 this.modelindex = this.lodmodelindex0;
354 vector pmin = this.mins, pmax = this.maxs;
355 setmodelindex(this, this.modelindex); // this retrieves the .model key and sets mins/maxs/absmin/absmax
356 setsize(this, pmin, pmax);
357 // if there's no second LOD model, fall back to the first
358 // avoids using the high quality model at a distance
359 if(!this.lodmodelindex2 && this.lodmodelindex1)
360 this.lodmodelindex2 = this.lodmodelindex1;
364 this.modelindex = ReadShort();
365 vector pmin = this.mins, pmax = this.maxs;
366 setmodelindex(this, this.modelindex); // this retrieves the .model key and sets mins/maxs/absmin/absmax
367 setsize(this, pmin, pmax);
368 this.loddistance1 = 0;
369 this.loddistance2 = 0;
371 this.solid = ReadByte();
372 this.scale = ReadShort() / 256.0;
375 this.mins = ReadVector();
376 this.maxs = ReadVector();
379 this.mins = this.maxs = '0 0 0';
380 setsize(this, this.mins, this.maxs);
382 string s = ReadString();
383 if(substring(s, 0, 1) == "<")
385 strcpy(this.bgmscript, substring(s, 1, -1));
386 this.bgmscriptangular = 1;
390 strcpy(this.bgmscript, s);
391 this.bgmscriptangular = 0;
393 if(this.bgmscript != "")
395 this.bgmscriptattack = ReadByte() / 64.0;
396 this.bgmscriptdecay = ReadByte() / 64.0;
397 this.bgmscriptsustain = ReadByte() / 255.0;
398 this.bgmscriptrelease = ReadByte() / 64.0;
399 this.movedir = ReadVector();
400 this.lip = ReadByte() / 255.0;
402 this.fade_start = ReadShort();
403 this.fade_end = ReadShort();
404 this.alpha_max = ReadByte() / 255.0;
405 this.alpha_min = ReadByte() / 255.0;
406 this.inactive = ReadByte();
407 this.fade_vertical_offset = ReadShort();
408 BGMScript_InitEntity(this);
413 InterpolateOrigin_Note(this);
415 this.saved = this.(fld);
417 this.entremove = Ent_Wall_Remove;
418 this.draw = Ent_Wall_Draw;
419 if (isnew) IL_PUSH(g_drawables, this);
420 setpredraw(this, Ent_Wall_PreDraw);