[Scummvm-git-logs] scummvm master -> 19d9e4cec818980a75772a204c96774afbd2b17e

peterkohaut peterkohaut at users.noreply.github.com
Sat Mar 17 16:42:34 CET 2018


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
19d9e4cec8 BLADERUNNER: Added combat


Commit: 19d9e4cec818980a75772a204c96774afbd2b17e
    https://github.com/scummvm/scummvm/commit/19d9e4cec818980a75772a204c96774afbd2b17e
Author: Peter Kohaut (peter.kohaut at gmail.com)
Date: 2018-03-17T16:42:25+01:00

Commit Message:
BLADERUNNER: Added combat

Math cleanup
Fixed obstacle detection

Changed paths:
    engines/bladerunner/actor.cpp
    engines/bladerunner/actor.h
    engines/bladerunner/actor_combat.cpp
    engines/bladerunner/actor_combat.h
    engines/bladerunner/bladerunner.cpp
    engines/bladerunner/combat.cpp
    engines/bladerunner/combat.h
    engines/bladerunner/debugger.cpp
    engines/bladerunner/game_constants.h
    engines/bladerunner/matrix.h
    engines/bladerunner/scene_objects.cpp
    engines/bladerunner/scene_objects.h
    engines/bladerunner/script/ai/clovis.cpp
    engines/bladerunner/script/ai/dektora.cpp
    engines/bladerunner/script/ai/gaff.cpp
    engines/bladerunner/script/ai/gordo.cpp
    engines/bladerunner/script/ai/guzza.cpp
    engines/bladerunner/script/ai/leon.cpp
    engines/bladerunner/script/ai/lucy.cpp
    engines/bladerunner/script/ai/mccoy.cpp
    engines/bladerunner/script/ai/mutant1.cpp
    engines/bladerunner/script/ai/mutant2.cpp
    engines/bladerunner/script/ai/mutant3.cpp
    engines/bladerunner/script/ai/officer_leary.cpp
    engines/bladerunner/script/ai/sadik.cpp
    engines/bladerunner/script/ai/steele.cpp
    engines/bladerunner/script/ai/taffy_patron.cpp
    engines/bladerunner/script/ai/zuben.cpp
    engines/bladerunner/script/ai_script.cpp
    engines/bladerunner/script/ai_script.h
    engines/bladerunner/script/scene/ct07.cpp
    engines/bladerunner/script/scene/hf01.cpp
    engines/bladerunner/script/scene/hf03.cpp
    engines/bladerunner/script/scene/hf05.cpp
    engines/bladerunner/script/scene/hf06.cpp
    engines/bladerunner/script/scene/hf07.cpp
    engines/bladerunner/script/scene/kp05.cpp
    engines/bladerunner/script/scene/ma04.cpp
    engines/bladerunner/script/scene/nr01.cpp
    engines/bladerunner/script/scene/nr11.cpp
    engines/bladerunner/script/scene/ug05.cpp
    engines/bladerunner/script/scene/ug18.cpp
    engines/bladerunner/script/script.cpp
    engines/bladerunner/script/script.h
    engines/bladerunner/slice_renderer.cpp
    engines/bladerunner/slice_renderer.h
    engines/bladerunner/view.cpp


diff --git a/engines/bladerunner/actor.cpp b/engines/bladerunner/actor.cpp
index d4c4eea..177734f 100644
--- a/engines/bladerunner/actor.cpp
+++ b/engines/bladerunner/actor.cpp
@@ -22,11 +22,11 @@
 
 #include "bladerunner/actor.h"
 
-#include "bladerunner/bladerunner.h"
 #include "bladerunner/actor_clues.h"
 #include "bladerunner/actor_combat.h"
 #include "bladerunner/actor_walk.h"
 #include "bladerunner/audio_speech.h"
+#include "bladerunner/bladerunner.h"
 #include "bladerunner/boundingbox.h"
 #include "bladerunner/game_info.h"
 #include "bladerunner/items.h"
@@ -671,6 +671,12 @@ bool Actor::tick(bool forceDraw, Common::Rect *screenRect) {
 	return isVisible;
 }
 
+void Actor::tickCombat() {
+	if (_id != kActorMcCoy && !_isRetired && _inCombat) {
+		_combatInfo->tick();
+	}
+}
+
 bool Actor::draw(Common::Rect *screenRect) {
 	Vector3 drawPosition(_position.x, -_position.z, _position.y + 2.0);
 	float drawAngle = M_PI - _facing * (M_PI / 512.0f);
@@ -904,16 +910,6 @@ void Actor::setImmunityToObstacles(bool isImmune) {
 	_isImmuneToObstacles = isImmune;
 }
 
-void Actor::modifyCurrentHP(signed int change) {
-	_currentHP = CLIP(_currentHP + change, 0, 100);
-	if (_currentHP > 0)
-		retire(false, 0, 0, -1);
-}
-
-void Actor::modifyMaxHP(signed int change) {
-	_maxHP = CLIP(_maxHP + change, 0, 100);
-}
-
 void Actor::modifyCombatAggressiveness(signed int change) {
 	_combatAggressiveness = CLIP(_combatAggressiveness + change, 0, 100);
 }
@@ -955,6 +951,13 @@ void Actor::setTarget(bool target) {
 	_isTarget = target;
 }
 
+void Actor::setCurrentHP(int hp) {
+	_currentHP = hp;
+	if (hp > 0) {
+		retire(false, 0, 0, -1);
+	}
+}
+
 void Actor::setHealth(int hp, int maxHp) {
 	_currentHP = hp;
 	_maxHP = maxHp;
@@ -963,13 +966,25 @@ void Actor::setHealth(int hp, int maxHp) {
 	}
 }
 
-void Actor::combatModeOn(int a2, int a3, int otherActorId, int a5, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int a9, int a10, int a11, int ammoDamage, int a13, int a14) {
+void Actor::modifyCurrentHP(signed int change) {
+	_currentHP = CLIP(_currentHP + change, 0, 100);
+	if (_currentHP > 0) {
+		retire(false, 0, 0, -1);
+	}
+}
+
+void Actor::modifyMaxHP(signed int change) {
+	_maxHP = CLIP(_maxHP + change, 0, 100);
+}
+
+
+void Actor::combatModeOn(int initialState, bool rangedAttack, int enemyId, int waypointType, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int fleeRatio, int coverRatio, int actionRatio, int damage, int range, bool a14) {
 	_animationModeCombatIdle = animationModeCombatIdle;
 	_animationModeCombatWalk = animationModeCombatWalk;
 	_animationModeCombatRun = animationModeCombatRun;
 	_inCombat = true;
 	if (_id != kActorMcCoy) {
-		_combatInfo->combatOn(_id, a2, a3, otherActorId, a5, a9, a10, a11, ammoDamage, a13, a14);
+		_combatInfo->combatOn(_id, initialState, rangedAttack, enemyId, waypointType, fleeRatio, coverRatio, actionRatio, damage, range, a14);
 	}
 	stopWalking(false);
 	changeAnimationMode(_animationModeCombatIdle, false);
@@ -1002,6 +1017,16 @@ float Actor::distanceFromActor(int otherActorId) {
 	return (_position - _vm->_actors[otherActorId]->_position).length();
 }
 
+int Actor::angleTo(const Vector3 &target) const {
+	int angle = angle_1024(_position.x, _position.z, target.x, target.z) - _facing;
+	if (angle < -512) {
+		angle += 1024;
+	} else if (angle > 512) {
+		angle -= 1024;
+	}
+	return angle;
+}
+
 float Actor::getX() const {
 	return _position.x;
 }
@@ -1014,10 +1039,8 @@ float Actor::getZ() const {
 	return _position.z;
 }
 
-void Actor::getXYZ(float *x, float *y, float *z) const {
-	*x = _position.x;
-	*y = _position.y;
-	*z = _position.z;
+Vector3 Actor::getXYZ() const {
+	return _position;
 }
 
 int Actor::getFacing() const {
@@ -1112,8 +1135,8 @@ int Actor::soundBalance() const {
 	return 35.0f * (CLIP(screenPosition.x / 640.0f, 0.0f, 1.0f) * 2.0f - 1.0f);
 }
 
-bool Actor::isObstacleBetween(float targetX, float targetZ) {
-	return _vm->_sceneObjects->isObstacleBetween(_position.x, _position.z, targetX, targetZ, _position.y, -1);
+bool Actor::isObstacleBetween(const Vector3 &target) {
+	return _vm->_sceneObjects->isObstacleBetween(_position, target, -1);
 }
 
 int Actor::findTargetUnderMouse(BladeRunnerEngine *vm, int mouseX, int mouseY) {
diff --git a/engines/bladerunner/actor.h b/engines/bladerunner/actor.h
index af0c14e..ace9055 100644
--- a/engines/bladerunner/actor.h
+++ b/engines/bladerunner/actor.h
@@ -39,18 +39,17 @@ class MovementTrack;
 class View;
 
 class Actor {
-	friend class ScriptBase;
-	friend class KIA;
-
 	BladeRunnerEngine *_vm;
 
-private:
+public:
 	BoundingBox   *_bbox;
 	Common::Rect   _screenRectangle;
 	MovementTrack *_movementTrack;
 	ActorWalk     *_walkInfo;
 	ActorCombat   *_combatInfo;
+	ActorClues    *_clues;
 
+private:
 	int                _honesty;
 	int                _intelligence;
 	int                _stability;
@@ -61,8 +60,6 @@ private:
 	int _currentHP;
 	int _maxHP;
 
-	ActorClues *_clues;
-
 	int     _id;
 	int     _setId;
 	Vector3 _position;
@@ -124,7 +121,7 @@ public:
 	float getX() const;
 	float getY() const;
 	float getZ() const;
-	void getXYZ(float *x, float *y, float *z) const;
+	Vector3 getXYZ() const;
 	int getFacing() const;
 	int getAnimationMode() const;
 
@@ -157,6 +154,7 @@ public:
 	void run();
 
 	bool tick(bool forceUpdate, Common::Rect *screenRect);
+	void tickCombat();
 	bool draw(Common::Rect *screenRect);
 
 	int getSetId()  const;
@@ -164,13 +162,16 @@ public:
 	BoundingBox *getBoundingBox() const { return _bbox; }
 	Common::Rect *getScreenRectangle() { return &_screenRectangle; }
 	int getWalkbox() const { return _walkboxId; }
+
 	bool isRetired() const { return _isRetired; }
-	bool isTarget() const { return _isTarget; }
+	bool isTarget() const { return true;/*return _isTarget; */}
 	void setTarget(bool targetable);
 	bool isImmuneToObstacles() const { return _isImmuneToObstacles; }
 	bool inCombat() const { return _inCombat; }
+
 	bool isMoving() const { return _isMoving; }
 	void setMoving(bool value) { _isMoving = value; }
+
 	bool inWalkLoop() const { return _inWalkLoop; }
 	bool isWalking() const;
 	bool isRunning() const;
@@ -184,33 +185,51 @@ public:
 	void faceXYZ(const Vector3 &pos, bool animate);
 	void faceCurrentCamera(bool animate);
 	void faceHeading(int heading, bool animate);
-	void modifyFriendlinessToOther(int otherActorId, signed int change);
+	void setFacing(int facing, bool halfOrSet = true);
+
+	int getCurrentHP() const { return _currentHP; }
+	int getMaxHP() const { return _maxHP; }
+	void setCurrentHP(int hp);
+	void setHealth(int hp, int maxHp);
+	void modifyCurrentHP(signed int change);
+	void modifyMaxHP(signed int change);
+
+	int getFriendlinessToOther(int otherActorId) const { return _friendlinessToOther[otherActorId]; }
 	void setFriendlinessToOther(int otherActorId, int friendliness);
+	void modifyFriendlinessToOther(int otherActorId, signed int change);
+
+	int getHonesty() const { return _honesty; }
 	void setHonesty(int honesty);
+	void modifyHonesty(signed int change);
+
+	int getIntelligence() const { return _intelligence; }
 	void setIntelligence(int intelligence);
+	void modifyIntelligence(signed int change);
+
+	int getStability() const { return _stability; }
 	void setStability(int stability);
+	void modifyStability(signed int change);
+
+	int getCombatAggressiveness() const { return _combatAggressiveness; }
 	void setCombatAggressiveness(int combatAggressiveness);
+	void modifyCombatAggressiveness(signed int change);
+
 	void setInvisible(bool isInvisible);
 	void setImmunityToObstacles(bool isImmune);
-	void modifyCurrentHP(signed int change);
-	void modifyMaxHP(signed int change);
-	void modifyCombatAggressiveness(signed int change);
-	void modifyHonesty(signed int change);
-	void modifyIntelligence(signed int change);
-	void modifyStability(signed int change);
+
 	void setFlagDamageAnimIfMoving(bool value);
-	bool getFlagDamageAnimIfMoving()  const;
-	void setHealth(int hp, int maxHp);
+	bool getFlagDamageAnimIfMoving() const;
 
 	void retire(bool isRetired, int width, int height, int retiredByActorId);
 
-	void combatModeOn(int a2, int a3, int a4, int a5, int combatAnimationMode, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14);
+	void combatModeOn(int initialState, bool rangedAttack, int enemyId, int waypointType, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int fleeRatio, int coverRatio, int actionRatio, int damage, int range, bool a14);
 	void combatModeOff();
 
 	void setGoal(int goalNumber);
 	int getGoal() const;
 
 	float distanceFromActor(int otherActorId);
+	int angleTo(const Vector3 &target) const;
 
 	void speechPlay(int sentenceId, bool voiceOver);
 	void speechStop();
@@ -225,11 +244,11 @@ public:
 	int soundVolume() const;
 	int soundBalance() const;
 
-	bool isObstacleBetween(float targetX, float targetZ);
+	bool isObstacleBetween(const Vector3 &target);
 
 	static int findTargetUnderMouse(BladeRunnerEngine *vm, int mouseX, int mouseY);
+
 private:
-	void setFacing(int facing, bool halfOrSet = true);
 	void setBoundingBox(const Vector3 &position, bool retired);
 	float distanceFromView(View *view) const;
 
diff --git a/engines/bladerunner/actor_combat.cpp b/engines/bladerunner/actor_combat.cpp
index 4bd8d17..47d1c2d 100644
--- a/engines/bladerunner/actor_combat.cpp
+++ b/engines/bladerunner/actor_combat.cpp
@@ -22,25 +22,624 @@
 
 #include "bladerunner/actor_combat.h"
 
+#include "bladerunner/actor.h"
+#include "bladerunner/audio_speech.h"
+#include "bladerunner/bladerunner.h"
+#include "bladerunner/combat.h"
+#include "bladerunner/game_constants.h"
+#include "bladerunner/game_info.h"
+#include "bladerunner/movement_track.h"
+#include "bladerunner/scene.h"
+#include "bladerunner/scene_objects.h"
+#include "bladerunner/script/ai_script.h"
+#include "bladerunner/set.h"
+#include "bladerunner/settings.h"
+
 namespace BladeRunner {
 
 ActorCombat::ActorCombat(BladeRunnerEngine *vm) {
 	_vm = vm;
+	reset();
 }
 
 ActorCombat::~ActorCombat() {
 }
 
-void ActorCombat::hitAttempt() {
+void ActorCombat::setup() {
+	reset();
 }
 
-void ActorCombat::combatOn(int actorId, int a3, int a4, int otherActorId, int a6, int a7, int a8, int a9, int ammoDamage, int a11, int a12) {
+void ActorCombat::combatOn(int actorId, int initialState, bool rangedAttack, int enemyId, int waypointType, int fleeRatio, int coverRatio, int actionRatio, int damage, int range, bool a12) {
+	_actorId = actorId;
+	_state = initialState;
+	_rangedAttack = rangedAttack;
+	_enemyId = enemyId;
+	_waypointType = waypointType;
+	_damage = damage;
+	_fleeRatioConst = fleeRatio;
+	_coverRatioConst = coverRatio;
+	_actionRatioConst = actionRatio;
+	_fleeRatio = fleeRatio;
+	_coverRatio = coverRatio;
+	_actionRatio = actionRatio;
+	_active = true;
+	if (rangedAttack == 1) {
+		_range = range;
+	} else {
+		_range = 300;
+	}
+	field_3C = a12;
+
+	Actor *actor = _vm->_actors[_actorId];
+
+	_actorPosition = actor->getXYZ();
+	_enemyPosition = _vm->_actors[_enemyId]->getXYZ();
+
+	actor->_movementTrack->flush();
+	actor->stopWalking(false);
+
+	if (_enemyId == kActorMcCoy) {
+		actor->setTarget(true);
+	}
+
+	_actorHp = actor->getCurrentHP();
+
+	_coversWaypointCount = 0;
+	for (int i = 0; i < (int)_vm->_gameInfo->getCoverWaypointCount(); ++i) {
+		if (_vm->_combat->_coverWaypoints[i].type == waypointType && _vm->_combat->_coverWaypoints[i].setId == actor->getSetId()) {
+			++_coversWaypointCount;
+		}
+	}
+	if (_coversWaypointCount == 0) {
+		_coverRatioConst = 0;
+		_coverRatio = 0;
+	}
+
+	_fleeWaypointsCount = 0;
+	for (int i = 0; i < (int)_vm->_gameInfo->getFleeWaypointCount(); ++i) {
+		if (_vm->_combat->_fleeWaypoints[i].type == waypointType && _vm->_combat->_fleeWaypoints[i].setId == actor->getSetId()) {
+			++_fleeWaypointsCount;
+		}
+	}
+	if (_fleeWaypointsCount == 0) {
+		_fleeRatioConst = 0;
+		_fleeRatio = 0;
+	}
 }
 
 void ActorCombat::combatOff() {
+	_active = false;
+	reset();
 }
 
-void ActorCombat::setup() {
+void ActorCombat::tick() {
+	static int processingCounter = 0;
+
+	if (!_active || processingCounter > 0) {
+		return;
+	}
+
+	Actor *actor = _vm->_actors[_actorId];
+	Actor *enemy = _vm->_actors[_enemyId];
+
+	if (actor->getSetId() != enemy->getSetId()) {
+		actor->combatModeOff();
+		return;
+	}
+
+	++processingCounter;
+
+	_actorPosition = actor->getXYZ();
+	_enemyPosition = enemy->getXYZ();
+
+	if (_actionRatioConst >= 0) {
+		_actionRatio = _actionRatioConst;
+	} else {
+		_actionRatio = calculateActionRatio();
+	}
+
+	if (_vm->_combat->findCoverWaypoint(_waypointType, _actorId, _enemyId) != -1) {
+		if (_coverRatioConst >= 0) {
+			_coverRatio = _coverRatioConst;
+		} else {
+			_coverRatio = calculateCoverRatio();
+		}
+	} else {
+		_coverRatio = 0;
+	}
+
+	if (_fleeRatioConst >= 0) {
+		_fleeRatio = _fleeRatioConst;
+	} else {
+		_fleeRatio = calculateFleeRatio();
+	}
+
+	float dist = actor->distanceFromActor(_enemyId);
+	int oldState = _state;
+
+	if (_actionRatio < _fleeRatio || _actionRatio < _coverRatio) {
+		if (_coverRatio >= _fleeRatio && _coverRatio >= _actionRatio) {
+			_state = kActorCombatStateCover;
+		} else {
+			_state = kActorCombatStateFlee;
+		}
+	} else {
+		if (_rangedAttack) {
+			if (dist > _range) {
+				_state = kActorCombatStateApproachRangedAttack;
+			} else {
+				if (actor->isObstacleBetween(_enemyPosition)) {
+					_state = kActorCombatStateUncover;
+				} else {
+					_state = kActorCombatStateRangedAttack;
+				}
+			}
+		} else {
+			if (dist > 36.0f) {
+				_state = kActorCombatStateApproachCloseAttack;
+			} else {
+				_state = kActorCombatStateCloseAttack;
+			}
+		}
+	}
+
+	if (enemy->isRetired()) {
+		_state = kActorCombatStateIdle;
+	}
+
+	if (actor->getAnimationMode() == kAnimationModeHit || actor->getAnimationMode() == kAnimationModeCombatHit) {
+		_state = kActorCombatStateIdle;
+	} else {
+		if (_state != oldState) {
+			actor->stopWalking(false);
+		}
+	}
+	switch (_state) {
+	case kActorCombatStateCover:
+		cover();
+		break;
+	case kActorCombatStateApproachCloseAttack:
+		approachToCloseAttack();
+		break;
+	case kActorCombatStateUncover:
+		uncover();
+		break;
+	case kActorCombatStateAim:
+		aim();
+		break;
+	case kActorCombatStateRangedAttack:
+		rangedAttack();
+		break;
+	case kActorCombatStateCloseAttack:
+		closeAttack();
+		break;
+	case kActorCombatStateFlee:
+		flee();
+		break;
+	case kActorCombatStateApproachRangedAttack:
+		approachToRangedAttack();
+		break;
+	}
+	--processingCounter;
+}
+
+void ActorCombat::hitAttempt() {
+	Actor *actor = _vm->_actors[_actorId];
+	Actor *enemy = _vm->_actors[_enemyId];
+
+	if (_enemyId == kActorMcCoy && !_vm->playerHasControl() && field_3C == 0) {
+		return;
+	}
+
+	if (actor->isRetired()) {
+		return;
+	}
+
+	int aggressiveness = 0;
+	if (_rangedAttack) {
+		aggressiveness = _rangedAttack == 1 ? getaggressivenessRangedAttack() : 0;
+	} else {
+		aggressiveness = getaggressivenessCloseAttack();
+	}
+
+	if (aggressiveness == 0) {
+		return;
+	}
+
+	int random = _vm->_rnd.getRandomNumberRng(1, 100);
+
+	if (random <= aggressiveness) {
+		if (enemy->isWalking()) {
+			enemy->stopWalking(true);
+		}
+
+		int sentenceId = _vm->_rnd.getRandomNumberRng(0, 1) ? 9000 : 9005;
+		if (enemy->inCombat()) {
+			enemy->changeAnimationMode(22, false);
+		} else {
+			enemy->changeAnimationMode(21, false);
+		}
+
+		int damage = 0;
+		if (_rangedAttack) {
+			damage = getDamageRangedAttack(random, aggressiveness);
+		} else {
+			damage = getDamageCloseAttack(random, aggressiveness);
+		}
+
+		int enemyHp = MAX(enemy->getCurrentHP() - damage, 0);
+		enemy->setCurrentHP(enemyHp);
+
+		if (enemyHp <= 0) {
+			if (!enemy->isRetired()) {
+				if (enemy->inCombat()) {
+					enemy->changeAnimationMode(49, false);
+				} else {
+					enemy->changeAnimationMode(48, false);
+				}
+				sentenceId = 9020;
+			}
+			enemy->retire(true, 6, 3, _actorId);
+		}
+
+		if (_enemyId == kActorMcCoy) {
+			sentenceId += 900;
+		}
+
+		_vm->_audioSpeech->playSpeechLine(_enemyId, sentenceId, 75, enemy->soundBalance(), 99);
+	}
+}
+
+void ActorCombat::reset() {
+	_active              = false;
+	_actorId             = -1;
+	_state               = -1;
+	_rangedAttack        = -1;
+	_enemyId             = -1;
+	_waypointType        = -1;
+	_damage              = 0;
+	_fleeRatio           = -1;
+	_coverRatio          = -1;
+	_actionRatio         = -1;
+	_fleeRatioConst      = -1;
+	_coverRatioConst     = -1;
+	_actionRatioConst    = -1;
+	_actorHp             = 0;
+	_range               = 300;
+	field_3C             = 0;
+	_actorPosition       = Vector3(0.0f, 0.0f, 0.0f);
+	_enemyPosition       = Vector3(0.0f, 0.0f, 0.0f);
+	_coversWaypointCount = 0;
+	_fleeWaypointsCount  = 0;
+	_fleeingTowards      = -1;
+}
+
+void ActorCombat::cover() {
+	Actor *actor = _vm->_actors[_actorId];
+
+	if (actor->isWalking()) {
+		return;
+	}
+
+	if (actor->isObstacleBetween(_enemyPosition)) {
+		faceEnemy();
+		return;
+	}
+
+	int coverWaypointId = _vm->_combat->findCoverWaypoint(_waypointType, _actorId, _enemyId);
+	if (coverWaypointId == -1) {
+		_state = kActorCombatStateIdle;
+	} else {
+		actor->asyncWalkToXYZ(_vm->_combat->_coverWaypoints[coverWaypointId].position, 0, true, 0);
+	}
+}
+
+void ActorCombat::approachToCloseAttack() {
+	Actor *actor = _vm->_actors[_actorId];
+	Actor *enemy = _vm->_actors[_enemyId];
+
+	float dist = actor->distanceFromActor(_enemyId);
+	if (dist > 36.0f) {
+		if (!actor->isWalking() || enemy->isWalking()) {
+			Vector3 target;
+			if (findClosestPositionToEnemy(target)) {
+				actor->asyncWalkToXYZ(target, 0, dist >= 240.0f, 0);
+			} else {
+				_state = kActorCombatStateCover;
+			}
+		}
+	} else {
+		if (actor->isWalking()) {
+			actor->stopWalking(false);
+		}
+		faceEnemy();
+		_state = kActorCombatStateCloseAttack;
+	}
+}
+
+void ActorCombat::approachToRangedAttack() {
+	Actor *actor = _vm->_actors[_actorId];
+	Actor *enemy = _vm->_actors[_enemyId];
+
+	float dist = actor->distanceFromActor(_enemyId);
+	if (dist > _range) {
+		if (!actor->isWalking() || enemy->isWalking()) {
+			Vector3 target;
+			if (findClosestPositionToEnemy(target)) {
+				actor->asyncWalkToXYZ(target, 0, dist >= 240.0f, 0);
+			} else {
+				_state = kActorCombatStateCover;
+			}
+		}
+	} else {
+		if (actor->isWalking()) {
+			actor->stopWalking(false);
+		}
+		faceEnemy();
+		_state = kActorCombatStateRangedAttack;
+	}
+}
+
+void ActorCombat::uncover() {
+	Actor *actor = _vm->_actors[_actorId];
+	Actor *enemy = _vm->_actors[_enemyId];
+
+	if (actor->isObstacleBetween(_enemyPosition)) {
+		actor->asyncWalkToXYZ(enemy->getXYZ(), 16, false, 0);
+	} else {
+		if (actor->isWalking()) {
+			actor->stopWalking(false);
+		}
+		faceEnemy();
+	}
+}
+
+void ActorCombat::aim() {
+	Actor *actor = _vm->_actors[_actorId];
+
+	if (actor->isObstacleBetween(_enemyPosition)) {
+		if (actor->getAnimationMode() != kAnimationModeCombatIdle) {
+			actor->changeAnimationMode(kAnimationModeCombatIdle, false);
+		}
+	} else {
+		faceEnemy();
+		if (actor->getAnimationMode() != kAnimationModeCombatAim) {
+			actor->changeAnimationMode(kAnimationModeCombatAim, false);
+		}
+	}
+}
+
+void ActorCombat::rangedAttack() {
+	Actor *actor = _vm->_actors[_actorId];
+
+	if (actor->isObstacleBetween(_enemyPosition) || (actor->distanceFromActor(_enemyId) > _range)) {
+		_state = kActorCombatStateApproachRangedAttack;
+	} else {
+		faceEnemy();
+		if (actor->getAnimationMode() != kAnimationModeCombatAttack) {
+			if (_enemyId != kActorMcCoy || _vm->playerHasControl() || field_3C != 0) {
+				actor->changeAnimationMode(kAnimationModeCombatAttack, false);
+			}
+		}
+	}
+}
+
+void ActorCombat::closeAttack() {
+	Actor *actor = _vm->_actors[_actorId];
+
+	if (actor->isObstacleBetween(_enemyPosition) || (actor->distanceFromActor(_enemyId) > 36.0f)) {
+		_state = kActorCombatStateApproachCloseAttack;
+	} else {
+		faceEnemy();
+		if (actor->getAnimationMode() != kAnimationModeCombatAttack) {
+			if (_enemyId != kActorMcCoy || _vm->playerHasControl() || field_3C != 0) {
+				actor->changeAnimationMode(kAnimationModeCombatAttack, false);
+			}
+		}
+	}
+}
+
+void ActorCombat::flee() {
+	Actor *actor = _vm->_actors[_actorId];
+
+	if (_fleeingTowards != -1 && actor->isWalking()) {
+		Vector3 fleeWaypointPosition = _vm->_combat->_fleeWaypoints[_fleeingTowards].position;
+		if (distance(_actorPosition, fleeWaypointPosition) <= 12.0f) {
+			_vm->_aiScripts->fledCombat(_actorId/*, _enemyId*/);
+			actor->setSetId(kSetFreeSlotG);
+			actor->combatModeOff();
+			_fleeingTowards = -1;
+		}
+	} else {
+		int fleeWaypointId = _vm->_combat->findFleeWaypoint(actor->getSetId(), _enemyId, _actorPosition);
+		if (fleeWaypointId == -1) {
+			_state = kActorCombatStateIdle;
+		} else {
+			Vector3 fleeWaypointPosition = _vm->_combat->_fleeWaypoints[fleeWaypointId].position;
+			actor->asyncWalkToXYZ(fleeWaypointPosition, 0, true, 0);
+			_fleeingTowards = fleeWaypointId;
+		}
+	}
+}
+
+void ActorCombat::faceEnemy() {
+	_vm->_actors[_actorId]->setFacing(angle_1024(_actorPosition.x, _actorPosition.z, _enemyPosition.x, _enemyPosition.z), false);
+}
+
+int ActorCombat::getaggressivenessCloseAttack() const{
+	Actor *actor = _vm->_actors[_actorId];
+	Actor *enemy = _vm->_actors[_enemyId];
+
+	float distance = actor->distanceFromActor(_enemyId);
+
+	if (distance > 36.0f) {
+		return 0;
+	}
+
+	int aggressiveness = 0;
+	if (enemy->isRunning()) {
+		aggressiveness = 11;
+	} else if (enemy->isMoving()) {
+		aggressiveness = 22;
+	} else {
+		aggressiveness = 33;
+	}
+
+	aggressiveness += actor->getCombatAggressiveness() / 3;
+
+	int angle = abs(actor->angleTo(_enemyPosition));
+
+	if (angle > 128) {
+		return false;
+	}
+
+	return aggressiveness + (abs(angle - 128) / 3.7f);
+}
+
+int ActorCombat::getaggressivenessRangedAttack() const {
+	Actor *actor = _vm->_actors[_actorId];
+	Actor *enemy = _vm->_actors[_enemyId];
+
+	if (actor->isObstacleBetween(_enemyPosition)) {
+		return 0;
+	}
+
+	float distance = MIN(actor->distanceFromActor(_enemyId), 900.0f);
+
+	int aggressiveness = 0;
+	if (enemy->isRunning()) {
+		aggressiveness = 10;
+	} else if (enemy->isMoving()) {
+		aggressiveness = 20;
+	} else {
+		aggressiveness = 30;
+	}
+
+	aggressiveness += actor->getCombatAggressiveness() / 5;
+	return aggressiveness + abs((distance / 30) - 30) + actor->getIntelligence() / 5;
+}
+
+int ActorCombat::getDamageCloseAttack(int min, int max) const {
+	if (_enemyId == kActorMcCoy && _vm->_settings->getDifficulty() == 0) {
+		return _damage / 2;
+	}
+	if (_enemyId == kActorMcCoy && _vm->_settings->getDifficulty() == 2) {
+		return _damage;
+	}
+	return ((MIN(max - min, 30) * 100.0f / 60.0f) + 50) * _damage / 100;
+}
+
+int ActorCombat::getDamageRangedAttack(int min, int max) const {
+	if (_enemyId == kActorMcCoy && _vm->_settings->getDifficulty() == 0) {
+		return _damage / 2;
+	}
+	if (_enemyId == kActorMcCoy && _vm->_settings->getDifficulty() == 2) {
+		return _damage;
+	}
+	return ((MIN(max - min, 30) * 100.0f / 60.0f) + 50) * _damage / 100;
+}
+
+int ActorCombat::calculateActionRatio() const {
+	Actor *actor = _vm->_actors[_actorId];
+	Actor *enemy = _vm->_actors[_enemyId];
+
+	int aggressivenessFactor = actor->getCombatAggressiveness();
+	int actorHpFactor        = actor->getCurrentHP();
+	int enemyHpFactor        = 100 - enemy->getCurrentHP();
+	int combatFactor         = enemy->inCombat() ? 0 : 100;
+	int angleFactor          = (100 * abs(enemy->angleTo(_actorPosition))) / 512;
+	int distanceFactor       = 2 * (50 - MAX(actor->distanceFromActor(_enemyId) / 12.0f, 50.0f));
+
+	if (_rangedAttack) {
+		return
+			angleFactor          * 0.25f +
+			combatFactor         * 0.05f +
+			enemyHpFactor        * 0.20f +
+			actorHpFactor        * 0.10f +
+			aggressivenessFactor * 0.40f;
+	} else {
+		return
+			distanceFactor       * 0.20f +
+			angleFactor          * 0.10f +
+			combatFactor         * 0.10f +
+			enemyHpFactor        * 0.15f +
+			actorHpFactor        * 0.15f +
+			aggressivenessFactor * 0.30f;
+	}
+}
+
+int ActorCombat::calculateCoverRatio() const {
+	if (_coversWaypointCount == 0) {
+		return 0;
+	}
+
+	Actor *actor = _vm->_actors[_actorId];
+	Actor *enemy = _vm->_actors[_enemyId];
+
+	int angleFactor          = 100 - (100 * abs(enemy->angleTo(_actorPosition))) / 512;
+	int actorHpFactor        = 100 - actor->getCurrentHP();
+	int enemyHpFactor        = enemy->getCurrentHP();
+	int aggressivenessFactor = 100 - actor->getCombatAggressiveness();
+	int distanceFactor       = 2 * MAX(actor->distanceFromActor(_enemyId) / 12.0f, 50.0f);
+
+	if (_rangedAttack) {
+		return
+			angleFactor          * 0.40f +
+			enemyHpFactor        * 0.05f +
+			actorHpFactor        * 0.15f +
+			aggressivenessFactor * 0.50f;
+	} else {
+		return
+			distanceFactor       * 0.25f +
+			angleFactor          * 0.20f +
+			enemyHpFactor        * 0.05f +
+			actorHpFactor        * 0.10f +
+			aggressivenessFactor * 0.50f;
+	}
+}
+
+int ActorCombat::calculateFleeRatio() const {
+	if (_fleeWaypointsCount == 0) {
+		return 0;
+	}
+
+	Actor *actor = _vm->_actors[_actorId];
+	Actor *enemy = _vm->_actors[_enemyId];
+
+	int aggressivenessFactor = 100 - actor->getCombatAggressiveness();
+	int actorHpFactor        = 100 - actor->getCurrentHP();
+	int combatFactor         = enemy->inCombat() ? 100 : 0;
+
+	return
+		combatFactor * 0.2f +
+		actorHpFactor * 0.4f +
+		aggressivenessFactor * 0.4f;
+}
+
+bool ActorCombat::findClosestPositionToEnemy(Vector3 &output) const {
+	output = Vector3();
+
+	Vector3 offsets[] = {
+		Vector3(  0.0f, 0.0f, -28.0f),
+		Vector3( 28.0f, 0.0f,   0.0f),
+		Vector3(  0.0f, 0.0f,  28.0f),
+		Vector3(-28.0f, 0.0f,   0.0f)
+	};
+
+	float min = -1.0f;
+
+	for (int i = 0; i < 4; ++i) {
+		Vector3 test = _enemyPosition + offsets[i];
+		float dist = distance(_actorPosition, test);
+		if ( min == -1.0f || dist < min) {
+			if (!_vm->_sceneObjects->existsOnXZ(_actorId, test.x, test.z, true, true) && _vm->_scene->_set->findWalkbox(test.x, test.z) >= 0) {
+				output = test;
+				min = dist;
+			}
+		}
+	}
+
+	return min >= 0.0f;
 }
 
 } // End of namespace BladeRunner
diff --git a/engines/bladerunner/actor_combat.h b/engines/bladerunner/actor_combat.h
index b7ec935..2c6ea8a 100644
--- a/engines/bladerunner/actor_combat.h
+++ b/engines/bladerunner/actor_combat.h
@@ -32,27 +32,27 @@ class BladeRunnerEngine;
 class ActorCombat {
 	BladeRunnerEngine *_vm;
 
-//	int _actorId;
-//	int _combatOn;
-//	int _field2;
-//	int _field3;
-//	int _otherActorId;
-//	int _field5;
-//	int _field6;
-//	int _field7;
-//	int _field8;
-//	int _field9;
-//	int _field10;
-//	int _field11;
-//	int _field12;
-//	int _actorHp;
-//	int _field14;
-//	int _field15;
-	Vector3 actorPosition;
-	Vector3 otherActorPosition;
-//	int _availableCoversCount;
-//	int _availableFleeWaypointsCount;
-//	int _field24;
+	int _actorId;
+	bool _active;
+	int _state;
+	int _rangedAttack;
+	int _enemyId;
+	int _waypointType;
+	int _damage;
+	int _fleeRatio;
+	int _coverRatio;
+	int _actionRatio;
+	int _fleeRatioConst;
+	int _coverRatioConst;
+	int _actionRatioConst;
+	int _actorHp;
+	int _range;
+	int field_3C;
+	Vector3 _actorPosition;
+	Vector3 _enemyPosition;
+	int _coversWaypointCount;
+	int _fleeWaypointsCount;
+	int _fleeingTowards;
 
 public:
 	ActorCombat(BladeRunnerEngine *vm);
@@ -60,10 +60,38 @@ public:
 
 	void setup();
 
+	void combatOn(int actorId, int initialState, bool rangedAttack, int enemyId, int waypointType, int fleeRatio, int coverRatio, int actionRatio, int damage, int range, bool a12);
+	void combatOff();
+
+	void tick();
+
 	void hitAttempt();
 
-	void combatOn(int actorId, int a3, int a4, int otherActorId, int a6, int a7, int a8, int a9, int a10, int a11, int a12);
-	void combatOff();
+private:
+	void reset();
+
+	void cover();
+	void approachToCloseAttack();
+	void approachToRangedAttack();
+	void uncover();
+	void aim();
+	void rangedAttack();
+	void closeAttack();
+	void flee();
+
+	void faceEnemy();
+
+	int getaggressivenessCloseAttack() const;
+	int getaggressivenessRangedAttack() const;
+
+	int getDamageCloseAttack(int min, int max) const;
+	int getDamageRangedAttack(int min, int max) const;
+
+	int calculateActionRatio() const;
+	int calculateCoverRatio() const;
+	int calculateFleeRatio() const;
+
+	bool findClosestPositionToEnemy(Vector3 &output) const;
 };
 
 } // End of namespace BladeRunner
diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp
index ea663b5..43f67ea 100644
--- a/engines/bladerunner/bladerunner.cpp
+++ b/engines/bladerunner/bladerunner.cpp
@@ -224,7 +224,6 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
 
 	_screenEffects = new ScreenEffects(this, 0x8000);
 
-	_combat = new Combat(this);
 
 	// TODO: end credits
 
@@ -265,8 +264,11 @@ bool BladeRunnerEngine::startup(bool hasSavegames) {
 		return false;
 
 	r = _gameInfo->open("GAMEINFO.DAT");
-	if (!r)
+	if (!r) {
 		return false;
+	}
+
+	_combat = new Combat(this);
 
 	// TODO: Create datetime - not used
 
@@ -751,8 +753,10 @@ void BladeRunnerEngine::gameTick() {
 			_sceneScript->playerWalkedIn();
 		}
 		bool inDialogueMenu = _dialogueMenu->isVisible();
-		if (!inDialogueMenu) {
-			// TODO: actors combat-tick
+		if  (!inDialogueMenu) {
+			for (int i = 0; i < (int)_gameInfo->getActorCount(); ++i) {
+				_actors[i]->tickCombat();
+			}
 		}
 
 		// TODO: Gun range announcements
@@ -769,9 +773,6 @@ void BladeRunnerEngine::gameTick() {
 		(void)backgroundChanged;
 		blit(_surfaceBack, _surfaceFront);
 
-		// TODO: remove zbuffer draw
-		// _surfaceFront.copyRectToSurface(_zbuffer->getData(), 1280, 0, 0, 640, 480);
-
 		_overlays->tick();
 
 		if (!inDialogueMenu) {
@@ -1226,7 +1227,7 @@ void BladeRunnerEngine::handleMouseClick3DObject(int objectId, bool buttonDown,
 		}
 		_playerActor->stopWalking(false);
 		_playerActor->faceObject(objectName, false);
-		_playerActor->changeAnimationMode(kAnimationModeCombatShoot, false);
+		_playerActor->changeAnimationMode(kAnimationModeCombatAttack, false);
 		_settings->decreaseAmmo();
 		_audioPlayer->playAud(_gameInfo->getSfxTrack(_combat->getHitSound()), 100, 0, 0, 90, 0);
 
@@ -1267,7 +1268,7 @@ void BladeRunnerEngine::handleMouseClickEmpty(int x, int y, Vector3 &scenePositi
 		} else {
 			_playerActor->faceItem(itemId, false);
 		}
-		_playerActor->changeAnimationMode(kAnimationModeCombatShoot, false);
+		_playerActor->changeAnimationMode(kAnimationModeCombatAttack, false);
 		_settings->decreaseAmmo();
 		_audioPlayer->playAud(_gameInfo->getSfxTrack(_combat->getMissSound()), 100, 0, 0, 90, 0);
 
@@ -1362,7 +1363,7 @@ void BladeRunnerEngine::handleMouseClickItem(int itemId, bool buttonDown) {
 
 		_playerActor->stopWalking(false);
 		_playerActor->faceItem(itemId, false);
-		_playerActor->changeAnimationMode(kAnimationModeCombatShoot, false);
+		_playerActor->changeAnimationMode(kAnimationModeCombatAttack, false);
 		_settings->decreaseAmmo();
 		_audioPlayer->playAud(_gameInfo->getSfxTrack(_combat->getHitSound()), 100, 0, 0, 90, 0);
 
@@ -1422,18 +1423,17 @@ void BladeRunnerEngine::handleMouseClickActor(int actorId, bool mainButton, bool
 			}
 		}
 	} else {
-		if (!_combat->isActive() || actorId == kActorMcCoy || !_actors[actorId]->isTarget() || _actors[actorId]->isRetired() /*|| _mouse->isRandomized()*/) {
+		Actor *actor = _actors[actorId];
+
+		if (!_combat->isActive() || actorId == kActorMcCoy || !actor->isTarget() || actor->isRetired() /*|| _mouse->isRandomized()*/) {
 			return;
 		}
 		_playerActor->stopWalking(false);
 		_playerActor->faceActor(actorId, false);
-		_playerActor->changeAnimationMode(kAnimationModeCombatShoot, false);
+		_playerActor->changeAnimationMode(kAnimationModeCombatAttack, false);
 		_settings->decreaseAmmo();
 
-		float targetX = _actors[actorId]->getX();
-		float targetZ = _actors[actorId]->getZ();
-
-		bool missed = _playerActor->isObstacleBetween(targetX, targetZ);
+		bool missed = _playerActor->isObstacleBetween(actor->getXYZ());
 
 		_audioPlayer->playAud(_gameInfo->getSfxTrack(missed ? _combat->getMissSound() : _combat->getHitSound()), 100, 0, 0, 90, 0);
 
diff --git a/engines/bladerunner/combat.cpp b/engines/bladerunner/combat.cpp
index c371f7b..ef7a589 100644
--- a/engines/bladerunner/combat.cpp
+++ b/engines/bladerunner/combat.cpp
@@ -22,10 +22,13 @@
 
 #include "bladerunner/combat.h"
 
-
 #include "bladerunner/actor.h"
+#include "bladerunner/audio_speech.h"
 #include "bladerunner/bladerunner.h"
 #include "bladerunner/game_constants.h"
+#include "bladerunner/game_info.h"
+#include "bladerunner/movement_track.h"
+#include "bladerunner/scene_objects.h"
 #include "bladerunner/settings.h"
 
 namespace BladeRunner {
@@ -33,6 +36,9 @@ namespace BladeRunner {
 Combat::Combat(BladeRunnerEngine *vm) {
 	_vm = vm;
 
+	_coverWaypoints.resize(_vm->_gameInfo->getCoverWaypointCount());
+	_fleeWaypoints.resize(_vm->_gameInfo->getFleeWaypointCount());
+
 	reset();
 }
 
@@ -55,7 +61,7 @@ void Combat::reset() {
 
 void Combat::activate() {
 	if(_enabled) {
-		_vm->_playerActor->combatModeOn(-1, -1, -1, -1, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, _vm->_combat->_ammoDamage[_vm->_settings->getAmmoType()], 0, 0);
+		_vm->_playerActor->combatModeOn(-1, true, -1, -1, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, _vm->_combat->_ammoDamage[_vm->_settings->getAmmoType()], 0, false);
 		_active = true;
 	}
 }
@@ -97,16 +103,105 @@ void Combat::setMissSound(int ammoType, int column, int soundId) {
 	_missSoundId[ammoType * 3 + column] = soundId;
 }
 
-int Combat::getHitSound() {
+int Combat::getHitSound() const {
 	return _hitSoundId[3 * _vm->_settings->getAmmoType() + _vm->_rnd.getRandomNumber(2)];
 }
 
-int Combat::getMissSound() {
+int Combat::getMissSound() const {
 	return _hitSoundId[3 * _vm->_settings->getAmmoType() + _vm->_rnd.getRandomNumber(2)];
 }
 
 void Combat::shoot(int actorId, Vector3 &to, int screenX) {
+	Actor *actor = _vm->_actors[actorId];
+
+	if (actor->isRetired()) {
+		return;
+	}
+
+	int sentenceId = -1;
+
+	/*
+	Distance from center as a percentage:
+	                            screenX - abs(right + left) / 2
+	distanceFromCenter = 100 *  -------------------------------
+	                                 abs(right - left) / 2
+	*/
+	Common::Rect *rect = actor->getScreenRectangle();
+	int distanceFromCenter = CLIP(100 * (screenX - abs((rect->right + rect->left) / 2)) / abs((rect->right - rect->left) / 2), 0, 100);
+
+	int damage = (100 - distanceFromCenter) * _ammoDamage[_vm->_settings->getAmmoType()] / 100;
 
+	int hp = MAX(actor->getCurrentHP() - damage, 0);
+
+	actor->setCurrentHP(hp);
+
+	bool setDamageAnimation = true;
+	if (actor->isWalking() == 1 && !actor->getFlagDamageAnimIfMoving()) {
+		setDamageAnimation = false;
+	}
+	if (actor->_movementTrack->hasNext() && !actor->_movementTrack->isPaused()) {
+		setDamageAnimation = false;
+	}
+	if (setDamageAnimation) {
+		if (actor->isWalking()) {
+			actor->stopWalking(false);
+		}
+		if (actor->getAnimationMode() != kAnimationModeHit && actor->getAnimationMode() != kAnimationModeCombatHit) {
+			actor->changeAnimationMode(kAnimationModeHit, false);
+			sentenceId = _vm->_rnd.getRandomNumberRng(0, 1) ? 9000 : 9005;
+		}
+	}
+
+	if (hp <= 0) {
+		actor->setTarget(false);
+		if (actor->inCombat()) {
+			actor->combatModeOff();
+		}
+		actor->stopWalking(false);
+		actor->changeAnimationMode(48, false);
+		actor->retire(true, 72, 36, kActorMcCoy);
+		actor->setAtXYZ(actor->getXYZ(), actor->getFacing(), true, false, true);
+		_vm->_sceneObjects->setRetired(actorId + kSceneObjectOffsetActors, true);
+		sentenceId = 9020;
+	}
+
+	if (sentenceId >= 0 && actor->inCombat()) {
+		_vm->_audioSpeech->playSpeechLine(actorId, sentenceId, 75, 0, 99);
+	}
+}
+
+int Combat::findFleeWaypoint(int setId, int enemyId, const Vector3& position) const {
+	float min = -1.0f;
+	int result = -1;
+	for (int i = 0; i < (int)_fleeWaypoints.size(); ++i) {
+		if (setId == _fleeWaypoints[i].setId) {
+			float dist = distance(position, _fleeWaypoints[i].position);
+			if (result == -1 || dist < min) {
+				result = i;
+				min = dist;
+			}
+		}
+	}
+	return result;
+}
+
+int Combat::findCoverWaypoint(int waypointType, int actorId, int enemyId) const {
+	Actor *actor = _vm->_actors[actorId];
+	Actor *enemy = _vm->_actors[enemyId];
+	int result = -1;
+	float min = -1.0f;
+	for (int i = 0; i < (int)_coverWaypoints.size(); ++i) {
+		if (waypointType == _coverWaypoints[i].type && actor->getSetId() == _coverWaypoints[i].setId) {
+			if (_vm->_sceneObjects->isObstacleBetween(_coverWaypoints[i].position, enemy->getXYZ(), enemyId)) {
+				float dist = distance(_coverWaypoints[i].position, actor->getXYZ());
+				if (result == -1 || dist < min) {
+					result = i;
+					min = dist;
+				}
+			}
+		}
+	}
+	return result;
 }
 
 } // End of namespace BladeRunner
diff --git a/engines/bladerunner/combat.h b/engines/bladerunner/combat.h
index 21989da..ab289cc 100644
--- a/engines/bladerunner/combat.h
+++ b/engines/bladerunner/combat.h
@@ -23,9 +23,11 @@
 #ifndef BLADERUNNER_COMBAT_H
 #define BLADERUNNER_COMBAT_H
 
-namespace BladeRunner {
+#include "bladerunner/vector.h"
+
+#include "common/array.h"
 
-class Vector3;
+namespace BladeRunner {
 
 class BladeRunnerEngine;
 
@@ -44,6 +46,24 @@ class Combat {
 public:
 	int _ammoDamage[3];
 
+	struct CoverWaypoint {
+		int      type;
+		int      setId;
+		int      sceneId;
+		Vector3  position;
+	};
+
+	struct FleeWaypoint {
+		int     type;
+		int     setId;
+		int     sceneId;
+		Vector3 position;
+		int     field7;
+	};
+
+	Common::Array<CoverWaypoint> _coverWaypoints;
+	Common::Array<FleeWaypoint>  _fleeWaypoints;
+
 public:
 	Combat(BladeRunnerEngine *vm);
 	~Combat();
@@ -60,10 +80,13 @@ public:
 
 	void setHitSound(int ammoType, int column, int soundId);
 	void setMissSound(int ammoType, int column, int soundId);
-	int getHitSound();
-	int getMissSound();
+	int getHitSound() const;
+	int getMissSound() const;
 
 	void shoot(int actorId, Vector3 &to, int screenX);
+
+	int findFleeWaypoint(int setId, int enemyId, const Vector3& position) const;
+	int findCoverWaypoint(int waypointType, int actorId, int enemyId) const;
 };
 
 } // End of namespace BladeRunner
diff --git a/engines/bladerunner/debugger.cpp b/engines/bladerunner/debugger.cpp
index 5539082..2c9b7e6 100644
--- a/engines/bladerunner/debugger.cpp
+++ b/engines/bladerunner/debugger.cpp
@@ -25,6 +25,7 @@
 #include "bladerunner/actor.h"
 #include "bladerunner/bladerunner.h"
 #include "bladerunner/boundingbox.h"
+#include "bladerunner/combat.h"
 #include "bladerunner/font.h"
 #include "bladerunner/game_constants.h"
 #include "bladerunner/game_flags.h"
@@ -271,8 +272,7 @@ bool Debugger::cmdPosition(int argc, const char **argv) {
 			return true;
 		}
 
-		Vector3 position;
-		otherActor->getXYZ(&position.x, &position.y, &position.z);
+		Vector3 position = otherActor->getXYZ();
 		actor->setSetId(otherActor->getSetId());
 		actor->setAtXYZ(position, otherActor->getFacing());
 		return true;
@@ -481,12 +481,13 @@ void Debugger::drawSceneObjects() {
 	}
 
 	//draw waypoints
-	for(int i = 0; i < _vm->_waypoints->_count; i++) {
+	for (int i = 0; i < _vm->_waypoints->_count; i++) {
 		Waypoints::Waypoint *waypoint = &_vm->_waypoints->_waypoints[i];
-		if(waypoint->setId != _vm->_scene->getSetId())
+		if(waypoint->setId != _vm->_scene->getSetId()) {
 			continue;
+		}
 		Vector3 pos = waypoint->position;
-		Vector3 size = Vector3(5.0f, 5.0f, 5.0f);
+		Vector3 size = Vector3(3.0f, 3.0f, 3.0f);
 		int color = 0x7FFF; // 11111 11111 11111
 		drawBBox(pos - size, pos + size, _vm->_view, &_vm->_surfaceFront, color);
 		Vector3 spos = _vm->_view->calculateScreenPosition(pos);
@@ -495,6 +496,38 @@ void Debugger::drawSceneObjects() {
 		_vm->_mainFont->drawColor(waypointText, _vm->_surfaceFront, spos.x, spos.y, color);
 	}
 
+	//draw combat cover waypoints
+	for (int i = 0; i < (int)_vm->_combat->_coverWaypoints.size(); i++) {
+		Combat::CoverWaypoint *cover = &_vm->_combat->_coverWaypoints[i];
+		if (cover->setId != _vm->_scene->getSetId()) {
+			continue;
+		}
+		Vector3 pos = cover->position;
+		Vector3 size = Vector3(3.0f, 3.0f, 3.0f);
+		int color = 0x7C1F; // 11111 00000 11111
+		drawBBox(pos - size, pos + size, _vm->_view, &_vm->_surfaceFront, color);
+		Vector3 spos = _vm->_view->calculateScreenPosition(pos);
+		char coverText[40];
+		sprintf(coverText, "cover %i", i);
+		_vm->_mainFont->drawColor(coverText, _vm->_surfaceFront, spos.x, spos.y, color);
+	}
+
+	//draw combat flee waypoints
+	for (int i = 0; i < (int)_vm->_combat->_fleeWaypoints.size(); i++) {
+		Combat::FleeWaypoint *flee = &_vm->_combat->_fleeWaypoints[i];
+		if (flee->setId != _vm->_scene->getSetId()) {
+			continue;
+		}
+		Vector3 pos = flee->position;
+		Vector3 size = Vector3(3.0f, 3.0f, 3.0f);
+		int color = 0x03FF; // 00000 11111 11111
+		drawBBox(pos - size, pos + size, _vm->_view, &_vm->_surfaceFront, color);
+		Vector3 spos = _vm->_view->calculateScreenPosition(pos);
+		char fleeText[40];
+		sprintf(fleeText, "flee %i", i);
+		_vm->_mainFont->drawColor(fleeText, _vm->_surfaceFront, spos.x, spos.y, color);
+	}
+
 #if 0
 	//draw aesc
 	for (uint i = 0; i < _screenEffects->_entries.size(); i++) {
diff --git a/engines/bladerunner/game_constants.h b/engines/bladerunner/game_constants.h
index af4728a..4aa72c1 100644
--- a/engines/bladerunner/game_constants.h
+++ b/engines/bladerunner/game_constants.h
@@ -597,14 +597,17 @@ enum AnimationModes {
 	kAnimationModeTalk = 3,
 	kAnimationModeCombatIdle = 4,
 	kAnimationModeCombatAim = 5,
-	kAnimationModeCombatShoot = 6,
+	kAnimationModeCombatAttack = 6,
 	kAnimationModeCombatWalk = 7,
 	kAnimationModeCombatRun = 8,
+	kAnimationModeHit = 21,
+	kAnimationModeCombatHit = 22,
 	kAnimationModeWalkUp = 44,
 	kAnimationModeWalkDown = 45,
 	kAnimationModeCombatWalkUp = 46,
 	kAnimationModeCombatWalkDown = 47,
-	kAnimationModeDie = 48, // TODO: check
+	kAnimationModeDie = 48,
+	kAnimationModeCombatDie = 49,
 	kAnimationModeFeeding = 52,
 	kAnimationModeSit = 53, // TODO: check
 	kAnimationModeClimbUp = 64,
@@ -871,6 +874,18 @@ enum SceneObjectOffset {
 	kSceneObjectOffsetObjects = 198
 };
 
+enum ActorCombatStates {
+	kActorCombatStateIdle = 0,
+	kActorCombatStateCover = 1,
+	kActorCombatStateApproachCloseAttack = 2,
+	kActorCombatStateUncover = 3,
+	kActorCombatStateAim = 4,
+	kActorCombatStateRangedAttack = 5,
+	kActorCombatStateCloseAttack = 6,
+	kActorCombatStateFlee = 7,
+	kActorCombatStateApproachRangedAttack = 8
+};
+
 } // End of namespace BladeRunner
 
 #endif
diff --git a/engines/bladerunner/matrix.h b/engines/bladerunner/matrix.h
index 5343eb6..d5922b4 100644
--- a/engines/bladerunner/matrix.h
+++ b/engines/bladerunner/matrix.h
@@ -57,8 +57,8 @@ inline Matrix3x2 operator*(const Matrix3x2 &a, const Matrix3x2 &b) {
 inline Matrix3x2 operator+(const Matrix3x2 &a, Vector2 b) {
 	Matrix3x2 t(a);
 
-	t(0,2) += b.x;
-	t(1,2) += b.y;
+	t(0, 2) += b.x;
+	t(1, 2) += b.y;
 
 	return t;
 }
diff --git a/engines/bladerunner/scene_objects.cpp b/engines/bladerunner/scene_objects.cpp
index 87320a3..148cde8 100644
--- a/engines/bladerunner/scene_objects.cpp
+++ b/engines/bladerunner/scene_objects.cpp
@@ -255,7 +255,7 @@ bool SceneObjects::isBetween(float sourceX, float sourceZ, float targetX, float
 	    || lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX1, objectZ2), Vector2(objectX1, objectZ1), &intersection);
 }
 
-bool SceneObjects::isObstacleBetween(float sourceX, float sourceZ, float targetX, float targetZ, float altitude, int exceptSceneObjectId) const {
+bool SceneObjects::isObstacleBetween(const Vector3 &source, const Vector3 &target, int exceptSceneObjectId) const {
 	for (int i = 0; i < _count; ++i) {
 		const SceneObject *sceneObject = &_sceneObjects[_sceneObjectsSortedByDistance[i]];
 
@@ -264,9 +264,9 @@ bool SceneObjects::isObstacleBetween(float sourceX, float sourceZ, float targetX
 		}
 
 		float objectX1, objectY1, objectZ1, objectX2, objectY2, objectZ2;
-		_sceneObjects[i].boundingBox->getXYZ(&objectX1, &objectY1, &objectZ1, &objectX2, &objectY2, &objectZ2);
+		sceneObject->boundingBox->getXYZ(&objectX1, &objectY1, &objectZ1, &objectX2, &objectY2, &objectZ2);
 
-		if (84.0f <= objectY1 - altitude || 72.0f >= objectY2 - altitude) {
+		if (84.0f <= objectY1 - source.y || 72.0f >= objectY2 - source.y) {
 			continue;
 		}
 
@@ -279,10 +279,10 @@ bool SceneObjects::isObstacleBetween(float sourceX, float sourceZ, float targetX
 		objectZ2 = objectZ2 - zAdjustement;
 
 		Vector2 intersection;
-		if (lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX1, objectZ1), Vector2(objectX2, objectZ1), &intersection)
-		 || lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX2, objectZ1), Vector2(objectX2, objectZ2), &intersection)
-		 || lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX2, objectZ2), Vector2(objectX1, objectZ2), &intersection)
-		 || lineIntersection(Vector2(sourceX, sourceZ), Vector2(targetX, targetZ), Vector2(objectX1, objectZ2), Vector2(objectX1, objectZ1), &intersection)) {
+		if (lineIntersection(Vector2(source.x, source.z), Vector2(target.x, target.z), Vector2(objectX1, objectZ1), Vector2(objectX2, objectZ1), &intersection)
+		 || lineIntersection(Vector2(source.x, source.z), Vector2(target.x, target.z), Vector2(objectX2, objectZ1), Vector2(objectX2, objectZ2), &intersection)
+		 || lineIntersection(Vector2(source.x, source.z), Vector2(target.x, target.z), Vector2(objectX2, objectZ2), Vector2(objectX1, objectZ2), &intersection)
+		 || lineIntersection(Vector2(source.x, source.z), Vector2(target.x, target.z), Vector2(objectX1, objectZ2), Vector2(objectX1, objectZ1), &intersection)) {
 			return true;
 		}
 	}
diff --git a/engines/bladerunner/scene_objects.h b/engines/bladerunner/scene_objects.h
index dbd61b6..de31eae 100644
--- a/engines/bladerunner/scene_objects.h
+++ b/engines/bladerunner/scene_objects.h
@@ -80,7 +80,7 @@ public:
 	void setMoving(int sceneObjectId, bool isMoving);
 	void setRetired(int sceneObjectId, bool isRetired);
 	bool isBetween(float sourceX, float sourceZ, float targetX, float targetZ, int sceneObjectId) const;
-	bool isObstacleBetween(float sourceX, float sourceZ, float targetX, float targetZ, float altitude, int exceptSceneObjectId) const;
+	bool isObstacleBetween(const Vector3 &source, const Vector3 &target, int exceptSceneObjectId) const;
 	void setIsClickable(int sceneObjectId, bool isClickable);
 	void setIsObstacle(int sceneObjectId, bool isObstacle);
 	void setIsTarget(int sceneObjectId, bool isTarget);
diff --git a/engines/bladerunner/script/ai/clovis.cpp b/engines/bladerunner/script/ai/clovis.cpp
index 9c8976e..e55fdb9 100644
--- a/engines/bladerunner/script/ai/clovis.cpp
+++ b/engines/bladerunner/script/ai/clovis.cpp
@@ -440,22 +440,22 @@ bool AIScriptClovis::GoalChanged(int currentGoalNumber, int newGoalNumber) {
 			Global_Variable_Decrement(51, 1);
 		}
 		if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_In_Set(kActorDektora, kSetKP07)) {
-			Non_Player_Actor_Combat_Mode_On(kActorDektora, 0, 0, 0, 19, 4, 7, 8, 0, 0, 100, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorDektora, kActorCombatStateIdle, false, kActorMcCoy, 19, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 10, 300, false);
 		}
 		if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_In_Set(kActorZuben, kSetKP07)) {
-			Non_Player_Actor_Combat_Mode_On(kActorZuben, 0, 0, 0, 19, 4, 7, 8, 0, 0, 100, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorZuben, kActorCombatStateIdle, false, kActorMcCoy, 19, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 10, 300, false);
 		}
 		if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_In_Set(kActorSadik, kSetKP07)) {
-			Non_Player_Actor_Combat_Mode_On(kActorSadik, 0, 1, 0, 19, 4, 7, 8, 0, 0, 100, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorSadik, kActorCombatStateIdle, true, kActorMcCoy, 19, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 10, 300, false);
 		}
 		if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_In_Set(kActorIzo, kSetKP07)) {
-			Non_Player_Actor_Combat_Mode_On(kActorIzo, 0, 0, 0, 19, 4, 7, 8, 0, 0, 100, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorIzo, kActorCombatStateIdle, false, kActorMcCoy, 19, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 10, 300, false);
 		}
 		if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_In_Set(kActorGordo, kSetKP07)) {
-			Non_Player_Actor_Combat_Mode_On(kActorGordo, 0, 1, 0, 19, 4, 7, 8, 0, 0, 100, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorGordo, kActorCombatStateIdle, true, kActorMcCoy, 19, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 10, 300, false);
 		}
 		if (Global_Variable_Query(kVariableChapter) == 5 && Actor_Query_In_Set(kActorClovis, kSetKP07)) {
-			Non_Player_Actor_Combat_Mode_On(kActorClovis, 0, 0, 0, 19, 4, 7, 8, 0, 0, 100, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorClovis, kActorCombatStateIdle, false, kActorMcCoy, 19, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 10, 300, false);
 		}
 		return true;
 
diff --git a/engines/bladerunner/script/ai/dektora.cpp b/engines/bladerunner/script/ai/dektora.cpp
index 905c3d1..28bdf3c 100644
--- a/engines/bladerunner/script/ai/dektora.cpp
+++ b/engines/bladerunner/script/ai/dektora.cpp
@@ -280,7 +280,7 @@ void AIScriptDektora::Retired(int byActorId) {
 	}
 
 	if (byActorId == kActorSteele && Actor_Query_In_Set(kActorSteele, kSetHF06) && Actor_Query_In_Set(kActorMcCoy, kSetHF06)) {
-		Non_Player_Actor_Combat_Mode_On(kActorSteele, 3, 1, 0, 15, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+		Non_Player_Actor_Combat_Mode_On(kActorSteele, kActorCombatStateUncover, true, kActorMcCoy, 15, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
 	}
 
 	if (Actor_Query_In_Set(kActorDektora, kSetKP07)) {
@@ -290,8 +290,8 @@ void AIScriptDektora::Retired(int byActorId) {
 		if (!Global_Variable_Query(51)) {
 			Player_Loses_Control();
 			Delay(2000);
-			Player_Set_Combat_Mode(0);
-			Loop_Actor_Walk_To_XYZ(0, -12.0, -41.580002, 72.0, 0, 1, 0, 0);
+			Player_Set_Combat_Mode(false);
+			Loop_Actor_Walk_To_XYZ(kActorMcCoy, -12.0f, -41.58f, 72.0f, 0, true, false, 0);
 			Ambient_Sounds_Remove_All_Non_Looping_Sounds(1);
 			Ambient_Sounds_Remove_All_Looping_Sounds(1);
 			Game_Flag_Set(579);
@@ -1095,11 +1095,11 @@ void AIScriptDektora::checkCombat() {
 			&& Global_Variable_Query(kVariableChapter) == 5
 			&& Actor_Query_Goal_Number(kActorDektora) != 450) {
 		if (Global_Variable_Query(kVariableAffectionTowards) == 2) {
-			Global_Variable_Set(45, 0);
+			Global_Variable_Set(kVariableAffectionTowards, 0);
 		}
 
 		Actor_Set_Goal_Number(kActorDektora, 450);
-		Non_Player_Actor_Combat_Mode_On(kActorDektora, 0, 0, kActorMcCoy, 4, 4, 7, 8, 0, -1, -1, 20, 300, 0);
+		Non_Player_Actor_Combat_Mode_On(kActorDektora, kActorCombatStateIdle, false, kActorMcCoy, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, -1, -1, 20, 300, false);
 	}
 }
 
diff --git a/engines/bladerunner/script/ai/gaff.cpp b/engines/bladerunner/script/ai/gaff.cpp
index c26f0d9..c5e629c 100644
--- a/engines/bladerunner/script/ai/gaff.cpp
+++ b/engines/bladerunner/script/ai/gaff.cpp
@@ -287,7 +287,7 @@ bool AIScriptGaff::GoalChanged(int currentGoalNumber, int newGoalNumber) {
 		return true;
 	case 303:
 		Actor_Face_Actor(kActorGaff, kActorMcCoy, 1);
-		Actor_Change_Animation_Mode(kActorGaff, kAnimationModeCombatShoot);
+		Actor_Change_Animation_Mode(kActorGaff, kAnimationModeCombatAttack);
 		Sound_Play(27, 100, 0, 0, 50);
 		Actor_Change_Animation_Mode(kActorMcCoy, 48);
 		Actor_Retired_Here(kActorMcCoy, 12, 12, 1, -1);
diff --git a/engines/bladerunner/script/ai/gordo.cpp b/engines/bladerunner/script/ai/gordo.cpp
index fd64112..c444971 100644
--- a/engines/bladerunner/script/ai/gordo.cpp
+++ b/engines/bladerunner/script/ai/gordo.cpp
@@ -1157,7 +1157,7 @@ bool AIScriptGordo::ChangeAnimationMode(int mode) {
 			break;
 		}
 		break;
-	case kAnimationModeCombatShoot:
+	case kAnimationModeCombatAttack:
 		_animationState = 18;
 		_animationFrame = 0;
 		break;
diff --git a/engines/bladerunner/script/ai/guzza.cpp b/engines/bladerunner/script/ai/guzza.cpp
index 0f99fa8..5a44595 100644
--- a/engines/bladerunner/script/ai/guzza.cpp
+++ b/engines/bladerunner/script/ai/guzza.cpp
@@ -728,7 +728,7 @@ bool AIScriptGuzza::ChangeAnimationMode(int mode) {
 			_animationFrame = 0;
 		}
 		break;
-	case kAnimationModeCombatShoot:
+	case kAnimationModeCombatAttack:
 		_animationState = 31;
 		_animationFrame = 0;
 		break;
diff --git a/engines/bladerunner/script/ai/leon.cpp b/engines/bladerunner/script/ai/leon.cpp
index fad9da3..fdcb538 100644
--- a/engines/bladerunner/script/ai/leon.cpp
+++ b/engines/bladerunner/script/ai/leon.cpp
@@ -386,7 +386,7 @@ bool AIScriptLeon::ChangeAnimationMode(int mode) {
 		_animationFrame = 0;
 		var_45EDAC = 0;
 		break;
-	case kAnimationModeCombatShoot:
+	case kAnimationModeCombatAttack:
 		_animationState = 10;
 		_animationFrame = 0;
 		break;
diff --git a/engines/bladerunner/script/ai/lucy.cpp b/engines/bladerunner/script/ai/lucy.cpp
index aebeac7..464f228 100644
--- a/engines/bladerunner/script/ai/lucy.cpp
+++ b/engines/bladerunner/script/ai/lucy.cpp
@@ -227,7 +227,7 @@ void AIScriptLucy::Retired(int byActorId) {
 	if ((byActorId == kActorSteele || byActorId == kActorMcCoy)
 			&& Actor_Query_In_Set(kActorSteele, kSetHF06)
 			&& Actor_Query_In_Set(kActorMcCoy, kSetHF06)) {
-		Non_Player_Actor_Combat_Mode_On(kActorSteele, 3, 1, 0, 15, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+		Non_Player_Actor_Combat_Mode_On(kActorSteele, kActorCombatStateUncover, true, kActorMcCoy, 15, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
 	}
 	if (Query_Difficulty_Level() && byActorId == kActorMcCoy && Game_Flag_Query(46)) {
 		Global_Variable_Increment(2, 200);
@@ -861,10 +861,10 @@ void AIScriptLucy::checkCombat() {
 			&& Global_Variable_Query(kVariableChapter) == 5
 			&& Actor_Query_Goal_Number(kActorLucy) != 450) {
 		if (Global_Variable_Query(kVariableAffectionTowards) == 3) {
-			Global_Variable_Set(45, 0);
+			Global_Variable_Set(kVariableAffectionTowards, 0);
 		}
 		Actor_Set_Goal_Number(kActorLucy, 450);
-		Non_Player_Actor_Combat_Mode_On(kActorLucy, 0, 0, 0, 4, 0, 1, 2, -1, 0, 0, 10, 300, 0);
+		Non_Player_Actor_Combat_Mode_On(kActorLucy, kActorCombatStateIdle, false, kActorMcCoy, 4, kAnimationModeIdle, kAnimationModeWalk, kAnimationModeRun, -1, 0, 0, 10, 300, false);
 	}
 }
 
diff --git a/engines/bladerunner/script/ai/mccoy.cpp b/engines/bladerunner/script/ai/mccoy.cpp
index 554de0c..56b54ac 100644
--- a/engines/bladerunner/script/ai/mccoy.cpp
+++ b/engines/bladerunner/script/ai/mccoy.cpp
@@ -242,22 +242,22 @@ bool AIScriptMcCoy::ShotAtAndHit() {
 void AIScriptMcCoy::Retired(int byActorId) {
 	if (byActorId == kActorSteele && Actor_Query_In_Set(kActorSteele, kSetHF06)) {
 		if (Actor_Query_In_Set(kActorDektora, kSetHF06) && Actor_Query_Goal_Number(kActorDektora) != 599) {
-			Non_Player_Actor_Combat_Mode_On(kActorSteele, 3, 1, kActorDektora, 15, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorSteele, kActorCombatStateUncover, true, kActorDektora, 15, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
 		} else if (Actor_Query_In_Set(kActorLucy, kSetHF06) && Actor_Query_Goal_Number(kActorLucy) != 599) {
-			Non_Player_Actor_Combat_Mode_On(kActorSteele, 3, 1, kActorLucy, 15, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorSteele, kActorCombatStateUncover, true, kActorLucy, 15, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
 		}
 	}
 	if (Actor_Query_In_Set(kActorMcCoy, kSetHF05) && Actor_Query_In_Set(kActorOfficerLeary, kSetHF05) && Actor_Query_In_Set(kActorDektora, kSetHF05) && Actor_Query_Goal_Number(kActorDektora) != 599) {
-		Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, 3, 1, kActorDektora, 4, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+		Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, kActorCombatStateUncover, true, kActorDektora, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
 	}
 	if (Actor_Query_In_Set(kActorMcCoy, kSetHF05) && Actor_Query_In_Set(kActorOfficerGrayford, kSetHF05) && Actor_Query_In_Set(kActorDektora, kSetHF05) && Actor_Query_Goal_Number(kActorDektora) != 599) {
-		Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, 3, 1, kActorDektora, 4, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+		Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateUncover, true, kActorDektora, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
 	}
 	if (Actor_Query_In_Set(kActorMcCoy, kSetHF05) && Actor_Query_In_Set(kActorOfficerLeary, kSetHF05) && Actor_Query_In_Set(kActorLucy, kSetHF05) && Actor_Query_Goal_Number(kActorLucy) != 599) {
-		Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, 3, 1, kActorLucy, 4, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+		Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, kActorCombatStateUncover, true, kActorLucy, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
 	}
 	if (Actor_Query_In_Set(kActorMcCoy, kSetHF05) && Actor_Query_In_Set(kActorOfficerGrayford, kSetHF05) && Actor_Query_In_Set(kActorLucy, kSetHF05) && Actor_Query_Goal_Number(kActorLucy) != 599) {
-		Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, 3, 1, kActorLucy, 4, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+		Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateUncover, true, kActorLucy, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
 	}
 }
 
@@ -307,7 +307,7 @@ bool AIScriptMcCoy::GoalChanged(int currentGoalNumber, int newGoalNumber) {
 		return true;
 	case 230:
 		dword_45A0FC = Actor_Query_Goal_Number(kActorSteele) == 215;
-		Actor_Change_Animation_Mode(kActorMcCoy, kAnimationModeCombatShoot);
+		Actor_Change_Animation_Mode(kActorMcCoy, kAnimationModeCombatAttack);
 		return true;
 	case 220:
 		Actor_Change_Animation_Mode(kActorMcCoy, 75);
@@ -412,7 +412,7 @@ bool AIScriptMcCoy::GoalChanged(int currentGoalNumber, int newGoalNumber) {
 	case 400:
 		Actor_Set_Health(kActorMcCoy, 50, 50);
 		Game_Flag_Set(373);
-		v5 = Global_Variable_Query(45);
+		v5 = Global_Variable_Query(kVariableAffectionTowards);
 		if (v5 == 1) {
 			Actor_Modify_Friendliness_To_Other(kActorSteele, kActorMcCoy, 3);
 		} else if (v5 == 2) {
@@ -428,14 +428,14 @@ bool AIScriptMcCoy::GoalChanged(int currentGoalNumber, int newGoalNumber) {
 		if (Actor_Query_Friendliness_To_Other(kActorSteele, kActorMcCoy) < Actor_Query_Friendliness_To_Other(kActorClovis, kActorMcCoy)) {
 			Game_Flag_Set(653);
 		}
-		v7 = Global_Variable_Query(45);
+		v7 = Global_Variable_Query(kVariableAffectionTowards);
 		if (v7 == 1) {
 			if (Game_Flag_Query(653)) {
-				Global_Variable_Set(45, 0);
+				Global_Variable_Set(kVariableAffectionTowards, 0);
 			}
 		} else if (v7 == 2 || v7 == 3) {
 			if (!Game_Flag_Query(653)) {
-				Global_Variable_Set(45, 0);
+				Global_Variable_Set(kVariableAffectionTowards, 0);
 			}
 		}
 		if (!Game_Flag_Query(653)) {
@@ -1382,7 +1382,7 @@ bool AIScriptMcCoy::ChangeAnimationMode(int mode) {
 			break;
 		}
 		break;
-	case kAnimationModeCombatShoot:
+	case kAnimationModeCombatAttack:
 		_animationState = 21;
 		_animationFrame = 0;
 		break;
diff --git a/engines/bladerunner/script/ai/mutant1.cpp b/engines/bladerunner/script/ai/mutant1.cpp
index 9ecaf9d..eb1c056 100644
--- a/engines/bladerunner/script/ai/mutant1.cpp
+++ b/engines/bladerunner/script/ai/mutant1.cpp
@@ -83,7 +83,7 @@ bool AIScriptMutant1::Update() {
 
 	case 410:
 		if (Actor_Query_Which_Set_In(kActorMutant1) != Player_Query_Current_Set()) {
-			Non_Player_Actor_Combat_Mode_Off(70);
+			Non_Player_Actor_Combat_Mode_Off(kActorMutant1);
 			Actor_Set_Goal_Number(kActorMutant1, 403);
 		}
 		break;
@@ -326,28 +326,23 @@ bool AIScriptMutant1::GoalChanged(int currentGoalNumber, int newGoalNumber) {
 	case 410:
 		switch (Actor_Query_Which_Set_In(kActorMutant1)) {
 		case kSetUG01:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant1, 0, 0, 0, 11, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorMutant1, kActorCombatStateIdle, false, kActorMcCoy, 11, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
 			break;
 
 		case kSetUG04:
 		case kSetUG05:
 		case kSetUG06:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant1, 0, 0, 0, 10, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorMutant1, kActorCombatStateIdle, false, kActorMcCoy, 10, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
 			break;
 
 		case kSetUG07:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant1, 0, 0, 0, 12, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorMutant1, kActorCombatStateIdle, false, kActorMcCoy, 12, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
 			break;
 
 		case kSetUG10:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant1, 0, 0, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
-			break;
-
 		case kSetUG12:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant1, 0, 0, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
-			break;
 		case kSetUG14:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant1, 0, 0, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorMutant1, kActorCombatStateIdle, false, kActorMcCoy, 14, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
 			break;
 		}
 		return true;
diff --git a/engines/bladerunner/script/ai/mutant2.cpp b/engines/bladerunner/script/ai/mutant2.cpp
index 6a51c71..6317311 100644
--- a/engines/bladerunner/script/ai/mutant2.cpp
+++ b/engines/bladerunner/script/ai/mutant2.cpp
@@ -305,25 +305,19 @@ bool AIScriptMutant2::GoalChanged(int currentGoalNumber, int newGoalNumber) {
 	case 410:
 		switch (Actor_Query_Which_Set_In(kActorMutant2)) {
 		case kSetUG01:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant2, 0, 0, 0, 11, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorMutant2, kActorCombatStateIdle, false, kActorMcCoy, 11, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
 			break;
 
 		case kSetUG04:
 		case kSetUG05:
 		case kSetUG06:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant2, 0, 0, 0, 10, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorMutant2, kActorCombatStateIdle, false, kActorMcCoy, 10, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
 			break;
 
 		case kSetUG10:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant2, 0, 0, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
-			break;
-
 		case kSetUG12:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant2, 0, 0, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
-			break;
-
 		case kSetUG14:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant2, 0, 0, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorMutant2, kActorCombatStateIdle, false, kActorMcCoy, 14, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
 			break;
 		}
 		return true;
diff --git a/engines/bladerunner/script/ai/mutant3.cpp b/engines/bladerunner/script/ai/mutant3.cpp
index 76a9a0e..db161d8 100644
--- a/engines/bladerunner/script/ai/mutant3.cpp
+++ b/engines/bladerunner/script/ai/mutant3.cpp
@@ -316,24 +316,19 @@ bool AIScriptMutant3::GoalChanged(int currentGoalNumber, int newGoalNumber) {
 	case 410:
 		switch (Actor_Query_Which_Set_In(kActorMutant3)) {
 		case kSetUG01:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant3, 0, 1, 0, 11, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorMutant3, kActorCombatStateIdle, false, kActorMcCoy, 11, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
 			break;
 
 		case kSetUG04:
 		case kSetUG05:
 		case kSetUG06:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant3, 0, 1, 0, 10, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorMutant3, kActorCombatStateIdle, false, kActorMcCoy, 10, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
 			break;
 
 		case kSetUG10:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant3, 0, 1, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
-			break;
 		case kSetUG12:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant3, 0, 1, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
-			break;
-
 		case kSetUG14:
-			Non_Player_Actor_Combat_Mode_On(kActorMutant3, 0, 1, 0, 14, 4, 7, 8, -1, -1, -1, 10, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorMutant3, kActorCombatStateIdle, false, kActorMcCoy, 14, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 10, 300, false);
 			break;
 		}
 		break;
@@ -342,6 +337,7 @@ bool AIScriptMutant3::GoalChanged(int currentGoalNumber, int newGoalNumber) {
 		AI_Movement_Track_Flush(kActorMutant3);
 		AI_Movement_Track_Append(kActorMutant3, 39, 100);
 		AI_Movement_Track_Repeat(kActorMutant3);
+		break;
 
 	case 599:
 		AI_Movement_Track_Flush(kActorMutant3);
diff --git a/engines/bladerunner/script/ai/officer_leary.cpp b/engines/bladerunner/script/ai/officer_leary.cpp
index b18ba08..0adbe7c 100644
--- a/engines/bladerunner/script/ai/officer_leary.cpp
+++ b/engines/bladerunner/script/ai/officer_leary.cpp
@@ -979,7 +979,7 @@ bool AIScriptOfficerLeary::ChangeAnimationMode(int mode) {
 			break;
 		}
 		break;
-	case kAnimationModeCombatShoot:
+	case kAnimationModeCombatAttack:
 		_animationState = 24;
 		_animationFrame = 0;
 		break;
diff --git a/engines/bladerunner/script/ai/sadik.cpp b/engines/bladerunner/script/ai/sadik.cpp
index b6abc8d..9fdb889 100644
--- a/engines/bladerunner/script/ai/sadik.cpp
+++ b/engines/bladerunner/script/ai/sadik.cpp
@@ -356,7 +356,7 @@ bool AIScriptSadik::GoalChanged(int currentGoalNumber, int newGoalNumber) {
 	case 413:
 		Loop_Actor_Walk_To_XYZ(kActorSadik, -1062.0f, 0.0f, 219.0f, 0, 0, 1, 0);
 		Actor_Set_Targetable(kActorSadik, 1);
-		Non_Player_Actor_Combat_Mode_On(kActorSadik, 0, 1, 0, 9, 4, 7, 8, 0, -1, -1, 15, 300, 0);
+		Non_Player_Actor_Combat_Mode_On(kActorSadik, kActorCombatStateIdle, true, kActorMcCoy, 9, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, -1, -1, 15, 300, false);
 		Actor_Set_Goal_Number(kActorSadik, 450);
 		return true;
 
@@ -412,7 +412,7 @@ bool AIScriptSadik::GoalChanged(int currentGoalNumber, int newGoalNumber) {
 	case 418:
 		Game_Flag_Reset(653);
 		Actor_Set_Goal_Number(kActorClovis, 518);
-		Non_Player_Actor_Combat_Mode_On(kActorSadik, 0, 1, 0, 9, 4, 7, 8, 0, -1, -1, 15, 300, 0);
+		Non_Player_Actor_Combat_Mode_On(kActorSadik, kActorCombatStateIdle, true, kActorMcCoy, 9, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, -1, -1, 15, 300, false);
 		return true;
 
 	case 419:
@@ -999,6 +999,7 @@ bool AIScriptSadik::ChangeAnimationMode(int mode) {
 			_animationState = 33;
 			_animationFrame = 0;
 		}
+		break;
 
 	case 63:
 		if (Actor_Query_Goal_Number(kActorSadik) != 105 && Actor_Query_Goal_Number(kActorSadik) != 106) {
diff --git a/engines/bladerunner/script/ai/steele.cpp b/engines/bladerunner/script/ai/steele.cpp
index e51a14a..ff2afa1 100644
--- a/engines/bladerunner/script/ai/steele.cpp
+++ b/engines/bladerunner/script/ai/steele.cpp
@@ -419,7 +419,7 @@ bool AIScriptSteele::ShotAtAndHit() {
 		Actor_Set_Goal_Number(kActorSteele, 271);
 
 	if (/* !a1 && */ Actor_Query_In_Set(kActorSteele, kSetHF06))
-		Non_Player_Actor_Combat_Mode_On(1, 3, 1, 0, 15, 4, 7, 8, 0, 0, 100, 25, 300, 0);
+		Non_Player_Actor_Combat_Mode_On(kActorSteele, kActorCombatStateUncover, true, kActorMcCoy, 15, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 25, 300, false);
 
 	return false;
 }
diff --git a/engines/bladerunner/script/ai/taffy_patron.cpp b/engines/bladerunner/script/ai/taffy_patron.cpp
index c7fa3a7..0bf6861 100644
--- a/engines/bladerunner/script/ai/taffy_patron.cpp
+++ b/engines/bladerunner/script/ai/taffy_patron.cpp
@@ -95,13 +95,13 @@ bool AIScriptTaffyPatron::GoalChanged(int currentGoalNumber, int newGoalNumber)
 
 	case 250:
 		Actor_Put_In_Set(kActorTaffyPatron, kSetNR01);
-		Actor_Set_At_XYZ(kActorTaffyPatron, -170.39999, 23.68, -850.0, 324);
-		Async_Actor_Walk_To_XYZ(kActorTaffyPatron, -390.0, 31.549999, -429.0, 24, 1);
+		Actor_Set_At_XYZ(kActorTaffyPatron, -170.4f, 23.68f, -850.0f, 324);
+		Async_Actor_Walk_To_XYZ(kActorTaffyPatron, -390.0f, 31.55f, -429.0f, 24, 1);
 		return true;
 
 	case 255:
 		Actor_Put_In_Set(kActorTaffyPatron, kSetNR01);
-		Actor_Set_At_XYZ(kActorTaffyPatron, -170.39999, 23.68, -850.0, 324);
+		Actor_Set_At_XYZ(kActorTaffyPatron, -170.4f, 23.68f, -850.0f, 324);
 		Actor_Change_Animation_Mode(kActorTaffyPatron, 48);
 		return true;
 
diff --git a/engines/bladerunner/script/ai/zuben.cpp b/engines/bladerunner/script/ai/zuben.cpp
index 9fe6aa2..58cea9d 100644
--- a/engines/bladerunner/script/ai/zuben.cpp
+++ b/engines/bladerunner/script/ai/zuben.cpp
@@ -152,7 +152,7 @@ void AIScriptZuben::CompletedMovementTrack() {
 			Set_Enter(kSetCT06, kSceneCT06);
 		}
 		if (Actor_Query_Goal_Number(kActorZuben) == 21) {
-			Non_Player_Actor_Combat_Mode_On(kActorZuben, 0, 0, kActorMcCoy, 6, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 15, 300, 0);
+			Non_Player_Actor_Combat_Mode_On(kActorZuben, kActorCombatStateIdle, false, kActorMcCoy, 6, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 15, 300, false);
 		}
 		int goal = Actor_Query_Goal_Number(kActorZuben);
 		if (goal == 200) {
@@ -977,7 +977,7 @@ bool AIScriptZuben::ChangeAnimationMode(int mode) {
 			break;
 		}
 		break;
-	case kAnimationModeCombatShoot:
+	case kAnimationModeCombatAttack:
 		_animationState = 8;
 		_animationFrame = 0;
 		break;
diff --git a/engines/bladerunner/script/ai_script.cpp b/engines/bladerunner/script/ai_script.cpp
index 98ad4c1..aa8c14c 100644
--- a/engines/bladerunner/script/ai_script.cpp
+++ b/engines/bladerunner/script/ai_script.cpp
@@ -329,4 +329,16 @@ void AIScripts::changeAnimationMode(int actor, int mode) {
 	_inScriptCounter--;
 }
 
+void AIScripts::fledCombat(int actor) {
+	if (actor >= _actorCount) {
+		return;
+	}
+
+	_inScriptCounter++;
+	if (_AIScripts[actor]) {
+		_AIScripts[actor]->FledCombat();
+	}
+	_inScriptCounter--;
+}
+
 } // End of namespace BladeRunner
diff --git a/engines/bladerunner/script/ai_script.h b/engines/bladerunner/script/ai_script.h
index edbb198..d746dce 100644
--- a/engines/bladerunner/script/ai_script.h
+++ b/engines/bladerunner/script/ai_script.h
@@ -535,6 +535,7 @@ public:
 	bool reachedMovementTrackWaypoint(int actor, int waypointId);
 	void updateAnimation(int actor, int *animation, int *frame);
 	void changeAnimationMode(int actor, int mode);
+	void fledCombat(int actor);
 
 	bool isInsideScript() const { return _inScriptCounter > 0; }
 
diff --git a/engines/bladerunner/script/scene/ct07.cpp b/engines/bladerunner/script/scene/ct07.cpp
index 2eb7805..ebbe604 100644
--- a/engines/bladerunner/script/scene/ct07.cpp
+++ b/engines/bladerunner/script/scene/ct07.cpp
@@ -89,7 +89,7 @@ void SceneScriptCT07::ActorChangedGoal(int actorId, int newGoal, int oldGoal, bo
 
 void SceneScriptCT07::PlayerWalkedIn() {
 	Player_Gains_Control();
-	Non_Player_Actor_Combat_Mode_On(kActorZuben, 0, 0, kActorMcCoy, 2, 4, 7, 8, 0, 0, 100, 15, 300, 0);
+	Non_Player_Actor_Combat_Mode_On(kActorZuben, kActorCombatStateIdle, false, kActorMcCoy, 2, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 15, 300, false);
 	Game_Flag_Set(516);
 	Actor_Face_Actor(kActorMcCoy, kActorZuben, true);
 }
diff --git a/engines/bladerunner/script/scene/hf01.cpp b/engines/bladerunner/script/scene/hf01.cpp
index ce36b91..d75c381 100644
--- a/engines/bladerunner/script/scene/hf01.cpp
+++ b/engines/bladerunner/script/scene/hf01.cpp
@@ -90,9 +90,9 @@ bool SceneScriptHF01::ClickedOn3DObject(const char *objectName, bool a2) {
 
 bool SceneScriptHF01::ClickedOnActor(int actorId) {
 	int v1;
-	if (Global_Variable_Query(45) == 2) {
+	if (Global_Variable_Query(kVariableAffectionTowards) == 2) {
 		v1 = kActorDektora;
-	} else if (Global_Variable_Query(45) == 3) {
+	} else if (Global_Variable_Query(kVariableAffectionTowards) == 3) {
 		v1 = kActorLucy;
 	} else {
 		v1 = -1;
@@ -295,15 +295,15 @@ void SceneScriptHF01::PlayerWalkedIn() {
 		Actor_Set_At_XYZ(kActorOfficerLeary, 8.2f, 8.0f, -346.67f, 1021);
 		Actor_Put_In_Set(kActorOfficerGrayford, 37);
 		Actor_Set_At_XYZ(kActorOfficerGrayford, 51.21f, 8.0f, -540.78f, 796);
-		Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, 3, 1, kActorMcCoy, 4, 4, 7, 8, 0, 0, 0, 100, 300, 0);
-		Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, 3, 1, kActorMcCoy, 4, 4, 7, 8, 0, 0, 0, 100, 300, 0);
+		Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, kActorCombatStateUncover, true, kActorMcCoy, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 0, 100, 300, false);
+		Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateUncover, true, kActorMcCoy, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 0, 100, 300, false);
 	}
 	if (!Game_Flag_Query(165) && Actor_Query_Goal_Number(kActorCrazylegs) != 2) {
-		if (Actor_Clue_Query(kActorMcCoy, kCluePhoneCallLucy1) && Global_Variable_Query(45) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
+		if (Actor_Clue_Query(kActorMcCoy, kCluePhoneCallLucy1) && Global_Variable_Query(kVariableAffectionTowards) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
 			Actor_Put_In_Set(kActorLucy, 37);
 			Actor_Set_At_XYZ(kActorLucy, -5.0f, 8.0f, -622.0f, 419);
 			Actor_Set_Targetable(kActorLucy, true);
-		} else if (Actor_Clue_Query(kActorMcCoy, kCluePhoneCallDektora1) && Global_Variable_Query(45) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599) {
+		} else if (Actor_Clue_Query(kActorMcCoy, kCluePhoneCallDektora1) && Global_Variable_Query(kVariableAffectionTowards) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599) {
 			Actor_Put_In_Set(kActorDektora, 37);
 			Actor_Set_At_XYZ(kActorDektora, -5.0f, 8.0f, -622.0f, 419);
 			Actor_Set_Targetable(kActorDektora, true);
diff --git a/engines/bladerunner/script/scene/hf03.cpp b/engines/bladerunner/script/scene/hf03.cpp
index 09bf589..e3b01df 100644
--- a/engines/bladerunner/script/scene/hf03.cpp
+++ b/engines/bladerunner/script/scene/hf03.cpp
@@ -96,8 +96,8 @@ void SceneScriptHF03::sub_401C80() {
 			Actor_Says(kActorLucy, 210, 13);
 			Actor_Says(kActorMcCoy, 1655, 15);
 			Actor_Modify_Friendliness_To_Other(kActorLucy, kActorMcCoy, Random_Query(9, 10));
-			if (Actor_Query_Friendliness_To_Other(kActorLucy, kActorMcCoy) > 59 && !Global_Variable_Query(45)) {
-				Global_Variable_Set(45, 3);
+			if (Actor_Query_Friendliness_To_Other(kActorLucy, kActorMcCoy) > 59 && Global_Variable_Query(kVariableAffectionTowards) == 0) {
+				Global_Variable_Set(kVariableAffectionTowards, 3);
 				Actor_Says(kActorLucy, 940, 14);
 				Actor_Says(kActorMcCoy, 6780, 11);
 				Actor_Says(kActorLucy, 950, 12);
diff --git a/engines/bladerunner/script/scene/hf05.cpp b/engines/bladerunner/script/scene/hf05.cpp
index ff497eb..a620d3a 100644
--- a/engines/bladerunner/script/scene/hf05.cpp
+++ b/engines/bladerunner/script/scene/hf05.cpp
@@ -483,10 +483,10 @@ void SceneScriptHF05::sub_403738() {
 }
 
 int SceneScriptHF05::sub_404858() {
-	if (Global_Variable_Query(45) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599) {
+	if (Global_Variable_Query(kVariableAffectionTowards) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599) {
 		return kActorDektora;
 	}
-	if (Global_Variable_Query(45) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
+	if (Global_Variable_Query(kVariableAffectionTowards) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
 		return kActorLucy;
 	}
 	return -1;
@@ -494,15 +494,15 @@ int SceneScriptHF05::sub_404858() {
 
 void SceneScriptHF05::sub_4042E4() {
 	Actor_Force_Stop_Walking(kActorMcCoy);
-	Actor_Put_In_Set(kActorOfficerLeary, 41);
-	Actor_Set_At_XYZ(kActorOfficerLeary, 430.39999f, 40.630001f, -258.17999f, 300);
-	Actor_Put_In_Set(kActorOfficerGrayford, 41);
-	Actor_Set_At_XYZ(kActorOfficerGrayford, 526.40002f, 37.18f, -138.17999f, 300);
+	Actor_Put_In_Set(kActorOfficerLeary, kSetHF05);
+	Actor_Set_At_XYZ(kActorOfficerLeary, 430.4f, 40.63f, -258.18f, 300);
+	Actor_Put_In_Set(kActorOfficerGrayford, kSetHF05);
+	Actor_Set_At_XYZ(kActorOfficerGrayford, 526.4f, 37.18f, -138.18f, 300);
 	ADQ_Flush();
 	ADQ_Add(kActorOfficerGrayford, 260, -1);
 	Player_Loses_Control();
-	Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, 3, 1, kActorMcCoy, 4, 4, 7, 8, 0, 0, 100, 100, 1200, 1);
-	return Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, 3, 1, kActorMcCoy, 4, 4, 7, 8, 0, 0, 100, 100, 300, 1);
+	Non_Player_Actor_Combat_Mode_On(kActorOfficerLeary, kActorCombatStateUncover, true, kActorMcCoy, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 100, 1200, true);
+	Non_Player_Actor_Combat_Mode_On(kActorOfficerGrayford, kActorCombatStateUncover, true, kActorMcCoy, 4, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 100, 300, true);
 }
 
 void SceneScriptHF05::sub_403F0C() {
diff --git a/engines/bladerunner/script/scene/hf06.cpp b/engines/bladerunner/script/scene/hf06.cpp
index 7a41c9e..49ea1d8 100644
--- a/engines/bladerunner/script/scene/hf06.cpp
+++ b/engines/bladerunner/script/scene/hf06.cpp
@@ -180,12 +180,13 @@ void SceneScriptHF06::ActorChangedGoal(int actorId, int newGoal, int oldGoal, bo
 
 void SceneScriptHF06::PlayerWalkedIn() {
 	if (Game_Flag_Query(662)) {
-		int actorId;
-		if (Global_Variable_Query(45) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
+		int actorId = -1;
+		if (Global_Variable_Query(kVariableAffectionTowards) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
 			actorId = kActorLucy;
-		} else {
-			actorId = Global_Variable_Query(45) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599 ? kActorDektora : -1;
-		}
+		} else if (Global_Variable_Query(kVariableAffectionTowards) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599) {
+			actorId = kActorDektora;
+		} 
+
 		if (actorId != -1) {
 			Actor_Put_In_Set(actorId, 42);
 			if (Game_Flag_Query(559)) {
@@ -267,7 +268,7 @@ void SceneScriptHF06::sub_401EF4() {
 	Sound_Play(562, 50, 0, 0, 50);
 	Game_Flag_Set(559);
 	Scene_Exits_Disable();
-	Non_Player_Actor_Combat_Mode_On(kActorSteele, 3, 1, actorId, 15, 4, 7, 8, 0, 0, 100, 10, 300, 0);
+	Non_Player_Actor_Combat_Mode_On(kActorSteele, kActorCombatStateUncover, true, actorId, 15, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, 0, 100, 10, 300, false);
 }
 
 void SceneScriptHF06::sub_4023E0() {
diff --git a/engines/bladerunner/script/scene/hf07.cpp b/engines/bladerunner/script/scene/hf07.cpp
index e9fe2f0..b653cfd 100644
--- a/engines/bladerunner/script/scene/hf07.cpp
+++ b/engines/bladerunner/script/scene/hf07.cpp
@@ -142,11 +142,11 @@ void SceneScriptHF07::DialogueQueueFlushed(int a1) {
 }
 
 int SceneScriptHF07::sub_401864() {
-	if (Global_Variable_Query(45) == 2 && Actor_Query_Goal_Number(3) != 599) {
-		return 3;
+	if (Global_Variable_Query(kVariableAffectionTowards) == 2 && Actor_Query_Goal_Number(3) != 599) {
+		return kActorDektora;
 	}
-	if (Global_Variable_Query(45) == 3 && Actor_Query_Goal_Number(6) != 599) {
-		return 6;
+	if (Global_Variable_Query(kVariableAffectionTowards) == 3 && Actor_Query_Goal_Number(6) != 599) {
+		return kActorLucy;
 	}
 	return -1;
 }
diff --git a/engines/bladerunner/script/scene/kp05.cpp b/engines/bladerunner/script/scene/kp05.cpp
index 9b080ac..99fa6c3 100644
--- a/engines/bladerunner/script/scene/kp05.cpp
+++ b/engines/bladerunner/script/scene/kp05.cpp
@@ -158,7 +158,7 @@ void SceneScriptKP05::PlayerWalkedIn() {
 		Actor_Says(kActorMcCoy, 2220, 3);
 		Actor_Says(kActorSteele, 620, 15);
 		Actor_Says(kActorSteele, 630, 17);
-		Non_Player_Actor_Combat_Mode_On(kActorSteele, 0, 1, kActorMcCoy, 9, 4, 7, 8, 0, -1, -1, 20, 240, 0);
+		Non_Player_Actor_Combat_Mode_On(kActorSteele, kActorCombatStateIdle, true, kActorMcCoy, 9, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, 0, -1, -1, 20, 240, false);
 	}
 }
 
diff --git a/engines/bladerunner/script/scene/ma04.cpp b/engines/bladerunner/script/scene/ma04.cpp
index 5f1b41e..ead9f19 100644
--- a/engines/bladerunner/script/scene/ma04.cpp
+++ b/engines/bladerunner/script/scene/ma04.cpp
@@ -176,9 +176,9 @@ bool SceneScriptMA04::ClickedOn2DRegion(int region) {
 				Overlay_Remove("MA04OVER");
 				Delay(500);
 				if (Game_Flag_Query(653)) {
-					if (Global_Variable_Query(45) == 2) {
+					if (Global_Variable_Query(kVariableAffectionTowards) == 2) {
 						phoneCallWithDektora();
-					} else if (Global_Variable_Query(45) == 3) {
+					} else if (Global_Variable_Query(kVariableAffectionTowards) == 3) {
 						phoneCallWithLucy();
 					} else {
 						phoneCallWithClovis();
diff --git a/engines/bladerunner/script/scene/nr01.cpp b/engines/bladerunner/script/scene/nr01.cpp
index 171cea5..fd7c991 100644
--- a/engines/bladerunner/script/scene/nr01.cpp
+++ b/engines/bladerunner/script/scene/nr01.cpp
@@ -384,7 +384,7 @@ void SceneScriptNR01::PlayerWalkedIn() {
 			if (Actor_Query_Goal_Number(kActorGordo) == 230) {
 				Scene_Exits_Disable();
 				Actor_Set_Goal_Number(kActorGordo, 231);
-				Non_Player_Actor_Combat_Mode_On(kActorGordo, 0, 1, kActorMcCoy, 3, 4, 7, 8, -1, -1, -1, 20, 300, 0);
+				Non_Player_Actor_Combat_Mode_On(kActorGordo, kActorCombatStateIdle, true, kActorMcCoy, 3, kAnimationModeCombatIdle, kAnimationModeCombatWalk, kAnimationModeCombatRun, -1, -1, -1, 20, 300, false);
 			}
 		} else if (Game_Flag_Query(545)) {
 			Game_Flag_Reset(545);
diff --git a/engines/bladerunner/script/scene/nr11.cpp b/engines/bladerunner/script/scene/nr11.cpp
index 95ef4b7..5c4f4c1 100644
--- a/engines/bladerunner/script/scene/nr11.cpp
+++ b/engines/bladerunner/script/scene/nr11.cpp
@@ -140,7 +140,7 @@ bool SceneScriptNR11::ClickedOn3DObject(const char *objectName, bool a2) {
 				} else {
 					Actor_Says(kActorMcCoy, 3840, 18);
 					Delay(1000);
-					if (Actor_Query_Friendliness_To_Other(kActorDektora, kActorMcCoy) > 59 && !Global_Variable_Query(45)) {
+					if (Actor_Query_Friendliness_To_Other(kActorDektora, kActorMcCoy) > 59 && Global_Variable_Query(kVariableAffectionTowards) == 0) {
 						Music_Play(21, 35, 0, 3, -1, 0, 0);
 					}
 					Loop_Actor_Walk_To_XYZ(kActorDektora, -135.0f, 0.33f, -267.0f, 0, 0, false, 0);
@@ -164,8 +164,8 @@ bool SceneScriptNR11::ClickedOn3DObject(const char *objectName, bool a2) {
 					Actor_Says(kActorMcCoy, 3870, 3);
 					Actor_Says(kActorDektora, 1070, 14);
 					Actor_Modify_Friendliness_To_Other(kActorDektora, kActorMcCoy, 5);
-					if (Actor_Query_Friendliness_To_Other(kActorDektora, kActorMcCoy) > 55 && !Global_Variable_Query(45)) {
-						Global_Variable_Set(45, 2);
+					if (Actor_Query_Friendliness_To_Other(kActorDektora, kActorMcCoy) > 55 && Global_Variable_Query(kVariableAffectionTowards) == 0) {
+						Global_Variable_Set(kVariableAffectionTowards, 2);
 						Actor_Says(kActorDektora, 1130, 17);
 						Actor_Says(kActorMcCoy, 6365, 12);
 						Actor_Says(kActorDektora, 1140, 14);
diff --git a/engines/bladerunner/script/scene/ug05.cpp b/engines/bladerunner/script/scene/ug05.cpp
index c3996dc..3348ebb 100644
--- a/engines/bladerunner/script/scene/ug05.cpp
+++ b/engines/bladerunner/script/scene/ug05.cpp
@@ -222,10 +222,10 @@ void SceneScriptUG05::DialogueQueueFlushed(int a1) {
 }
 
 int SceneScriptUG05::sub_4021B0() {
-	if (Global_Variable_Query(45) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599) {
+	if (Global_Variable_Query(kVariableAffectionTowards) == 2 && Actor_Query_Goal_Number(kActorDektora) != 599) {
 		return kActorDektora;
 	}
-	if (Global_Variable_Query(45) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
+	if (Global_Variable_Query(kVariableAffectionTowards) == 3 && Actor_Query_Goal_Number(kActorLucy) != 599) {
 		return kActorLucy;
 	}
 	return -1;
diff --git a/engines/bladerunner/script/scene/ug18.cpp b/engines/bladerunner/script/scene/ug18.cpp
index cafe426..c20c58c 100644
--- a/engines/bladerunner/script/scene/ug18.cpp
+++ b/engines/bladerunner/script/scene/ug18.cpp
@@ -323,9 +323,8 @@ void SceneScriptUG18::sub_402734() {
 }
 
 void SceneScriptUG18::sub_402DE8() {
-
 	if (Player_Query_Agenda()) {
-		if (Global_Variable_Query(45) > 1 || Player_Query_Agenda() == 2) {
+		if (Global_Variable_Query(kVariableAffectionTowards) > 1 || Player_Query_Agenda() == 2) {
 			sub_403114();
 		} else {
 			sub_402F8C();
diff --git a/engines/bladerunner/script/script.cpp b/engines/bladerunner/script/script.cpp
index 2aca6db..ff2a840 100644
--- a/engines/bladerunner/script/script.cpp
+++ b/engines/bladerunner/script/script.cpp
@@ -130,7 +130,7 @@ void ScriptBase::Actor_Face_Heading(int actorId, int heading, bool animate) {
 }
 
 int ScriptBase::Actor_Query_Friendliness_To_Other(int actorId, int otherActorId) {
-	return _vm->_actors[actorId]->_friendlinessToOther[otherActorId];
+	return _vm->_actors[actorId]->getFriendlinessToOther(otherActorId);
 }
 
 void ScriptBase::Actor_Modify_Friendliness_To_Other(int actorId, int otherActorId, signed int change) {
@@ -158,27 +158,27 @@ void ScriptBase::Actor_Set_Combat_Aggressiveness(int actorId, int combatAggressi
 }
 
 int ScriptBase::Actor_Query_Current_HP(int actorId) {
-	return _vm->_actors[actorId]->_currentHP;
+	return _vm->_actors[actorId]->getCurrentHP();
 }
 
 int ScriptBase::Actor_Query_Max_HP(int actorId) {
-	return _vm->_actors[actorId]->_maxHP;
+	return _vm->_actors[actorId]->getMaxHP();
 }
 
 int ScriptBase::Actor_Query_Combat_Aggressiveness(int actorId) {
-	return _vm->_actors[actorId]->_combatAggressiveness;
+	return _vm->_actors[actorId]->getCombatAggressiveness();
 }
 
 int ScriptBase::Actor_Query_Honesty(int actorId) {
-	return _vm->_actors[actorId]->_honesty;
+	return _vm->_actors[actorId]->getHonesty();
 }
 
 int ScriptBase::Actor_Query_Intelligence(int actorId) {
-	return _vm->_actors[actorId]->_intelligence;
+	return _vm->_actors[actorId]->getIntelligence();
 }
 
 int ScriptBase::Actor_Query_Stability(int actorId) {
-	return _vm->_actors[actorId]->_stability;
+	return _vm->_actors[actorId]->getStability();
 }
 
 void ScriptBase::Actor_Modify_Current_HP(int actorId, signed int change) {
@@ -218,8 +218,8 @@ void ScriptBase::Actor_Combat_AI_Hit_Attempt(int actorId) {
 		_vm->_actors[actorId]->_combatInfo->hitAttempt();
 }
 
-void ScriptBase::Non_Player_Actor_Combat_Mode_On(int actorId, int a2, int a3, int otherActorId, int a5, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int a9, int a10, int a11, int a12, int a13, int a14) {
-	_vm->_actors[actorId]->combatModeOn(a2, a3, otherActorId, a5, animationModeCombatIdle, animationModeCombatWalk, animationModeCombatRun, a9, a10, a11, a12, a13, a14);
+void ScriptBase::Non_Player_Actor_Combat_Mode_On(int actorId, int initialState, bool rangedAttack, int enemyId, int waypointType, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int fleeRatio, int coverRatio, int actionRatio, int damage, int range, bool a14) {
+	_vm->_actors[actorId]->combatModeOn(initialState, rangedAttack, enemyId, waypointType, animationModeCombatIdle, animationModeCombatWalk, animationModeCombatRun, fleeRatio, coverRatio, actionRatio, damage, range, a14);
 }
 
 void ScriptBase::Non_Player_Actor_Combat_Mode_Off(int actorId) {
@@ -723,8 +723,9 @@ int ScriptBase::Animation_Skip_To_Frame() {
 void ScriptBase::Delay(int miliseconds) {
 	Player_Loses_Control();
 	int endTime = _vm->getTotalPlayTime() + miliseconds;
-	while ((int)_vm->getTotalPlayTime() < endTime)
+	while ((int)_vm->getTotalPlayTime() < endTime) {
 		_vm->gameTick();
+	}
 	Player_Gains_Control();
 }
 
@@ -1075,14 +1076,27 @@ float ScriptBase::World_Waypoint_Query_Z(int waypointId) {
 	return _vm->_waypoints->getZ(waypointId);
 }
 
-void ScriptBase::Combat_Cover_Waypoint_Set_Data(int combatCoverId, int type, int setId, int sceneId, float x, float y, float z) {
-	//TODO
-	warning("Combat_Cover_Waypoint_Set_Data(%d, %d, %d, %d, %f, %f, %f)", combatCoverId, type, setId, sceneId, x, y, z);
+void ScriptBase::Combat_Cover_Waypoint_Set_Data(int coverWaypointId, int type, int setId, int sceneId, float x, float y, float z) {
+	assert(coverWaypointId < (int)_vm->_combat->_coverWaypoints.size());
+
+	_vm->_combat->_coverWaypoints[coverWaypointId].type = type;
+	_vm->_combat->_coverWaypoints[coverWaypointId].setId = setId;
+	_vm->_combat->_coverWaypoints[coverWaypointId].sceneId = sceneId;
+	_vm->_combat->_coverWaypoints[coverWaypointId].position.x = x;
+	_vm->_combat->_coverWaypoints[coverWaypointId].position.y = y;
+	_vm->_combat->_coverWaypoints[coverWaypointId].position.z = z;
 }
 
-void ScriptBase::Combat_Flee_Waypoint_Set_Data(int combatFleeWaypointId, int type, int setId, int sceneId, float x, float y, float z, int a8) {
-	//TODO
-	warning("Combat_Cover_Waypoint_Set_Data(%d, %d, %d, %d, %f, %f, %f, %d)", combatFleeWaypointId, type, setId, sceneId, x, y, z, a8);
+void ScriptBase::Combat_Flee_Waypoint_Set_Data(int fleeWaypointId, int type, int setId, int sceneId, float x, float y, float z, int a8) {
+	assert(fleeWaypointId < (int)_vm->_combat->_fleeWaypoints.size());
+
+	_vm->_combat->_fleeWaypoints[fleeWaypointId].type = type;
+	_vm->_combat->_fleeWaypoints[fleeWaypointId].setId = setId;
+	_vm->_combat->_fleeWaypoints[fleeWaypointId].sceneId = sceneId;
+	_vm->_combat->_fleeWaypoints[fleeWaypointId].position.x = x;
+	_vm->_combat->_fleeWaypoints[fleeWaypointId].position.y = y;
+	_vm->_combat->_fleeWaypoints[fleeWaypointId].position.z = z;
+	_vm->_combat->_fleeWaypoints[fleeWaypointId].field7 = a8;
 }
 
 void ScriptBase::Police_Maze_Target_Track_Add(int itemId, float startX, float startY, float startZ, float endX, float endY, float endZ, int steps, signed int data[], bool a10) {
@@ -1221,10 +1235,8 @@ bool ScriptBase::Query_System_Currently_Loading_Game() {
 
 void ScriptBase::Actor_Retired_Here(int actorId, int width, int height, int retired, int retiredByActorId) {
 	Actor *actor = _vm->_actors[actorId];
-	Vector3 actorPosition;
-	actor->getXYZ(&actorPosition.x, &actorPosition.y, &actorPosition.z);
 	actor->retire(retired, width, height, retiredByActorId);
-	actor->setAtXYZ(actorPosition, actor->getFacing(), true, false, true);
+	actor->setAtXYZ(actor->getXYZ(), actor->getFacing(), true, false, true);
 	_vm->_sceneObjects->setRetired(actorId + kSceneObjectOffsetActors, true);
 }
 
diff --git a/engines/bladerunner/script/script.h b/engines/bladerunner/script/script.h
index 7faf388..9df231a 100644
--- a/engines/bladerunner/script/script.h
+++ b/engines/bladerunner/script/script.h
@@ -78,7 +78,7 @@ protected:
 	void Actor_Set_Flag_Damage_Anim_If_Moving(int actorId, bool value);
 	bool Actor_Query_Flag_Damage_Anim_If_Moving(int actorId);
 	void Actor_Combat_AI_Hit_Attempt(int actorId);
-	void Non_Player_Actor_Combat_Mode_On(int actorId, int a2, int a3, int otherActorId, int a5, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int a9, int a10, int a11, int a12, int a13, int a14);
+	void Non_Player_Actor_Combat_Mode_On(int actorId, int initialState, bool rangedAttack, int enemyId, int waypointType, int animationModeCombatIdle, int animationModeCombatWalk, int animationModeCombatRun, int fleeRatio, int coverRatio, int actionRatio, int damage, int range, bool a14);
 	void Non_Player_Actor_Combat_Mode_Off(int actorId);
 	void Actor_Set_Health(int actorId, int hp, int maxHp);
 	void Actor_Set_Targetable(int actorId, bool targetable);
@@ -205,8 +205,8 @@ protected:
 	float World_Waypoint_Query_X(int waypointId);
 	float World_Waypoint_Query_Y(int waypointId);
 	float World_Waypoint_Query_Z(int waypointId);
-	void Combat_Cover_Waypoint_Set_Data(int combatCoverId, int a2, int setId, int a4, float x, float y, float z);
-	void Combat_Flee_Waypoint_Set_Data(int combatFleeWaypointId, int a2, int setId, int a4, float x, float y, float z, int a8);
+	void Combat_Cover_Waypoint_Set_Data(int coverWaypointId, int a2, int setId, int a4, float x, float y, float z);
+	void Combat_Flee_Waypoint_Set_Data(int fleeWaypointId, int a2, int setId, int a4, float x, float y, float z, int a8);
 	void Police_Maze_Target_Track_Add(int itemId, float startX, float startY, float startZ, float endX, float endY, float endZ, int steps, signed int data[], bool a10);
 	// Police_Maze_Query_Score
 	// Police_Maze_Zero_Score
diff --git a/engines/bladerunner/slice_renderer.cpp b/engines/bladerunner/slice_renderer.cpp
index 15633f6..31da697 100644
--- a/engines/bladerunner/slice_renderer.cpp
+++ b/engines/bladerunner/slice_renderer.cpp
@@ -122,7 +122,7 @@ Matrix3x2 SliceRenderer::calculateFacingRotationMatrix() {
 	float s = sinf(dir);
 	float c = cosf(dir);
 
-	Matrix3x2 mRotation( c, -s, 0.0f,
+	Matrix3x2 mRotation(c, -s, 0.0f,
 	                    s,  c, 0.0f);
 
 	Matrix3x2 mView(_view->_sliceViewMatrix(0,0), _view->_sliceViewMatrix(0,1), 0.0f,
@@ -164,29 +164,20 @@ void SliceRenderer::calculateBoundingRect() {
 	Matrix3x2 mScale(_frameScale.x,          0.0f, 0.0f,
 	                          0.0f, _frameScale.y, 0.0f);
 
-	_modelMatrix = mProjection * (facingRotation * (mOffset * mScale));
+	_mvpMatrix = mProjection * (facingRotation * (mOffset * mScale));
 
 	Vector4 startScreenVector(
-	           _view->_viewportPosition.x + top.x / top.z * _view->_viewportPosition.z,
-	           _view->_viewportPosition.y + top.y / top.z * _view->_viewportPosition.z,
+	           _view->_viewportPosition.x + (top.x / top.z) * _view->_viewportPosition.z,
+	           _view->_viewportPosition.y + (top.y / top.z) * _view->_viewportPosition.z,
 	           1.0f / top.z,
 	           _frameSliceCount * (1.0f / top.z));
 
 	Vector4 endScreenVector(
-	           _view->_viewportPosition.x + bottom.x / bottom.z * _view->_viewportPosition.z,
-	           _view->_viewportPosition.y + bottom.y / bottom.z * _view->_viewportPosition.z,
+	           _view->_viewportPosition.x + (bottom.x / bottom.z) * _view->_viewportPosition.z,
+	           _view->_viewportPosition.y + (bottom.y / bottom.z) * _view->_viewportPosition.z,
 	           1.0f / bottom.z,
 	           0.0f);
 
-	_startScreenVector.x = startScreenVector.x;
-	_startScreenVector.y = startScreenVector.y;
-	_startScreenVector.z = startScreenVector.z;
-	_endScreenVector.x   = endScreenVector.x;
-	_endScreenVector.y   = endScreenVector.y;
-	_endScreenVector.z   = endScreenVector.z;
-	_startSlice          = startScreenVector.w;
-	_endSlice            = endScreenVector.w;
-
 	Vector4 delta = endScreenVector - startScreenVector;
 
 	if (delta.y == 0.0f) {
@@ -197,60 +188,68 @@ void SliceRenderer::calculateBoundingRect() {
 	 * Calculate min and max Y
 	 */
 
-	float screenMinY =   0.0f;
-	float screenMaxY = 479.0f;
+	float screenTop    =   0.0f;
+	float screenBottom = 479.0f;
 
-	if (startScreenVector.y < screenMinY) {
-		if (endScreenVector.y < screenMinY)
+	if (startScreenVector.y < screenTop) {
+		if (endScreenVector.y < screenTop) {
 			return;
-
-		float f = (screenMinY - startScreenVector.y) / delta.y;
+		}
+		float f = (screenTop - startScreenVector.y) / delta.y;
 		startScreenVector = startScreenVector + f * delta;
-	} else if (startScreenVector.y > screenMaxY) {
-		if (endScreenVector.y >= screenMaxY)
+	} else if (startScreenVector.y > screenBottom) {
+		if (endScreenVector.y >= screenBottom) {
 			return;
-
-		float f = (screenMaxY - startScreenVector.y) / delta.y;
+		}
+		float f = (screenBottom - startScreenVector.y) / delta.y;
 		startScreenVector = startScreenVector + f * delta;
 	}
 
-	if (endScreenVector.y < screenMinY) {
-		float f = (screenMinY - endScreenVector.y) / delta.y;
+	if (endScreenVector.y < screenTop) {
+		float f = (screenTop - endScreenVector.y) / delta.y;
 		endScreenVector = endScreenVector + f * delta;
-	} else if (endScreenVector.y > screenMaxY) {
-		float f = (screenMaxY - endScreenVector.y) / delta.y;
+	} else if (endScreenVector.y > screenBottom) {
+		float f = (screenBottom - endScreenVector.y) / delta.y;
 		endScreenVector = endScreenVector + f * delta;
 	}
 
-	int bbox_min_y = (int)MIN(startScreenVector.y, endScreenVector.y);
-	int bbox_max_y = (int)MAX(startScreenVector.y, endScreenVector.y) + 1;
+	_screenRectangle.top    = (int)MIN(startScreenVector.y, endScreenVector.y);
+	_screenRectangle.bottom = (int)MAX(startScreenVector.y, endScreenVector.y) + 1;
 
 	/*
 	 * Calculate min and max X
 	 */
 
-	Matrix3x2 mB6 = _modelMatrix + Vector2(startScreenVector.x, 25.5f / startScreenVector.z);
-	Matrix3x2 mC2 = _modelMatrix + Vector2(endScreenVector.x,   25.5f / endScreenVector.z);
+	Matrix3x2 mStart(
+		1.0f, 0.0f, startScreenVector.x,
+		0.0f, 1.0f, 25.5f / startScreenVector.z
+	);
 
-	float min_x =  640.0f;
-	float max_x =    0.0f;
+	Matrix3x2 mEnd(
+		1.0f, 0.0f, endScreenVector.x,
+		0.0f, 1.0f, 25.5f / endScreenVector.z
+	);
 
-	for (float i = 0.0f; i <= 256.0f; i += 255.0f) {
-		for (float j = 0.0f; j <= 256.0f; j += 255.0f) {
-			Vector2 v1 = mB6 * Vector2(i, j);
+	Matrix3x2 mStartMVP = mStart * _mvpMatrix;
+	Matrix3x2 mEndMVP   = mEnd   * _mvpMatrix;
 
-			min_x = MIN(min_x, v1.x);
-			max_x = MAX(max_x, v1.x);
+	float minX =  640.0f;
+	float maxX =    0.0f;
 
-			Vector2 v2 = mC2 * Vector2(i, j);
+	for (float i = 0.0f; i <= 256.0f; i += 255.0f) {
+		for (float j = 0.0f; j <= 256.0f; j += 255.0f) {
+			Vector2 v1 = mStartMVP * Vector2(i, j);
+			minX = MIN(minX, v1.x);
+			maxX = MAX(maxX, v1.x);
 
-			min_x = MIN(min_x, v2.x);
-			max_x = MAX(max_x, v2.x);
+			Vector2 v2 = mEndMVP * Vector2(i, j);
+			minX = MIN(minX, v2.x);
+			maxX = MAX(maxX, v2.x);
 		}
 	}
 
-	int bbox_min_x = CLIP((int)min_x,     0, 640);
-	int bbox_max_x = CLIP((int)max_x + 1, 0, 640);
+	_screenRectangle.left  = CLIP((int)minX,     0, 640);
+	_screenRectangle.right = CLIP((int)maxX + 1, 0, 640);
 
 	_startScreenVector.x = startScreenVector.x;
 	_startScreenVector.y = startScreenVector.y;
@@ -260,11 +259,6 @@ void SliceRenderer::calculateBoundingRect() {
 	_endScreenVector.z   = endScreenVector.z;
 	_startSlice          = startScreenVector.w;
 	_endSlice            = endScreenVector.w;
-
-	_screenRectangle.left   = bbox_min_x;
-	_screenRectangle.right  = bbox_max_x;
-	_screenRectangle.top    = bbox_min_y;
-	_screenRectangle.bottom = bbox_max_y;
 }
 
 void SliceRenderer::loadFrame(int animation, int frame) {
@@ -285,7 +279,8 @@ void SliceRenderer::loadFrame(int animation, int frame) {
 }
 
 struct SliceLineIterator {
-	int _sliceMatrix[2][3];
+	// int _sliceMatrix[2][3];
+	Matrix3x2 _sliceMatrix;
 	int _startY;
 	int _endY;
 
@@ -316,8 +311,9 @@ void SliceLineIterator::setup(
 
 	float size = endScreenY - startScreenY;
 
-	if (size <= 0.0f || startScreenZ <= 0.0f)
+	if (size <= 0.0f || startScreenZ <= 0.0f) {
 		_currentY = _endY + 1;
+	}
 
 	_currentZ  = startScreenZ;
 	_stepZ     = (endScreenZ - startScreenZ) / size;
@@ -328,7 +324,7 @@ void SliceLineIterator::setup(
 	_currentX = startScreenX;
 	_stepX    = (endScreenX - startScreenX) / size;
 
-	_field_38 = (int)((25.5f / size) * (1.0f / endScreenZ - 1.0f / startScreenZ) * 64.0);
+	_field_38 = (int)((25.5f / size) * (1.0f / endScreenZ - 1.0f / startScreenZ) * 64.0f);
 	_currentY = _startY;
 
 	float offsetX =         _currentX;
@@ -342,9 +338,7 @@ void SliceLineIterator::setup(
 
 	m = scale_matrix * (translate_matrix * m);
 
-	for (int r = 0; r != 2; ++r)
-		for (int c = 0; c != 3; ++c)
-			_sliceMatrix[r][c] = m(r, c);
+	_sliceMatrix = m;
 }
 
 float SliceLineIterator::line() {
@@ -364,8 +358,8 @@ void SliceLineIterator::advance() {
 	_currentSlice      += _stepSlice;
 	_currentX          += _stepX;
 	_currentY          += 1;
-	_sliceMatrix[0][2] += (int)(65536.0f * _stepX);
-	_sliceMatrix[1][2] += _field_38;
+	_sliceMatrix._m[0][2] += (int)(65536.0f * _stepX);
+	_sliceMatrix._m[1][2] += _field_38;
 }
 
 static void setupLookupTable(int t[256], int inc) {
@@ -393,7 +387,7 @@ void SliceRenderer::drawInWorld(int animationId, int animationFrame, Vector3 pos
 		_endScreenVector.x,   _endScreenVector.y,   _endScreenVector.z,
 		_startScreenVector.x, _startScreenVector.y, _startScreenVector.z,
 		_endSlice,            _startSlice,
-		_modelMatrix
+		_mvpMatrix
 	);
 
 	SliceRendererLights sliceRendererLights = SliceRendererLights(_lights);
@@ -424,12 +418,12 @@ void SliceRenderer::drawInWorld(int animationId, int animationFrame, Vector3 pos
 	_setEffectColor.g = setEffectColor.g * 31.0f * 65536.0f;
 	_setEffectColor.b = setEffectColor.b * 31.0f * 65536.0f;
 
-	setupLookupTable(_m11lookup, sliceLineIterator._sliceMatrix[0][0]);
-	setupLookupTable(_m12lookup, sliceLineIterator._sliceMatrix[0][1]);
-	_m13 = sliceLineIterator._sliceMatrix[0][2];
-	setupLookupTable(_m21lookup, sliceLineIterator._sliceMatrix[1][0]);
-	setupLookupTable(_m22lookup, sliceLineIterator._sliceMatrix[1][1]);
-	_m23 = sliceLineIterator._sliceMatrix[1][2];
+	setupLookupTable(_m12lookup, sliceLineIterator._sliceMatrix(0, 1));
+	setupLookupTable(_m11lookup, sliceLineIterator._sliceMatrix(0, 0));
+	_m13 = sliceLineIterator._sliceMatrix(0, 2);
+	setupLookupTable(_m21lookup, sliceLineIterator._sliceMatrix(1, 0));
+	setupLookupTable(_m22lookup, sliceLineIterator._sliceMatrix(1, 1));
+	_m23 = sliceLineIterator._sliceMatrix(1, 2);
 
 	if (_animationsShadowEnabled[_animation]) {
 		float coeficientShadow;
@@ -545,8 +539,9 @@ void SliceRenderer::drawOnScreen(int animationId, int animationFrame, int screen
 }
 
 void SliceRenderer::drawSlice(int slice, bool advanced, uint16 *frameLinePtr, uint16 *zbufLinePtr, int y) {
-	if (slice < 0 || (uint32)slice >= _frameSliceCount)
+	if (slice < 0 || (uint32)slice >= _frameSliceCount) {
 		return;
+	}
 
 	SliceAnimations::Palette &palette = _vm->_sliceAnimations->getPalette(_framePaletteIndex);
 
@@ -714,7 +709,12 @@ void SliceRenderer::drawShadowPolygon(int transparency, Graphics::Surface &surfa
 	yMax = CLIP(yMax, 0, 480);
 	yMin = CLIP(yMin, 0, 480);
 
-	int ditheringFactor[] = { 0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5 };
+	int ditheringFactor[] = {
+		0,  8,  2, 10,
+		12, 4, 14,  6,
+		3, 11,  1,  9,
+		15, 7, 13,  5
+	};
 
 	for (int y = yMin; y < yMax; ++y) {
 		int xMin = CLIP(polygonLeft[y], 0, 640);
diff --git a/engines/bladerunner/slice_renderer.h b/engines/bladerunner/slice_renderer.h
index d2de61e..2e36171 100644
--- a/engines/bladerunner/slice_renderer.h
+++ b/engines/bladerunner/slice_renderer.h
@@ -67,7 +67,7 @@ class SliceRenderer {
 	uint32  _framePaletteIndex;
 	uint32  _frameSliceCount;
 
-	Matrix3x2    _modelMatrix;
+	Matrix3x2    _mvpMatrix;
 	Vector3      _startScreenVector;
 	Vector3      _endScreenVector;
 	float        _startSlice;
diff --git a/engines/bladerunner/view.cpp b/engines/bladerunner/view.cpp
index d304b92..72c070e 100644
--- a/engines/bladerunner/view.cpp
+++ b/engines/bladerunner/view.cpp
@@ -31,8 +31,9 @@ bool View::readVqa(Common::ReadStream *stream) {
 	_frame = stream->readUint32LE();
 
 	float d[12];
-	for (int i = 0; i != 12; ++i)
+	for (int i = 0; i != 12; ++i) {
 		d[i] = stream->readFloatLE();
+	}
 
 	_frameViewMatrix = Matrix4x3(d);
 
@@ -54,17 +55,11 @@ void View::setFovX(float fovX) {
 }
 
 void View::calculateSliceViewMatrix() {
-	Matrix4x3 m = _frameViewMatrix;
-
-	m = m * rotationMatrixX(float(M_PI) / 2.0f);
-
-	Matrix4x3 a(-1.0f,  0.0f, 0.0f, 0.0f,
-	             0.0f, -1.0f, 0.0f, 0.0f,
-	             0.0f,  0.0f, 1.0f, 0.0f);
-
-	m = a * m;
-
-	_sliceViewMatrix = m;
+	Matrix4x3 mRotation = rotationMatrixX(float(M_PI) / 2.0f);
+	Matrix4x3 mInvert(-1.0f,  0.0f, 0.0f, 0.0f,
+	                   0.0f, -1.0f, 0.0f, 0.0f,
+	                   0.0f,  0.0f, 1.0f, 0.0f);
+	_sliceViewMatrix = mInvert * (_frameViewMatrix * mRotation);
 }
 
 void View::calculateCameraPosition() {





More information about the Scummvm-git-logs mailing list