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 this.solid = SOLID_NOT;
49 else if (this.antiwall_flag == 2)
52 this.solid = this.default_solid;
54 g_clientmodel_setcolormaptoactivator(this, actor, trigger);
57 void g_model_dropbyspawnflags(entity this)
59 if((this.spawnflags & 3) == 1) // ALIGN_ORIGIN
61 traceline(this.origin, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
62 setorigin(this, trace_endpos);
64 else if((this.spawnflags & 3) == 2) // ALIGN_BOTTOM
66 tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
67 setorigin(this, trace_endpos);
69 else if((this.spawnflags & 3) == 3) // ALIGN_ORIGIN | ALIGN_BOTTOM
71 traceline(this.origin, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
72 setorigin(this, trace_endpos - '0 0 1' * this.mins.z);
76 void g_clientmodel_think(entity this)
78 this.nextthink = time;
79 if(this.oldorigin != this.origin)
80 this.SendFlags |= BIT(1);
81 this.oldorigin = this.origin;
84 void g_clientmodel_dropbyspawnflags(entity this)
88 g_model_dropbyspawnflags(this);
90 this.SendFlags |= BIT(1);
93 bool g_clientmodel_genericsendentity(entity this, entity to, int sf)
96 if(this.angles != '0 0 0')
98 if(this.mins != '0 0 0' || this.maxs != '0 0 0')
100 if(this.colormap != 0)
102 if(this.lodmodelindex1)
105 WriteHeader(MSG_ENTITY, ENT_CLIENT_WALL);
106 WriteByte(MSG_ENTITY, sf);
111 WriteShort(MSG_ENTITY, this.colormap);
112 WriteByte(MSG_ENTITY, this.skin);
117 WriteVector(MSG_ENTITY, this.origin);
123 WriteAngleVector(MSG_ENTITY, this.angles);
130 WriteShort(MSG_ENTITY, this.lodmodelindex0);
131 WriteShort(MSG_ENTITY, bound(0, this.loddistance1, 32767));
132 WriteShort(MSG_ENTITY, this.lodmodelindex1);
133 WriteShort(MSG_ENTITY, bound(0, this.loddistance2, 32767));
134 WriteShort(MSG_ENTITY, this.lodmodelindex2);
137 WriteShort(MSG_ENTITY, this.modelindex);
138 WriteByte(MSG_ENTITY, this.solid);
139 WriteShort(MSG_ENTITY, floor(this.scale * 256));
142 WriteVector(MSG_ENTITY, this.mins);
143 WriteVector(MSG_ENTITY, this.maxs);
145 WriteString(MSG_ENTITY, this.bgmscript);
146 if(this.bgmscript != "")
148 WriteByte(MSG_ENTITY, floor(this.bgmscriptattack * 64));
149 WriteByte(MSG_ENTITY, floor(this.bgmscriptdecay * 64));
150 WriteByte(MSG_ENTITY, floor(this.bgmscriptsustain * 255));
151 WriteByte(MSG_ENTITY, floor(this.bgmscriptrelease * 64));
152 WriteVector(MSG_ENTITY, this.movedir);
153 WriteByte(MSG_ENTITY, floor(this.lip * 255));
155 WriteShort(MSG_ENTITY, bound(0, this.fade_start, 32767));
156 WriteShort(MSG_ENTITY, bound(0, this.fade_end, 32767));
157 WriteByte(MSG_ENTITY, floor(this.alpha_max * 256));
158 WriteByte(MSG_ENTITY, floor(this.alpha_min * 256));
159 WriteByte(MSG_ENTITY, this.inactive);
160 WriteShort(MSG_ENTITY, this.fade_vertical_offset);
166 void g_model_init(entity ent, float sol)
168 if(ent.geomtype && autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) set_movetype(ent, MOVETYPE_PHYSICS);
169 if(!ent.scale) ent.scale = ent.modelscale;
170 SetBrushEntityModel(ent,true);
171 ent.use = g_model_setcolormaptoactivator;
172 InitializeEntity(ent, g_model_dropbyspawnflags, INITPRIO_DROPTOFLOOR);
173 if(!ent.solid) ent.solid = (sol);
174 else if(ent.solid < 0) ent.solid = SOLID_NOT;
177 void g_clientmodel_init(entity ent, float sol)
179 if(ent.geomtype && autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) set_movetype(ent, MOVETYPE_PHYSICS);
180 if(!ent.scale) ent.scale = ent.modelscale;
181 SetBrushEntityModel(ent,true);
182 ent.use = g_clientmodel_use;
183 setthink(ent, g_clientmodel_think);
184 ent.nextthink = time;
185 ent.oldorigin = ent.origin; // don't run an initial double update
186 InitializeEntity(ent, g_clientmodel_dropbyspawnflags, INITPRIO_DROPTOFLOOR);
187 if(!ent.solid) ent.solid = (sol);
188 else if(ent.solid < 0) ent.solid = SOLID_NOT;
189 if(!ent.bgmscriptsustain) ent.bgmscriptsustain = 1;
190 else if(ent.bgmscriptsustain < 0) ent.bgmscriptsustain = 0;
191 Net_LinkEntity(ent, true, 0, g_clientmodel_genericsendentity);
192 ent.default_solid = sol;
195 // non-solid model entities:
196 spawnfunc(misc_gamemodel) { this.angles_x = -this.angles.x; g_model_init(this, SOLID_NOT); } // model entity
197 spawnfunc(misc_clientmodel) { this.angles_x = -this.angles.x; g_clientmodel_init(this, SOLID_NOT); } // model entity
198 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
200 // non-solid brush entities:
201 spawnfunc(func_illusionary) { g_model_init(this, SOLID_NOT); } // Q1 name (WARNING: MISPREDICTED)
202 spawnfunc(func_clientillusionary) { g_clientmodel_init(this, SOLID_NOT); } // brush entity
204 // solid brush entities
205 spawnfunc(func_wall) { g_model_init(this, SOLID_BSP); } // Q1 name
206 spawnfunc(func_clientwall) { g_clientmodel_init(this, SOLID_BSP); } // brush entity (WARNING: MISPREDICTED)
207 spawnfunc(func_static) { g_model_init(this, SOLID_BSP); } // DEPRECATED old alias name from some other game
213 void Ent_Wall_PreDraw(entity this)
215 float alph = this.alpha;
222 vector org = getpropertyvec(VF_ORIGIN);
223 if(!checkpvs(org, this))
225 else if(this.fade_start || this.fade_end) {
226 vector offset = '0 0 0';
227 offset_z = this.fade_vertical_offset;
228 vector player_dist_math = org - this.origin - 0.5 * (this.mins + this.maxs) + offset;
229 if (this.fade_end == this.fade_start)
231 if (vdist(player_dist_math, >=, this.fade_start))
238 float player_dist = vlen(player_dist_math);
239 alph = (this.alpha_min + this.alpha_max * bound(0,
240 (this.fade_end - player_dist)
241 / (this.fade_end - this.fade_start), 1)) / 100.0;
250 this.drawmask = (alph <= 0) ? 0 : MASK_NORMAL;
253 void Ent_Wall_Draw(entity this)
258 if(this.bgmscriptangular)
262 this.(fld) = this.saved;
264 CSQCModel_LOD_Apply(this, false);
266 InterpolateOrigin_Do(this);
268 this.saved = this.(fld);
270 f = doBGMScript(this);
273 if(this.lip < 0) // < 0: alpha goes from 1 to 1-|lip| when toggled (toggling subtracts lip)
274 this.alpha = 1 + this.lip * f;
275 else // > 0: alpha goes from 1-|lip| to 1 when toggled (toggling adds lip)
276 this.alpha = 1 - this.lip * (1 - f);
277 this.(fld) = this.(fld) + this.movedir * f;
282 if(this.alpha >= ALPHA_MIN_VISIBLE)
283 this.drawmask = MASK_NORMAL;
288 void Ent_Wall_Remove(entity this)
290 strfree(this.bgmscript);
293 NET_HANDLE(ENT_CLIENT_WALL, bool isnew)
298 InterpolateOrigin_Undo(this);
299 this.iflags = IFLAG_ANGLES | IFLAG_ORIGIN;
301 if(this.bgmscriptangular)
305 this.(fld) = this.saved;
312 this.colormap = ReadShort();
315 this.skin = ReadByte();
320 this.origin = ReadVector();
321 setorigin(this, this.origin);
327 this.angles = ReadAngleVector();
329 this.angles = '0 0 0';
336 this.lodmodelindex0 = ReadShort();
337 this.loddistance1 = ReadShort();
338 this.lodmodelindex1 = ReadShort();
339 this.loddistance2 = ReadShort();
340 this.lodmodelindex2 = ReadShort();
341 this.modelindex = this.lodmodelindex0;
342 vector pmin = this.mins, pmax = this.maxs;
343 setmodelindex(this, this.modelindex); // this retrieves the .model key and sets mins/maxs/absmin/absmax
344 setsize(this, pmin, pmax);
345 // if there's no second LOD model, fall back to the first
346 // avoids using the high quality model at a distance
347 if(!this.lodmodelindex2 && this.lodmodelindex1)
348 this.lodmodelindex2 = this.lodmodelindex1;
352 this.modelindex = ReadShort();
353 vector pmin = this.mins, pmax = this.maxs;
354 setmodelindex(this, this.modelindex); // this retrieves the .model key and sets mins/maxs/absmin/absmax
355 setsize(this, pmin, pmax);
356 this.loddistance1 = 0;
357 this.loddistance2 = 0;
359 this.solid = ReadByte();
360 this.scale = ReadShort() / 256.0;
363 this.mins = ReadVector();
364 this.maxs = ReadVector();
367 this.mins = this.maxs = '0 0 0';
368 setsize(this, this.mins, this.maxs);
370 string s = ReadString();
371 if(substring(s, 0, 1) == "<")
373 strcpy(this.bgmscript, substring(s, 1, -1));
374 this.bgmscriptangular = 1;
378 strcpy(this.bgmscript, s);
379 this.bgmscriptangular = 0;
381 if(this.bgmscript != "")
383 this.bgmscriptattack = ReadByte() / 64.0;
384 this.bgmscriptdecay = ReadByte() / 64.0;
385 this.bgmscriptsustain = ReadByte() / 255.0;
386 this.bgmscriptrelease = ReadByte() / 64.0;
387 this.movedir = ReadVector();
388 this.lip = ReadByte() / 255.0;
390 this.fade_start = ReadShort();
391 this.fade_end = ReadShort();
392 this.alpha_max = ReadByte() / 255.0;
393 this.alpha_min = ReadByte() / 255.0;
394 this.inactive = ReadByte();
395 this.fade_vertical_offset = ReadShort();
396 BGMScript_InitEntity(this);
401 InterpolateOrigin_Note(this);
403 this.saved = this.(fld);
405 this.entremove = Ent_Wall_Remove;
406 this.draw = Ent_Wall_Draw;
407 if (isnew) IL_PUSH(g_drawables, this);
408 setpredraw(this, Ent_Wall_PreDraw);