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