]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/monsters/cl_monsters.qc
Merge branch 'master' into Mario/monsters
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / monsters / cl_monsters.qc
1 // =========================
2 //  CSQC Monster Properties
3 // =========================
4
5
6 .vector glowmod;
7 void monster_changeteam()
8 {
9         self.glowmod = Team_ColorRGB(self.team - 1);
10
11         if(self.team)
12         {
13                 self.teamradar_color = Team_ColorRGB(self.team - 1);
14                 self.colormap = 1024 + (self.team - 1) * 17;
15         }
16         else
17         {
18                 self.teamradar_color = '1 0 0';
19                 self.colormap = 1024;
20         }
21 }
22
23 void monster_die()
24 {
25         MON_ACTION(self.monsterid, MR_DEATH);
26
27         self.solid = SOLID_CORPSE;
28 }
29
30 void monster_draw2d()
31 {
32         if(self.netname == "")
33                 return;
34
35         if(!autocvar_g_waypointsprite_monsters)
36                 return;
37
38         if(autocvar_cl_hidewaypoints)
39                 return;
40                 
41         if(self.solid == SOLID_CORPSE)
42                 return; // re-spawning
43
44         if(self.health <= 0)
45                 return;
46
47         float dist = vlen(self.origin - view_origin);
48         float t = (GetPlayerColor(player_localnum) + 1);
49
50         vector o;
51         string txt;
52
53         if(autocvar_cl_vehicles_hud_tactical)
54         if(dist < 10240 && t != self.team)
55         {
56                 // TODO: Vehicle tactical hud
57                 o = project_3d_to_2d(self.origin + '0 0 1' * ((self.maxs_z + self.mins_z) * 0.5));
58                 if(o_z < 0
59                 || o_x < (vid_conwidth * waypointsprite_edgeoffset_left)
60                 || o_y < (vid_conheight * waypointsprite_edgeoffset_top)
61                 || o_x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right))
62                 || o_y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)))
63                         return; // Dont draw wp's for monsters out of view
64                 o_z = 0;
65                 if(hud != HUD_NORMAL)
66                 {
67                         switch(hud)
68                         {
69                                 case HUD_SPIDERBOT:
70                                 case HUD_WAKIZASHI:
71                                 case HUD_RAPTOR:
72                                 case HUD_BUMBLEBEE:
73                                         vector pz = drawgetimagesize("gfx/vehicles/vth-mover.tga") * 0.25;
74                                         drawpic(o - pz * 0.5, "gfx/vehicles/vth-mover.tga", pz , '1 1 1', 0.75, DRAWFLAG_NORMAL);
75                                         break;
76                         }
77                 }
78         }
79
80         if(dist > self.maxdistance)
81                 return;
82
83         string spriteimage = self.netname;
84         float a = self.alpha * autocvar_hud_panel_fg_alpha;
85         vector rgb = spritelookupcolor(spriteimage, self.teamradar_color);
86
87
88         if(self.maxdistance > waypointsprite_normdistance)
89                 a *= pow(bound(0, (self.maxdistance - dist) / (self.maxdistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent);
90         else if(self.maxdistance > 0)
91                 a *= pow(bound(0, (waypointsprite_fadedistance - dist) / (waypointsprite_fadedistance - waypointsprite_normdistance), 1), waypointsprite_distancealphaexponent) * (1 - waypointsprite_minalpha) + waypointsprite_minalpha;
92
93         if(rgb == '0 0 0')
94         {
95                 self.teamradar_color = '1 0 0';
96                 print(sprintf("WARNING: sprite of name %s has no color, using red so you notice it\n", spriteimage));
97         }
98
99         txt = self.netname;
100         if(autocvar_g_waypointsprite_spam && waypointsprite_count >= autocvar_g_waypointsprite_spam)
101                 txt = _("Spam");
102         else
103                 txt = spritelookuptext(spriteimage);
104
105         if(autocvar_g_waypointsprite_uppercase)
106                 txt = strtoupper(txt);
107
108         if(a > 1)
109         {
110                 rgb *= a;
111                 a = 1;
112         }
113
114         if(a <= 0)
115                 return;
116
117         rgb = fixrgbexcess(rgb);
118
119         o = project_3d_to_2d(self.origin + '0 0 1' * (self.maxs_z + 15));
120         if(o_z < 0
121         || o_x < (vid_conwidth * waypointsprite_edgeoffset_left)
122         || o_y < (vid_conheight * waypointsprite_edgeoffset_top)
123         || o_x > (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right))
124         || o_y > (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)))
125                 return; // Dont draw wp's for monsters out of view
126
127         o_z = 0;
128
129         float edgedistance_min, crosshairdistance;
130                 edgedistance_min = min((o_y - (vid_conheight * waypointsprite_edgeoffset_top)),
131         (o_x - (vid_conwidth * waypointsprite_edgeoffset_left)),
132         (vid_conwidth - (vid_conwidth * waypointsprite_edgeoffset_right)) - o_x,
133         (vid_conheight - (vid_conheight * waypointsprite_edgeoffset_bottom)) - o_y);
134
135         float vidscale = max(vid_conwidth / vid_width, vid_conheight / vid_height);
136
137         crosshairdistance = sqrt( pow(o_x - vid_conwidth/2, 2) + pow(o_y - vid_conheight/2, 2) );
138
139         t = waypointsprite_scale * vidscale;
140         a *= waypointsprite_alpha;
141
142         {
143                 a = a * (1 - (1 - waypointsprite_distancefadealpha) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
144                 t = t * (1 - (1 - waypointsprite_distancefadescale) * (bound(0, dist/waypointsprite_distancefadedistance, 1)));
145         }
146         if (edgedistance_min < waypointsprite_edgefadedistance) {
147                 a = a * (1 - (1 - waypointsprite_edgefadealpha) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
148                 t = t * (1 - (1 - waypointsprite_edgefadescale) * (1 - bound(0, edgedistance_min/waypointsprite_edgefadedistance, 1)));
149         }
150         if(crosshairdistance < waypointsprite_crosshairfadedistance) {
151                 a = a * (1 - (1 - waypointsprite_crosshairfadealpha) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
152                 t = t * (1 - (1 - waypointsprite_crosshairfadescale) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
153         }
154
155         draw_beginBoldFont();
156         o = drawspritearrow(o, M_PI, rgb, a, SPRITE_ARROW_SCALE * t);
157         o = drawspritetext(o, M_PI, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
158         drawhealthbar(
159                         o,
160                         0,
161                         self.health / 255,
162                         '0 0 0',
163                         '0 0 0',
164                         0.5 * SPRITE_HEALTHBAR_WIDTH * t,
165                         0.5 * SPRITE_HEALTHBAR_HEIGHT * t,
166                         SPRITE_HEALTHBAR_MARGIN * t + 0.5 * waypointsprite_fontsize,
167                         SPRITE_HEALTHBAR_BORDER * t,
168                         0,
169                         rgb,
170                         a * SPRITE_HEALTHBAR_BORDERALPHA,
171                         rgb,
172                         a * SPRITE_HEALTHBAR_HEALTHALPHA,
173                         DRAWFLAG_NORMAL
174                         );
175         draw_endBoldFont();
176 }
177
178 void monster_draw()
179 {
180         float dt;
181
182         dt = time - self.move_time;
183         self.move_time = time;
184         if(dt <= 0)
185                 return;
186
187         fixedmakevectors(self.angles);
188         //movelib_groundalign4point(50, 25, 0.25, 45);
189         setorigin(self, self.origin + self.velocity * dt);
190         self.angles_y = self.move_angles_y;
191 }
192
193 void monster_construct()
194 {
195         entity mon = get_monsterinfo(self.monsterid);
196
197         if(mon.spawnflags & MONSTER_SIZE_BROKEN)
198                 self.scale = 1.3;
199
200         self.netname = M_NAME(self.monsterid);
201
202         setorigin(self, self.origin);
203         setmodel(self, mon.model);
204         setsize(self, mon.mins, mon.maxs);
205
206         self.move_movetype      = MOVETYPE_BOUNCE;
207         self.health                     = 255;
208         self.solid                      = SOLID_BBOX;
209         self.movetype           = MOVETYPE_BOUNCE;
210         self.move_origin        = self.origin;
211         self.move_time          = time;
212         self.drawmask           = MASK_NORMAL;
213         self.alpha                      = 1;
214         self.gravity            = 1;
215         self.draw                       = monster_draw;
216         self.draw2d                     = monster_draw2d;
217         self.maxdistance        = autocvar_g_waypointsprite_monsters_maxdist;
218 }
219
220 void ent_monster()
221 {
222         float sf;
223         sf = ReadByte();
224
225         if(sf & MSF_SETUP)
226         {
227                 self.monsterid = ReadByte();
228
229                 self.origin_x = ReadCoord();
230                 self.origin_y = ReadCoord();
231                 self.origin_z = ReadCoord();
232                 setorigin(self, self.origin);
233
234                 self.angles_x = ReadAngle();
235                 self.angles_y = ReadAngle();
236
237                 self.skin = ReadByte();
238                 self.team = ReadByte();
239
240                 monster_construct();
241                 monster_changeteam();
242         }
243
244         if(sf & MSF_ANG)
245         {
246                 self.move_angles_x = ReadShort();
247                 self.move_angles_y = ReadShort();
248                 self.angles = self.move_angles;
249         }
250
251         if(sf & MSF_MOVE)
252         {
253                 self.origin_x = ReadShort();
254                 self.origin_y = ReadShort();
255                 self.origin_z = ReadShort();
256                 setorigin(self, self.origin);
257
258                 self.velocity_x = ReadShort();
259                 self.velocity_y = ReadShort();
260                 self.velocity_z = ReadShort();
261
262                 self.move_angles_y = ReadShort();
263
264                 self.move_time = time;
265                 self.move_velocity = self.velocity;
266                 self.move_origin = self.origin;
267         }
268
269         if(sf & MSF_ANIM)
270         {
271                 self.frame1time = ReadCoord();
272                 self.frame = ReadByte();
273         }
274
275         if(sf & MSF_STATUS)
276         {
277                 self.skin = ReadByte();
278
279                 float _tmp;
280                 _tmp = ReadByte();
281                 if(_tmp != self.team)
282                 {
283                         self.team = _tmp;
284                         monster_changeteam();
285                 }
286
287                 _tmp = ReadByte();
288                 if(_tmp == 4) // respawning
289                         setmodel(self, "null");
290
291                 _tmp = ReadByte();
292
293                 if(_tmp == 0 && self.health != 0)
294                         monster_die();
295
296                 self.health = _tmp;
297         }
298 }