Properly support team field on trigger_multiple
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / g_models.qc
1 #include "g_models.qh"
2
3 #include <server/defs.qh>
4 #include <server/miscfunctions.qh>
5 #include "g_subs.qh"
6 #include <common/net_linked.qh>
7 #include "../common/triggers/subs.qh"
8 #include "../common/triggers/triggers.qh"
9
10 entityclass(BGMScript);
11 class(BGMScript) .string bgmscript;
12 class(BGMScript) .float bgmscriptattack;
13 class(BGMScript) .float bgmscriptdecay;
14 class(BGMScript) .float bgmscriptsustain;
15 class(BGMScript) .float bgmscriptrelease;
16
17 #include "../common/constants.qh"
18 #include "../lib/csqcmodel/sv_model.qh"
19
20 .float modelscale;
21
22 void g_model_setcolormaptoactivator(entity this, entity actor, entity trigger)
23 {
24         if(teamplay)
25         {
26                 if(actor.team)
27                         this.colormap = (actor.team - 1) * 0x11;
28                 else
29                         this.colormap = 0x00;
30         }
31         else
32                 this.colormap = floor(random() * 256);
33         this.colormap |= BIT(10); // RENDER_COLORMAPPED
34 }
35
36 void g_clientmodel_setcolormaptoactivator(entity this, entity actor, entity trigger)
37 {
38         g_model_setcolormaptoactivator(this, actor, trigger);
39         this.SendFlags |= (BIT(3) | BIT(0));
40 }
41
42 void g_clientmodel_use(entity this, entity actor, entity trigger)
43 {
44         if (this.antiwall_flag == 1)
45         {
46                 this.inactive = 1;
47                 this.solid = SOLID_NOT;
48         }
49         else if (this.antiwall_flag == 2)
50         {
51                 this.inactive = 0;
52                 this.solid = this.default_solid;
53         }
54         g_clientmodel_setcolormaptoactivator(this, actor, trigger);
55 }
56
57 void g_model_dropbyspawnflags(entity this)
58 {
59         if((this.spawnflags & 3) == 1) // ALIGN_ORIGIN
60         {
61                 traceline(this.origin, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
62                 setorigin(this, trace_endpos);
63         }
64         else if((this.spawnflags & 3) == 2) // ALIGN_BOTTOM
65         {
66                 tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
67                 setorigin(this, trace_endpos);
68         }
69         else if((this.spawnflags & 3) == 3) // ALIGN_ORIGIN | ALIGN_BOTTOM
70         {
71                 traceline(this.origin, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
72                 setorigin(this, trace_endpos - '0 0 1' * this.mins.z);
73         }
74 }
75
76 void g_clientmodel_dropbyspawnflags(entity this)
77 {
78         vector o0;
79         o0 = this.origin;
80         g_model_dropbyspawnflags(this);
81         if(this.origin != o0)
82                 this.SendFlags |= 2;
83 }
84
85 bool g_clientmodel_genericsendentity(entity this, entity to, int sf)
86 {
87         sf = sf & 0x0F;
88         if(this.angles != '0 0 0')
89                 sf |= 0x10;
90         if(this.mins != '0 0 0' || this.maxs != '0 0 0')
91                 sf |= 0x20;
92         if(this.colormap != 0)
93                 sf |= 0x40;
94         if(this.lodmodelindex1)
95                 sf |= 0x80;
96
97         WriteHeader(MSG_ENTITY, ENT_CLIENT_WALL);
98         WriteByte(MSG_ENTITY, sf);
99
100         if(sf & BIT(0))
101         {
102                 if(sf & 0x40)
103                         WriteShort(MSG_ENTITY, this.colormap);
104                 WriteByte(MSG_ENTITY, this.skin);
105         }
106
107         if(sf & BIT(1))
108         {
109                 WriteCoord(MSG_ENTITY, this.origin.x);
110                 WriteCoord(MSG_ENTITY, this.origin.y);
111                 WriteCoord(MSG_ENTITY, this.origin.z);
112         }
113
114         if(sf & BIT(2))
115         {
116                 if(sf & 0x10)
117                 {
118                         WriteAngle(MSG_ENTITY, this.angles.x);
119                         WriteAngle(MSG_ENTITY, this.angles.y);
120                         WriteAngle(MSG_ENTITY, this.angles.z);
121                 }
122         }
123
124         if(sf & BIT(3))
125         {
126                 if(sf & 0x80)
127                 {
128                         WriteShort(MSG_ENTITY, this.lodmodelindex0);
129                         WriteShort(MSG_ENTITY, bound(0, this.loddistance1, 65535));
130                         WriteShort(MSG_ENTITY, this.lodmodelindex1);
131                         WriteShort(MSG_ENTITY, bound(0, this.loddistance2, 65535));
132                         WriteShort(MSG_ENTITY, this.lodmodelindex2);
133                 }
134                 else
135                         WriteShort(MSG_ENTITY, this.modelindex);
136                 WriteByte(MSG_ENTITY, this.solid);
137                 WriteShort(MSG_ENTITY, floor(this.scale * 256));
138                 if(sf & 0x20)
139                 {
140                         WriteCoord(MSG_ENTITY, this.mins.x);
141                         WriteCoord(MSG_ENTITY, this.mins.y);
142                         WriteCoord(MSG_ENTITY, this.mins.z);
143                         WriteCoord(MSG_ENTITY, this.maxs.x);
144                         WriteCoord(MSG_ENTITY, this.maxs.y);
145                         WriteCoord(MSG_ENTITY, this.maxs.z);
146                 }
147                 WriteString(MSG_ENTITY, this.bgmscript);
148                 if(this.bgmscript != "")
149                 {
150                         WriteByte(MSG_ENTITY, floor(this.bgmscriptattack * 64));
151                         WriteByte(MSG_ENTITY, floor(this.bgmscriptdecay * 64));
152                         WriteByte(MSG_ENTITY, floor(this.bgmscriptsustain * 255));
153                         WriteByte(MSG_ENTITY, floor(this.bgmscriptrelease * 64));
154                         WriteCoord(MSG_ENTITY, this.movedir.x);
155                         WriteCoord(MSG_ENTITY, this.movedir.y);
156                         WriteCoord(MSG_ENTITY, this.movedir.z);
157                         WriteByte(MSG_ENTITY, floor(this.lip * 255));
158                 }
159                 WriteByte(MSG_ENTITY, this.fade_start);
160                 WriteByte(MSG_ENTITY, this.fade_end);
161                 WriteByte(MSG_ENTITY, this.alpha_max);
162                 WriteByte(MSG_ENTITY, this.alpha_min);
163                 WriteByte(MSG_ENTITY, this.inactive);
164                 WriteShort(MSG_ENTITY, this.fade_vertical_offset);
165         }
166
167         return true;
168 }
169
170
171 #define G_MODEL_INIT(ent,sol) \
172         if(ent.geomtype) if(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) set_movetype(ent, MOVETYPE_PHYSICS); \
173         if(!ent.scale) ent.scale = ent.modelscale; \
174         SetBrushEntityModel(ent); \
175         ent.use = g_model_setcolormaptoactivator; \
176         InitializeEntity(ent, g_model_dropbyspawnflags, INITPRIO_DROPTOFLOOR); \
177         if(!ent.solid) ent.solid = (sol); else if(ent.solid < 0) ent.solid = SOLID_NOT;
178
179 #define G_CLIENTMODEL_INIT(ent,sol) \
180         if(ent.geomtype) if(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) set_movetype(ent, MOVETYPE_PHYSICS); \
181         if(!ent.scale) ent.scale = ent.modelscale; \
182         SetBrushEntityModel(ent); \
183         ent.use = g_clientmodel_use; \
184         InitializeEntity(ent, g_clientmodel_dropbyspawnflags, INITPRIO_DROPTOFLOOR); \
185         if(!ent.solid) ent.solid = (sol); else if(ent.solid < 0) ent.solid = SOLID_NOT; \
186         if(!ent.bgmscriptsustain) ent.bgmscriptsustain = 1; else if(ent.bgmscriptsustain < 0) ent.bgmscriptsustain = 0; \
187         Net_LinkEntity(ent, true, 0, g_clientmodel_genericsendentity); \
188         ent.default_solid = sol;
189
190 // non-solid model entities:
191 spawnfunc(misc_gamemodel)         { this.angles_x = -this.angles.x; G_MODEL_INIT      (this, SOLID_NOT) } // model entity
192 spawnfunc(misc_clientmodel)       { this.angles_x = -this.angles.x; G_CLIENTMODEL_INIT(this, SOLID_NOT) } // model entity
193 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
194
195 // non-solid brush entities:
196 spawnfunc(func_illusionary)       { G_MODEL_INIT      (this, SOLID_NOT) } // Q1 name (WARNING: MISPREDICTED)
197 spawnfunc(func_clientillusionary) { G_CLIENTMODEL_INIT(this, SOLID_NOT) } // brush entity
198 spawnfunc(func_static)            { G_MODEL_INIT      (this, SOLID_NOT) } // DEPRECATED old alias name from some other game
199
200 // solid brush entities
201 spawnfunc(func_wall)              { G_MODEL_INIT      (this, SOLID_BSP) } // Q1 name
202 spawnfunc(func_clientwall)        { G_CLIENTMODEL_INIT(this, SOLID_BSP) } // brush entity (WARNING: MISPREDICTED)