1 #ifndef H_ENEMY
2 #define H_ENEMY
3 
4 #include "character.h"
5 #include "objects.h"
6 
7 #define STALK_BOX       (1024 * 3)
8 #define ESCAPE_BOX      (1024 * 5)
9 #define ATTACK_BOX      STALK_BOX
10 
11 #define MAX_SHOT_DIST   (64 * 1024)
12 
13 struct Enemy : Character {
14 
15     struct Path {
16         int16       index;
17         int16       count;
18         uint16      *boxes;
19         TR::Level   *level;
20 
PathEnemy::Path21         Path(TR::Level *level, uint16 *boxes, int count) : index(0), count(count), boxes(new uint16[count]), level(level) {
22             memcpy(this->boxes, boxes, count * sizeof(boxes[0]));
23         }
24 
~PathEnemy::Path25         ~Path() {
26             delete[] boxes;
27         }
28 
getNextPointEnemy::Path29         bool getNextPoint(TR::Level *level, vec3 &point) {
30             if (index >= count - 1)
31                 return false;
32 
33             TR::Box &a = level->boxes[boxes[index++]];
34             TR::Box &b = level->boxes[boxes[index]];
35 
36             int minX = max(a.minX, b.minX);
37             int minZ = max(a.minZ, b.minZ);
38             int maxX = min(a.maxX, b.maxX);
39             int maxZ = min(a.maxZ, b.maxZ);
40 
41             point.x = float(minX + 512) + randf() * (maxX - minX - 1024);
42             point.y = float((a.floor + b.floor) / 2);
43             point.z = float(minZ + 512) + randf() * (maxZ - minZ - 1024);
44 
45             return true;
46         }
47     };
48 
49     enum AI {
50         AI_FIXED, AI_RANDOM
51     } ai;
52 
53     enum Mood {
54         MOOD_SLEEP, MOOD_STALK, MOOD_ATTACK, MOOD_ESCAPE
55     } mood;
56 
57     bool  wound;
58     int   nextState;
59 
60     uint16 targetBox;
61     vec3   waypoint;
62 
63     float thinkTime;
64     float length;       // dist from center to head (jaws)
65     float aggression;
66     int   radius;
67     int   hitSound;
68 
69     Character *target;
70     Path      *path;
71 
72     float targetDist;
73     float targetAngle;
74     bool  targetDead;
75     bool  targetInView;     // target in enemy view zone
76     bool  targetFromView;   // enemy in target view zone
77     bool  targetCanAttack;
78 
EnemyEnemy79     Enemy(IGame *game, int entity, float health, int radius, float length, float aggression) : Character(game, entity, health), ai(AI_RANDOM), mood(MOOD_SLEEP), wound(false), nextState(0), targetBox(TR::NO_BOX), thinkTime(1.0f / 30.0f), length(length), aggression(aggression), radius(radius), hitSound(-1), target(NULL), path(NULL) {
80         targetDist   = +INF;
81         targetInView = targetFromView = targetCanAttack = false;
82         waypoint     = pos;
83     }
84 
~EnemyEnemy85     virtual ~Enemy() {
86         delete path;
87     }
88 
getSaveDataEnemy89     virtual bool getSaveData(SaveEntity &data) {
90         Character::getSaveData(data);
91         data.extraSize = sizeof(data.extra.enemy);
92         data.extra.enemy.health    = health;
93         data.extra.enemy.spec.mood = mood;
94         data.extra.enemy.targetBox = targetBox;
95         return true;
96     }
97 
setSaveDataEnemy98     virtual void setSaveData(const SaveEntity &data) {
99         Character::setSaveData(data);
100         health    = data.extra.enemy.health;
101         mood      = Mood(data.extra.enemy.spec.mood);
102         targetBox = data.extra.enemy.targetBox;
103         updateZone();
104     }
105 
activateEnemy106     virtual bool activate() {
107         return health > 0.0f && Character::activate();
108     }
109 
updateVelocityEnemy110     virtual void updateVelocity() {
111         if (stand == STAND_AIR && (!flying || health <= 0.0f))
112             applyGravity(velocity.y);
113         else
114             velocity = getDir() * animation.getSpeed();
115 
116         if (health <= 0.0f)
117             velocity.x = velocity.z = 0.0f;
118     }
119 
checkPointEnemy120     bool checkPoint(int x, int z) {
121         TR::Box &a = level->boxes[box];
122         if (a.contains(x, z))
123             return true;
124 
125         bool big = getEntity().isBigEnemy();
126         TR::Overlap *o = &level->overlaps[a.overlap.index];
127         do {
128             TR::Box &b = level->boxes[o->boxIndex];
129             if (!b.contains(x, z))
130                 continue;
131             if (big && b.overlap.blockable)
132                 continue;
133             if (getZones()[o->boxIndex] == zone) {
134                 int d = a.floor - b.floor;
135                 if (d <= stepHeight && d >= dropHeight)
136                     return true;
137             }
138         } while (!(o++)->end);
139 
140         return false;
141     }
142 
clipByBoxEnemy143     void clipByBox(vec3 &pos) {
144         int px = int(pos.x);
145         int pz = int(pos.z);
146         int nx = px;
147         int nz = pz;
148 
149         TR::Box &a = level->boxes[box];
150 
151         if (!checkPoint(px - radius, pz)) nx = a.minX + radius;
152         if (!checkPoint(px + radius, pz)) nx = a.maxX - radius;
153         if (!checkPoint(px, pz - radius)) nz = a.minZ + radius;
154         if (!checkPoint(px, pz + radius)) nz = a.maxZ - radius;
155 
156         if (px != nx) pos.x = float(nx);
157         if (pz != nz) pos.z = float(nz);
158     }
159 
collideEnemiesEnemy160     void collideEnemies() {
161         if (getEntity().isBigEnemy())
162             return;
163 
164         Controller *c = Controller::first;
165         while (c) {
166             if (c != this && c->getEntity().isEnemy()) {
167                 Enemy *enemy = (Enemy*)c;
168                 if (enemy->health > 0.0f) {
169                     vec3 dir = vec3(enemy->pos.x - pos.x, 0.0f, enemy->pos.z - pos.z);
170                     float D = dir.length2();
171                     float R = float((enemy->radius + radius) / 2);
172                     if (D < R * R) {
173                         D = sqrtf(D);
174                         pos -= dir.normal() * (R - D);
175                     }
176                 }
177             }
178             c = c->next;
179         }
180     }
181 
updatePositionEnemy182     virtual void updatePosition() {
183         if (!flags.active) return;
184 
185         vec3 p = pos;
186         pos += velocity * (30.0f * Core::deltaTime);
187 
188         collideEnemies();
189 
190         clipByBox(pos);
191 
192         TR::Level::FloorInfo info;
193         getFloorInfo(getRoomIndex(), pos, info);
194         if (stand == STAND_AIR && !flying && info.floor < pos.y) {
195             stand = STAND_GROUND;
196             pos.y = info.floor;
197         }
198 
199         if (info.boxIndex != 0xFFFF && zone == getZones()[info.boxIndex] && !level->boxes[info.boxIndex].overlap.block) {
200             switch (stand) {
201                 case STAND_GROUND : {
202                     float fallSpeed = 2048.0f * Core::deltaTime;
203                     decrease(info.floor - pos.y, pos.y, fallSpeed);
204                     break;
205                 }
206                 case STAND_AIR    :
207                     pos.y = clamp(pos.y, info.ceiling, info.floor);
208                     break;
209                 default : ;
210             }
211         } else
212             pos = p;
213 
214         updateRoom();
215     }
216 
setOverridesEnemy217     void setOverrides(bool active, int chest, int head) {
218         if (active && head  > -1) {
219             animation.overrides[head] = animation.getJointRot(head);
220             animation.overrideMask |=  (1 << head);
221         } else
222             animation.overrideMask &= ~(1 << head);
223 
224         if (active && chest  > -1) {
225             animation.overrides[chest] = animation.getJointRot(chest);
226             animation.overrideMask |=  (1 << chest);
227         } else
228             animation.overrideMask &= ~(1 << chest);
229     }
230 
targetIsVisibleEnemy231     bool targetIsVisible(float maxDist) {
232         if (targetInView && targetDist < maxDist && target->health > 0.0f) {
233             TR::Location from, to;
234             from.room = getRoomIndex();
235             from.pos  = pos;
236             to.pos    = target->pos;
237 
238         // vertical offset to ~gun/head height
239             from.pos.y -= 768.0f;
240             if (target->stand != STAND_UNDERWATER && target->stand != STAND_ONWATER)
241                 to.pos.y -= 768.0f;
242 
243             return trace(from, to);
244         }
245         return false;
246     }
247 
lookAtEnemy248     virtual void lookAt(Controller *target) {
249         Character::lookAt(targetInView ? target : NULL);
250     }
251 
turnEnemy252     void turn(bool tilt, float w) {
253         float speed = animation.getSpeed();
254 
255         if (!target || speed == 0.0f || w == 0.0f) {
256             angle.z = lerp(angle.z, 0.0f, 4.0f * Core::deltaTime);
257             return;
258         }
259 
260         vec3  d = waypoint - pos;
261         float a = clampAngle(normalizeAngle(PIH - d.angleY() - angle.y));
262 
263         w /= 30.0f;
264 
265         float minDist = speed * PIH / w;
266 
267         if ( (a > PIH || a < -PIH) && (SQR(d.x) + SQR(d.z) < SQR(minDist)) )
268             w *= 0.5f;
269 
270         a = clamp(a, -w, w);
271 
272         angle.y += a * 30.0f * Core::deltaTime;
273         angle.z = lerp(angle.z, tilt ? a * 2.0f : 0.0f, 4.0f * Core::deltaTime);
274     }
275 
liftEnemy276     int lift(float delta, float speed) {
277         speed *= Core::deltaTime;
278         decrease(delta, pos.y, speed);
279         if (speed != 0.0f) {
280             return speed < 0 ? FORTH : BACK;
281         }
282         return 0;
283     }
284 
285     virtual void hit(float damage, Controller *enemy = NULL, TR::HitType hitType = TR::HIT_DEFAULT) {
286         if (hitSound > -1 && health > 0.0f)
287             game->playSound(hitSound, pos, Sound::PAN);
288         Character::hit(damage, enemy, hitType);
289         wound = true;
290     };
291 
biteEnemy292     void bite(int joint, const vec3 &offset, float damage) {
293         ASSERT(target);
294         target->hit(damage, this);
295         if (joint >= 0)
296             game->addEntity(TR::Entity::BLOOD, target->getRoomIndex(), getJoint(joint) * offset);
297     }
298 
getMoodFixedEnemy299     Mood getMoodFixed() {
300         bool inZone = zone == target->zone;
301 
302         if (mood == MOOD_SLEEP || mood == MOOD_STALK)
303             return inZone ? MOOD_ATTACK : (wound ? MOOD_ESCAPE : mood);
304 
305         if (mood == MOOD_ATTACK)
306             return inZone ? mood : MOOD_SLEEP;
307 
308         return inZone ? MOOD_ATTACK : mood;
309     }
310 
getMoodRandomEnemy311     Mood getMoodRandom() {
312         bool inZone = zone == target->zone;
313         bool brave  = rand() < (mood != MOOD_ESCAPE ? 0x7800 : 0x0100) && inZone;
314 
315         if (mood == MOOD_SLEEP || mood == MOOD_STALK) {
316             if (wound && !brave)
317                 return MOOD_ESCAPE;
318             if (inZone) {
319                 int dx = abs(int(pos.x - target->pos.x));
320                 int dz = abs(int(pos.z - target->pos.z));
321                 return ((dx <= ATTACK_BOX && dz <= ATTACK_BOX) || (mood == MOOD_STALK && targetBox == TR::NO_BOX)) ? MOOD_ATTACK : MOOD_STALK;
322             }
323             return mood;
324         }
325 
326         if (mood == MOOD_ATTACK)
327             return (wound && !brave) ? MOOD_ESCAPE : (!inZone ? MOOD_SLEEP : mood);
328 
329         return brave ? MOOD_STALK : mood;
330     }
331 
thinkEnemy332     bool think(bool fixedLogic) {
333         thinkTime += Core::deltaTime;
334         if (thinkTime < 1.0f / 30.0f)
335             return false;
336         thinkTime -= 1.0f / 30.0f;
337 
338         int zoneOld = zone;
339         updateZone();
340 
341         target = (Character*)game->getLara(pos);
342 
343         vec3 targetVec  = target->pos - pos - getDir() * length;
344         targetDist      = targetVec.length();
345         targetAngle     = clampAngle(atan2f(targetVec.x, targetVec.z) - angle.y);
346         targetDead      = target->health <= 0;
347         targetInView    = targetVec.dot(getDir()) > 0;
348         targetFromView  = targetVec.dot(target->getDir()) < 0;
349         targetCanAttack = targetInView && fabsf(targetVec.y) <= 256.0f;
350 
351         int targetBoxOld = targetBox;
352 
353         bool inZone = zone == target->zone;
354 
355         if (target->health <= 0.0f || !inZone)
356             targetBox = TR::NO_BOX;
357 
358     // update mood
359         if (mood != MOOD_ATTACK && targetBox != TR::NO_BOX && !checkBox(targetBox)) {
360             if (!inZone)
361                 mood = MOOD_SLEEP;
362             targetBox = TR::NO_BOX;
363         }
364 
365         mood = target->health <= 0 ? MOOD_SLEEP : (ai == AI_FIXED ? getMoodFixed() : getMoodRandom());
366 
367     // set behavior and target
368         int box;
369 
370         switch (mood) {
371             case MOOD_SLEEP :
372                 if (targetBox == TR::NO_BOX && checkBox(box = getRandomZoneBox()) && isStalkBox(box)) {
373                     mood = MOOD_STALK;
374                     gotoBox(box);
375                 }
376                 break;
377             case MOOD_STALK :
378                 if ((targetBox == TR::NO_BOX || !isStalkBox(targetBox)) && checkBox(box = getRandomZoneBox())) {
379                     if (isStalkBox(box))
380                         gotoBox(box);
381                     else
382                         if (targetBox == TR::NO_BOX) {
383                             if (!inZone)
384                                 mood = MOOD_SLEEP;
385                             gotoBox(box);
386                         }
387                 }
388                 break;
389             case MOOD_ATTACK :
390                 if (randf() > aggression)
391                     break;
392                 targetBox = TR::NO_BOX;
393                 break;
394             case MOOD_ESCAPE :
395                 if (targetBox == TR::NO_BOX && checkBox(box = getRandomZoneBox())) {
396                     if (isEscapeBox(box))
397                         gotoBox(box);
398                     else
399                         if (inZone && isStalkBox(box)) {
400                             mood = MOOD_STALK;
401                             gotoBox(box);
402                         }
403                 }
404                 break;
405         }
406 
407         if (targetBox == TR::NO_BOX)
408             gotoBox(target->box);
409 
410         if (path && this->box != path->boxes[path->index - 1] && this->box != path->boxes[path->index])
411             targetBoxOld = TR::NO_BOX;
412 
413         if (zoneOld != zone)
414             targetBoxOld = TR::NO_BOX;
415 
416         if (targetBoxOld != targetBox) {
417             if (findPath(stepHeight, dropHeight, getEntity().isBigEnemy()))
418                 nextWaypoint();
419             else
420                 targetBox = TR::NO_BOX;
421         }
422 
423         if (targetBox != TR::NO_BOX && path) {
424             vec3 d = pos - waypoint;
425 
426             if (fabsf(d.x) < 512 && fabsf(d.y) < 512 && fabsf(d.z) < 512)
427                 nextWaypoint();
428         }
429 
430         return true;
431     }
432 
nextWaypointEnemy433     void nextWaypoint() {
434         if (!path->getNextPoint(level, waypoint))
435             waypoint = target->pos;
436     }
437 
getRandomZoneBoxEnemy438     uint16 getRandomZoneBox() {
439         return game->getRandomBox(zone, getZones());
440     }
441 
gotoBoxEnemy442     void gotoBox(int box) {
443         targetBox = box;
444     }
445 
checkBoxEnemy446     bool checkBox(int box) {
447         if (zone != getZones()[box])
448             return false;
449 
450         TR::Box    &b = game->getLevel()->boxes[box];
451         uint16   type = getEntity().type;
452 
453         if (b.overlap.block)
454             return false;
455 
456         if (type == TR::Entity::ENEMY_REX || type == TR::Entity::ENEMY_MUTANT_1 || type == TR::Entity::ENEMY_CENTAUR) {
457             if (b.overlap.blockable)
458                 return false;
459         } else
460             if (b.overlap.block)
461                 return false;
462 
463         return int(pos.x) < int(b.minX) || int(pos.x) > int(b.maxX) || int(pos.z) < int(b.minZ) || int(pos.z) > int(b.maxZ);
464     }
465 
isStalkBoxEnemy466     bool isStalkBox(int box) {
467         TR::Box    &b = game->getLevel()->boxes[box];
468 
469         int x = (b.minX + b.maxX) / 2 - int(target->pos.x);
470         if (abs(x) > STALK_BOX) return false;
471 
472         int z = (b.minZ + b.maxZ) / 2 - int(target->pos.z);
473         if (abs(z) > STALK_BOX) return false;
474 
475         int target_quadrant = angleQuadrant(target->angle.y, 0.0);
476         int box_quadrant = z > 0 ? (x > 0 ? 2 : 1) : (x > 0 ? 3 : 0);
477 
478         if (target_quadrant == box_quadrant) return false;
479 
480         int controller_quadrant = pos.z > target->pos.z ? (pos.x > target->pos.x ? 2 : 1) : (pos.x > target->pos.x ? 3 : 0);
481 
482         if (target_quadrant == controller_quadrant && abs(target_quadrant - box_quadrant) == 2) return false;
483 
484         return true;
485     }
486 
isEscapeBoxEnemy487     bool isEscapeBox(int box) {
488         TR::Box    &b = game->getLevel()->boxes[box];
489 
490         int x = (b.minX + b.maxX) / 2 - int(target->pos.x);
491         if (abs(x) < ESCAPE_BOX) return false;
492 
493         int z = (b.minZ + b.maxZ) / 2 - int(target->pos.z);
494         if (abs(z) < ESCAPE_BOX) return false;
495 
496         return !((pos.x > target->pos.x) ^ (x > 0)) || !((pos.z > target->pos.z) ^ (z > 0));
497     }
498 
findPathEnemy499     bool findPath(int ascend, int descend, bool big) {
500         delete path;
501         path = NULL;
502 
503         uint16 *boxes;
504         uint16 count = game->findPath(ascend, descend, big, box, targetBox, getZones(), &boxes);
505         if (count) {
506             path = new Path(level, boxes, count);
507             return true;
508         }
509 
510         return false;
511     }
512 
shotEnemy513     void shot(TR::Entity::Type type, int joint, const vec3 &offset, float rx, float ry) {
514         vec3 from = getJoint(joint) * offset;
515         vec3 to   = target->getBoundingBox().center();
516 
517         Bullet *bullet = (Bullet*)game->addEntity(type, getRoomIndex(), from);
518         if (bullet) {
519             vec3 dir = to - from;
520             vec3 ang = vec3(-atan2f(dir.y, sqrtf(dir.x * dir.x + dir.z * dir.z)), atan2f(dir.x, dir.z), 0.0f);
521             ang += vec3(rx, ry, 0.0f);
522             bullet->setAngle(ang);
523         }
524     }
525 
shotEnemy526     void shot(TR::Entity::Type type, int joint, const vec3 &offset) {
527         shot(type, joint, offset, (randf() * 2.0f - 1.0f) * (1.5f * DEG2RAD), (randf() * 2.0f - 1.0f) * (1.5f * DEG2RAD));
528     }
529 
isVisibleEnemy530     bool isVisible() {
531         for (int i = 0; i < 2; i++) {
532             ICamera *camera = game->getCamera(i);
533             if (!camera) continue;
534 
535             TR::Location eye = camera->eye;
536             TR::Location loc;
537             loc.room = getRoomIndex();
538             loc.box  = box;
539             loc.pos  = pos;
540             loc.pos.y -= 1024;
541 
542             if (trace(eye, loc))
543                 return true;
544         }
545         return false;
546     }
547 };
548 
549 
550 #define WOLF_TURN_FAST   (DEG2RAD * 150)
551 #define WOLF_TURN_SLOW   (DEG2RAD * 60)
552 #define WOLF_DIST_STALK  STALK_BOX
553 #define WOLF_DIST_BITE   345
554 #define WOLF_DIST_ATTACK (1024 + 512)
555 
556 struct Wolf : Enemy {
557 
558     enum {
559         HIT_MASK = 0x774F,  // body, head, front legs
560     };
561 
562     enum {
563         ANIM_DEATH      = 20,
564         ANIM_DEATH_RUN  = 21,
565         ANIM_DEATH_JUMP = 22,
566     };
567 
568     enum {
569         STATE_NONE   ,
570         STATE_STOP   ,
571         STATE_WALK   ,
572         STATE_RUN    ,
573         STATE_JUMP   , // unused
574         STATE_STALK  ,
575         STATE_ATTACK ,
576         STATE_HOWL   ,
577         STATE_SLEEP  ,
578         STATE_GROWL  ,
579         STATE_TURN   , // unused
580         STATE_DEATH  ,
581         STATE_BITE   ,
582     };
583 
WolfWolf584     Wolf(IGame *game, int entity) : Enemy(game, entity, 6, 341, 375.0f, 0.25f) {
585         dropHeight = -1024;
586         jointChest = 2;
587         jointHead  = 3;
588         hitSound   = TR::SND_HIT_WOLF;
589         nextState  = STATE_NONE;
590         animation.time = animation.timeMax;
591         updateAnimation(false);
592     }
593 
getStateGroundWolf594     virtual int getStateGround() {
595         if (!think(false))
596             return state;
597 
598         if (nextState == state)
599             nextState = STATE_NONE;
600 
601         switch (state) {
602             case STATE_SLEEP    :
603                 if (mood == MOOD_ESCAPE || target->zone == zone)
604                     nextState = STATE_GROWL;
605                 else if (rand() < 32)
606                     nextState = STATE_WALK;
607                 else
608                     break;
609                 return STATE_STOP;
610             case STATE_STOP     : return nextState != STATE_NONE ? nextState : STATE_WALK;
611             case STATE_WALK     :
612                 if (mood != MOOD_SLEEP) {
613                     nextState = STATE_NONE;
614                     return STATE_STALK;
615                 }
616                 if (rand() < 32) {
617                     nextState = STATE_SLEEP;
618                     return STATE_STOP;
619                 }
620                 break;
621             case STATE_GROWL    :
622                 if (nextState != STATE_NONE) return nextState;
623                 if (mood == MOOD_ESCAPE)     return STATE_RUN;
624                 if (targetDist < WOLF_DIST_BITE && targetCanAttack) return STATE_BITE;
625                 if (mood == MOOD_STALK)      return STATE_STALK;
626                 if (mood == MOOD_SLEEP)      return STATE_STOP;
627                 return STATE_RUN;
628             case STATE_STALK    :
629                 if (mood == MOOD_ESCAPE)            return STATE_RUN;
630                 if (targetDist < WOLF_DIST_BITE && targetCanAttack) return STATE_BITE;
631                 if (targetDist > WOLF_DIST_STALK)   return STATE_RUN;
632                 if (mood == MOOD_ATTACK) {
633                     if (!targetInView || targetFromView || targetDist > WOLF_DIST_ATTACK)
634                         return STATE_RUN;
635                 }
636                 if (rand() < 384) {
637                     nextState = STATE_HOWL;
638                     return STATE_GROWL;
639                 }
640                 if (mood == MOOD_SLEEP)     return STATE_GROWL;
641                 break;
642             case STATE_RUN      :
643                 if (targetDist < WOLF_DIST_ATTACK && targetInView) {
644                     if (targetDist < WOLF_DIST_ATTACK * 0.5f && targetFromView) {
645                         nextState = STATE_NONE;
646                         return STATE_ATTACK;
647                     }
648                     nextState = STATE_STALK;
649                     return STATE_GROWL;
650                 }
651                 if (mood == MOOD_STALK && targetDist < WOLF_DIST_STALK) {
652                     nextState = STATE_STALK;
653                     return STATE_GROWL;
654                 }
655                 if (mood == MOOD_SLEEP) return STATE_GROWL;
656                 break;
657             case STATE_ATTACK :
658             case STATE_BITE   :
659                 if (nextState == STATE_NONE && targetInView && (collide(target) & HIT_MASK)) {
660                     bite(6, vec3(0.0f, -14.0f, 174.0f), state == STATE_ATTACK ? 50.0f : 100.0f);
661                     nextState = state == STATE_ATTACK ? STATE_RUN : STATE_GROWL;
662                 }
663                 return state == STATE_ATTACK ? STATE_RUN : state;
664         }
665 
666         return state;
667     }
668 
getStateDeathWolf669     virtual int getStateDeath() {
670         switch (state) {
671             case STATE_DEATH : return state;
672             case STATE_RUN   : return animation.setAnim(ANIM_DEATH_RUN);
673             case STATE_JUMP  : return animation.setAnim(ANIM_DEATH_JUMP);
674             default          : return animation.setAnim(ANIM_DEATH);
675         }
676     }
677 
updatePositionWolf678     virtual void updatePosition() {
679         turn(state == STATE_RUN || state == STATE_WALK || state == STATE_STALK, state == STATE_RUN ? WOLF_TURN_FAST : WOLF_TURN_SLOW);
680 
681         if (state == STATE_DEATH) {
682             animation.overrideMask = 0;
683             return;
684         }
685 
686         Enemy::updatePosition();
687         setOverrides(state != STATE_DEATH, jointChest, jointHead);
688         lookAt(target);
689     }
690 };
691 
692 
693 #define LION_DIST_ATTACK 1024
694 #define LION_TURN_FAST   (DEG2RAD * 150)
695 #define LION_TURN_SLOW   (DEG2RAD * 60)
696 
697 struct Lion : Enemy {
698 
699     enum {
700         HIT_MASK = 0x380066,
701     };
702 
703     enum {
704         ANIM_DEATH_LION = 7,
705         ANIM_DEATH_PUMA = 4,
706     };
707 
708     enum {
709         STATE_NONE   ,
710         STATE_STOP   ,
711         STATE_WALK   ,
712         STATE_RUN    ,
713         STATE_ATTACK ,
714         STATE_DEATH  ,
715         STATE_ROAR   ,
716         STATE_BITE   ,
717     };
718 
LionLion719     Lion(IGame *game, int entity) : Enemy(game, entity, 6, 341, 400.0f, 0.25f) {
720         dropHeight = -1024;
721         jointChest = 19;
722         jointHead  = 20;
723         switch (getEntity().type) {
724             case TR::Entity::ENEMY_LION_MALE :
725                 hitSound   = TR::SND_HIT_LION;
726                 health     = 30.0f;
727                 aggression = 1.0f;
728                 break;
729             case TR::Entity::ENEMY_LION_FEMALE :
730                 hitSound = TR::SND_HIT_LION;
731                 health   = 25.0f;
732                 break;
733             case TR::Entity::ENEMY_PUMA :
734                 health   = 45.0f;
735                 break;
736             default : ;
737         }
738     }
739 
getStateGroundLion740     virtual int getStateGround() {
741         if (!think(true))
742             return state;
743 
744         if (nextState == state)
745             nextState = STATE_NONE;
746 
747         switch (state) {
748             case STATE_STOP    :
749                 if (nextState != STATE_NONE)
750                     return nextState;
751                 if (mood == MOOD_SLEEP)
752                     return STATE_WALK;
753                 if (targetInView && (collide(target) & HIT_MASK))
754                     return STATE_BITE;
755                 if (targetInView && targetDist < LION_DIST_ATTACK)
756                     return STATE_ATTACK;
757                 return STATE_RUN;
758             case STATE_WALK     :
759                 if (mood != MOOD_SLEEP)
760                     return STATE_STOP;
761                 if (randf() < 0.0004f) {
762                     nextState = STATE_ROAR;
763                     return STATE_STOP;
764                 }
765                 break;
766             case STATE_RUN      :
767                 if ((mood == MOOD_SLEEP) ||
768                     (targetInView && targetDist < LION_DIST_ATTACK) ||
769                     (targetInView && (collide(target) & HIT_MASK)))
770                     return STATE_STOP;
771                 if (mood == MOOD_ESCAPE && randf() < 0.0004f) {
772                     nextState = STATE_ROAR;
773                     return STATE_STOP;
774                 }
775                 break;
776             case STATE_ATTACK :
777             case STATE_BITE   :
778                 if (nextState == STATE_NONE && (collide(target) & HIT_MASK)) {
779                     bite(21, vec3(-2.0f, -10.0f, 132.0f), state == STATE_ATTACK ? 150.0f : 250.0f);
780                     nextState = STATE_STOP;
781                 }
782         }
783 
784         return state;
785     }
786 
getStateDeathLion787     virtual int getStateDeath() {
788         if (state == STATE_DEATH)
789             return state;
790         int deathAnim = (getEntity().type == TR::Entity::ENEMY_PUMA) ? ANIM_DEATH_PUMA : ANIM_DEATH_LION;
791         return animation.setAnim(deathAnim + rand() % 2);
792     }
793 
updatePositionLion794     virtual void updatePosition() {
795         turn(state == STATE_RUN || state == STATE_WALK || state == STATE_ROAR, state == STATE_RUN ? LION_TURN_FAST : LION_TURN_SLOW);
796 
797         if (state == STATE_DEATH) {
798             animation.overrideMask = 0;
799             return;
800         }
801 
802         Enemy::updatePosition();
803         setOverrides(true, jointChest, jointHead);
804         lookAt(target);
805     }
806 };
807 
808 
809 #define GORILLA_DIST_ATTACK     430
810 #define GORILLA_DIST_AGGRESSION 2048
811 #define GORILLA_TURN_FAST       (DEG2RAD * 150)
812 
813 struct Gorilla : Enemy {
814 
815     enum {
816         HIT_MASK = 0x00FF00,
817     };
818 
819     enum {
820         ANIM_DEATH = 7,
821         ANIM_CLIMB = 19,
822     };
823 
824     enum {
825         STATE_NONE   ,
826         STATE_STOP   ,
827         STATE_UNUSED ,
828         STATE_RUN    ,
829         STATE_ATTACK ,
830         STATE_DEATH  ,
831         STATE_IDLE1  ,
832         STATE_IDLE2  ,
833         STATE_LEFT   ,
834         STATE_RIGHT  ,
835         STATE_JUMP   ,
836         STATE_CLIMB  ,
837     };
838 
839     enum {
840         FLAG_ATTACK = 1,
841         FLAG_LEFT   = 2,
842         FLAG_RIGHT  = 4,
843     };
844 
GorillaGorilla845     Gorilla(IGame *game, int entity) : Enemy(game, entity, 22, 341, 250.0f, 1.0f) {
846         dropHeight = -1024;
847         stepHeight =  1024;
848         jointChest = -1;//7;
849         jointHead  = 14;
850         flags.unused = 0;
851     }
852 
getStateGroundGorilla853     virtual int getStateGround() {
854         if (!think(true))
855             return state;
856 
857         if (nextState == state)
858             nextState = STATE_NONE;
859 
860         if (targetDist < GORILLA_DIST_AGGRESSION)
861             flags.unused |= FLAG_ATTACK;
862 
863         switch (state) {
864             case STATE_STOP    :
865                 if (nextState != STATE_NONE)
866                     return nextState;
867                 if (targetCanAttack && targetDist < GORILLA_DIST_ATTACK)
868                     return STATE_ATTACK;
869                 if (!(flags.unused & FLAG_ATTACK) && zone == target->zone && targetInView) {
870                     int r = rand() % 512;
871                     if (r < 120) return STATE_JUMP;
872                     if (r < 240) return STATE_IDLE1;
873                     if (r < 360) return STATE_IDLE2;
874                     if (r < 480) return STATE_RUN;
875                     return (r % 2) ? STATE_LEFT : STATE_RIGHT;
876                 }
877                 return STATE_RUN;
878             case STATE_RUN      :
879                 if (!flags.unused && targetInView)
880                     return STATE_STOP;
881                 if (targetInView && (collide(target) & HIT_MASK)) {
882                     nextState = STATE_ATTACK;
883                     return STATE_STOP;
884                 }
885                 if (mood != MOOD_ESCAPE) {
886                     int r = rand();
887                     if (r < 160)
888                         nextState = STATE_JUMP;
889                     else if (r < 320)
890                         nextState = STATE_IDLE1;
891                     else if (r < 480)
892                         nextState = STATE_IDLE2;
893                     else
894                         break;
895                     return STATE_STOP;
896                 }
897                 break;
898             case STATE_ATTACK :
899                 if (nextState == STATE_NONE && (collide(target) & HIT_MASK)) {
900                     bite(15, vec3(0.0f, -19.0f, 75.0f), 200.0f);
901                     nextState = STATE_STOP;
902                 }
903                 break;
904             case STATE_LEFT  :
905             case STATE_RIGHT :
906                 return STATE_STOP;
907             default : ;
908         }
909 
910         return state;
911     }
912 
913     virtual void hit(float damage, Controller *enemy = NULL, TR::HitType hitType = TR::HIT_DEFAULT) {
914         Enemy::hit(damage, enemy, hitType);
915         flags.unused |= FLAG_ATTACK;
916     };
917 
getStateDeathGorilla918     virtual int getStateDeath() {
919         if (state == STATE_DEATH)
920             return state;
921         return animation.setAnim(ANIM_DEATH + rand() % 2);
922     }
923 
strafeGorilla924     void strafe(int dir) {
925         switch (state) {
926             case STATE_STOP :
927                 if (flags.unused & FLAG_LEFT)  angle.y += PI * 0.5f;
928                 if (flags.unused & FLAG_RIGHT) angle.y -= PI * 0.5f;
929                 flags.unused &= ~(FLAG_LEFT | FLAG_RIGHT);
930                 break;
931             case STATE_LEFT :
932                 if (!(flags.unused & FLAG_LEFT)) {
933                     flags.unused |= FLAG_LEFT;
934                     angle.y -= PI * 0.5f;
935                 }
936                 break;
937             case STATE_RIGHT :
938                 if (!(flags.unused & FLAG_RIGHT)) {
939                     flags.unused |= FLAG_RIGHT;
940                     angle.y += PI * 0.5f;
941                 }
942                 break;
943             default : ;
944         }
945     }
946 
updateAnimationGorilla947     virtual void updateAnimation(bool commands) {
948         Enemy::updateAnimation(commands);
949 
950         strafe(state);
951 
952         if ((state == STATE_LEFT || state == STATE_RIGHT) && animation.isPrepareToNext && animation.anims[animation.next].state == STATE_STOP)
953             animation.rot = (state == STATE_LEFT ? -PI : PI) * 0.5f;
954     }
955 
updatePositionGorilla956     virtual void updatePosition() {
957         turn(state == STATE_RUN, GORILLA_TURN_FAST);
958 
959         if (state == STATE_DEATH) {
960             animation.overrideMask = 0;
961             return;
962         }
963 
964         vec3 old = pos;
965 
966         TR::Level::FloorInfo infoA, infoB;
967         getFloorInfo(getRoomIndex(), old, infoA);
968         old.y = infoA.floor;
969 
970         Enemy::updatePosition();
971 
972         getFloorInfo(getRoomIndex(), pos, infoB);
973 
974         if (infoB.floor < old.y - 384)
975             climb(old);
976 
977         setOverrides(true, jointChest, jointHead);
978         lookAt(target);
979     }
980 
climbGorilla981     void climb(const vec3 &old) {
982         int ox = int(old.x) / 1024;
983         int oz = int(old.z) / 1024;
984 
985         int cx = int(pos.x) / 1024;
986         int cz = int(pos.z) / 1024;
987 
988         if ((ox == cx) == (oz == cz))
989             return;
990 
991         strafe(STATE_STOP);
992 
993         if (oz == cz) {
994             if (ox < cx) {
995                 pos.x   = float(cx * 1024 - 75);
996                 angle.y = PI * 0.5f;
997             } else {
998                 pos.x   = float(ox * 1024 + 75);
999                 angle.y = -PI * 0.5f;
1000             }
1001         } else {
1002             if (oz < cz) {
1003                 pos.z   = float(cz * 1024 - 75);
1004                 angle.y = 0.0f;
1005             } else {
1006                 pos.z   = float(oz * 1024 + 75);
1007                 angle.y = -PI;
1008             }
1009         }
1010 
1011         pos.y = old.y;
1012         animation.setAnim(ANIM_CLIMB);
1013     }
1014 };
1015 
1016 
1017 #define RAT_TURN_SLOW   (DEG2RAD * 90)
1018 #define RAT_TURN_FAST   (DEG2RAD * 180)
1019 #define RAT_DIST_BITE   341.0f
1020 #define RAT_DIST_ATTACK 1536.0f
1021 #define RAT_WAIT        0.01f
1022 #define RAT_DAMAGE      20
1023 
1024 struct Rat : Enemy {
1025 
1026     enum {
1027         HIT_MASK = 0x0300018F,
1028     };
1029 
1030     enum {
1031         ANIM_DEATH_LAND  = 8,
1032         ANIM_DEATH_WATER = 2,
1033     };
1034 
1035     enum {
1036     // land
1037         STATE_NONE   ,
1038         STATE_STOP   ,
1039         STATE_ATTACK ,
1040         STATE_RUN    ,
1041         STATE_BITE   ,
1042         STATE_DEATH  ,
1043         STATE_WAIT   ,
1044     // water
1045         STATE_WATER_SWIM = 1,
1046         STATE_WATER_BITE    ,
1047         STATE_WATER_DEATH   ,
1048     };
1049 
1050     int modelLand, modelWater;
1051 
RatRat1052     Rat(IGame *game, int entity) : Enemy(game, entity, 5, 204, 200.0f, 0.25f) {
1053         hitSound   = TR::SND_HIT_RAT;
1054         jointChest = 1;
1055         jointHead  = 2;
1056 
1057         modelLand  = level->getModelIndex(TR::Entity::ENEMY_RAT_LAND)  - 1;
1058         modelWater = level->getModelIndex(TR::Entity::ENEMY_RAT_WATER) - 1;
1059     }
1060 
getModelRat1061     const virtual TR::Model* getModel() {
1062         bool water = getRoom().flags.water || modelWater == -1;
1063         stand = water ? STAND_ONWATER : STAND_GROUND;
1064 
1065         int modelIndex = water ? modelWater : modelLand;
1066 
1067         if (modelIndex == -1) {
1068             water = modelWater != -1;
1069             modelIndex = water ? modelWater : modelLand;
1070         }
1071 
1072         ASSERT(modelIndex > -1);
1073         const TR::Model *model = &level->models[modelIndex];
1074         if (animation.model != model) {
1075             targetBox = TR::NO_BOX;
1076             animation.setModel(model);
1077 
1078             int16 rIndex = getRoomIndex();
1079             if (water) {
1080                 TR::Room::Sector *sector = level->getWaterLevelSector(rIndex, pos);
1081                 if (sector) {
1082                     pos.y = float(sector->ceiling * 256);
1083                     roomIndex = rIndex;
1084                 }
1085             } else {
1086                 TR::Room::Sector *sector = level->getSector(rIndex, pos);
1087                 if (sector) {
1088                     pos.y = float(sector->floor * 256);
1089                     roomIndex = rIndex;
1090                 }
1091             }
1092 
1093             nextState = STATE_NONE;
1094             state     = STATE_NONE;
1095 
1096             if (health <= 0.0f) {
1097                 getStateDeath();
1098                 animation.goEnd(false);
1099             }
1100 
1101             updateZone();
1102         }
1103         return animation.model;
1104     }
1105 
getStateGroundRat1106     virtual int getStateGround() {
1107         if (!think(false))
1108             return state;
1109 
1110         if (nextState == state)
1111             nextState = STATE_NONE;
1112 
1113         switch (state) {
1114             case STATE_STOP :
1115                 if (nextState != STATE_NONE)
1116                     return nextState;
1117                 if (targetCanAttack && targetDist < RAT_DIST_BITE)
1118                     return STATE_BITE;
1119                 return STATE_RUN;
1120             case STATE_RUN :
1121                 if (targetInView && (collide(target) & HIT_MASK))
1122                     return STATE_STOP;
1123                 if (targetCanAttack && targetDist < RAT_DIST_ATTACK)
1124                     return STATE_ATTACK;
1125                 if (targetInView && randf() < RAT_WAIT) {
1126                     nextState = STATE_WAIT;
1127                     return STATE_STOP;
1128                 }
1129                 break;
1130             case STATE_ATTACK :
1131             case STATE_BITE   :
1132                 if (nextState == STATE_NONE && targetInView && (collide(target) & HIT_MASK)) {
1133                     bite(3, vec3(0.0f, -11.0f, 108.0f), RAT_DAMAGE);
1134                     nextState = state == STATE_ATTACK ? STATE_RUN : STATE_STOP;
1135                 }
1136                 break;
1137             case STATE_WAIT :
1138                 if (mood == MOOD_SLEEP || randf() < RAT_WAIT)
1139                     return STATE_STOP;
1140             default : ;
1141         }
1142 
1143         return state;
1144     }
1145 
getStateOnwaterRat1146     virtual int getStateOnwater() {
1147         if (!think(false))
1148             return state;
1149 
1150         if (nextState == state)
1151             nextState = STATE_NONE;
1152 
1153         if (animation.frameIndex % 4 == 0)
1154             game->waterDrop(getJoint(jointHead).pos, 96.0f, 0.02f);
1155 
1156         switch (state) {
1157             case STATE_WATER_SWIM :
1158                 if (targetInView && (collide(target) & HIT_MASK))
1159                     return STATE_WATER_BITE;
1160                 break;
1161             case STATE_WATER_BITE :
1162                 if (nextState == STATE_NONE && targetInView && (collide(target) & HIT_MASK)) {
1163                     game->waterDrop(getJoint(jointHead).pos, 256.0f, 0.2f);
1164                     bite(3, vec3(0.0f, -11.0f, 108.0f), RAT_DAMAGE);
1165                     nextState = STATE_WATER_SWIM;
1166                 }
1167                 return STATE_NONE;
1168             default : ;
1169         }
1170 
1171         return state;
1172     }
1173 
updatePositionRat1174     virtual void updatePosition() {
1175         turn((stand == STAND_GROUND && state == STATE_RUN) || (stand == STAND_ONWATER && state == STATE_WATER_SWIM), RAT_TURN_FAST);
1176 
1177         if (state == STATE_DEATH) {
1178             animation.overrideMask = 0;
1179             return;
1180         }
1181 
1182         Enemy::updatePosition();
1183         setOverrides(state != STATE_DEATH, jointChest, jointHead);
1184         lookAt(target);
1185     }
1186 
getStateDeathRat1187     virtual int getStateDeath() {
1188         bool water = getRoom().flags.water;
1189         if ((water && state == STATE_WATER_DEATH) || (!water && state == STATE_DEATH))
1190             return state;
1191         return animation.setAnim(water ? ANIM_DEATH_WATER : ANIM_DEATH_LAND);
1192     }
1193 };
1194 
1195 
1196 #define CROCODILE_TURN_SLOW   (DEG2RAD * 90)
1197 #define CROCODILE_TURN_FAST   (DEG2RAD * 180)
1198 #define CROCODILE_DIST_BITE   435.0f
1199 #define CROCODILE_DIST_TURN   (1024 * 3)
1200 #define CROCODILE_LIFT_SPEED  960.0f
1201 #define CROCODILE_DAMAGE      25
1202 
1203 struct Crocodile : Enemy {
1204 
1205     enum {
1206         HIT_MASK = 0x000003FC,
1207     };
1208 
1209     enum {
1210         ANIM_DEATH_LAND  = 11,
1211         ANIM_DEATH_WATER = 4,
1212     };
1213 
1214     enum {
1215     // land
1216         STATE_NONE   ,
1217         STATE_STOP   ,
1218         STATE_RUN    ,
1219         STATE_WALK   ,
1220         STATE_TURN   ,
1221         STATE_BITE   ,
1222         STATE_UNUSED ,
1223         STATE_DEATH  ,
1224     // water
1225         STATE_WATER_SWIM = 1,
1226         STATE_WATER_BITE    ,
1227         STATE_WATER_DEATH   ,
1228     };
1229 
1230     int modelLand, modelWater;
1231 
CrocodileCrocodile1232     Crocodile(IGame *game, int entity) : Enemy(game, entity, 20, 341, 600.0f, 0.25f) {
1233         jointChest = 1;
1234         jointHead  = 8;
1235 
1236         modelLand  = level->getModelIndex(TR::Entity::ENEMY_CROCODILE_LAND)  - 1;
1237         modelWater = level->getModelIndex(TR::Entity::ENEMY_CROCODILE_WATER) - 1;
1238 
1239         bool water = getRoom().flags.water || modelWater == -1;
1240         flying     = water;
1241         stand      = water ? STAND_UNDERWATER : STAND_GROUND;
1242     }
1243 
getModelCrocodile1244     const virtual TR::Model* getModel() {
1245         bool water = getRoom().flags.water || modelWater == -1;
1246         stand  = water ? STAND_UNDERWATER : STAND_GROUND;
1247 
1248         int modelIndex = water ? modelWater : modelLand;
1249 
1250         if (modelIndex == -1) {
1251             water = modelWater != -1;
1252             modelIndex = water ? modelWater : modelLand;
1253         }
1254 
1255         ASSERT(modelIndex > -1);
1256         const TR::Model *model = &level->models[modelIndex];
1257         if (animation.model != model) {
1258             targetBox = TR::NO_BOX;
1259             animation.setModel(model);
1260             flying = water;
1261 
1262             int16 rIndex = getRoomIndex();
1263             if (water) {
1264                 TR::Room::Sector *sector = level->getWaterLevelSector(rIndex, pos);
1265                 if (sector) {
1266                     pos.y = float(sector->ceiling * 256);
1267                     roomIndex = rIndex;
1268                 }
1269             } else {
1270                 TR::Room::Sector *sector = level->getSector(rIndex, pos);
1271                 if (sector) {
1272                     pos.y = float(sector->floor * 256);
1273                     roomIndex = rIndex;
1274                 }
1275             }
1276 
1277             nextState = STATE_NONE;
1278             state     = STATE_NONE;
1279 
1280             if (health <= 0.0f) {
1281                 getStateDeath();
1282                 animation.goEnd(false);
1283             }
1284 
1285             updateZone();
1286         }
1287         return animation.model;
1288     }
1289 
getStateGroundCrocodile1290     virtual int getStateGround() {
1291         if (!think(true))
1292             return state;
1293 
1294         if (nextState == state)
1295             nextState = STATE_NONE;
1296 
1297         switch (state) {
1298             case STATE_STOP :
1299                 if (targetCanAttack && targetDist < CROCODILE_DIST_BITE)
1300                     return STATE_BITE;
1301                 switch (mood) {
1302                     case MOOD_ESCAPE : return STATE_RUN;
1303                     case MOOD_ATTACK : return (targetInView || targetDist < CROCODILE_DIST_TURN) ? STATE_RUN : STATE_TURN;
1304                     case MOOD_STALK  : return STATE_WALK;
1305                     default          : return state;
1306                 }
1307             case STATE_RUN  :
1308                 if (targetInView && (collide(target) & HIT_MASK))
1309                     return STATE_STOP;
1310                 switch (mood) {
1311                     case MOOD_SLEEP  : return STATE_STOP;
1312                     case MOOD_STALK  : return STATE_WALK;
1313                     case MOOD_ATTACK : if (targetDist > CROCODILE_DIST_TURN && !targetInView) return STATE_STOP;
1314                     default          : return state;
1315                 }
1316             case STATE_WALK :
1317                 if (targetInView && (collide(target) & HIT_MASK))
1318                     return STATE_STOP;
1319                 switch (mood) {
1320                     case MOOD_SLEEP  : return STATE_STOP;
1321                     case MOOD_ATTACK :
1322                     case MOOD_ESCAPE : return STATE_RUN;
1323                     default          : return state;
1324                 }
1325             case STATE_TURN :
1326                 return targetInView ? STATE_WALK : state;
1327             case STATE_BITE   :
1328                 if (nextState == STATE_NONE) {
1329                     bite(9, vec3(5.0f, -21.0f, 467.0f), CROCODILE_DAMAGE);
1330                     nextState = STATE_STOP;
1331                 }
1332                 break;
1333             default : ;
1334         }
1335 
1336         return state;
1337     }
1338 
getStateUnderwaterCrocodile1339     virtual int getStateUnderwater() {
1340         if (!think(false))
1341             return state;
1342 
1343         if (nextState == state)
1344             nextState = STATE_NONE;
1345 
1346         if (animation.frameIndex % 4 == 0)
1347             game->waterDrop(getJoint(jointHead).pos, 96.0f, 0.02f);
1348 
1349         switch (state) {
1350             case STATE_WATER_SWIM :
1351                 if (targetInView && collide(target))
1352                     return STATE_WATER_BITE;
1353                 break;
1354             case STATE_WATER_BITE :
1355                 if (collide(target)) {
1356                     if (nextState != STATE_NONE)
1357                         return state;
1358                     bite(9, vec3(5.0f, -21.0f, 467.0f), CROCODILE_DAMAGE);
1359                     nextState = STATE_WATER_SWIM;
1360                 }
1361                 return STATE_WATER_SWIM;
1362             default : ;
1363         }
1364 
1365         return state;
1366     }
1367 
updatePositionCrocodile1368     virtual void updatePosition() {
1369         if (state == STATE_TURN)
1370             angle.y += CROCODILE_TURN_FAST * Core::deltaTime;
1371         else
1372             turn((stand == STAND_GROUND && (state == STATE_RUN || state == STATE_WALK)) || (stand == STAND_UNDERWATER && state == STATE_WATER_SWIM), CROCODILE_TURN_FAST);
1373         angle.z = 0.0f;
1374 
1375         if (state == STATE_DEATH) {
1376             animation.overrideMask = 0;
1377             return;
1378         }
1379 
1380         if (flying) {
1381             lift(waypoint.y - pos.y, CROCODILE_LIFT_SPEED);
1382             int16 rIndex = getRoomIndex();
1383             TR::Room::Sector *sector = level->getWaterLevelSector(rIndex, pos);
1384             if (sector) {
1385                 float waterLevel = float(sector->ceiling * 256) + 256;
1386                 if (pos.y < waterLevel)
1387                     pos.y = waterLevel;
1388             }
1389         }
1390 
1391         Enemy::updatePosition();
1392         setOverrides(state != STATE_DEATH, jointChest, jointHead);
1393         lookAt(target);
1394     }
1395 
getStateDeathCrocodile1396     virtual int getStateDeath() {
1397         bool water = getRoom().flags.water;
1398         if ((water && state == STATE_WATER_DEATH) || (!water && state == STATE_DEATH))
1399             return state;
1400         return animation.setAnim(water ? ANIM_DEATH_WATER : ANIM_DEATH_LAND);
1401     }
1402 };
1403 
1404 
1405 #define BEAR_DIST_EAT    768
1406 #define BEAR_DIST_HOWL   2048
1407 #define BEAR_DIST_BITE   1024
1408 #define BEAR_DIST_ATTACK 600
1409 
1410 #define BEAR_TURN_FAST   (DEG2RAD * 150)
1411 #define BEAR_TURN_SLOW   (DEG2RAD * 60)
1412 
1413 struct Bear : Enemy {
1414 
1415     enum {
1416         HIT_MASK = 0x2406C, // front legs and head
1417     };
1418 
1419     enum {
1420         ANIM_DEATH_HIND = 19,
1421         ANIM_DEATH      = 20,
1422     };
1423 
1424     enum {
1425         STATE_NONE   = -1,
1426         STATE_WALK   ,
1427         STATE_STOP   ,
1428         STATE_HIND   ,
1429         STATE_RUN    ,
1430         STATE_HOWL   ,
1431         STATE_GROWL  ,
1432         STATE_BITE   ,
1433         STATE_ATTACK ,
1434         STATE_EAT    ,
1435         STATE_DEATH  ,
1436     };
1437 
BearBear1438     Bear(IGame *game, int entity) : Enemy(game, entity, 20, 341, 500.0f, 0.5f) {
1439         jointChest = 13;
1440         jointHead  = 14;
1441         hitSound   = TR::SND_HIT_BEAR;
1442         nextState  = STATE_NONE;
1443     }
1444 
getStateGroundBear1445     virtual int getStateGround() {
1446         if (!flags.active)
1447             return state;
1448 
1449         if (!think(true))
1450             return state;
1451 
1452         if (nextState == state)
1453             nextState = STATE_NONE;
1454 
1455         switch (state) {
1456             case STATE_WALK     :
1457                 if (nextState != STATE_NONE) return STATE_STOP;
1458                 if (targetDead && targetInView && (collide(target) & HIT_MASK))
1459                     return nextState = STATE_STOP; // eat lara! >:E
1460                 if (mood != MOOD_SLEEP) {
1461                     if (mood == MOOD_ESCAPE)
1462                         nextState = STATE_NONE;
1463                     return STATE_STOP;
1464                 } else if (randf() < 0.003f) {
1465                     nextState = STATE_GROWL;
1466                     return STATE_STOP;
1467                 }
1468                 break;
1469             case STATE_STOP     :
1470                 if (targetDead)
1471                     return (targetDist < BEAR_DIST_EAT && targetCanAttack) ? STATE_EAT : STATE_WALK;
1472                 else
1473                     return nextState != STATE_NONE ? nextState : (mood == MOOD_SLEEP ? STATE_WALK : STATE_RUN);
1474             case STATE_HIND     :
1475                 if (wound) {
1476                     nextState = STATE_NONE;
1477                     return STATE_HOWL;
1478                 }
1479 
1480                 if (targetInView && (collide(target) & HIT_MASK)) return STATE_HOWL;
1481 
1482                 if (mood == MOOD_ESCAPE)
1483                     nextState = STATE_NONE;
1484                 else if (mood == MOOD_SLEEP || randf() < 0.003f)
1485                     nextState = STATE_GROWL;
1486                 else if (targetDist > BEAR_DIST_HOWL || randf() < 0.05f)
1487                     nextState = STATE_STOP;
1488 
1489                 return STATE_HOWL;
1490                 break;
1491             case STATE_RUN      :
1492                 if (collide(target) & HIT_MASK)
1493                     target->hit(3, this);
1494                 if (targetDead || mood == MOOD_SLEEP)
1495                     return STATE_STOP;
1496                 if (nextState != STATE_NONE) return STATE_STOP;
1497                 if (targetInView) {
1498                     if (!wound && targetDist < BEAR_DIST_HOWL && randf() < 0.025f) {
1499                         nextState = STATE_HOWL;
1500                         return STATE_STOP;
1501                     }
1502                     if (targetDist < BEAR_DIST_BITE) return STATE_BITE;
1503                 }
1504                 break;
1505             case STATE_HOWL     :
1506                 if (wound) {
1507                     nextState = STATE_NONE;
1508                     return STATE_STOP;
1509                 }
1510                 if (nextState != STATE_NONE) return nextState;
1511                 if (mood == MOOD_SLEEP || mood == MOOD_ESCAPE) return STATE_STOP;
1512                 if (targetDist < BEAR_DIST_ATTACK) return STATE_ATTACK;
1513                 return STATE_HIND;
1514             case STATE_BITE     :
1515             case STATE_ATTACK   :
1516                 if (nextState == STATE_NONE && (collide(target) & HIT_MASK)) {
1517                     bite(14, vec3(0.0f, 96.0f, 335.0f), state == STATE_BITE ? 200.0f : 400.0f);
1518                     nextState = state == STATE_BITE ? STATE_STOP : STATE_HOWL;
1519                 }
1520                 break;
1521         }
1522 
1523         return state;
1524     }
1525 
getStateDeathBear1526     virtual int getStateDeath() {
1527         switch (state) {
1528             case STATE_HIND : return STATE_HOWL;
1529             case STATE_RUN  :
1530             case STATE_WALK : return STATE_STOP;
1531             case STATE_HOWL :
1532             case STATE_STOP : return STATE_DEATH;
1533         }
1534         return state;// == STATE_DEATH ? state : animation.setAnim(ANIM_DEATH);
1535     }
1536 
updatePositionBear1537     virtual void updatePosition() {
1538         turn(state == STATE_RUN || state == STATE_WALK || state == STATE_HIND, state == STATE_RUN ? BEAR_TURN_FAST : BEAR_TURN_SLOW);
1539 
1540         if (state == STATE_DEATH) {
1541             animation.overrideMask = 0;
1542             return;
1543         }
1544 
1545         Enemy::updatePosition();
1546         setOverrides(state == STATE_RUN || state == STATE_WALK || state == STATE_HIND, jointChest, jointHead);
1547         lookAt(target);
1548     }
1549 };
1550 
1551 
1552 #define BAT_TURN_SPEED  (DEG2RAD * 300)
1553 #define BAT_LIFT_SPEED  512.0f
1554 
1555 struct Bat : Enemy {
1556 
1557     enum {
1558         ANIM_DEATH = 4,
1559     };
1560 
1561     enum {
1562         STATE_NONE,
1563         STATE_AWAKE,
1564         STATE_FLY,
1565         STATE_ATTACK,
1566         STATE_CIRCLING,
1567         STATE_DEATH,
1568     };
1569 
BatBat1570     Bat(IGame *game, int entity) : Enemy(game, entity, 1, 102, 0.0f, 0.03f) {
1571         stand = STAND_AIR;
1572         stepHeight =  20 * 1024;
1573         dropHeight = -20 * 1024;
1574         jointHead  = 4;
1575     }
1576 
getStateAirBat1577     virtual int getStateAir() {
1578         if (!flags.active) {
1579             animation.time = 0.0f;
1580             animation.dir  = 0.0f;
1581             return STATE_AWAKE;
1582         }
1583 
1584         if (!think(false))
1585             return state;
1586 
1587         switch (state) {
1588             case STATE_AWAKE  : return STATE_FLY;
1589             case STATE_ATTACK :
1590                 if (!collide(target)) {
1591                     mood = MOOD_SLEEP;
1592                     return STATE_FLY;
1593                 } else
1594                     bite(4, vec3(0.0f, 16.0f, 45.0f), 2);
1595                 break;
1596             case STATE_FLY    :
1597                 if (collide(target)) {
1598                     mood = MOOD_ATTACK;
1599                     return STATE_ATTACK;
1600                 }
1601                 break;
1602         }
1603 
1604         return state;
1605     }
1606 
getStateDeathBat1607     virtual int getStateDeath() {
1608         return state == STATE_DEATH ? state : animation.setAnim(ANIM_DEATH);
1609     }
1610 
updatePositionBat1611     virtual void updatePosition() {
1612         turn(state == STATE_FLY || state == STATE_ATTACK, BAT_TURN_SPEED);
1613 
1614         if (flying) {
1615             float wy = waypoint.y - (target->stand != STAND_ONWATER ? 765.0f : 64.0f);
1616             lift(wy - pos.y, BAT_LIFT_SPEED);
1617         }
1618         Enemy::updatePosition();
1619     }
1620 
1621     virtual void deactivate(bool removeFromList = false) {
1622         if (health <= 0.0f) {
1623             TR::Level::FloorInfo info;
1624             getFloorInfo(getRoomIndex(), pos, info);
1625             if (info.floor > pos.y)
1626                 return;
1627             pos.y = info.floor;
1628         }
1629         Enemy::deactivate(removeFromList);
1630     }
1631 };
1632 
1633 
1634 #define REX_DIST_BITE       1500
1635 #define REX_DIST_BITE_MAX   4096
1636 #define REX_DIST_WALK       5120
1637 #define REX_TURN_FAST       (DEG2RAD * 120)
1638 #define REX_TURN_SLOW       (DEG2RAD * 60)
1639 #define REX_DAMAGE          1000
1640 #define REX_DAMAGE_WALK     1
1641 #define REX_DAMAGE_RUN      10
1642 
1643 struct Rex : Enemy {
1644 
1645     enum {
1646         HIT_MASK = (1 << 12) | (1 << 13),  // head
1647     };
1648 
1649     enum {
1650         STATE_NONE,
1651         STATE_STOP,
1652         STATE_WALK,
1653         STATE_RUN,
1654         STATE_UNUSED,
1655         STATE_DEATH,
1656         STATE_BAWL,
1657         STATE_BITE,
1658         STATE_FATAL,
1659     };
1660 
RexRex1661     Rex(IGame *game, int entity) : Enemy(game, entity, 100, 341, 2000.0f, 1.0f) {
1662         jointChest = 10;
1663         jointHead  = 12;
1664         nextState  = STATE_NONE;
1665     }
1666 
getStateGroundRex1667     virtual int getStateGround() {
1668         if (!flags.active)
1669             return state;
1670 
1671         if (!think(true))
1672             return state;
1673 
1674         if (nextState == state)
1675             nextState = STATE_NONE;
1676 
1677         if (targetDead) {
1678             return (state == STATE_STOP || state == STATE_WALK) ? STATE_WALK : STATE_STOP;
1679             if (state != STATE_STOP) return STATE_STOP;
1680             return STATE_WALK;
1681         }
1682 
1683         int mask = collide(target);
1684 
1685         // if Lara is behind and watching Rex we need to rotate
1686         bool walk = targetFromView && !targetInView && mood != MOOD_ESCAPE;
1687         if (!walk && targetCanAttack && targetDist > REX_DIST_BITE && targetDist < REX_DIST_BITE_MAX)
1688             walk = true;
1689 
1690         switch (state) {
1691             case STATE_STOP :
1692                 if (nextState != STATE_NONE)                        return nextState;
1693                 if (targetCanAttack && targetDist < REX_DIST_BITE)  return STATE_BITE;
1694                 if (mood == MOOD_SLEEP || walk)                     return STATE_WALK;
1695                 return STATE_RUN;
1696             case STATE_WALK :
1697                 if (mask) target->hit(REX_DAMAGE_WALK, this);
1698                 if (mood != MOOD_SLEEP && !walk)    return STATE_STOP;
1699                 if (targetInView && randf() < 0.015f) {
1700                     nextState = STATE_BAWL;
1701                     return STATE_STOP;
1702                 }
1703                 break;
1704             case STATE_RUN :
1705                 if (mask) target->hit(REX_DAMAGE_RUN, this);
1706                 if ((targetCanAttack && targetDist < REX_DIST_WALK) || walk)
1707                     return STATE_STOP;
1708                 if (targetInView && mood != MOOD_ESCAPE && randf() < 0.015f) {
1709                     nextState = STATE_BAWL;
1710                     return STATE_STOP;
1711                 }
1712                 if (mood == MOOD_SLEEP)
1713                     return STATE_STOP;
1714                 break;
1715             case STATE_BITE :
1716                 if (mask & HIT_MASK) {
1717                     target->hit(REX_DAMAGE, this, TR::HIT_REX);
1718                     return STATE_FATAL;
1719                 }
1720                 nextState = STATE_WALK;
1721                 break;
1722         }
1723 
1724         return state;
1725     }
1726 
getStateDeathRex1727     virtual int getStateDeath() {
1728         return state == STATE_STOP ? STATE_DEATH : STATE_STOP;
1729     }
1730 
updatePositionRex1731     virtual void updatePosition() {
1732         if (state == STATE_DEATH) {
1733             animation.overrideMask = 0;
1734             angle.z = 0.0f;
1735             return;
1736         }
1737 
1738         turn(state == STATE_RUN || state == STATE_WALK, state == STATE_RUN ? REX_TURN_FAST : REX_TURN_SLOW);
1739 
1740         Enemy::updatePosition();
1741         setOverrides(true, jointChest, jointHead);
1742         lookAt(target);
1743     }
1744 };
1745 
1746 #define RAPTOR_DIST_BITE        680
1747 #define RAPTOR_DIST_ATTACK      (1024 + 512)
1748 
1749 #define RAPTOR_TURN_FAST        (DEG2RAD * 120)
1750 #define RAPTOR_TURN_SLOW        (DEG2RAD * 30)
1751 
1752 struct Raptor : Enemy {
1753 
1754     enum {
1755         HIT_MASK = 0xFF7C00,  // hands and head
1756     };
1757 
1758     enum {
1759         ANIM_DEATH_1 = 9,
1760         ANIM_DEATH_2 = 10,
1761     };
1762 
1763     enum {
1764         STATE_NONE = -1,
1765         STATE_DEATH,
1766         STATE_STOP,
1767         STATE_WALK,
1768         STATE_RUN,
1769         STATE_ATTACK_1,
1770         STATE_UNUSED,
1771         STATE_BAWL,
1772         STATE_ATTACK_2,
1773         STATE_BITE,
1774     };
1775 
RaptorRaptor1776     Raptor(IGame *game, int entity) : Enemy(game, entity, 20, 341, 400.0f, 0.5f) {
1777         jointChest = -1;
1778         jointHead  = 21;
1779         nextState  = STATE_NONE;
1780     }
1781 
getStateGroundRaptor1782     virtual int getStateGround() {
1783         if (!flags.active)
1784             return state;
1785 
1786         if (!think(true))
1787             return state;
1788 
1789         if (nextState == state)
1790             nextState = STATE_NONE;
1791 
1792         if (targetDead) {
1793             return (state == STATE_STOP || state == STATE_WALK) ? STATE_WALK : STATE_STOP;
1794             if (state != STATE_STOP) return STATE_STOP;
1795             return STATE_WALK;
1796         }
1797 
1798         int mask = collide(target);
1799 
1800         switch (state) {
1801             case STATE_STOP :
1802                 if (nextState != STATE_NONE) return nextState;
1803                 if ((mask & HIT_MASK) || (targetCanAttack && targetDist < RAPTOR_DIST_BITE)) return STATE_BITE;
1804                 if (targetCanAttack && targetDist < RAPTOR_DIST_ATTACK) return STATE_ATTACK_1;
1805                 if (mood == MOOD_SLEEP) return STATE_WALK;
1806                 return STATE_RUN;
1807             case STATE_WALK :
1808                 if (nextState != STATE_NONE) return STATE_STOP;
1809                 if (mood != MOOD_SLEEP) return STATE_STOP;
1810                 if (targetInView && randf() < 0.01f) {
1811                     nextState = STATE_BAWL;
1812                     return STATE_STOP;
1813                 }
1814                 break;
1815             case STATE_RUN :
1816                 if (nextState != STATE_NONE) return STATE_STOP;
1817                 if (mask & HIT_MASK) return STATE_STOP;
1818                 if (targetCanAttack && targetDist < RAPTOR_DIST_ATTACK)
1819                     return (randf() < 0.25) ? STATE_STOP : STATE_ATTACK_2;
1820                 if (mood == MOOD_ESCAPE && targetInView) {
1821                     nextState = STATE_BAWL;
1822                     return STATE_STOP;
1823                 }
1824                 if (mood == MOOD_SLEEP)
1825                     return STATE_STOP;
1826                 break;
1827             case STATE_ATTACK_1 :
1828             case STATE_ATTACK_2 :
1829             case STATE_BITE     :
1830                 if (nextState == STATE_NONE && targetInView && (mask & HIT_MASK)) {
1831                     bite(22, vec3(0.0f, 66.0f, 318.0f), 100);
1832                     nextState = state == STATE_ATTACK_2 ? STATE_RUN : STATE_STOP;
1833                 }
1834                 break;
1835         }
1836 
1837         return state;
1838     }
1839 
getStateDeathRaptor1840     virtual int getStateDeath() {
1841         if (state == STATE_DEATH) return state;
1842         return animation.setAnim((rand() % 2) ? ANIM_DEATH_1 : ANIM_DEATH_2);
1843     }
1844 
updatePositionRaptor1845     virtual void updatePosition() {
1846         if (state == STATE_DEATH) {
1847             animation.overrideMask = 0;
1848             angle.z = 0.0f;
1849             return;
1850         }
1851 
1852         turn(state == STATE_RUN || state == STATE_WALK, state == STATE_RUN ? RAPTOR_TURN_FAST : RAPTOR_TURN_SLOW);
1853 
1854         Enemy::updatePosition();
1855         setOverrides(true, jointChest, jointHead);
1856         lookAt(target);
1857     }
1858 };
1859 
1860 
1861 #define MUTANT_TURN_FAST        (DEG2RAD * 180)
1862 #define MUTANT_TURN_SLOW        (DEG2RAD * 60)
1863 #define MUTANT_LIFT_SPEED       512.0f
1864 #define MUTANT_DIST_ATTACK_1    600
1865 #define MUTANT_DIST_ATTACK_2    (2048 + 512)
1866 #define MUTANT_DIST_ATTACK_3    300
1867 #define MUTANT_DIST_SHOT        3840
1868 #define MUTANT_DIST_STALK       (4096 + 512)
1869 #define MUTANT_PART_DAMAGE      100
1870 
1871 struct Mutant : Enemy {
1872 
1873     enum {
1874         HIT_MASK = 0x0678,
1875     };
1876 
1877     enum {
1878         STATE_NONE,
1879         STATE_STOP,
1880         STATE_WALK,
1881         STATE_RUN,
1882         STATE_ATTACK_1,
1883         STATE_DEATH,
1884         STATE_LOOKING,
1885         STATE_ATTACK_2,
1886         STATE_ATTACK_3,
1887         STATE_AIM_1,
1888         STATE_AIM_2,
1889         STATE_FIRE,
1890         STATE_IDLE,
1891         STATE_FLY,
1892     };
1893 
1894     enum {
1895         FLAG_FLY      = 1,
1896         FLAG_BULLET_1 = 2,
1897         FLAG_BULLET_2 = 4,
1898     };
1899 
MutantMutant1900     Mutant(IGame *game, int entity) : Enemy(game, entity, 50, 341, 150.0f, 1.0f) {
1901         if (getEntity().type != TR::Entity::ENEMY_MUTANT_1) {
1902             initMeshOverrides();
1903             layers[0].mask = 0xffe07fff;
1904             aggression     = 0.25f;
1905         }
1906 
1907         flags.unused = 0;
1908         jointChest   = 1;
1909         jointHead    = 2;
1910     }
1911 
setSaveDataMutant1912     virtual void setSaveData(const SaveEntity &data) {
1913         Enemy::setSaveData(data);
1914         if (flags.invisible)
1915             deactivate(true);
1916     }
1917 
updateMutant1918     virtual void update() {
1919         bool exploded = explodeMask != 0;
1920 
1921         if (health <= 0.0f && !exploded) {
1922             game->playSound(TR::SND_MUTANT_DEATH, pos, Sound::PAN);
1923             explode(0xffffffff, MUTANT_PART_DAMAGE);
1924         }
1925 
1926         Enemy::update();
1927 
1928         if (exploded && !explodeMask) {
1929             deactivate(true);
1930             flags.invisible = true;
1931         }
1932     }
1933 
getStateGroundMutant1934     virtual int getStateGround() {
1935         if (state == STATE_FLY) {
1936             stand  = STAND_AIR;
1937             flying = true;
1938             updateZone();
1939             return getStateAir();
1940         }
1941 
1942         stepHeight = 256;
1943         dropHeight = -stepHeight;
1944 
1945         if (!think(true))
1946             return state;
1947 
1948         if (nextState == state)
1949             nextState = STATE_NONE;
1950 
1951         if (getEntity().type != TR::Entity::ENEMY_MUTANT_3) {
1952             if (flags.unused & (FLAG_BULLET_1 | FLAG_BULLET_2)) {
1953                 if (targetAngle > PI * 0.25f)
1954                     flags.unused &= ~(FLAG_BULLET_1 | FLAG_BULLET_2);
1955             } else {
1956                 if (targetAngle < PI * 0.25f && state != STATE_FIRE && (targetDist > MUTANT_DIST_SHOT || zone != target->zone) && targetIsVisible(MAX_SHOT_DIST))
1957                     flags.unused |= (rand() % 2) ? FLAG_BULLET_1 : FLAG_BULLET_2;
1958             }
1959         }
1960 
1961         if (getEntity().type == TR::Entity::ENEMY_MUTANT_1) { // flying mutant
1962             if (mood == MOOD_ESCAPE || (zone != target->zone && !(flags.unused & (FLAG_BULLET_1 | FLAG_BULLET_2)))) {
1963                 flags.unused |= FLAG_FLY;
1964             }
1965         }
1966 
1967         int mask = collide(target);
1968 
1969         switch (state) {
1970             case STATE_STOP :
1971                 if (flags.unused & FLAG_FLY)
1972                     return STATE_FLY;
1973                 if ((targetCanAttack && targetDist < MUTANT_DIST_ATTACK_3) || (mask & HIT_MASK))
1974                     return STATE_ATTACK_3;
1975                 if ((targetCanAttack && targetDist < MUTANT_DIST_ATTACK_1))
1976                     return STATE_ATTACK_1;
1977                 if (flags.unused & FLAG_BULLET_1)
1978                     return STATE_AIM_1;
1979                 if (flags.unused & FLAG_BULLET_2)
1980                     return STATE_AIM_2;
1981                 if (mood == MOOD_SLEEP || (mood == MOOD_STALK && targetDist < MUTANT_DIST_STALK))
1982                     return STATE_LOOKING;
1983                 return STATE_RUN;
1984             case STATE_WALK :
1985                 if (flags.unused)
1986                     return STATE_STOP;
1987                 if (mood == MOOD_ATTACK || mood == MOOD_ESCAPE)
1988                     return STATE_STOP;
1989                 if (mood == MOOD_SLEEP || (mood == MOOD_STALK && target->zone != zone)) {
1990                     if (rand() < 50)
1991                         return STATE_LOOKING;
1992                 } else if (mood == MOOD_STALK && targetDist > MUTANT_DIST_STALK)
1993                     return STATE_STOP;
1994                 break;
1995             case STATE_RUN :
1996                 if (flags.unused & FLAG_FLY)
1997                     return STATE_STOP;
1998                 if (mask & HIT_MASK)
1999                     return STATE_STOP;
2000                 if (targetCanAttack && targetDist < MUTANT_DIST_ATTACK_1)
2001                     return STATE_STOP;
2002                 if (targetInView && targetDist < MUTANT_DIST_ATTACK_2)
2003                     return STATE_ATTACK_2;
2004                 if (flags.unused & (FLAG_BULLET_1 | FLAG_BULLET_2))
2005                     return STATE_STOP;
2006                 if (mood == MOOD_SLEEP || (mood == MOOD_STALK && targetDist < MUTANT_DIST_STALK))
2007                     return STATE_STOP;
2008                 break;
2009             case STATE_LOOKING :
2010                 if (flags.unused)
2011                     return STATE_STOP;
2012                 switch (mood) {
2013                     case MOOD_SLEEP :
2014                         if (rand() < 256)
2015                             return STATE_WALK;
2016                         break;
2017                     case MOOD_STALK :
2018                         if (targetDist < MUTANT_DIST_STALK) {
2019                             if (target->zone == zone && rand() < 256)
2020                                 return STATE_WALK;
2021                         } else
2022                             return STATE_STOP;
2023                         break;
2024                     case MOOD_ATTACK :
2025                     case MOOD_ESCAPE :
2026                         return STATE_STOP;
2027                 }
2028             case STATE_ATTACK_1 :
2029             case STATE_ATTACK_2 :
2030             case STATE_ATTACK_3 :
2031                 if (nextState == STATE_NONE && (mask & HIT_MASK)) {
2032                     float damage = state == STATE_ATTACK_1 ? 150.0f : (state == STATE_ATTACK_2 ? 100.0f : 200.0f);
2033                     bite(10, vec3(-27.0f, 98.0f, 0.0f), damage);
2034                     nextState = STATE_STOP;
2035                 }
2036                 break;
2037             case STATE_AIM_1 :
2038                 return (flags.unused & FLAG_BULLET_1) ? STATE_FIRE : STATE_STOP;
2039             case STATE_AIM_2 :
2040                 return (flags.unused & FLAG_BULLET_2) ? STATE_FIRE : STATE_STOP;
2041             case STATE_FIRE :
2042                 if (flags.unused & FLAG_BULLET_1)
2043                     shot(TR::Entity::MUTANT_BULLET, 9, vec3(-35.0f, 269.0f, 0.0f));
2044                 if (flags.unused & FLAG_BULLET_2)
2045                     shot(TR::Entity::CENTAUR_BULLET, 14, vec3(51.0f, 213.0f, 0.0f));
2046                 flags.unused &= ~(FLAG_BULLET_1 | FLAG_BULLET_2);
2047                 break;
2048             case STATE_IDLE :
2049                 return STATE_STOP;
2050             default : ;
2051         }
2052 
2053         return state;
2054     }
2055 
getStateAirMutant2056     virtual int getStateAir() {
2057         if (state != STATE_FLY) {
2058             stand  = STAND_GROUND;
2059             flying = false;
2060             updateZone();
2061             return getStateGround();
2062         }
2063 
2064         stepHeight = 30 * 1024;
2065         dropHeight = -stepHeight;
2066 
2067         if (!think(true))
2068             return state;
2069 
2070         if ((flags.unused & FLAG_FLY) && mood != MOOD_ESCAPE && zone == target->zone)
2071             flags.unused &= ~FLAG_FLY;
2072 
2073         if (!(flags.unused & FLAG_FLY)) {
2074             int16 roomIndex = getRoomIndex();
2075             TR::Room::Sector *sector = level->getSector(roomIndex, pos);
2076             float floor = level->getFloor(sector, pos) - 128.0f;
2077             if (pos.y >= floor)
2078                 return STATE_STOP;
2079         }
2080 
2081         return STATE_FLY;
2082     }
2083 
updatePositionMutant2084     virtual void updatePosition() {
2085         turn(state == STATE_RUN || state == STATE_WALK || state == STATE_FLY, (state == STATE_RUN || state == STATE_FLY) ? MUTANT_TURN_FAST : MUTANT_TURN_SLOW);
2086 
2087         if (flying)
2088             lift(target->pos.y - pos.y, MUTANT_LIFT_SPEED);
2089 
2090         Enemy::updatePosition();
2091         setOverrides(true, jointChest, jointHead);
2092         lookAt(target);
2093     }
2094 };
2095 
2096 #define GIANT_MUTANT_TURN_SLOW    (DEG2RAD * 90)
2097 #define GIANT_MUTANT_MIN_ANGLE    (DEG2RAD * 10)
2098 #define GIANT_MUTANT_MAX_ANGLE    (DEG2RAD * 45)
2099 #define GIANT_MUTANT_DAMAGE       500
2100 #define GIANT_MUTANT_DAMAGE_WALK  5
2101 #define GIANT_MUTANT_DAMAGE_FATAL 1000
2102 #define GIANT_MUTANT_DIST_ATTACK  2600
2103 #define GIANT_MUTANT_DIST_FATAL   2250
2104 #define GIANT_MUTANT_PART_DAMAGE  250
2105 
2106 struct GiantMutant : Enemy {
2107 
2108     enum {
2109         HIT_MASK_HAND  = 0x3FF8000,
2110         HIT_MASK_HANDS = 0x3FFFFF0,
2111     };
2112 
2113     enum {
2114         ANIM_DEATH = 13,
2115     };
2116 
2117     enum {
2118         STATE_NONE,
2119         STATE_STOP,
2120         STATE_TURN_LEFT,
2121         STATE_TURN_RIGHT,
2122         STATE_ATTACK_1,
2123         STATE_ATTACK_2,
2124         STATE_ATTACK_3,
2125         STATE_WALK,
2126         STATE_BORN,
2127         STATE_FALL,
2128         STATE_UNUSED,
2129         STATE_FATAL,
2130     };
2131 
GiantMutantGiantMutant2132     GiantMutant(IGame *game, int entity) : Enemy(game, entity, 500, 341, 375.0f, 1.0f) {
2133         hitSound   = TR::SND_HIT_MUTANT;
2134         stand      = STAND_AIR;
2135         jointChest = -1;
2136         jointHead  = -1; // 3; TODO: fix head orientation
2137         rangeHead  = vec4(-0.5f, 0.5f, -0.5f, 0.5f) * PI;
2138         invertAim  = true;
2139     }
2140 
setSaveDataGiantMutant2141     virtual void setSaveData(const SaveEntity &data) {
2142         Enemy::setSaveData(data);
2143         if (flags.invisible)
2144             deactivate(true);
2145     }
2146 
updateGiantMutant2147     void update() {
2148         bool exploded = explodeMask != 0;
2149 
2150         Enemy::update();
2151 
2152         if (health <= 0.0f && !exploded && animation.index == ANIM_DEATH && flags.state == TR::Entity::asInactive) {
2153             flags.state = TR::Entity::asActive;
2154             game->playSound(TR::SND_MUTANT_DEATH, pos, Sound::PAN);
2155             explode(0xffffffff, GIANT_MUTANT_PART_DAMAGE);
2156             game->checkTrigger(this, true);
2157         }
2158 
2159         setOverrides(true, jointChest, jointHead);
2160         lookAt(target);
2161 
2162         if (exploded && !explodeMask) {
2163             deactivate(true);
2164             flags.invisible = true;
2165         }
2166     }
2167 
getStateAirGiantMutant2168     virtual int getStateAir() {
2169         if (state == STATE_BORN)
2170             return STATE_FALL;
2171         return state;
2172     }
2173 
getStateGroundGiantMutant2174     virtual int getStateGround() {
2175         if (health <= 0)
2176             return state;
2177 
2178         if (!think(true))
2179             return state;
2180 
2181         if (!target || target->health <= 0.0f)
2182             return STATE_STOP;
2183 
2184         int mask = collide(target);
2185 
2186         if (mask) target->hit(GIANT_MUTANT_DAMAGE_WALK, this);
2187 
2188         switch (state) {
2189             case STATE_FALL :
2190                 animation.setState(STATE_STOP);
2191                 game->shakeCamera(5.0f);
2192                 break;
2193             case STATE_STOP :
2194                 flags.unused = false;
2195                 if (targetAngle >  GIANT_MUTANT_MAX_ANGLE) return STATE_TURN_RIGHT;
2196                 if (targetAngle < -GIANT_MUTANT_MAX_ANGLE) return STATE_TURN_LEFT;
2197                 if (targetDist < GIANT_MUTANT_DIST_ATTACK) {
2198                     if (target->health <= GIANT_MUTANT_DAMAGE) {
2199                         if (targetDist < GIANT_MUTANT_DIST_FATAL)
2200                             return STATE_ATTACK_3;
2201                     } else
2202                         return ((rand() % 2) ? STATE_ATTACK_1 : STATE_ATTACK_2);
2203                 }
2204                 return STATE_WALK;
2205             case STATE_WALK :
2206                 if (targetDist  <  GIANT_MUTANT_DIST_ATTACK ||
2207                     targetAngle >  GIANT_MUTANT_MAX_ANGLE   ||
2208                     targetAngle < -GIANT_MUTANT_MAX_ANGLE)
2209                     return STATE_STOP;
2210                 break;
2211             case STATE_TURN_RIGHT :
2212                 if (targetAngle < GIANT_MUTANT_MAX_ANGLE)
2213                     return STATE_STOP;
2214                 break;
2215             case STATE_TURN_LEFT :
2216                 if (targetAngle > -GIANT_MUTANT_MAX_ANGLE)
2217                     return STATE_STOP;
2218                 break;
2219             case STATE_ATTACK_1 :
2220             case STATE_ATTACK_2 :
2221                 if (!flags.unused && (
2222                     (state == STATE_ATTACK_1 && (mask & HIT_MASK_HAND)) ||
2223                     (state == STATE_ATTACK_2 && (mask & HIT_MASK_HANDS)))) {
2224                     target->hit(GIANT_MUTANT_DAMAGE, this);
2225                     flags.unused = true;
2226                 }
2227                 break;
2228             case STATE_ATTACK_3 :
2229                 if ((mask & HIT_MASK_HAND) && (target->stand != STAND_HANG)) {
2230                     target->hit(GIANT_MUTANT_DAMAGE_FATAL, this, TR::HIT_GIANT_MUTANT);
2231                     return STATE_FATAL;
2232                 }
2233                 break;
2234             default : ;
2235         }
2236 
2237         return state;
2238     }
2239 
getStateDeathGiantMutant2240     virtual int getStateDeath() {
2241         if (animation.index != ANIM_DEATH)
2242             return animation.setAnim(ANIM_DEATH);
2243         return state;
2244     }
2245 
turnGiantMutant2246     int turn(float delta, float speed) {
2247         float w = speed * Core::deltaTime;
2248 
2249         updateTilt(delta, w, speed * 0.1f);
2250 
2251         if (delta != 0.0f) {
2252             decrease(delta, angle.y, w);
2253             if (speed != 0.0f) {
2254                 velocity = velocity.rotateY(-w);
2255                 return speed < 0 ? LEFT : RIGHT;
2256             }
2257         }
2258 
2259         angle.z = 0.0f;
2260         return 0;
2261     }
2262 
updatePositionGiantMutant2263     virtual void updatePosition() {
2264         float angleY = 0.0f;
2265         if (target && target->health > 0.0f && fabsf(targetAngle) > GIANT_MUTANT_MIN_ANGLE)
2266             if (state == STATE_TURN_LEFT || state == STATE_TURN_RIGHT || state == STATE_WALK || state == STATE_STOP)
2267                 angleY = targetAngle;
2268 
2269         if (angleY != 0.0f) {
2270             turn(targetAngle, GIANT_MUTANT_TURN_SLOW);
2271         }
2272 
2273         Enemy::updatePosition();
2274         //setOverrides(true, jointChest, jointHead);
2275         //lookAt(target);
2276     }
2277 };
2278 
2279 #define CENTAUR_TURN_FAST   (DEG2RAD * 120)
2280 #define CENTAUR_DIST_RUN    (1024 + 512)
2281 #define CENTAUR_PART_DAMAGE 100
2282 
2283 struct Centaur : Enemy {
2284 
2285     enum {
2286         HIT_MASK = 0x030199,
2287     };
2288 
2289     enum {
2290         ANIM_DEATH = 8,
2291     };
2292 
2293     enum {
2294         STATE_NONE,
2295         STATE_STOP,
2296         STATE_FIRE,
2297         STATE_RUN,
2298         STATE_AIM,
2299         STATE_DEATH,
2300         STATE_IDLE,
2301     };
2302 
CentaurCentaur2303     Centaur(IGame *game, int entity) : Enemy(game, entity, 120, 341, 400.0f, 1.0f) {
2304         jointChest = 10;
2305         jointHead  = 17;
2306     }
2307 
setSaveDataCentaur2308     virtual void setSaveData(const SaveEntity &data) {
2309         Enemy::setSaveData(data);
2310         if (flags.invisible)
2311             deactivate(true);
2312     }
2313 
getStateGroundCentaur2314     virtual int getStateGround() {
2315         if (!think(true))
2316             return state;
2317 
2318         if (nextState == state)
2319             nextState = STATE_NONE;
2320 
2321         switch (state) {
2322             case STATE_STOP :
2323                 if (nextState != STATE_NONE)
2324                     return nextState;
2325                 if (targetCanAttack && targetDist < CENTAUR_DIST_RUN)
2326                     return STATE_RUN;
2327                 if (targetIsVisible(MAX_SHOT_DIST))
2328                     return STATE_AIM;
2329                 return STATE_RUN;
2330             case STATE_RUN :
2331                 if (targetCanAttack && targetDist < CENTAUR_DIST_RUN) {
2332                     nextState = STATE_IDLE;
2333                     return STATE_STOP;
2334                 }
2335                 if (targetIsVisible(MAX_SHOT_DIST)) {
2336                     nextState = STATE_AIM;
2337                     return STATE_STOP;
2338                 }
2339                 if (rand() < 96) {
2340                     nextState = STATE_IDLE;
2341                     return STATE_STOP;
2342                 }
2343                 break;
2344             case STATE_AIM :
2345                 if (nextState != STATE_NONE)
2346                     return nextState;
2347                 if (targetIsVisible(MAX_SHOT_DIST))
2348                     return STATE_FIRE;
2349                 return STATE_STOP;
2350             case STATE_FIRE :
2351                 if (nextState != STATE_NONE)
2352                     break;
2353                 nextState = STATE_AIM;
2354                 shot(TR::Entity::CENTAUR_BULLET, 13, vec3(11.0f, 415.0f, 41.0f));
2355                 break;
2356             case STATE_IDLE :
2357                 if (nextState == STATE_NONE && (collide(target) & HIT_MASK)) {
2358                     bite(5, vec3(50.0f, 30.0f, 0.0f), 200);
2359                     nextState = STATE_STOP;
2360                 }
2361                 break;
2362         }
2363 
2364         return state;
2365     }
2366 
getStateDeathCentaur2367     virtual int getStateDeath() {
2368         if (state == STATE_DEATH) return state;
2369         return animation.setAnim(ANIM_DEATH);
2370     }
2371 
updatePositionCentaur2372     virtual void updatePosition() {
2373         turn(state == STATE_RUN, CENTAUR_TURN_FAST);
2374 
2375         Enemy::updatePosition();
2376         setOverrides(true, jointChest, jointHead);
2377         lookAt(target);
2378     }
2379 
2380     virtual void deactivate(bool removeFromList = false) {
2381         if (!removeFromList) {
2382             if (!explodeMask)
2383                 explode(0xffffffff, CENTAUR_PART_DAMAGE);
2384             return;
2385         }
2386         Enemy::deactivate(removeFromList);
2387     }
2388 
updateCentaur2389     virtual void update() {
2390         bool exploded = explodeMask != 0;
2391 
2392         Enemy::update();
2393 
2394         if (exploded && !explodeMask) {
2395             deactivate(true);
2396             flags.invisible = true;
2397         }
2398     }
2399 };
2400 
2401 
2402 struct Mummy : Enemy {
2403     enum {
2404         STATE_NONE,
2405         STATE_IDLE,
2406         STATE_FALL,
2407     };
2408 
MummyMummy2409     Mummy(IGame *game, int entity) : Enemy(game, entity, 18, 341, 150.0f, 0.0f) {
2410         jointHead = 2;
2411     }
2412 
updateMummy2413     virtual void update() {
2414         if (state == STATE_IDLE && (health <= 0.0f || collide(game->getLara(pos)))) {
2415             animation.setState(STATE_FALL);
2416             health = 0.0f;
2417         }
2418         Enemy::update();
2419     }
2420 
getStateGroundMummy2421     virtual int getStateGround() {
2422         if (!think(true))
2423             return state;
2424         return state;
2425     }
2426 
updatePositionMummy2427     virtual void updatePosition() {
2428         Enemy::updatePosition();
2429         setOverrides(true, jointChest, jointHead);
2430         lookAt(target);
2431     }
2432 };
2433 
2434 
2435 #define DOPPELGANGER_ROOM_CENTER (vec3(36, 0, 60) * 1024.0f)
2436 
2437 struct Doppelganger : Enemy {
2438     enum {
2439         ANIM_FALL = 34,
2440     };
2441 
DoppelgangerDoppelganger2442     Doppelganger(IGame *game, int entity) : Enemy(game, entity, 1000, 341, 150.0f, 0.0f) {
2443         jointChest = 7;
2444         jointHead  = 14;
2445     }
2446 
2447     virtual void hit(float damage, Controller *enemy = NULL, TR::HitType hitType = TR::HIT_DEFAULT) {
2448         enemy->hit(damage * 10, this);
2449     };
2450 
updateDoppelganger2451     virtual void update() {
2452         if (!target)
2453             target = (Character*)game->getLara(pos);
2454 
2455         if (stand != STAND_AIR) {
2456             pos      = DOPPELGANGER_ROOM_CENTER * 2.0f - target->pos;
2457             pos.y    = target->pos.y;
2458             angle    = target->angle;
2459             angle.y -= PI;
2460         }
2461 
2462         Enemy::updateRoom();
2463 
2464         TR::Level::FloorInfo info;
2465         getFloorInfo(getRoomIndex(), target->pos, info);
2466         float laraHeight = info.floor - target->pos.y;
2467 
2468         getFloorInfo(getRoomIndex(), pos, info);
2469         float selfHeight = info.floor - pos.y;
2470 
2471         if (stand != STAND_AIR && target->stand == Character::STAND_GROUND && selfHeight > 1024 && laraHeight < 256) {
2472             animation = Animation(level, target->getModel());
2473             animation.setAnim(ANIM_FALL, 1);
2474             stand = STAND_AIR;
2475             velocity.x = velocity.y = 0.0f;
2476         }
2477 
2478         if (stand == STAND_AIR) {
2479             if (selfHeight < 128.0f) {
2480                 game->checkTrigger(this, true);
2481                 flags.invisible = true;
2482                 deactivate(true);
2483             } else {
2484                 updateAnimation(true);
2485                 applyGravity(velocity.y);
2486                 pos += velocity * (30.0f * Core::deltaTime);
2487             }
2488         } else {
2489             animation.frameA = target->animation.frameA;
2490             animation.frameB = target->animation.frameB;
2491             animation.delta  = target->animation.delta;
2492         }
2493     }
2494 
getStateGroundDoppelganger2495     virtual int getStateGround() {
2496         if (!think(true))
2497             return state;
2498         return state;
2499     }
2500 
updatePositionDoppelganger2501     virtual void updatePosition() {
2502         Enemy::updatePosition();
2503         setOverrides(true, jointChest, jointHead);
2504         lookAt(target);
2505     }
2506 };
2507 
2508 
2509 struct ScionTarget : Enemy {
ScionTargetScionTarget2510     ScionTarget(IGame *game, int entity) : Enemy(game, entity, 5, 0, 0, 0) {}
2511 
updateScionTarget2512     virtual void update() {
2513         Controller::update();
2514 
2515         if (health <= 0.0f) {
2516             if (timer == 0.0f) {
2517                 flags.invisible = true;
2518                 game->checkTrigger(this, true);
2519                 timer = 3.0f;
2520             }
2521 
2522             if (timer > 0.0f) {
2523                 int index = int(timer / 0.3f);
2524                 timer -= Core::deltaTime;
2525 
2526                 if (index != int(timer / 0.3f)) {
2527                     vec3 p = pos + vec3((randf() * 2.0f - 1.0f) * 512.0f, (randf() * 2.0f - 1.0f) * 64.0f - 500.0f, (randf() * 2.0f - 1.0f) * 512.0f);
2528                     game->addEntity(TR::Entity::EXPLOSION, getRoomIndex(), p);
2529                     game->shakeCamera(0.5f);
2530                 }
2531 
2532                 if (timer < 0.0f)
2533                     deactivate(true);
2534             }
2535         }
2536     }
2537 };
2538 
2539 #define HUMAN_WAIT       0.01f
2540 #define HUMAN_DIST_WALK  (1024 * 3)
2541 #define HUMAN_DIST_SHOT  (1024 * 7)
2542 #define HUMAN_TURN_SLOW  (DEG2RAD * 90)
2543 #define HUMAN_TURN_FAST  (DEG2RAD * 180)
2544 
2545 struct Human : Enemy {
2546     enum {
2547         STATE_NONE,
2548         STATE_STOP,
2549         STATE_WALK,
2550         STATE_RUN,
2551         STATE_AIM,
2552         STATE_DEATH,
2553         STATE_WAIT, // == STATE_FIRE for MrT and Cowboy
2554         STATE_FIRE
2555     };
2556 
2557     int jointGun;
2558     int animDeath;
2559 
HumanHuman2560     Human(IGame *game, int entity, float health) : Enemy(game, entity, health, 100, 0.0f, 1.0f), animDeath(-1) {
2561         jointGun   = 0;
2562         jointChest = 7;
2563         jointHead  = 8;
2564     }
2565 
2566     virtual void deactivate(bool removeFromList = false) {
2567         if (health <= 0.0f)
2568             onDead();
2569         Enemy::deactivate(removeFromList);
2570         getRoom().removeDynLight(entity);
2571     }
2572 
getStateDeathHuman2573     virtual int getStateDeath() {
2574         return (animDeath == -1 || state == STATE_DEATH || state == STATE_NONE) ? STATE_DEATH : animation.setAnim(animDeath);
2575     }
2576 
getStateGroundHuman2577     virtual int getStateGround() {
2578         if (!think(true))
2579             return state;
2580         return state;
2581     }
2582 
updatePositionHuman2583     virtual void updatePosition() {
2584         turn(state == STATE_RUN || state == STATE_WALK, state == STATE_RUN ? HUMAN_TURN_FAST : HUMAN_TURN_SLOW);
2585 
2586         Enemy::updatePosition();
2587         setOverrides(true, jointChest, jointHead);
2588         lookAt(target);
2589     }
2590 
onDeadHuman2591     virtual void onDead() {}
2592 
doShotHuman2593     bool doShot(float damage, const vec3 &muzzleOffset) {
2594         game->addMuzzleFlash(this, jointGun, muzzleOffset, -1);
2595 
2596         if (targetDist < HUMAN_DIST_SHOT && randf() < ((HUMAN_DIST_SHOT - targetDist) / HUMAN_DIST_SHOT - 0.25f)) {
2597             bite(-1, vec3(0.0f), damage);
2598             game->addEntity(TR::Entity::BLOOD, target->getRoomIndex(), target->getJoint(rand() % target->getModel()->mCount).pos);
2599             game->playSound(target->stand == STAND_UNDERWATER ? TR::SND_HIT_UNDERWATER : TR::SND_HIT, target->pos, Sound::PAN);
2600             return true;
2601         }
2602 
2603         int16 roomIndex = getRoomIndex();
2604         TR::Room::Sector *sector = level->getSector(roomIndex, target->pos);
2605         float floor = level->getFloor(sector, target->pos) - 64.0f;
2606         vec3 p = vec3(target->pos.x + randf() * 512.0f - 256.0f, floor, target->pos.z + randf() * 512.0f - 256.0f);
2607 
2608         target->addRicochet(p, true);
2609         return false;
2610     }
2611 };
2612 
2613 
2614 #define LARSON_DAMAGE 50
2615 
2616 struct Larson : Human {
2617 
LarsonLarson2618     Larson(IGame *game, int entity) : Human(game, entity, 50) {
2619         animDeath = 15;
2620         jointGun  = 14;
2621     }
2622 
getStateGroundLarson2623     virtual int getStateGround() {
2624         if (!think(false))
2625             return state;
2626 
2627         fullChestRotation = state == STATE_FIRE || state == STATE_AIM;
2628 
2629         if (nextState == state)
2630             nextState = STATE_NONE;
2631 
2632         switch (state) {
2633             case STATE_STOP :
2634                 if (nextState != STATE_NONE)
2635                     return nextState;
2636                 if (mood == MOOD_SLEEP)
2637                     return randf() < HUMAN_WAIT ? STATE_WAIT : STATE_WALK;
2638                 if (mood == MOOD_ESCAPE)
2639                     return STATE_RUN;
2640                 return STATE_WALK;
2641             case STATE_WAIT :
2642                 if (mood != MOOD_SLEEP)
2643                     return STATE_STOP;
2644                 if (randf() < HUMAN_WAIT) {
2645                     nextState = STATE_WALK;
2646                     return STATE_STOP;
2647                 }
2648                 break;
2649             case STATE_WALK :
2650                 if (mood == MOOD_SLEEP && randf() < HUMAN_WAIT)
2651                     nextState = STATE_WAIT;
2652                 else if (mood == MOOD_ESCAPE)
2653                     nextState = STATE_RUN;
2654                 else if (targetIsVisible(HUMAN_DIST_SHOT))
2655                     nextState = STATE_AIM;
2656                 else if (!targetInView || targetDist > HUMAN_DIST_WALK)
2657                     nextState = STATE_RUN;
2658                 else
2659                     break;
2660                 return STATE_STOP;
2661             case STATE_RUN :
2662                 if (mood == MOOD_SLEEP && randf() < HUMAN_WAIT)
2663                     nextState = STATE_WAIT;
2664                 else if (targetIsVisible(HUMAN_DIST_SHOT))
2665                     nextState = STATE_AIM;
2666                 else if (targetInView && targetDist < HUMAN_DIST_WALK)
2667                     nextState = STATE_WALK;
2668                 else
2669                     break;
2670                 return STATE_STOP;
2671             case STATE_AIM :
2672                 if (nextState != STATE_NONE)
2673                     return nextState;
2674                 if (targetIsVisible(HUMAN_DIST_SHOT))
2675                     return STATE_FIRE;
2676                 return STATE_STOP;
2677             case STATE_FIRE :
2678                 if (nextState == STATE_NONE) {
2679                     doShot(LARSON_DAMAGE, vec3(-50, 0, 20));
2680                     nextState = STATE_AIM;
2681                 }
2682                 if (mood == MOOD_ESCAPE || target->health <= 0.0f)
2683                     nextState = STATE_STOP;
2684                 break;
2685         }
2686 
2687         return state;
2688     }
2689 };
2690 
2691 
2692 #define PIERRE_MIN_HEALTH   40
2693 #define PIERRE_DAMAGE       25
2694 
2695 struct Pierre : Human {
2696 
PierrePierre2697     Pierre(IGame *game, int entity) : Human(game, entity, 70) {
2698         animDeath = 12;
2699     }
2700 
onDeadPierre2701     virtual void onDead() {
2702         game->addEntity(TR::Entity::MAGNUMS,           getRoomIndex(), pos, 0);
2703         game->addEntity(TR::Entity::SCION_PICKUP_DROP, getRoomIndex(), pos, 0);
2704         game->addEntity(TR::Entity::KEY_ITEM_1,        getRoomIndex(), pos, 0);
2705     }
2706 
getStateGroundPierre2707     virtual int getStateGround() {
2708         if (!think(false))
2709             return state;
2710 
2711         if (!flags.once && health <= PIERRE_MIN_HEALTH) {
2712             health = PIERRE_MIN_HEALTH;
2713             timer += Core::deltaTime;
2714         }
2715 
2716         if (timer > 0.0f && isVisible()) // time to run away!
2717             timer = 0.0f;
2718 
2719         if (getRoom().flags.water)
2720             timer = 1.0f;
2721 
2722         if (timer > 0.4f) {
2723             flags.invisible = true;
2724             deactivate(true);
2725         }
2726 
2727         fullChestRotation = state == STATE_FIRE || state == STATE_AIM;
2728 
2729         if (nextState == state)
2730             nextState = STATE_NONE;
2731 
2732         switch (state) {
2733             case STATE_STOP :
2734                 if (nextState != STATE_NONE)
2735                     return nextState;
2736                 if (mood == MOOD_SLEEP)
2737                     return randf() < HUMAN_WAIT ? STATE_WAIT : STATE_WALK;
2738                 if (mood == MOOD_ESCAPE)
2739                     return STATE_RUN;
2740                 return STATE_WALK;
2741             case STATE_WAIT :
2742                 if (mood != MOOD_SLEEP)
2743                     return STATE_STOP;
2744                 if (randf() < HUMAN_WAIT) {
2745                     nextState = STATE_WALK;
2746                     return STATE_STOP;
2747                 }
2748                 break;
2749             case STATE_WALK :
2750                 if (mood == MOOD_SLEEP && randf() < HUMAN_WAIT)
2751                     nextState = STATE_WAIT;
2752                 else if (mood == MOOD_ESCAPE)
2753                     nextState = STATE_RUN;
2754                 else if (targetIsVisible(HUMAN_DIST_SHOT))
2755                     nextState = STATE_AIM;
2756                 else if (!targetInView || targetDist > HUMAN_DIST_WALK)
2757                     nextState = STATE_RUN;
2758                 else
2759                     break;
2760                 return STATE_STOP;
2761             case STATE_RUN :
2762                 if (mood == MOOD_SLEEP && randf() < HUMAN_WAIT)
2763                     nextState = STATE_WAIT;
2764                 else if (targetIsVisible(HUMAN_DIST_SHOT))
2765                     nextState = STATE_AIM;
2766                 else if (targetInView && targetDist < HUMAN_DIST_WALK)
2767                     nextState = STATE_WALK;
2768                 else
2769                     break;
2770                 return STATE_STOP;
2771             case STATE_AIM :
2772                 if (nextState != STATE_NONE)
2773                     return nextState;
2774                 if (targetIsVisible(HUMAN_DIST_SHOT))
2775                     return STATE_FIRE;
2776                 return STATE_STOP;
2777             case STATE_FIRE :
2778                 if (nextState == STATE_NONE) {
2779                     jointGun = 11; doShot(PIERRE_DAMAGE, vec3(60, 0, 50));
2780                     jointGun = 14; doShot(PIERRE_DAMAGE, vec3(-60, 0, 50));
2781                     nextState = STATE_AIM;
2782                 }
2783                 if (mood == MOOD_ESCAPE && (rand() % 2))
2784                     nextState = STATE_STOP;
2785                 break;
2786         }
2787 
2788         return state;
2789     }
2790 };
2791 
2792 
2793 #define SKATERBOY_DIST_MIN      2560
2794 #define SKATERBOY_DIST_MAX      4096
2795 #define SKATERBOY_TURN_FAST     (120 * DEG2RAD)
2796 #define SKATERBOY_DAMAGE_STAND  50.0f
2797 #define SKATERBOY_DAMAGE_MOVE   40.0f
2798 
2799 struct SkaterBoy : Human {
2800 
2801     enum {
2802         STATE_STOP,
2803         STATE_STAND_FIRE,
2804         STATE_MOVE,
2805         STATE_STEP,
2806         STATE_MOVE_FIRE,
2807         STATE_DEATH
2808     };
2809 
2810     Controller *board;
2811 
SkaterBoySkaterBoy2812     SkaterBoy(IGame *game, int entity) : Human(game, entity, 125) {
2813         animDeath  = 13;
2814         jointChest = 1;
2815 
2816         board = game->addEntity(TR::Entity::ENEMY_SKATEBOARD, getRoomIndex(), pos, 0.0f);
2817         board->activate();
2818     }
2819 
onDeadSkaterBoy2820     virtual void onDead() {
2821         game->addEntity(TR::Entity::UZIS, getRoomIndex(), pos, 0);
2822     }
2823 
2824     virtual void hit(float damage, Controller *enemy = NULL, TR::HitType hitType = TR::HIT_DEFAULT) {
2825         bool flag = health >= 120;
2826         Human::hit(damage, enemy, hitType);
2827         if (flag && health < 120) {
2828             game->playTrack(56, true);
2829         }
2830     };
2831 
getStateGroundSkaterBoy2832     virtual int getStateGround() {
2833         if (!think(false))
2834             return state;
2835 
2836         fullChestRotation = state == STATE_STAND_FIRE || state == STATE_MOVE_FIRE;
2837 
2838         switch (state) {
2839             case STATE_STOP :
2840                 flags.unused = 0;
2841                 if (targetIsVisible(HUMAN_DIST_SHOT))
2842                     return STATE_STAND_FIRE;
2843                 return STATE_MOVE;
2844             case STATE_MOVE :
2845                 flags.unused = 0;
2846                 if (rand() < 512)
2847                     return STATE_STEP;
2848                 if (targetIsVisible(HUMAN_DIST_SHOT))
2849                     return (mood != MOOD_ESCAPE && targetDist > SKATERBOY_DIST_MIN && targetDist < SKATERBOY_DIST_MAX) ? STATE_STOP : STATE_MOVE_FIRE;
2850                 break;
2851             case STATE_STEP :
2852                 if (rand() < 1024)
2853                     return STATE_MOVE;
2854                 break;
2855             case STATE_STAND_FIRE :
2856             case STATE_MOVE_FIRE  :
2857                 if (!flags.unused && targetIsVisible(HUMAN_DIST_SHOT)) {
2858                     float damage = state == STATE_STAND_FIRE ? SKATERBOY_DAMAGE_STAND : SKATERBOY_DAMAGE_MOVE;
2859                     jointGun = 7; doShot(damage, vec3(0, -32, 0));
2860                     jointGun = 4; doShot(damage, vec3(0, -32, 0));
2861                     flags.unused = 1;
2862                 }
2863 
2864                 if (mood == MOOD_ESCAPE || targetDist < 1024)
2865                     return STATE_RUN;
2866                 break;
2867         }
2868 
2869         return state;
2870     }
2871 
updateSkaterBoy2872     virtual void update() {
2873         Human::update();
2874         board->pos   = pos;
2875         board->angle = angle;
2876         if (board->animation.index != animation.index)
2877             board->animation.setAnim(animation.index);
2878         board->animation.time = animation.time - Core::deltaTime;
2879     }
2880 
deactivateSkaterBoy2881     virtual void deactivate(bool removeFromList) {
2882         board->deactivate(removeFromList);
2883         Human::deactivate(removeFromList);
2884     }
2885 };
2886 
2887 
2888 #define COWBOY_DIST_WALK (3 * 1024)
2889 #define COWBOY_DAMAGE    70
2890 
2891 struct Cowboy : Human {
2892 
CowboyCowboy2893     Cowboy(IGame *game, int entity) : Human(game, entity, 150) {
2894         animDeath  = 7;
2895         jointChest = 1;
2896         jointHead  = 2;
2897     }
2898 
onDeadCowboy2899     virtual void onDead() {
2900         game->addEntity(TR::Entity::MAGNUMS, getRoomIndex(), pos, 0);
2901     }
2902 
getStateGroundCowboy2903     virtual int getStateGround() {
2904         if (!think(false))
2905             return state;
2906 
2907         fullChestRotation = state == STATE_WAIT || state == STATE_AIM;
2908 
2909         if (nextState == state)
2910             nextState = STATE_NONE;
2911 
2912         switch (state) {
2913             case STATE_STOP :
2914                 if (nextState != STATE_NONE)
2915                     return nextState;
2916                 if (targetIsVisible(HUMAN_DIST_SHOT))
2917                     return STATE_AIM;
2918                 if (mood == MOOD_SLEEP)
2919                     return STATE_WALK;
2920                 return STATE_RUN;
2921             case STATE_WALK :
2922                 if (mood == MOOD_ESCAPE || !targetInView)
2923                     nextState = STATE_RUN;
2924                 else if (targetIsVisible(HUMAN_DIST_SHOT))
2925                     nextState = STATE_AIM;
2926                 else if (targetDist > COWBOY_DIST_WALK)
2927                     nextState = STATE_RUN;
2928                 else
2929                     break;
2930                 return STATE_STOP;
2931             case STATE_RUN :
2932                 if (mood == MOOD_ESCAPE || !targetInView)
2933                     break;
2934                 if (targetIsVisible(HUMAN_DIST_SHOT))
2935                     nextState = STATE_AIM;
2936                 else if (targetDist < COWBOY_DIST_WALK && targetInView)
2937                     nextState = STATE_WALK;
2938                 else
2939                     break;
2940                 return STATE_STOP;
2941             case STATE_AIM :
2942                 flags.unused = 7;
2943                 if (nextState != STATE_NONE)
2944                     return STATE_STOP;
2945                 if (targetIsVisible(HUMAN_DIST_SHOT))
2946                     return STATE_WAIT; // STATE_FIRE
2947                 return STATE_STOP;
2948             case STATE_WAIT : // STATE_FIRE
2949                 if (animation.frameIndex != flags.unused && (animation.frameIndex == 0 || animation.frameIndex == 4)) {
2950                     jointGun = (flags.unused == 7) ? 8 : 5;
2951                     doShot(COWBOY_DAMAGE, vec3(0, -40, 40));
2952                     flags.unused = animation.frameIndex;
2953                 }
2954 
2955                 if (mood == MOOD_ESCAPE)
2956                     nextState = STATE_RUN;
2957                 break;
2958         }
2959 
2960         return state;
2961     }
2962 };
2963 
2964 
2965 #define MRT_DIST_WALK (4 * 1024)
2966 #define MRT_DAMAGE    150
2967 
2968 struct MrT : Human {
2969 
MrTMrT2970     MrT(IGame *game, int entity) : Human(game, entity, 200) {
2971         animDeath  = 14;
2972         jointGun   = 9;
2973         jointChest = 1;
2974         jointHead  = 2;
2975         state = STATE_RUN;
2976     }
2977 
onDeadMrT2978     virtual void onDead() {
2979         game->addEntity(TR::Entity::SHOTGUN, getRoomIndex(), pos, 0);
2980     }
2981 
getStateGroundMrT2982     virtual int getStateGround() {
2983         if (!think(false))
2984             return state;
2985 
2986         fullChestRotation = state == STATE_WAIT || state == STATE_AIM;
2987 
2988         if (nextState == state)
2989             nextState = STATE_NONE;
2990 
2991         switch (state) {
2992             case STATE_STOP :
2993                 if (nextState != STATE_NONE)
2994                     return nextState;
2995                 if (targetIsVisible(HUMAN_DIST_SHOT))
2996                     return STATE_AIM;
2997                 if (mood == MOOD_SLEEP)
2998                     return STATE_WALK;
2999                 return STATE_RUN;
3000             case STATE_WALK :
3001                 if (mood == MOOD_ESCAPE || !targetInView)
3002                     nextState = STATE_RUN;
3003                 else if (targetIsVisible(HUMAN_DIST_SHOT))
3004                     nextState = STATE_AIM;
3005                 else if (targetDist > MRT_DIST_WALK)
3006                     nextState = STATE_RUN;
3007                 else
3008                     break;
3009                 return STATE_STOP;
3010             case STATE_RUN :
3011                 if (mood == MOOD_ESCAPE || !targetInView)
3012                     break;
3013                 if (targetIsVisible(HUMAN_DIST_SHOT))
3014                     nextState = STATE_AIM;
3015                 else if (targetDist < MRT_DIST_WALK && targetInView)
3016                     nextState = STATE_WALK;
3017                 else
3018                     break;
3019                 return STATE_STOP;
3020             case STATE_AIM :
3021                 flags.unused = false;
3022                 if (nextState != STATE_NONE)
3023                     return STATE_STOP;
3024                 if (targetIsVisible(HUMAN_DIST_SHOT))
3025                     return STATE_WAIT; // STATE_FIRE
3026                 return STATE_STOP;
3027             case STATE_WAIT : // STATE_FIRE
3028                 if (!flags.unused) {
3029                     doShot(MRT_DAMAGE, vec3(-20, -20, 300));
3030                     flags.unused = true;
3031                 }
3032                 if (mood == MOOD_ESCAPE)
3033                     nextState = STATE_RUN;
3034                 break;
3035         }
3036 
3037         return state;
3038     }
3039 };
3040 
3041 #define NATLA_FIRE_ANGLE    (30 * DEG2RAD)
3042 #define NATLA_FAINT_TIME    16.0f
3043 #define NATLA_HALF_HEALTH   200.0f
3044 #define NATLA_FAINT_HEALTH  -8192.0f
3045 #define NATLA_LIFT_SPEED    MUTANT_LIFT_SPEED
3046 
3047 struct Natla : Human {
3048 
3049     enum {
3050         STATE_NONE,
3051         STATE_STOP,
3052         STATE_FLY,
3053         STATE_RUN,
3054         STATE_AIM,
3055         STATE_FAINT,
3056         STATE_FIRE,
3057         STATE_FALL,
3058         STATE_STAND,
3059         STATE_DEATH,
3060     };
3061 
3062     enum {
3063         FLAG_FLY = 1,
3064     };
3065 
NatlaNatla3066     Natla(IGame *game, int entity) : Human(game, entity, 400) {
3067         jointChest = 1;
3068         jointHead  = 2;
3069     }
3070 
stage1Natla3071     int stage1() {
3072         flying = (flags.unused & FLAG_FLY);
3073 
3074         stepHeight =  256;
3075         dropHeight = -256;
3076 
3077         if (flying) {
3078             stepHeight *= 80;
3079             dropHeight *= 80;
3080         }
3081 
3082         if (!think(false))
3083             return state;
3084 
3085         timer += Core::deltaTime;
3086         bool canShot = target && target->health > 0.0f && targetIsVisible(HUMAN_DIST_SHOT);
3087 
3088         if (canShot && state == STATE_FLY && flying && rand() < 256)
3089             flags.unused &= ~FLAG_FLY;
3090         else if (!canShot)
3091             flags.unused |= FLAG_FLY;
3092 
3093         flying = (flags.unused & FLAG_FLY);
3094 
3095         if (state == nextState)
3096             nextState = STATE_NONE;
3097 
3098         switch (state) {
3099             case STATE_STOP :
3100                 timer = 0.0f;
3101                 return flying ? STATE_FLY : STATE_AIM;
3102             case STATE_FLY : {
3103                 if (timer >= 1.0f) {
3104                     { //if (canShot) { ???
3105                         game->playSound(TR::SND_NATLA_SHOT, pos, Sound::PAN);
3106                         shot(TR::Entity::CENTAUR_BULLET, 4, vec3(5.0f, 220.0f, 7.0f));
3107                     }
3108                     timer -= 1.0f;
3109                 }
3110 
3111                 int16 roomIndex = getRoomIndex();
3112                 TR::Room::Sector *sector = level->getSector(roomIndex, pos);
3113                 float floor = level->getFloor(sector, pos) - 128.0f;
3114 
3115                 if (!flying && pos.y >= floor)
3116                     return STATE_STOP;
3117 
3118                 break;
3119             }
3120             case STATE_AIM :
3121                 if (nextState != STATE_NONE)
3122                     return nextState;
3123                 return canShot ? STATE_FIRE : STATE_STOP;
3124             case STATE_FIRE :
3125                 if (nextState != STATE_NONE)
3126                     return state;
3127 
3128                 game->playSound(TR::SND_NATLA_SHOT, pos, Sound::PAN);
3129                 shot(TR::Entity::CENTAUR_BULLET, 4, vec3(5.0f, 220.0f, 7.0f));
3130                 shot(TR::Entity::CENTAUR_BULLET, 4, vec3(5.0f, 220.0f, 7.0f), 0.0f, (randf() * 2.0f - 1.0f) * (25.0f * DEG2RAD));
3131                 shot(TR::Entity::CENTAUR_BULLET, 4, vec3(5.0f, 220.0f, 7.0f), 0.0f, (randf() * 2.0f - 1.0f) * (25.0f * DEG2RAD));
3132 
3133                 nextState = STATE_STOP;
3134                 break;
3135         }
3136 
3137         return state;
3138     }
3139 
stage2Natla3140     int stage2() {
3141         stepHeight =  256;
3142         dropHeight = -256;
3143         flying     = false;
3144 
3145         if (!think(true))
3146             return state;
3147 
3148         timer += Core::deltaTime;
3149         bool canShot = target && target->health > 0.0f && fabsf(targetAngle) < NATLA_FIRE_ANGLE && targetIsVisible(HUMAN_DIST_SHOT);
3150 
3151         switch (state) {
3152             case STATE_RUN   :
3153             case STATE_STAND :
3154                 if (timer >= 20.0f / 30.0f) {
3155                     { // if (canShot) { ???
3156                         game->playSound(TR::SND_NATLA_SHOT, pos, Sound::PAN);
3157                         shot(TR::Entity::MUTANT_BULLET, 4, vec3(5.0f, 220.0f, 7.0f));
3158                     }
3159                     timer -= 20.0f / 30.0f;
3160                 }
3161                 return canShot ? STATE_STAND : STATE_RUN;
3162             case STATE_FLY  :
3163                 health = NATLA_FAINT_HEALTH;
3164                 return STATE_FALL;
3165             case STATE_STOP :
3166             case STATE_AIM  :
3167             case STATE_FIRE :
3168                 health = NATLA_FAINT_HEALTH;
3169                 return STATE_FAINT;
3170         }
3171         return state;
3172     }
3173 
getStateGroundNatla3174     virtual int getStateGround() {
3175         if (health > NATLA_HALF_HEALTH)
3176             return stage1();
3177         return stage2();
3178     }
3179 
getStateDeathNatla3180     virtual int getStateDeath() {
3181         switch (state) {
3182             case STATE_FALL : {
3183                 int16 roomIndex = getRoomIndex();
3184                 TR::Room::Sector *sector = level->getSector(roomIndex, pos);
3185                 float floor = level->getFloor(sector, pos);
3186                 if (pos.y >= floor) {
3187                     pos.y = floor;
3188                     timer = 0.0f;
3189                     return STATE_FAINT;
3190                 }
3191                 return state;
3192             }
3193             case STATE_FAINT : {
3194                 timer += Core::deltaTime;
3195                 if (timer >= NATLA_FAINT_TIME) {
3196                     health = NATLA_HALF_HEALTH;
3197                     timer  = 0.0f;
3198                     flags.unused = 0;
3199                     game->playTrack(54, true);
3200                     return STATE_STAND;
3201                 }
3202                 return state;
3203             }
3204         }
3205         return STATE_DEATH;
3206     }
3207 
updateVelocityNatla3208     virtual void updateVelocity() {
3209         if (state == STATE_FLY) {
3210             angle.y += targetAngle;
3211             updateJoints();
3212             angle.y -= targetAngle;
3213         }
3214         Enemy::updateVelocity();
3215     }
3216 
updatePositionNatla3217     virtual void updatePosition() {
3218         if (flying) {
3219             stand = STAND_AIR;
3220             lift(target->pos.y - pos.y, NATLA_LIFT_SPEED);
3221         }
3222 
3223         turn(true, state == STATE_RUN ? HUMAN_TURN_FAST : HUMAN_TURN_SLOW);
3224 
3225         Enemy::updatePosition();
3226         setOverrides(state != STATE_FAINT, jointChest, jointHead);
3227         lookAt(target);
3228 
3229         stand = STAND_GROUND;
3230     }
3231 };
3232 
3233 struct Dog : Enemy {
3234 
3235     enum {
3236         ANIM_SLEEP = 5,
3237         ANIM_DEATH = 13,
3238     };
3239 
3240     enum {
3241         STATE_DEATH = 10,
3242     };
3243 
DogDog3244     Dog(IGame *game, int entity) : Enemy(game, entity, 6, 10, 0.0f, 0.0f) {
3245         jointChest = 19;
3246         jointHead  = 20;
3247         animation.setAnim(ANIM_SLEEP);
3248     }
3249 
getStateDeathDog3250     virtual int getStateDeath() {
3251         if (state != STATE_DEATH)
3252             return animation.setAnim(ANIM_DEATH);
3253         return state;
3254     }
3255 };
3256 
3257 #define TIGER_WALK           1120
3258 #define TIGER_ROAR           96
3259 #define TIGER_DIST_ATTACK_1  341
3260 #define TIGER_DIST_ATTACK_2  1536
3261 #define TIGER_DIST_ATTACK_3  1024
3262 #define TIGER_DAMAGE         100
3263 #define TIGER_TURN_FAST      (DEG2RAD * 180)
3264 #define TIGER_TURN_SLOW      (DEG2RAD * 90)
3265 
3266 struct Tiger : Enemy {
3267 
3268     enum {
3269         HIT_MASK = 0x7FDC000,
3270     };
3271 
3272     enum {
3273         ANIM_DEATH = 11,
3274     };
3275 
3276     enum {
3277         STATE_NONE = -1,
3278         STATE_DEATH    ,
3279         STATE_STOP     ,
3280         STATE_WALK     ,
3281         STATE_RUN      ,
3282         STATE_IDLE     ,
3283         STATE_ROAR     ,
3284         STATE_ATTACK_1 ,
3285         STATE_ATTACK_2 ,
3286         STATE_ATTACK_3 ,
3287     };
3288 
TigerTiger3289     Tiger(IGame *game, int entity) : Enemy(game, entity, 20, 341, 200.0f, 0.25f) {
3290         dropHeight = -1024;
3291         jointChest = -1;//21;
3292         jointHead  = -1;//22;
3293         nextState  = STATE_NONE;
3294     }
3295 
getStateGroundTiger3296     virtual int getStateGround() {
3297         if (!think(true))
3298             return state;
3299 
3300         if (nextState == state)
3301             nextState = STATE_NONE;
3302 
3303         switch (state) {
3304             case STATE_STOP    :
3305                 if (mood == MOOD_ESCAPE)
3306                     return STATE_RUN;
3307                 if (mood == MOOD_SLEEP) {
3308                     int r = rand();
3309                     if (r < TIGER_ROAR) return STATE_ROAR;
3310                     if (r < TIGER_WALK) return STATE_WALK;
3311                     return state;
3312                 }
3313                 if (targetInView && targetDist < TIGER_DIST_ATTACK_1)
3314                     return STATE_ATTACK_1;
3315                 if (targetInView && targetDist < TIGER_DIST_ATTACK_3)
3316                     return STATE_ATTACK_3;
3317                 if (nextState != STATE_NONE)
3318                     return nextState;
3319                 if (mood != MOOD_ATTACK && rand() < TIGER_ROAR)
3320                     return STATE_ROAR;
3321                 return STATE_RUN;
3322             case STATE_WALK     :
3323                 if (mood == MOOD_ATTACK || mood == MOOD_ESCAPE)
3324                     return STATE_RUN;
3325                 if (rand() < TIGER_ROAR) {
3326                     nextState = STATE_ROAR;
3327                     return STATE_STOP;
3328                 }
3329                 break;
3330             case STATE_RUN      : {
3331                 bool melee = flags.unused != 0;
3332                 flags.unused = 0;
3333 
3334                 if (mood == MOOD_SLEEP)
3335                     return STATE_STOP;
3336                 if (targetInView && melee)
3337                     return STATE_STOP;
3338                 if (targetInView && targetDist < TIGER_DIST_ATTACK_2) {
3339                     if (target->velocity.length2() < SQR(16.0f))
3340                         return STATE_STOP;
3341                     else
3342                         return STATE_ATTACK_2;
3343                 }
3344                 if (mood != MOOD_ATTACK && rand() < TIGER_ROAR) {
3345                     nextState = STATE_ROAR;
3346                     return STATE_STOP;
3347                 }
3348                 break;
3349             }
3350             case STATE_ATTACK_1 :
3351             case STATE_ATTACK_2 :
3352             case STATE_ATTACK_3 :
3353                 if (flags.unused == 0 && (collide(target) & HIT_MASK)) {
3354                     bite(26, vec3(19.0f, -13.0f, 3.0f), TIGER_DAMAGE);
3355                     flags.unused = 1;
3356                 }
3357         }
3358         return state;
3359     }
3360 
getStateDeathTiger3361     virtual int getStateDeath() {
3362         if (state == STATE_DEATH)
3363             return state;
3364         return animation.setAnim(ANIM_DEATH);
3365     }
3366 
updatePositionTiger3367     virtual void updatePosition() {
3368         turn(state == STATE_RUN || state == STATE_WALK || state == STATE_ROAR, state == STATE_RUN ? TIGER_TURN_FAST : TIGER_TURN_SLOW);
3369 
3370         if (state == STATE_DEATH) {
3371             animation.overrideMask = 0;
3372             return;
3373         }
3374 
3375         Enemy::updatePosition();
3376         setOverrides(true, jointChest, jointHead);
3377         lookAt(target);
3378     }
3379 };
3380 
3381 
3382 #define WINSTON_DIST        1536.0f
3383 #define WINSTON_TURN_SLOW   (DEG2RAD * 60)
3384 #define WINSTON_FREEZE_TIME 60.0f
3385 
3386 struct Winston : Enemy {
3387 
3388     enum {
3389         STATE_NONE ,
3390         STATE_STOP ,
3391         STATE_WALK ,
3392     };
3393 
3394     Texture *environment;
3395 
WinstonWinston3396     Winston(IGame *game, int entity) : Enemy(game, entity, 20, 341, 200.0f, 0.25f), environment(NULL) {
3397         dropHeight = -1024;
3398         jointChest = 11;
3399         jointHead  = 25;
3400         nextState  = STATE_NONE;
3401         lookAtSpeed = 1.0f;
3402         timer = 0.0f;
3403     }
3404 
~WinstonWinston3405     virtual ~Winston() {
3406         delete environment;
3407     }
3408 
getStateGroundWinston3409     virtual int getStateGround() {
3410         if (getRoomIndex() == 94) {
3411             int doorIndex = (level->version & TR::VER_TR2) ? 38 : 68;
3412 
3413             Controller *door = (Controller*)game->getLevel()->entities[doorIndex].controller;
3414             if (!door->isActive()) {
3415                 if (timer > WINSTON_FREEZE_TIME) {
3416                     flags.unused |= 4;
3417                     if (!environment) {
3418                         bakeEnvironment(environment);
3419                     }
3420                 } else {
3421                     timer += Core::deltaTime;
3422                 }
3423                 return STATE_STOP;
3424             } else {
3425                 if (!(flags.unused & 4)) {
3426                     timer = 0.0f;
3427                 }
3428             }
3429         }
3430 
3431         if (flags.unused & 4) {
3432             timer -= Core::deltaTime;
3433             if (timer < 0.0f) {
3434                 timer = 0.0f;
3435                 flags.unused &= ~4;
3436             }
3437             return STATE_STOP;
3438         }
3439 
3440         if (!think(false))
3441             return state;
3442 
3443         if (nextState == state)
3444             nextState = STATE_NONE;
3445 
3446         if (nextState != STATE_NONE)
3447             return nextState;
3448 
3449         switch (state) {
3450             case STATE_STOP    :
3451                 if ((targetDist > WINSTON_DIST || !targetInView) && nextState != STATE_WALK) {
3452                     nextState = STATE_WALK;
3453                     game->playSound(TR::SND_WINSTON_WALK, pos, Sound::PAN);
3454                 }
3455             case STATE_WALK     :
3456                 if (targetDist < WINSTON_DIST) {
3457                     if (targetInView) {
3458                         nextState = STATE_STOP;
3459                         flags.unused &= ~1;
3460                     } else if (!(flags.unused & 1)) {
3461                         game->playSound(TR::SND_WINSTON_SCARED, pos, Sound::PAN);
3462                         game->playSound(TR::SND_WINSTON_TRAY, pos, Sound::PAN);
3463                         flags.unused |= 1;
3464                     }
3465                 }
3466         }
3467 
3468         bool touch = collide(target) != 0;
3469         bool push  = (flags.unused & 2) != 0;
3470 
3471         if (!push && touch) {
3472             game->playSound(TR::SND_WINSTON_PUSH, pos, Sound::PAN);
3473             game->playSound(TR::SND_WINSTON_TRAY, pos, Sound::PAN);
3474             flags.unused |= 2;
3475         }
3476 
3477         if (push && !touch) {
3478             flags.unused &= ~2;
3479         }
3480 
3481         if (rand() < 0x100) {
3482             game->playSound(TR::SND_WINSTON_TRAY, pos, Sound::PAN);
3483         }
3484 
3485         return state;
3486     }
3487 
updatePositionWinston3488     virtual void updatePosition() {
3489         if (flags.unused & 4) {
3490             animation.time = 0.0f;
3491             animation.updateInfo();
3492             return;
3493         }
3494 
3495         turn(state == STATE_WALK, WINSTON_TURN_SLOW);
3496         angle.z = 0.0f;
3497 
3498         Enemy::updatePosition();
3499         setOverrides(true, jointChest, jointHead);
3500         lookAt(target);
3501     }
3502 
renderWinston3503     virtual void render(Frustum *frustum, MeshBuilder *mesh, Shader::Type type, bool caustics) {
3504         if (environment && (flags.unused & 4)) {
3505             game->setRoomParams(getRoomIndex(), Shader::MIRROR, 1.5f, 2.0f, 2.5f, 1.0f, false);
3506             GAPI::Texture *dtex = Core::active.textures[sDiffuse];
3507             environment->bind(sDiffuse);
3508             Controller::render(frustum, mesh, type, caustics);
3509             if (dtex) dtex->bind(sDiffuse);
3510         } else {
3511             Enemy::render(frustum, mesh, type, caustics);
3512         }
3513     }
3514 };
3515 
3516 #endif