]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/attic/monsters/m_monsters.qc
msgmerge run
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / attic / monsters / m_monsters.qc
1 /* ALL MONSTERS SHOULD BE 1 0 0 IN COLOR */
2
3 // name =[framenum,     nexttime, nextthink] {code}
4 // expands to:
5 // name ()
6 // {
7 //              self.frame=framenum;
8 //              self.nextthink = time + nexttime;
9 //              self.think = nextthink
10 //              <code>
11 // }
12
13 .float ismonster;
14
15 .float modelindex2;
16
17 /*
18 ================
19 monster_use
20
21 Using a monster makes it angry at the current activator
22 LordHavoc: using a monster with the spawnflag 'Appear' makes it appear
23 ================
24 */
25 void() monster_use =
26 {
27         if (self.enemy)
28                 return;
29         if (self.health < 1)
30                 return;
31         if (self.mdl)
32         if (self.spawnflags & MONSTER_APPEAR)
33         {
34                 self.nextthink = time + 0.1;
35                 self.spawnflags = self.spawnflags - MONSTER_APPEAR;
36                 self.solid = SOLID_SLIDEBOX;
37                 self.takedamage = DAMAGE_AIM;
38                 //self.movetype = MOVETYPE_STEP;
39                 self.model = self.mdl;
40                 self.mdl = "";
41                 self.modelindex = self.modelindex2;
42                 self.modelindex2 = 0;
43                 //setorigin(self, self.origin + '0 0 1');
44                 spawn_tdeath(self.origin, self, self.origin);
45                 return;
46         }
47
48 #if 0
49         if (activator.items & IT_INVISIBILITY)
50                 return;
51 #endif
52         if (activator.flags & FL_NOTARGET)
53                 return;
54         if (activator.classname != "player")
55                 return;
56
57         // delay reaction so if the monster is teleported, its sound is still heard
58         self.enemy = activator;
59         self.nextthink = time + 0.1;
60         self.think = FoundTarget;
61 }
62
63 void() monster_appearsetup =
64 {
65         if ((self.spawnflags & MONSTER_APPEAR) == 0)
66                 return;
67         self.mdl = self.model;
68         self.modelindex2 = self.modelindex;
69         self.modelindex = 0;
70         self.solid = SOLID_NOT;
71         self.takedamage = DAMAGE_NO;
72         //self.movetype = MOVETYPE_NONE;
73         self.nextthink = -1;
74         self.model = "";
75 }
76
77 /*
78 ================
79 monster_setalpha
80
81 Sets relative alpha of monster in skill 4 mode.
82 ================
83 */
84 void(float a) monster_setalpha =
85 {
86         if (skill < 4 || self.classname == "monster_hellfish")
87         {
88                 self.alpha = 1.0;
89                 return;
90         }
91
92         if (skill >= 5)
93         {
94                 // randomly forget enemy, this makes monsters randomly return to their normal ghostlike state
95                 if (a == 0)
96                 if (self.enemy)
97                 if (random() < 0.1)
98                         self.enemy = world;
99                 // randomly blink (playing the same alarming sound as if attacking)
100                 if (self.enemy == world)
101                 {
102                         a = 0;
103                         if (time >= 0.3) // don't blink during the init process because it might become permanent
104                         if (random() < 0.005)
105                         {
106                                 // blink for an instant, this causes the appear sound, alarming the player as if under attack
107                                 /* PLEASE FIX THE SOUND CHANNEL BEFORE ACTIVATING THIS
108                                 sound(self, CHAN_AUTO, "wizard/wsight.wav", 1, ATTN_NORM);
109                                 */
110                                 a = 1;
111                         }
112                 }
113                 // if ghosted, become non-solid and immune to damage
114                 if (a <= 0 || self.enemy == world)
115                 {
116                         self.solid = SOLID_NOT;
117                         self.takedamage = DAMAGE_NO;
118                 }
119                 else
120                 {
121                         // if unghosting, make sure we have an enemy, otherwise stay ghosted (even if blinking) so we can't be shot while blinking
122                         /* PLEASE FIX THE SOUND CHANNEL BEFORE ACTIVATING THIS
123                         if (self.solid != SOLID_SLIDEBOX)
124                                 sound(self, CHAN_AUTO, "wizard/wsight.wav", 1, ATTN_NORM);
125                         */
126                         self.solid = SOLID_SLIDEBOX;
127                         self.takedamage = DAMAGE_AIM;
128                 }
129         }
130         self.alpha = SKILL4_MINALPHA + (1 - SKILL4_MINALPHA) * bound(0, a, 1);
131 }
132
133 /*
134 ================
135 monster_death_use
136
137 When a mosnter dies, it fires all of its targets with the current
138 enemy as activator.
139 ================
140 */
141 void() monster_death_use =
142 {
143 // fall to ground
144         if (self.flags & FL_FLY)
145                 self.flags = self.flags - FL_FLY;
146         if (self.flags & FL_SWIM)
147                 self.flags = self.flags - FL_SWIM;
148
149         if (!self.target)
150                 return;
151
152         activator = self.enemy;
153         SUB_UseTargets ();
154 }
155
156
157 void() monsterinwall =
158 {
159         entity e;
160         if (!autocvar_developer)
161                 return;
162         // this is handy for level designers,
163         // puts a spikey ball where the error is...
164         e = spawn();
165         setorigin(e, self.origin);
166         setmodel (e, "models/ebomb.mdl");
167         e.movetype = MOVETYPE_NONE;
168         e.solid = SOLID_NOT;
169         e.think = func_null;
170         e.nextthink = -1;
171         e.scale = 16;
172 }
173
174 //============================================================================
175
176 void() walkmonster_start_go =
177 {
178         self.origin_z = self.origin_z + 1; // raise off floor a bit
179
180         tracebox(self.origin, self.mins, self.maxs, self.origin, TRUE, self);
181         if (trace_startsolid)
182         {
183                 dprint("walkmonster in wall at: ");
184                 dprint(vtos(self.origin));
185                 dprint("\n");
186                 monsterinwall();
187                 droptofloor();
188         }
189         else
190         {
191                 droptofloor();
192                 if (!walkmove(0,0))
193                 {
194                         dprint("walkmonster in wall at: ");
195                         dprint(vtos(self.origin));
196                         dprint("\n");
197                         monsterinwall();
198                 }
199         }
200
201         //self.cantrigger = TRUE;
202
203         self.takedamage = DAMAGE_AIM;
204
205         self.ideal_yaw = self.angles * '0 1 0';
206         if (!self.yaw_speed)
207                 self.yaw_speed = 20;
208         self.view_ofs = '0 0 25';
209         self.use = monster_use;
210
211         self.flags = self.flags | FL_MONSTER;
212
213         if (monsterwander)
214                 self.spawnflags = self.spawnflags | MONSTER_WANDER;
215
216         if (self.target)
217         {
218                 self.goalentity = self.movetarget = find(world, targetname, self.target);
219                 self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
220                 if (!self.movetarget)
221                 {
222                         dprint("Monster can't find target at ");
223                         dprint(vtos(self.origin));
224                         dprint("\n");
225                 }
226                 // this used to be an objerror
227                 if (self.movetarget.classname == "path_corner")
228                         self.th_walk ();
229                 else
230                 {
231                         if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp"))
232                         {
233                                 monster_spawnwanderpath();
234                                 self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
235                                 self.th_walk ();
236                         }
237                         else
238                         {
239                                 self.pausetime = 99999999;
240                                 self.th_stand ();
241                         }
242                 }
243         }
244         else
245         {
246                 if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp"))
247                 {
248                         monster_spawnwanderpath();
249                         self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
250                         self.th_walk ();
251                 }
252                 else
253                 {
254                         self.pausetime = 99999999;
255                         self.th_stand ();
256                 }
257         }
258
259 // spread think times so they don't all happen at same time
260         self.nextthink = self.nextthink + random()*0.5 + 0.1;
261         self.iscreature = TRUE;
262         self.teleportable = TELEPORT_NORMAL;
263         self.damagedbycontents = TRUE;
264
265         force_retouch = 2; // mainly to detect teleports
266
267         monster_appearsetup();
268 }
269
270
271 void() walkmonster_start =
272 {
273         self.candrown = 1; // this is turned off by some monsters like zombies
274         // delay drop to floor to make sure all doors have been spawned
275         // spread think times so they don't all happen at same time
276         self.nextthink = time + random()*0.5 + 0.3;
277         self.think = walkmonster_start_go;
278         total_monsters = total_monsters + 1;
279         self.bot_attack = TRUE;
280         self.frags = 2; // actually just used to get havocbots to attack it...
281         self.bleedfunc = genericbleedfunc;
282         self.ismonster = TRUE;
283
284         monster_setalpha (0);
285 }
286
287
288
289 void() flymonster_start_go =
290 {
291         self.takedamage = DAMAGE_AIM;
292
293         self.ideal_yaw = self.angles * '0 1 0';
294         if (!self.yaw_speed)
295                 self.yaw_speed = 10;
296         self.view_ofs = '0 0 25';
297         self.use = monster_use;
298
299         self.flags = self.flags | FL_FLY;
300         self.flags = self.flags | FL_MONSTER;
301
302         if (!walkmove(0,0))
303         {
304                 dprint("flymonster in wall at: ");
305                 dprint(vtos(self.origin));
306                 dprint("\n");
307                 monsterinwall();
308         }
309
310         //self.cantrigger = TRUE;
311
312         if (monsterwander)
313                 self.spawnflags = self.spawnflags | MONSTER_WANDER;
314
315         if (self.target)
316         {
317                 self.goalentity = self.movetarget = find(world, targetname, self.target);
318                 if (!self.movetarget)
319                 {
320                         dprint("Monster can't find target at ");
321                         dprint(vtos(self.origin));
322                         dprint("\n");
323                 }
324                 // this used to be an objerror
325                 if (self.movetarget.classname == "path_corner")
326                         self.th_walk ();
327                 else
328                 {
329                         if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp"))
330                         {
331                                 monster_spawnwanderpath();
332                                 self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
333                                 self.th_walk ();
334                         }
335                         else
336                         {
337                                 self.pausetime = 99999999;
338                                 self.th_stand ();
339                         }
340                 }
341         }
342         else
343         {
344                 if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp"))
345                 {
346                         monster_spawnwanderpath();
347                         self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
348                         self.th_walk ();
349                 }
350                 else
351                 {
352                         self.pausetime = 99999999;
353                         self.th_stand ();
354                 }
355         }
356         self.iscreature = TRUE;
357         self.teleportable = TELEPORT_NORMAL;
358         self.damagedbycontents = TRUE;
359
360         force_retouch = 2; // mainly to detect teleports
361
362         monster_appearsetup();
363 }
364
365 void() flymonster_start =
366 {
367         self.candrown = 1;
368         // spread think times so they don't all happen at same time
369         self.nextthink = time + random()*0.5 + 0.1;
370         self.think = flymonster_start_go;
371         total_monsters = total_monsters + 1;
372         self.bot_attack = TRUE;
373         self.frags = 2; // actually just used to get havocbots to attack it...
374         self.bleedfunc = genericbleedfunc;
375         self.ismonster = TRUE;
376
377         monster_setalpha (0);
378 }
379
380
381 void() swimmonster_start_go =
382 {
383         if (deathmatch)
384         {
385                 remove(self);
386                 return;
387         }
388
389         //self.cantrigger = TRUE;
390
391         self.takedamage = DAMAGE_AIM;
392
393         self.ideal_yaw = self.angles * '0 1 0';
394         if (!self.yaw_speed)
395                 self.yaw_speed = 10;
396         self.view_ofs = '0 0 10';
397         self.use = monster_use;
398
399         self.flags = self.flags | FL_SWIM;
400         self.flags = self.flags | FL_MONSTER;
401
402         if (monsterwander)
403                 self.spawnflags = self.spawnflags | MONSTER_WANDER;
404
405         if (self.target)
406         {
407                 self.goalentity = self.movetarget = find(world, targetname, self.target);
408                 if (!self.movetarget)
409                 {
410                         dprint("Monster can't find target at ");
411                         dprint(vtos(self.origin));
412                         dprint("\n");
413                 }
414                 // this used to be an objerror
415                 if (self.movetarget.classname == "path_corner")
416                         self.th_walk ();
417                 else
418                 {
419                         if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp"))
420                         {
421                                 monster_spawnwanderpath();
422                                 self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
423                                 self.th_walk ();
424                         }
425                         else
426                         {
427                                 self.pausetime = 99999999;
428                                 self.th_stand ();
429                         }
430                 }
431         }
432         else
433         {
434                 if ((self.spawnflags & MONSTER_WANDER) && (!self.monsterawaitingteleport) && (self.spawnflags & 3) == 0 && (world.model != "maps/e1m7.bsp"))
435                 {
436                         monster_spawnwanderpath();
437                         self.ideal_yaw = vectoyaw(self.goalentity.origin - self.origin);
438                         self.th_walk ();
439                 }
440                 else
441                 {
442                         self.pausetime = 99999999;
443                         self.th_stand ();
444                 }
445         }
446         self.iscreature = TRUE;
447         self.teleportable = TELEPORT_NORMAL;
448         self.damagedbycontents = TRUE;
449
450         force_retouch = 2; // mainly to detect teleports
451
452         monster_appearsetup();
453 }
454
455 void() swimmonster_start =
456 {
457         // spread think times so they don't all happen at same time
458         self.candrown = 0;
459         self.nextthink = time + random()*0.5 + 0.1;
460         self.think = swimmonster_start_go;
461         total_monsters = total_monsters + 1;
462         self.bot_attack = TRUE;
463         self.frags = 2; // actually just used to get havocbots to attack it...
464         self.bleedfunc = genericbleedfunc;
465         self.ismonster = TRUE;
466
467         monster_setalpha(0);
468 }
469
470 void(vector org, float bodydamage, float armordamage, vector force, float damgtype) genericbleedfunc =
471 {
472         vector v;
473         v = '0 0 0' - force * 0.05;
474         if (armordamage > 0)
475                 te_spark(org, v, armordamage * 3);
476         if (bodydamage > 0)
477                 te_blood(org, v, bodydamage);
478 }