|
|
1.1 root 1: /*
2: fixbot.c
3: */
4:
5:
6: #include "g_local.h"
7: #include "m_fixbot.h"
8:
9:
10: #define MZ2_fixbot_BLASTER_1 MZ2_HOVER_BLASTER_1
11:
12: qboolean visible (edict_t *self, edict_t *other);
13: qboolean infront (edict_t *self, edict_t *other);
14:
15: static int sound_pain1;
16: static int sound_die;
17: static int sound_weld1;
18: static int sound_weld2;
19: static int sound_weld3;
20:
21: void fixbot_run (edict_t *self);
22: void fixbot_stand (edict_t *self);
23: void fixbot_dead (edict_t *self);
24: void fixbot_attack (edict_t *self);
25: void fixbot_fire_blaster (edict_t *self);
26: void fixbot_fire_welder (edict_t *self);
27: void fixbot_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
28:
29: void use_scanner (edict_t *self);
30: void change_to_roam (edict_t *self);
31: void fly_vertical (edict_t *self);
32:
33: extern mmove_t fixbot_move_forward;
34: extern mmove_t fixbot_move_stand;
35: extern mmove_t fixbot_move_stand2;
36: extern mmove_t fixbot_move_roamgoal;
37:
38: extern mmove_t fixbot_move_weld_start;
39: extern mmove_t fixbot_move_weld;
40: extern mmove_t fixbot_move_weld_end;
41: extern mmove_t fixbot_move_takeoff;
42: extern mmove_t fixbot_move_landing;
43: extern mmove_t fixbot_move_turn;
44:
45: extern void roam_goal (edict_t *self);
46: void ED_CallSpawn (edict_t *ent);
47:
48: float crand(void)
49: {
50: return (rand()&32767)*(2.0/32767)-1;
51: };
52:
53: edict_t *fixbot_FindDeadMonster (edict_t *self)
54: {
55: edict_t *ent = NULL;
56: edict_t *best = NULL;
57:
58: while ((ent = findradius(ent, self->s.origin, 1024)) != NULL)
59: {
60: if (ent == self)
61: continue;
62: if (!(ent->svflags & SVF_MONSTER))
63: continue;
64: if (ent->monsterinfo.aiflags & AI_GOOD_GUY)
65: continue;
66: if (ent->owner)
67: continue;
68: if (ent->health > 0)
69: continue;
70: if (ent->nextthink)
71: continue;
72: if (!visible(self, ent))
73: continue;
74: if (!best)
75: {
76: best = ent;
77: continue;
78: }
79: if (ent->max_health <= best->max_health)
80: continue;
81: best = ent;
82: }
83:
84: return best;
85: }
86:
87:
88: int fixbot_search (edict_t *self)
89: {
90: edict_t *ent;
91:
92: if (!self->goalentity)
93: {
94: ent = fixbot_FindDeadMonster(self);
95: if (ent)
96: {
97: self->oldenemy = self->enemy;
98: self->enemy = ent;
99: self->enemy->owner = self;
100: self->monsterinfo.aiflags |= AI_MEDIC;
101: FoundTarget (self);
102: return (1);
103: }
104: }
105: return (0);
106: }
107:
108: void landing_goal (edict_t *self)
109: {
110: trace_t tr;
111: vec3_t forward, right, up;
112: vec3_t end;
113: edict_t *ent;
114:
115: ent = G_Spawn ();
116: ent->classname = "bot_goal";
117: ent->solid = SOLID_BBOX;
118: ent->owner = self;
119: gi.linkentity (ent);
120:
121: VectorSet (ent->mins, -32, -32, -24);
122: VectorSet (ent->maxs, 32, 32, 24);
123:
124: AngleVectors (self->s.angles, forward, right, up);
125: VectorMA (self->s.origin, 32, forward, end);
126: VectorMA (self->s.origin, -8096, up, end);
127:
128: tr = gi.trace (self->s.origin, ent->mins, ent->maxs, end, self, MASK_MONSTERSOLID);
129:
130: VectorCopy (tr.endpos, ent->s.origin);
131:
132: self->goalentity = self->enemy = ent;
133: self->monsterinfo.currentmove = &fixbot_move_landing;
134:
135:
136: }
137:
138:
139: void takeoff_goal (edict_t *self)
140: {
141: trace_t tr;
142: vec3_t forward, right, up;
143: vec3_t end;
144: edict_t *ent;
145:
146: ent = G_Spawn ();
147: ent->classname = "bot_goal";
148: ent->solid = SOLID_BBOX;
149: ent->owner = self;
150: gi.linkentity (ent);
151:
152: VectorSet (ent->mins, -32, -32, -24);
153: VectorSet (ent->maxs, 32, 32, 24);
154:
155:
156: AngleVectors (self->s.angles, forward, right, up);
157: VectorMA (self->s.origin, 32, forward, end);
158: VectorMA (self->s.origin, 128, up, end);
159:
160: tr = gi.trace (self->s.origin, ent->mins, ent->maxs, end, self, MASK_MONSTERSOLID);
161:
162: VectorCopy (tr.endpos, ent->s.origin);
163:
164: self->goalentity = self->enemy = ent;
165: self->monsterinfo.currentmove = &fixbot_move_takeoff;
166:
167:
168: }
169:
170: void change_to_roam (edict_t *self)
171: {
172:
173: if (fixbot_search(self))
174: return;
175:
176: self->monsterinfo.currentmove = &fixbot_move_roamgoal;
177:
178:
179: if (self->spawnflags & 16)
180: {
181: landing_goal (self);
182: self->monsterinfo.currentmove = &fixbot_move_landing;
183: self->spawnflags &= ~16;
184: self->spawnflags = 32;
185: }
186: if (self->spawnflags & 8)
187: {
188: takeoff_goal (self);
189: self->monsterinfo.currentmove = &fixbot_move_takeoff;
190: self->spawnflags &= ~8;
191: self->spawnflags = 32;
192: }
193: if (self->spawnflags & 4)
194: {
195: self->monsterinfo.currentmove = &fixbot_move_roamgoal;
196: self->spawnflags &= ~4;
197: self->spawnflags = 32;
198: }
199: if (!self->spawnflags)
200: {
201: self->monsterinfo.currentmove = &fixbot_move_stand2;
202: }
203:
204: }
205:
206:
207: void roam_goal (edict_t *self)
208: {
209:
210: trace_t tr;
211: vec3_t forward, right, up;
212: vec3_t end;
213: edict_t *ent;
214: vec3_t dang;
215: int len, oldlen, whichi, i;
216: vec3_t vec;
217: vec3_t whichvec;
218:
219: ent = G_Spawn ();
220: ent->classname = "bot_goal";
221: ent->solid = SOLID_BBOX;
222: ent->owner = self;
223: gi.linkentity (ent);
224:
225: oldlen = 0;
226: whichi = 0;
227: for (i=0; i<12; i++)
228: {
229:
230: VectorCopy (self->s.angles, dang);
231:
232: if (i < 6)
233: dang[YAW] += 30 * i;
234: else
235: dang[YAW] -= 30 * (i-6);
236:
237: AngleVectors (dang, forward, right, up);
238: VectorMA (self->s.origin, 8192, forward, end);
239:
240: tr = gi.trace (self->s.origin, NULL, NULL, end, self, MASK_SHOT);
241:
242: VectorSubtract (self->s.origin, tr.endpos, vec);
243: len = VectorNormalize (vec);
244:
245: if (len > oldlen)
246: {
247: oldlen=len;
248: VectorCopy (tr.endpos, whichvec);
249: }
250:
251: }
252:
253: VectorCopy (whichvec, ent->s.origin);
254: self->goalentity = self->enemy = ent;
255:
256: self->monsterinfo.currentmove = &fixbot_move_turn;
257:
258:
259: }
260:
261: void use_scanner (edict_t *self)
262: {
263: edict_t *ent = NULL;
264:
265: float radius = 1024;
266: vec3_t vec;
267:
268: int len;
269: int oldlen = 0x10000;
270: edict_t *tempent = NULL;
271:
272:
273: while ((ent = findradius(ent, self->s.origin, radius)) != NULL)
274: {
275: if (ent->health >= 100)
276: {
277: if (strcmp (ent->classname, "object_repair") == 0)
278: {
279: if (visible(self, ent))
280: {
281: // remove the old one
282: if (strcmp (self->goalentity->classname, "bot_goal") == 0)
283: {
284: self->goalentity->nextthink = level.time + 0.1;
285: self->goalentity->think = G_FreeEdict;
286: }
287:
288: self->goalentity = self->enemy = ent;
289:
290: VectorSubtract (self->s.origin, self->goalentity->s.origin, vec);
291: len = VectorNormalize (vec);
292:
293: if (len < 32)
294: {
295: self->monsterinfo.currentmove = &fixbot_move_weld_start;
296: return;
297: }
298: return;
299: }
300: }
301: }
302: }
303:
304: VectorSubtract (self->s.origin, self->goalentity->s.origin, vec);
305: len = VectorLength (vec);
306:
307: if (len < 32)
308: {
309: if (strcmp (self->goalentity->classname, "object_repair") == 0)
310: {
311: self->monsterinfo.currentmove = &fixbot_move_weld_start;
312: }
313: else
314: {
315: self->goalentity->nextthink = level.time + 0.1;
316: self->goalentity->think = G_FreeEdict;
317: self->goalentity = self->enemy = NULL;
318: self->monsterinfo.currentmove = &fixbot_move_stand;
319: }
320: return;
321: }
322:
323: VectorSubtract (self->s.origin, self->s.old_origin, vec);
324: len = VectorLength (vec);
325:
326: /*
327: bot is stuck get new goalentity
328: */
329: if (len == 0)
330: {
331: if (strcmp (self->goalentity->classname , "object_repair") == 0)
332: {
333: self->monsterinfo.currentmove = &fixbot_move_stand;
334: }
335: else
336: {
337: self->goalentity->nextthink = level.time + 0.1;
338: self->goalentity->think = G_FreeEdict;
339: self->goalentity = self->enemy = NULL;
340: self->monsterinfo.currentmove = &fixbot_move_stand;
341: }
342: }
343:
344: }
345:
346:
347: /*
348: when the bot has found a landing pad
349: it will proceed to its goalentity
350: just above the landing pad and
351: decend translated along the z the current
352: frames are at 10fps
353: */
354: void blastoff (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick, int te_impact, int hspread, int vspread)
355: {
356: trace_t tr;
357: vec3_t dir;
358: vec3_t forward, right, up;
359: vec3_t end;
360: float r;
361: float u;
362: vec3_t water_start;
363: qboolean water = false;
364: int content_mask = MASK_SHOT | MASK_WATER;
365:
366: hspread+= (self->s.frame - FRAME_takeoff_01);
367: vspread+= (self->s.frame - FRAME_takeoff_01);
368:
369: tr = gi.trace (self->s.origin, NULL, NULL, start, self, MASK_SHOT);
370: if (!(tr.fraction < 1.0))
371: {
372: vectoangles (aimdir, dir);
373: AngleVectors (dir, forward, right, up);
374:
375: r = crandom()*hspread;
376: u = crandom()*vspread;
377: VectorMA (start, 8192, forward, end);
378: VectorMA (end, r, right, end);
379: VectorMA (end, u, up, end);
380:
381: if (gi.pointcontents (start) & MASK_WATER)
382: {
383: water = true;
384: VectorCopy (start, water_start);
385: content_mask &= ~MASK_WATER;
386: }
387:
388: tr = gi.trace (start, NULL, NULL, end, self, content_mask);
389:
390: // see if we hit water
391: if (tr.contents & MASK_WATER)
392: {
393: int color;
394:
395: water = true;
396: VectorCopy (tr.endpos, water_start);
397:
398: if (!VectorCompare (start, tr.endpos))
399: {
400: if (tr.contents & CONTENTS_WATER)
401: {
402: if (strcmp(tr.surface->name, "*brwater") == 0)
403: color = SPLASH_BROWN_WATER;
404: else
405: color = SPLASH_BLUE_WATER;
406: }
407: else if (tr.contents & CONTENTS_SLIME)
408: color = SPLASH_SLIME;
409: else if (tr.contents & CONTENTS_LAVA)
410: color = SPLASH_LAVA;
411: else
412: color = SPLASH_UNKNOWN;
413:
414: if (color != SPLASH_UNKNOWN)
415: {
416: gi.WriteByte (svc_temp_entity);
417: gi.WriteByte (TE_SPLASH);
418: gi.WriteByte (8);
419: gi.WritePosition (tr.endpos);
420: gi.WriteDir (tr.plane.normal);
421: gi.WriteByte (color);
422: gi.multicast (tr.endpos, MULTICAST_PVS);
423: }
424:
425: // change bullet's course when it enters water
426: VectorSubtract (end, start, dir);
427: vectoangles (dir, dir);
428: AngleVectors (dir, forward, right, up);
429: r = crandom()*hspread*2;
430: u = crandom()*vspread*2;
431: VectorMA (water_start, 8192, forward, end);
432: VectorMA (end, r, right, end);
433: VectorMA (end, u, up, end);
434: }
435:
436: // re-trace ignoring water this time
437: tr = gi.trace (water_start, NULL, NULL, end, self, MASK_SHOT);
438: }
439: }
440:
441: // send gun puff / flash
442: if (!((tr.surface) && (tr.surface->flags & SURF_SKY)))
443: {
444: if (tr.fraction < 1.0)
445: {
446: if (tr.ent->takedamage)
447: {
448: T_Damage (tr.ent, self, self, aimdir, tr.endpos, tr.plane.normal, damage, kick, DAMAGE_BULLET, MOD_BLASTOFF);
449: }
450: else
451: {
452: if (strncmp (tr.surface->name, "sky", 3) != 0)
453: {
454: gi.WriteByte (svc_temp_entity);
455: gi.WriteByte (te_impact);
456: gi.WritePosition (tr.endpos);
457: gi.WriteDir (tr.plane.normal);
458: gi.multicast (tr.endpos, MULTICAST_PVS);
459:
460: if (self->client)
461: PlayerNoise(self, tr.endpos, PNOISE_IMPACT);
462: }
463: }
464: }
465: }
466:
467: // if went through water, determine where the end and make a bubble trail
468: if (water)
469: {
470: vec3_t pos;
471:
472: VectorSubtract (tr.endpos, water_start, dir);
473: VectorNormalize (dir);
474: VectorMA (tr.endpos, -2, dir, pos);
475: if (gi.pointcontents (pos) & MASK_WATER)
476: VectorCopy (pos, tr.endpos);
477: else
478: tr = gi.trace (pos, NULL, NULL, water_start, tr.ent, MASK_WATER);
479:
480: VectorAdd (water_start, tr.endpos, pos);
481: VectorScale (pos, 0.5, pos);
482:
483: gi.WriteByte (svc_temp_entity);
484: gi.WriteByte (TE_BUBBLETRAIL);
485: gi.WritePosition (water_start);
486: gi.WritePosition (tr.endpos);
487: gi.multicast (pos, MULTICAST_PVS);
488: }
489: }
490:
491:
492: void fly_vertical (edict_t *self)
493: {
494: int i;
495: vec3_t v;
496: vec3_t forward, right, up;
497: vec3_t start;
498: vec3_t tempvec;
499:
500: VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
501: self->ideal_yaw = vectoyaw(v);
502: M_ChangeYaw (self);
503:
504: if (self->s.frame == FRAME_landing_58 || self->s.frame == FRAME_takeoff_16)
505: {
506: self->goalentity->nextthink = level.time + 0.1;
507: self->goalentity->think = G_FreeEdict;
508: self->monsterinfo.currentmove = &fixbot_move_stand;
509: self->goalentity = self->enemy = NULL;
510: }
511:
512: // kick up some particles
513: VectorCopy (self->s.angles, tempvec);
514: tempvec[PITCH] += 90;
515:
516: AngleVectors (tempvec, forward, right, up);
517: VectorCopy (self->s.origin, start);
518:
519: for (i=0; i< 10; i++)
520: blastoff (self, start, forward, 2, 1, TE_SHOTGUN, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD);
521:
522: // needs sound
523: }
524:
525:
526: void fly_vertical2 (edict_t *self)
527: {
528: vec3_t v;
529: int len;
530:
531: VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
532: len = VectorLength (v);
533: self->ideal_yaw = vectoyaw(v);
534: M_ChangeYaw (self);
535:
536: if (len < 32)
537: {
538: self->goalentity->nextthink = level.time + 0.1;
539: self->goalentity->think = G_FreeEdict;
540: self->monsterinfo.currentmove = &fixbot_move_stand;
541: self->goalentity = self->enemy = NULL;
542: }
543:
544: // needs sound
545: }
546:
547: mframe_t fixbot_frames_landing [] =
548: {
549: ai_move, 0, NULL,
550: ai_move, 0, fly_vertical2,
551: ai_move, 0, fly_vertical2,
552: ai_move, 0, fly_vertical2,
553: ai_move, 0, fly_vertical2,
554: ai_move, 0, fly_vertical2,
555: ai_move, 0, fly_vertical2,
556: ai_move, 0, fly_vertical2,
557: ai_move, 0, fly_vertical2,
558: ai_move, 0, fly_vertical2,
559:
560: ai_move, 0, fly_vertical2,
561: ai_move, 0, fly_vertical2,
562: ai_move, 0, fly_vertical2,
563: ai_move, 0, fly_vertical2,
564: ai_move, 0, fly_vertical2,
565: ai_move, 0, fly_vertical2,
566: ai_move, 0, fly_vertical2,
567: ai_move, 0, fly_vertical2,
568: ai_move, 0, fly_vertical2,
569: ai_move, 0, fly_vertical2,
570:
571: ai_move, 0, fly_vertical2,
572: ai_move, 0, fly_vertical2,
573: ai_move, 0, fly_vertical2,
574: ai_move, 0, fly_vertical2,
575: ai_move, 0, fly_vertical2,
576: ai_move, 0, fly_vertical2,
577: ai_move, 0, fly_vertical2,
578: ai_move, 0, fly_vertical2,
579: ai_move, 0, fly_vertical2,
580: ai_move, 0, fly_vertical2,
581:
582: ai_move, 0, fly_vertical2,
583: ai_move, 0, fly_vertical2,
584: ai_move, 0, fly_vertical2,
585: ai_move, 0, fly_vertical2,
586: ai_move, 0, fly_vertical2,
587: ai_move, 0, fly_vertical2,
588: ai_move, 0, fly_vertical2,
589: ai_move, 0, fly_vertical2,
590: ai_move, 0, fly_vertical2,
591: ai_move, 0, fly_vertical2,
592:
593: ai_move, 0, fly_vertical2,
594: ai_move, 0, fly_vertical2,
595: ai_move, 0, fly_vertical2,
596: ai_move, 0, fly_vertical2,
597: ai_move, 0, fly_vertical2,
598: ai_move, 0, fly_vertical2,
599: ai_move, 0, fly_vertical2,
600: ai_move, 0, fly_vertical2,
601: ai_move, 0, fly_vertical2,
602: ai_move, 0, fly_vertical2,
603:
604: ai_move, 0, fly_vertical2,
605: ai_move, 0, fly_vertical2,
606: ai_move, 0, fly_vertical2,
607: ai_move, 0, fly_vertical2,
608: ai_move, 0, fly_vertical2,
609: ai_move, 0, fly_vertical2,
610: ai_move, 0, fly_vertical2,
611: ai_move, 0, fly_vertical2
612: };
613: mmove_t fixbot_move_landing = { FRAME_landing_01, FRAME_landing_58, fixbot_frames_landing, NULL };
614:
615: /*
616: generic ambient stand
617: */
618: mframe_t fixbot_frames_stand [] =
619: {
620: ai_move, 0, NULL,
621: ai_move, 0, NULL,
622: ai_move, 0, NULL,
623: ai_move, 0, NULL,
624: ai_move, 0, NULL,
625: ai_move, 0, NULL,
626: ai_move, 0, NULL,
627: ai_move, 0, NULL,
628: ai_move, 0, NULL,
629: ai_move, 0, NULL,
630:
631: ai_move, 0, NULL,
632: ai_move, 0, NULL,
633: ai_move, 0, NULL,
634: ai_move, 0, NULL,
635: ai_move, 0, NULL,
636: ai_move, 0, NULL,
637: ai_move, 0, NULL,
638: ai_move, 0, NULL,
639: ai_move, 0, change_to_roam
640:
641: };
642: mmove_t fixbot_move_stand = {FRAME_ambient_01, FRAME_ambient_19, fixbot_frames_stand, NULL};
643:
644: mframe_t fixbot_frames_stand2 [] =
645: {
646:
647: ai_stand, 0, NULL,
648: ai_stand, 0, NULL,
649: ai_stand, 0, NULL,
650: ai_stand, 0, NULL,
651: ai_stand, 0, NULL,
652: ai_stand, 0, NULL,
653: ai_stand, 0, NULL,
654: ai_stand, 0, NULL,
655: ai_stand, 0, NULL,
656: ai_stand, 0, NULL,
657:
658: ai_stand, 0, NULL,
659: ai_stand, 0, NULL,
660: ai_stand, 0, NULL,
661: ai_stand, 0, NULL,
662: ai_stand, 0, NULL,
663: ai_stand, 0, NULL,
664: ai_stand, 0, NULL,
665: ai_stand, 0, NULL,
666: ai_stand, 0, NULL
667:
668: };
669: mmove_t fixbot_move_stand2 = {FRAME_ambient_01, FRAME_ambient_19, fixbot_frames_stand2, NULL};
670:
671:
672: /*
673: will need the pickup offset for the front pincers
674: object will need to stop forward of the object
675: and take the object with it ( this may require a variant of liftoff and landing )
676: */
677: mframe_t fixbot_frames_pickup [] =
678: {
679: ai_move, 0, NULL,
680: ai_move, 0, NULL,
681: ai_move, 0, NULL,
682: ai_move, 0, NULL,
683: ai_move, 0, NULL,
684: ai_move, 0, NULL,
685: ai_move, 0, NULL,
686: ai_move, 0, NULL,
687: ai_move, 0, NULL,
688: ai_move, 0, NULL,
689:
690: ai_move, 0, NULL,
691: ai_move, 0, NULL,
692: ai_move, 0, NULL,
693: ai_move, 0, NULL,
694: ai_move, 0, NULL,
695: ai_move, 0, NULL,
696: ai_move, 0, NULL,
697: ai_move, 0, NULL,
698: ai_move, 0, NULL,
699: ai_move, 0, NULL,
700:
701: ai_move, 0, NULL,
702: ai_move, 0, NULL,
703: ai_move, 0, NULL,
704: ai_move, 0, NULL,
705: ai_move, 0, NULL,
706: ai_move, 0, NULL,
707: ai_move, 0, NULL
708:
709: };
710: mmove_t fixbot_move_pickup = { FRAME_pickup_01, FRAME_pickup_27, fixbot_frames_pickup, NULL};
711:
712: /*
713: generic frame to move bot
714: */
715: mframe_t fixbot_frames_roamgoal [] =
716: {
717: ai_move, 0, roam_goal
718: };
719: mmove_t fixbot_move_roamgoal = {FRAME_freeze_01, FRAME_freeze_01, fixbot_frames_roamgoal, NULL};
720:
721:
722: void ai_facing (edict_t *self, float dist)
723: {
724: vec3_t v;
725:
726: if (infront (self, self->goalentity))
727: self->monsterinfo.currentmove = &fixbot_move_forward;
728: else
729: {
730: VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
731: self->ideal_yaw = vectoyaw(v);
732: M_ChangeYaw (self);
733: }
734:
735: };
736:
737: mframe_t fixbot_frames_turn [] =
738: {
739: ai_facing, 0, NULL
740: };
741: mmove_t fixbot_move_turn = {FRAME_freeze_01, FRAME_freeze_01, fixbot_frames_turn, NULL};
742:
743:
744: void go_roam (edict_t *self)
745: {
746: self->monsterinfo.currentmove = &fixbot_move_stand;
747: }
748:
749:
750: /*
751: takeoff
752: */
753: mframe_t fixbot_frames_takeoff [] =
754: {
755: ai_move, 0.01, fly_vertical,
756: ai_move, 0.01, fly_vertical,
757: ai_move, 0.01, fly_vertical,
758: ai_move, 0.01, fly_vertical,
759: ai_move, 0.01, fly_vertical,
760: ai_move, 0.01, fly_vertical,
761: ai_move, 0.01, fly_vertical,
762: ai_move, 0.01, fly_vertical,
763: ai_move, 0.01, fly_vertical,
764: ai_move, 0.01, fly_vertical,
765:
766: ai_move, 0.01, fly_vertical,
767: ai_move, 0.01, fly_vertical,
768: ai_move, 0.01, fly_vertical,
769: ai_move, 0.01, fly_vertical,
770: ai_move, 0.01, fly_vertical,
771: ai_move, 0.01, fly_vertical
772: };
773: mmove_t fixbot_move_takeoff = {FRAME_takeoff_01, FRAME_takeoff_16, fixbot_frames_takeoff, NULL};
774:
775:
776: /* findout what this is */
777: mframe_t fixbot_frames_paina [] =
778: {
779: ai_move, 0, NULL,
780: ai_move, 0, NULL,
781: ai_move, 0, NULL,
782: ai_move, 0, NULL,
783: ai_move, 0, NULL,
784: ai_move, 0, NULL
785: };
786: mmove_t fixbot_move_paina = {FRAME_paina_01, FRAME_paina_06, fixbot_frames_paina, fixbot_run};
787:
788: /* findout what this is */
789: mframe_t fixbot_frames_painb [] =
790: {
791: ai_move, 0, NULL,
792: ai_move, 0, NULL,
793: ai_move, 0, NULL,
794: ai_move, 0, NULL,
795: ai_move, 0, NULL,
796: ai_move, 0, NULL,
797: ai_move, 0, NULL,
798: ai_move, 0, NULL
799: };
800: mmove_t fixbot_move_painb = {FRAME_painb_01, FRAME_painb_08, fixbot_frames_painb, fixbot_run};
801:
802: /*
803: backup from pain
804: call a generic painsound
805: some spark effects
806: */
807: mframe_t fixbot_frames_pain3 [] =
808: {
809: ai_move, -1, NULL
810: };
811: mmove_t fixbot_move_pain3 = {FRAME_freeze_01, FRAME_freeze_01, fixbot_frames_pain3, fixbot_run};
812:
813: /*
814: bot has compleated landing
815: and is now on the grownd
816: ( may need second land if the bot is releasing jib into jib vat )
817: */
818: mframe_t fixbot_frames_land [] =
819: {
820: ai_move, 0, NULL
821: };
822: mmove_t fixbot_move_land = {FRAME_freeze_01, FRAME_freeze_01, fixbot_frames_land, NULL};
823:
824:
825: void M_MoveToGoal (edict_t *ent, float dist);
826:
827: void ai_movetogoal (edict_t *self, float dist)
828: {
829: M_MoveToGoal (self, dist);
830: }
831: /*
832:
833: */
834: mframe_t fixbot_frames_forward [] =
835: {
836: ai_movetogoal, 5, use_scanner
837: };
838: mmove_t fixbot_move_forward = {FRAME_freeze_01, FRAME_freeze_01, fixbot_frames_forward, NULL};
839:
840:
841: /*
842:
843: */
844: mframe_t fixbot_frames_walk [] =
845: {
846: ai_walk, 5, NULL
847: };
848: mmove_t fixbot_move_walk = {FRAME_freeze_01, FRAME_freeze_01, fixbot_frames_walk, NULL};
849:
850:
851: /*
852:
853: */
854: mframe_t fixbot_frames_run [] =
855: {
856: ai_run, 10, NULL
857: };
858: mmove_t fixbot_move_run = {FRAME_freeze_01, FRAME_freeze_01, fixbot_frames_run, NULL};
859:
860: /*
861: raf
862: note to self
863: they could have a timer that will cause
864: the bot to explode on countdown
865: */
866: mframe_t fixbot_frames_death1 [] =
867: {
868: ai_move, 0, NULL
869: };
870: mmove_t fixbot_move_death1 = {FRAME_freeze_01, FRAME_freeze_01, fixbot_frames_death1, fixbot_dead};
871:
872: //
873: mframe_t fixbot_frames_backward [] =
874: {
875: ai_move, 0, NULL
876: };
877: mmove_t fixbot_move_backward = {FRAME_freeze_01, FRAME_freeze_01, fixbot_frames_backward, NULL};
878:
879: //
880: mframe_t fixbot_frames_start_attack [] =
881: {
882: ai_charge, 0, NULL
883: };
884: mmove_t fixbot_move_start_attack = {FRAME_freeze_01, FRAME_freeze_01, fixbot_frames_start_attack, fixbot_attack};
885:
886: /*
887: TBD:
888: need to get laser attack anim
889: attack with the laser blast
890: */
891: mframe_t fixbot_frames_attack1 [] =
892: {
893: ai_charge, 0, NULL,
894: ai_charge, 0, NULL,
895: ai_charge, 0, NULL,
896: ai_charge, 0, NULL,
897: ai_charge, 0, NULL,
898: ai_charge, -10, fixbot_fire_blaster
899: };
900: mmove_t fixbot_move_attack1 = {FRAME_shoot_01, FRAME_shoot_06, fixbot_frames_attack1, NULL};
901:
902:
903: int check_telefrag (edict_t *self)
904: {
905: vec3_t start = { 0, 0, 0 };
906: vec3_t forward, right, up;
907: trace_t tr;
908:
909: AngleVectors (self->enemy->s.angles, forward, right, up);
910: VectorMA (start, 48, up, start);
911: tr = gi.trace (self->enemy->s.origin, self->enemy->mins, self->enemy->maxs, start, self, MASK_MONSTERSOLID);
912: if (tr.ent->takedamage)
913: {
914: tr.ent->health = -1000;
915: return (0);
916: }
917:
918: return (1);
919: }
920:
921: void fixbot_fire_laser (edict_t *self)
922: {
923:
924: vec3_t forward, right, up;
925: vec3_t tempang, start;
926: vec3_t dir, angles, end;
927: edict_t *ent;
928:
929: // critter dun got blown up while bein' fixed
930: if (self->enemy->health <= self->enemy->gib_health)
931: {
932: self->monsterinfo.currentmove = &fixbot_move_stand;
933: self->monsterinfo.aiflags &= ~AI_MEDIC;
934: return;
935: }
936:
937: gi.sound(self, CHAN_AUTO, gi.soundindex("misc/lasfly.wav"), 1, ATTN_STATIC, 0);
938:
939: VectorCopy (self->s.origin, start);
940: VectorCopy (self->enemy->s.origin, end);
941: VectorSubtract (end, start, dir);
942: vectoangles (dir, angles);
943:
944: ent = G_Spawn ();
945: VectorCopy (self->s.origin, ent->s.origin);
946: VectorCopy (angles, tempang);
947: AngleVectors (tempang, forward, right, up);
948: VectorCopy (tempang, ent->s.angles);
949: VectorCopy (ent->s.origin, start);
950:
951: VectorMA (start, 16, forward, start);
952:
953: VectorCopy (start, ent->s.origin);
954: ent->enemy = self->enemy;
955: ent->owner = self;
956: ent->dmg = -1;
957: monster_dabeam (ent);
958:
959: if (self->enemy->health > (self->enemy->mass/10))
960: {
961: // sorry guys but had to fix the problem this way
962: // if it doesn't do this then two creatures can share the same space
963: // and its real bad.
964: if (check_telefrag (self))
965: {
966: self->enemy->spawnflags = 0;
967: self->enemy->monsterinfo.aiflags = 0;
968: self->enemy->target = NULL;
969: self->enemy->targetname = NULL;
970: self->enemy->combattarget = NULL;
971: self->enemy->deathtarget = NULL;
972: self->enemy->owner = self;
973: ED_CallSpawn (self->enemy);
974: self->enemy->owner = NULL;
975: self->s.origin[2] += 1;
976:
977: self->enemy->monsterinfo.aiflags &= ~AI_RESURRECTING;
978:
979: self->monsterinfo.currentmove = &fixbot_move_stand;
980: self->monsterinfo.aiflags &= ~AI_MEDIC;
981:
982: }
983: }
984: else
985: self->enemy->monsterinfo.aiflags |= AI_RESURRECTING;
986: }
987:
988: mframe_t fixbot_frames_laserattack [] =
989: {
990: ai_charge, 0, fixbot_fire_laser,
991: ai_charge, 0, fixbot_fire_laser,
992: ai_charge, 0, fixbot_fire_laser,
993: ai_charge, 0, fixbot_fire_laser,
994: ai_charge, 0, fixbot_fire_laser,
995: ai_charge, 0, fixbot_fire_laser
996: };
997: mmove_t fixbot_move_laserattack = {FRAME_shoot_01, FRAME_shoot_06, fixbot_frames_laserattack, NULL};
998:
999:
1000: /*
1001: need to get forward translation data
1002: for the charge attack
1003: */
1004: mframe_t fixbot_frames_attack2 [] =
1005: {
1006: ai_charge, 0, NULL,
1007: ai_charge, 0, NULL,
1008: ai_charge, 0, NULL,
1009: ai_charge, 0, NULL,
1010: ai_charge, 0, NULL,
1011: ai_charge, 0, NULL,
1012: ai_charge, 0, NULL,
1013: ai_charge, 0, NULL,
1014: ai_charge, 0, NULL,
1015: ai_charge, 0, NULL,
1016:
1017: ai_charge, -10, NULL,
1018: ai_charge, -10, NULL,
1019: ai_charge, -10, NULL,
1020: ai_charge, -10, NULL,
1021: ai_charge, -10, NULL,
1022: ai_charge, -10, NULL,
1023: ai_charge, -10, NULL,
1024: ai_charge, -10, NULL,
1025: ai_charge, -10, NULL,
1026: ai_charge, -10, NULL,
1027:
1028: ai_charge, 0, fixbot_fire_blaster,
1029: ai_charge, 0, NULL,
1030: ai_charge, 0, NULL,
1031: ai_charge, 0, NULL,
1032: ai_charge, 0, NULL,
1033: ai_charge, 0, NULL,
1034: ai_charge, 0, NULL,
1035: ai_charge, 0, NULL,
1036: ai_charge, 0, NULL,
1037: ai_charge, 0, NULL,
1038:
1039: ai_charge, 0, NULL
1040: };
1041: mmove_t fixbot_move_attack2 = {FRAME_charging_01, FRAME_charging_31, fixbot_frames_attack2, fixbot_run};
1042:
1043: void weldstate (edict_t *self)
1044: {
1045: if (self->s.frame == FRAME_weldstart_10)
1046: self->monsterinfo.currentmove = &fixbot_move_weld;
1047: else if (self->s.frame == FRAME_weldmiddle_07)
1048: {
1049: if (self->goalentity->health < 0)
1050: {
1051: self->enemy->owner = NULL;
1052: self->monsterinfo.currentmove = &fixbot_move_weld_end;
1053: }
1054: else
1055: self->goalentity->health-=10;
1056: }
1057: else
1058: {
1059: self->goalentity = self->enemy = NULL;
1060: self->monsterinfo.currentmove = &fixbot_move_stand;
1061: }
1062: }
1063:
1064: void ai_move2 (edict_t *self, float dist)
1065: {
1066: vec3_t v;
1067:
1068: if (dist)
1069: M_walkmove (self, self->s.angles[YAW], dist);
1070:
1071: VectorSubtract (self->goalentity->s.origin, self->s.origin, v);
1072: self->ideal_yaw = vectoyaw(v);
1073: M_ChangeYaw (self);
1074: };
1075:
1076: mframe_t fixbot_frames_weld_start [] =
1077: {
1078: ai_move2, 0, NULL,
1079: ai_move2, 0, NULL,
1080: ai_move2, 0, NULL,
1081: ai_move2, 0, NULL,
1082: ai_move2, 0, NULL,
1083: ai_move2, 0, NULL,
1084: ai_move2, 0, NULL,
1085: ai_move2, 0, NULL,
1086: ai_move2, 0, NULL,
1087: ai_move2, 0, weldstate
1088: };
1089: mmove_t fixbot_move_weld_start = {FRAME_weldstart_01, FRAME_weldstart_10, fixbot_frames_weld_start, NULL};
1090:
1091: mframe_t fixbot_frames_weld [] =
1092: {
1093: ai_move2, 0, fixbot_fire_welder,
1094: ai_move2, 0, fixbot_fire_welder,
1095: ai_move2, 0, fixbot_fire_welder,
1096: ai_move2, 0, fixbot_fire_welder,
1097: ai_move2, 0, fixbot_fire_welder,
1098: ai_move2, 0, fixbot_fire_welder,
1099: ai_move2, 0, weldstate
1100: };
1101: mmove_t fixbot_move_weld = {FRAME_weldmiddle_01, FRAME_weldmiddle_07, fixbot_frames_weld, NULL};
1102:
1103: mframe_t fixbot_frames_weld_end [] =
1104: {
1105: ai_move2, -2, NULL,
1106: ai_move2, -2, NULL,
1107: ai_move2, -2, NULL,
1108: ai_move2, -2, NULL,
1109: ai_move2, -2, NULL,
1110: ai_move2, -2, NULL,
1111: ai_move2, -2, weldstate
1112: };
1113: mmove_t fixbot_move_weld_end = {FRAME_weldend_01, FRAME_weldend_07, fixbot_frames_weld_end, NULL};
1114:
1115:
1116: void fixbot_fire_welder (edict_t *self)
1117: {
1118: vec3_t start;
1119: vec3_t forward, right, up;
1120: vec3_t end;
1121: vec3_t dir;
1122: int count = 2;
1123: vec3_t vec;
1124: float r;
1125:
1126: if (!self->enemy)
1127: return;
1128:
1129:
1130: vec[0]=24.0;
1131: vec[1]=-0.8;
1132: vec[2]=-10.0;
1133:
1134: AngleVectors (self->s.angles, forward, right, up);
1135: G_ProjectSource (self->s.origin, vec, forward, right, start);
1136:
1137: VectorCopy (self->enemy->s.origin, end);
1138:
1139: VectorSubtract (end, start, dir);
1140:
1141: gi.WriteByte (svc_temp_entity);
1142: gi.WriteByte (TE_WELDING_SPARKS);
1143: gi.WriteByte (10);
1144: gi.WritePosition (start);
1145: gi.WriteDir (vec3_origin);
1146: gi.WriteByte (0xe0 + (rand()&7));
1147: gi.multicast (self->s.origin, MULTICAST_PVS);
1148:
1149:
1150: if (random() > 0.8)
1151: {
1152: r = random();
1153:
1154: if (r < 0.33)
1155: gi.sound (self, CHAN_VOICE, sound_weld1, 1, ATTN_IDLE, 0);
1156: else if (r < 0.66)
1157: gi.sound (self, CHAN_VOICE, sound_weld2, 1, ATTN_IDLE, 0);
1158: else
1159: gi.sound (self, CHAN_VOICE, sound_weld3, 1, ATTN_IDLE, 0);
1160: }
1161: }
1162:
1163: void fixbot_fire_blaster (edict_t *self)
1164: {
1165: vec3_t start;
1166: vec3_t forward, right, up;
1167: vec3_t end;
1168: vec3_t dir;
1169:
1170: if (!visible(self, self->enemy))
1171: {
1172: self->monsterinfo.currentmove = &fixbot_move_run;
1173: }
1174:
1175: AngleVectors (self->s.angles, forward, right, up);
1176: G_ProjectSource (self->s.origin, monster_flash_offset[MZ2_fixbot_BLASTER_1], forward, right, start);
1177:
1178: VectorCopy (self->enemy->s.origin, end);
1179: end[2] += self->enemy->viewheight;
1180: VectorSubtract (end, start, dir);
1181:
1182: monster_fire_blaster (self, start, dir, 15, 1000, MZ2_fixbot_BLASTER_1, EF_BLASTER);
1183:
1184: }
1185:
1186: void fixbot_stand (edict_t *self)
1187: {
1188: self->monsterinfo.currentmove = &fixbot_move_stand;
1189: }
1190:
1191: void fixbot_run (edict_t *self)
1192: {
1193: if (self->monsterinfo.aiflags & AI_STAND_GROUND)
1194: self->monsterinfo.currentmove = &fixbot_move_stand;
1195: else
1196: self->monsterinfo.currentmove = &fixbot_move_run;
1197: }
1198:
1199: void fixbot_walk (edict_t *self)
1200: {
1201: vec3_t vec;
1202: int len;
1203:
1204: if (strcmp (self->goalentity->classname, "object_repair") == 0)
1205: {
1206: VectorSubtract (self->s.origin, self->goalentity->s.origin, vec);
1207: len = VectorLength (vec);
1208: if (len < 32)
1209: {
1210: self->monsterinfo.currentmove = &fixbot_move_weld_start;
1211: return;
1212: }
1213: }
1214: self->monsterinfo.currentmove = &fixbot_move_walk;
1215: }
1216:
1217: void fixbot_start_attack (edict_t *self)
1218: {
1219: self->monsterinfo.currentmove = &fixbot_move_start_attack;
1220: }
1221:
1222: void fixbot_attack(edict_t *self)
1223: {
1224: vec3_t vec;
1225: int len;
1226:
1227: if (self->monsterinfo.aiflags & AI_MEDIC)
1228: {
1229: if (!visible (self, self->goalentity))
1230: return;
1231: VectorSubtract (self->s.origin, self->enemy->s.origin, vec);
1232: len = VectorLength(vec);
1233: if (len > 128)
1234: return;
1235: else
1236: self->monsterinfo.currentmove = &fixbot_move_laserattack;
1237: }
1238: else
1239: self->monsterinfo.currentmove = &fixbot_move_attack2;
1240:
1241: }
1242:
1243:
1244: void fixbot_pain (edict_t *self, edict_t *other, float kick, int damage)
1245: {
1246: // if (self->health < (self->max_health / 2))
1247: // self->s.skinnum = 1;
1248: // gi.dprintf("pain\n");
1249:
1250: if (level.time < self->pain_debounce_time)
1251: return;
1252:
1253: self->pain_debounce_time = level.time + 3;
1254: gi.sound (self, CHAN_VOICE, sound_pain1, 1, ATTN_NORM, 0);
1255:
1256: if (damage <= 10)
1257: self->monsterinfo.currentmove = &fixbot_move_pain3;
1258: else if (damage <= 25)
1259: self->monsterinfo.currentmove = &fixbot_move_painb;
1260: else
1261: self->monsterinfo.currentmove = &fixbot_move_paina;
1262: }
1263:
1264: void fixbot_dead (edict_t *self)
1265: {
1266: VectorSet (self->mins, -16, -16, -24);
1267: VectorSet (self->maxs, 16, 16, -8);
1268: self->movetype = MOVETYPE_TOSS;
1269: self->svflags |= SVF_DEADMONSTER;
1270: self->nextthink = 0;
1271: gi.linkentity (self);
1272: }
1273:
1274: void fixbot_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
1275: {
1276: gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
1277: BecomeExplosion1(self);
1278:
1279: // shards
1280:
1281: }
1282:
1283: /*QUAKED monster_fixbot (1 .5 0) (-32 -32 -24) (32 32 24) Ambush Trigger_Spawn Fixit Takeoff Landing
1284: */
1285: void SP_monster_fixbot (edict_t *self)
1286: {
1287: if (deathmatch->value)
1288: {
1289: G_FreeEdict (self);
1290: return;
1291: }
1292:
1293: sound_pain1 = gi.soundindex ("flyer/flypain1.wav");
1294: sound_die = gi.soundindex ("flyer/flydeth1.wav");
1295:
1296: sound_weld1 = gi.soundindex ("misc/welder1.wav");
1297: sound_weld2 = gi.soundindex ("misc/welder2.wav");
1298: sound_weld3 = gi.soundindex ("misc/welder3.wav");
1299:
1300: self->s.modelindex = gi.modelindex ("models/monsters/fixbot/tris.md2");
1301:
1302: VectorSet (self->mins, -32, -32, -24);
1303: VectorSet (self->maxs, 32, 32, 24);
1304:
1305: self->movetype = MOVETYPE_STEP;
1306: self->solid = SOLID_BBOX;
1307:
1308: self->health = 150;
1309: self->mass = 150;
1310:
1311: self->pain = fixbot_pain;
1312: self->die = fixbot_die;
1313:
1314: self->monsterinfo.stand = fixbot_stand;
1315: self->monsterinfo.walk = fixbot_walk;
1316: self->monsterinfo.run = fixbot_run;
1317: self->monsterinfo.attack = fixbot_attack;
1318:
1319: gi.linkentity (self);
1320:
1321: self->monsterinfo.currentmove = &fixbot_move_stand;
1322: self->monsterinfo.scale = MODEL_SCALE;
1323:
1324: flymonster_start (self);
1325:
1326: }
1327:
1328:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.