mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-07 10:21:31 +00:00
1159 lines
33 KiB
C++
1159 lines
33 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*
|
|
* Based on the original sources
|
|
* Faery Tale II -- The Halls of the Dead
|
|
* (c) 1993-1996 The Wyrmkeep Entertainment Co.
|
|
*/
|
|
|
|
#ifndef SAGA2_ACTOR_H
|
|
#define SAGA2_ACTOR_H
|
|
|
|
#include "saga2/objects.h"
|
|
#include "saga2/saveload.h"
|
|
|
|
namespace Saga2 {
|
|
|
|
class ActorAssignment;
|
|
class Band;
|
|
class MotionTask;
|
|
class TaskStack;
|
|
|
|
const int kBandingDist = kSectorSize * 2;
|
|
const int kActorScriptVars = 4;
|
|
|
|
/* ===================================================================== *
|
|
Actor character attributes
|
|
* ===================================================================== */
|
|
|
|
// Defines the colors of MANA
|
|
|
|
enum ActorSkillID {
|
|
kSkillIDArchery = 0,
|
|
kSkillIDSwordcraft,
|
|
kSkillIDShieldcraft,
|
|
kSkillIDBludgeon,
|
|
kSkillIDThrowing, // gone
|
|
kSkillIDSpellcraft,
|
|
kSkillIDStealth, // gone
|
|
kSkillIDAgility,
|
|
kSkillIDBrawn,
|
|
kSkillIDLockpick, // gone
|
|
kSkillIDPilfer, // gone
|
|
kSkillIDFirstAid, // gone
|
|
kSkillIDSpotHidden, // gone
|
|
kNumSkills
|
|
};
|
|
|
|
enum ArmorObjectTypes {
|
|
SHIRT_ARMOR = 0,
|
|
BOOT_ARMOR,
|
|
BRACER_ARMOR,
|
|
HELM_ARMOR,
|
|
NECKLACE_ARMOR,
|
|
CLOAK_ARMOR,
|
|
RING_ARMOR,
|
|
|
|
ARMOR_COUNT
|
|
};
|
|
|
|
/* ===================================================================== *
|
|
ArmorAttributes struct
|
|
* ===================================================================== */
|
|
|
|
struct ArmorAttributes {
|
|
uint8 damageAbsorbtion,
|
|
damageDivider,
|
|
defenseBonus;
|
|
};
|
|
|
|
/* ===================================================================== *
|
|
ActorAttributes structure
|
|
* ===================================================================== */
|
|
|
|
// this enum acts as a layer of indirection for the unioned allSkills
|
|
// array.
|
|
|
|
|
|
// This defines the basic skills possessed by an actor
|
|
struct ActorAttributes {
|
|
enum skillInfo {
|
|
kSkillBasePercent = 100,
|
|
kSkillFracPointsPerLevel = 5, // this being twenty and levels at 5
|
|
kSkillLevels = 20, // will make the advancement calc quick & easy
|
|
kSkillMaxLevel = kSkillFracPointsPerLevel * kSkillLevels
|
|
};
|
|
|
|
enum vitalityInfo {
|
|
kVitalityLimit = 256
|
|
};
|
|
|
|
// Automatic skills
|
|
uint8 archery, // Accuracy of missile weapons
|
|
swordcraft, // Accuracy of bladed melee weapons
|
|
shieldcraft, // Actor's ability to use a shield
|
|
bludgeon, // Accuracy of non-bladed melee weapons
|
|
throwing, // Ability to throw objects accurately
|
|
spellcraft, // Accuracy of spell combat
|
|
stealth, // Ability to remain unnoticed
|
|
agility, // Ability to dodge
|
|
brawn, // Ability to lift, and damage of weapons
|
|
lockpick; // Ability to pick locks
|
|
|
|
// Manual skills
|
|
uint8 pilfer, // Ability to "lift" an item
|
|
firstAid, // Ability to heal recent injuries
|
|
spotHidden; // Ability to spot hidden objects
|
|
|
|
// Pad byte for alignment
|
|
int8 pad;
|
|
|
|
// Hit-points
|
|
int16 vitality;
|
|
|
|
// Magic energy
|
|
int16 redMana,
|
|
orangeMana,
|
|
yellowMana,
|
|
greenMana,
|
|
blueMana,
|
|
violetMana;
|
|
|
|
uint8 &skill(int16 id) {
|
|
switch (id) {
|
|
case kSkillIDArchery: return archery;
|
|
case kSkillIDSwordcraft: return swordcraft;
|
|
case kSkillIDShieldcraft: return shieldcraft;
|
|
case kSkillIDBludgeon: return bludgeon;
|
|
case kSkillIDThrowing: return throwing;
|
|
case kSkillIDSpellcraft: return spellcraft;
|
|
case kSkillIDStealth: return stealth;
|
|
case kSkillIDAgility: return agility;
|
|
case kSkillIDBrawn: return brawn;
|
|
case kSkillIDLockpick: return lockpick;
|
|
case kSkillIDPilfer: return pilfer;
|
|
case kSkillIDFirstAid: return firstAid;
|
|
case kSkillIDSpotHidden: return spotHidden;
|
|
}
|
|
error("Incorrect skill id: %d", id);
|
|
}
|
|
int16 &mana(int16 id) {
|
|
switch (id) {
|
|
case kManaIDRed: return redMana;
|
|
case kManaIDOrange: return orangeMana;
|
|
case kManaIDYellow: return yellowMana;
|
|
case kManaIDGreen: return greenMana;
|
|
case kManaIDBlue: return blueMana;
|
|
case kManaIDViolet: return violetMana;
|
|
}
|
|
error("Incorrect mana id: %d", id);
|
|
}
|
|
|
|
uint8 getSkillLevel(int16 id) {
|
|
return skill(id) / kSkillFracPointsPerLevel + 1;
|
|
}
|
|
|
|
void read(Common::InSaveFile *in) {
|
|
archery = in->readByte();
|
|
swordcraft = in->readByte();
|
|
shieldcraft = in->readByte();
|
|
bludgeon = in->readByte();
|
|
throwing = in->readByte();
|
|
spellcraft = in->readByte();
|
|
stealth = in->readByte();
|
|
agility = in->readByte();
|
|
brawn = in->readByte();
|
|
lockpick = in->readByte();
|
|
pilfer = in->readByte();
|
|
firstAid = in->readByte();
|
|
spotHidden = in->readByte();
|
|
pad = in->readSByte();
|
|
vitality = in->readSint16LE();
|
|
redMana = in->readSint16LE();
|
|
orangeMana = in->readSint16LE();
|
|
yellowMana = in->readSint16LE();
|
|
greenMana = in->readSint16LE();
|
|
blueMana = in->readSint16LE();
|
|
violetMana = in->readSint16LE();
|
|
}
|
|
|
|
void write(Common::MemoryWriteStreamDynamic *out) {
|
|
out->writeByte(archery);
|
|
out->writeByte(swordcraft);
|
|
out->writeByte(shieldcraft);
|
|
out->writeByte(bludgeon);
|
|
out->writeByte(throwing);
|
|
out->writeByte(spellcraft);
|
|
out->writeByte(stealth);
|
|
out->writeByte(agility);
|
|
out->writeByte(brawn);
|
|
out->writeByte(lockpick);
|
|
out->writeByte(pilfer);
|
|
out->writeByte(firstAid);
|
|
out->writeByte(spotHidden);
|
|
out->writeSByte(pad);
|
|
out->writeSint16LE(vitality);
|
|
out->writeSint16LE(redMana);
|
|
out->writeSint16LE(orangeMana);
|
|
out->writeSint16LE(yellowMana);
|
|
out->writeSint16LE(greenMana);
|
|
out->writeSint16LE(blueMana);
|
|
out->writeSint16LE(violetMana);
|
|
}
|
|
}; // 28 bytes
|
|
|
|
|
|
const int kBaseCarryingCapacity = 100;
|
|
const int kCarryingCapacityBonusPerBrawn = 200 / ActorAttributes::kSkillLevels;
|
|
|
|
/* ===================================================================== *
|
|
ResourceActorProtoExtension structure
|
|
* ===================================================================== */
|
|
|
|
enum combatBehaviorTypes {
|
|
kBehaviorHungry,
|
|
kBehaviorCowardly,
|
|
kBehaviorBerserk,
|
|
kBehaviorSmart
|
|
};
|
|
|
|
// This defines the additional data fields needed for actor prototypes
|
|
struct ResourceActorProtoExtension {
|
|
|
|
ActorAttributes baseStats; // Base stats for non-player actors
|
|
|
|
// Defines behavior for combat tactics.
|
|
uint8 combatBehavior;
|
|
uint8 gruntStyle;
|
|
|
|
uint32 baseEffectFlags; // special effects, see EFFECTS.H
|
|
|
|
// Default constructor -- do nothing
|
|
ResourceActorProtoExtension() {
|
|
memset(&baseStats, 0, sizeof(baseStats));
|
|
|
|
combatBehavior = 0;
|
|
gruntStyle = 0;
|
|
baseEffectFlags = 0;
|
|
}
|
|
|
|
// Copy constructor
|
|
ResourceActorProtoExtension(ResourceActorProtoExtension &ext) {
|
|
memcpy(this, &ext, sizeof(ResourceActorProtoExtension));
|
|
}
|
|
|
|
void load(Common::SeekableReadStream *stream) {
|
|
baseStats.read(stream);
|
|
combatBehavior = stream->readByte();
|
|
gruntStyle = stream->readByte();
|
|
baseEffectFlags = stream->readUint32LE();
|
|
}
|
|
}; // 28 bytes
|
|
|
|
/* ===================================================================== *
|
|
ResourceActorPrototype structure
|
|
* ===================================================================== */
|
|
|
|
// Defines the actor prototype data as read from the resource file
|
|
struct ResourceActorPrototype {
|
|
ResourceObjectPrototype proto; // Standard prototype data
|
|
ResourceActorProtoExtension ext; // Extended actor data
|
|
|
|
void load(Common::SeekableReadStream *stream) {
|
|
proto.load(stream);
|
|
ext.load(stream);
|
|
}
|
|
};
|
|
|
|
/* ===================================================================== *
|
|
ActorProto prototype behavior for Actors
|
|
* ===================================================================== */
|
|
|
|
class ActorProto : public ProtoObj, public ResourceActorProtoExtension {
|
|
|
|
private:
|
|
enum {
|
|
kViewableRows = 3,
|
|
kViewableCols = 3,
|
|
kMaxRows = 3,
|
|
kMaxCols = 3
|
|
};
|
|
|
|
public:
|
|
ActorProto(ResourceActorPrototype &a) :
|
|
ProtoObj(a.proto),
|
|
ResourceActorProtoExtension(a.ext) {
|
|
}
|
|
|
|
// returns the containment type flags for this object
|
|
virtual uint16 containmentSet();
|
|
|
|
// returns true if this object can contain another object
|
|
virtual bool canContain(ObjectID dObj, ObjectID item);
|
|
|
|
// Determine if this object can contain another object at a
|
|
// specified slot
|
|
virtual bool canContainAt(
|
|
ObjectID dObj,
|
|
ObjectID item,
|
|
const TilePoint &where);
|
|
|
|
weaponID getWeaponID();
|
|
|
|
// use this actor
|
|
bool useAction(ObjectID dObj, ObjectID enactor);
|
|
|
|
// open this actor
|
|
bool canOpen(ObjectID dObj, ObjectID enactor);
|
|
bool openAction(ObjectID dObj, ObjectID enactor);
|
|
|
|
// close this actor
|
|
bool closeAction(ObjectID dObj, ObjectID enactor);
|
|
|
|
bool strikeAction(
|
|
ObjectID dObj,
|
|
ObjectID enactor,
|
|
ObjectID item);
|
|
|
|
bool damageAction(
|
|
ObjectID dObj,
|
|
ObjectID enactor,
|
|
ObjectID target);
|
|
|
|
// drop another object onto this actor.
|
|
bool acceptDropAction(
|
|
ObjectID dObj,
|
|
ObjectID enactor,
|
|
ObjectID droppedObj,
|
|
int count);
|
|
|
|
// cause damage directly
|
|
bool acceptDamageAction(
|
|
ObjectID dObj,
|
|
ObjectID enactor,
|
|
int8 absDamage,
|
|
effectDamageTypes dType,
|
|
int8 dice,
|
|
uint8 sides,
|
|
int8 perDieMod);
|
|
|
|
// cause healing directly
|
|
bool acceptHealingAction(ObjectID dObj, ObjectID enactor, int8 healing);
|
|
|
|
// Accept strike from an object (allows this actor to cause
|
|
// damage to the striking object).
|
|
bool acceptStrikeAction(
|
|
ObjectID dObj,
|
|
ObjectID enactor,
|
|
ObjectID strikingObj,
|
|
uint8 skillIndex);
|
|
|
|
// Handle the results of an object being inserted into this object
|
|
// at the specified slot
|
|
bool acceptInsertionAtAction(
|
|
ObjectID dObj,
|
|
ObjectID enactor,
|
|
ObjectID item,
|
|
const TilePoint &where,
|
|
int16 num = 1);
|
|
|
|
// Initiate an attack using this type of object
|
|
virtual void initiateAttack(ObjectID attacker, ObjectID target);
|
|
|
|
// Given an object sound effect record, which sound should be made
|
|
// when this object is damaged
|
|
virtual uint8 getDamageSound(const ObjectSoundFXs &soundFXs);
|
|
|
|
// Do the background processing, if needed, for this object.
|
|
void doBackgroundUpdate(GameObject *obj);
|
|
|
|
// Cause the user's associated skill to grow
|
|
void applySkillGrowth(ObjectID enactor, uint8 points = 1);
|
|
|
|
bool greetActor(
|
|
ObjectID dObj, // object dropped on
|
|
ObjectID enactor); // person doing dropping
|
|
|
|
public:
|
|
virtual uint16 getViewableRows() {
|
|
return kViewableRows;
|
|
}
|
|
virtual uint16 getViewableCols() {
|
|
return kViewableCols;
|
|
}
|
|
virtual uint16 getMaxRows() {
|
|
return kMaxRows;
|
|
}
|
|
virtual uint16 getMaxCols() {
|
|
return kMaxCols;
|
|
}
|
|
|
|
virtual bool canFitBulkwise(GameObject *container, GameObject *obj);
|
|
virtual bool canFitMasswise(GameObject *container, GameObject *obj);
|
|
|
|
virtual uint16 massCapacity(GameObject *container);
|
|
virtual uint16 bulkCapacity(GameObject *container);
|
|
};
|
|
|
|
/* ============================================================================ *
|
|
Actor: Describes an instance of a character
|
|
* ============================================================================ */
|
|
|
|
enum actorCreationFlags {
|
|
kActorPermanent = (1 << 0)
|
|
};
|
|
|
|
enum DispositionType {
|
|
kDispositionFriendly,
|
|
kDispositionEnemy,
|
|
|
|
kDispositionPlayer
|
|
};
|
|
|
|
enum actionSequenceOptions {
|
|
|
|
// Flags set by call to setAction
|
|
kAnimateRepeat = (1 << 0), // repeat animation when done
|
|
kAnimateReverse = (1 << 1), // animate in reverse direction
|
|
kAnimateAlternate = (1 << 2), // both directions, back & forth
|
|
kAnimateRandom = (1 << 3), // pick a random frame
|
|
kAnimateNoRestart = (1 << 4), // don't reset from start
|
|
|
|
// This flag is set if the animation has been put on hold until
|
|
// the actor's appearance is reloaded.
|
|
kAnimateOnHold = (1 << 5),
|
|
|
|
// This flag is set if the final frame of the animation has
|
|
// been reached.
|
|
kAnimateFinished = (1 << 6),
|
|
|
|
// This flag gets set if the sprite could not be displayed
|
|
// because it's bank hasn't been loaded yet.
|
|
kAnimateNotLoaded = (1 << 7)
|
|
};
|
|
|
|
// Various types of action sequences
|
|
|
|
|
|
enum ActorAnimationTypes {
|
|
|
|
// Various types of stands
|
|
kActionStand = 0, // standing still
|
|
kActionWaitAgressive, // an agigressive wait cycle
|
|
kActionWaitImpatient, // an impatient wait cycle
|
|
kActionWaitFriendly, // a a friendly wait cycle
|
|
|
|
// Walking and running
|
|
kActionWalk, // walking motion
|
|
kActionRun, // running motion
|
|
|
|
// Squatting
|
|
kActionDuck, // stoop to dodge sword
|
|
kActionStoop, // stoop to pick up object
|
|
|
|
// Jumping
|
|
kActionFreeFall, // how he looks in ballistic
|
|
kActionFreeFallRunning, // a running leap (free fall)
|
|
kActionJumpUp, // begin jump straight up
|
|
kActionJumpFwd, // begin jump forward
|
|
kActionJumpBack, // begin jump back in surprise
|
|
kActionLand, // land after jump
|
|
kActionFallBadly, // after a very long fall
|
|
|
|
// Climbing
|
|
kActionClimbLadder, // climb a ladder (2 directions)
|
|
|
|
// Talking & interacting
|
|
kActionTalk, // talking
|
|
kActionGesture, // gesture with hands or body
|
|
kActionGiveItem, // give or take item
|
|
|
|
// Two-handed weapon use
|
|
kActionTwoHandSwingHigh, // full overhead swing aim high
|
|
kActionTwoHandSwingLow, // full overhead swing aim low
|
|
kActionTwoHandSwingLeftHigh, // partial swing on left (high)
|
|
kActionTwoHandSwingLeftLow, // partial swing on left (low)
|
|
kActionTwoHandSwingRightHigh, // partial swing on rgt (high)
|
|
kActionTwoHandSwingRightLow, // partial swing on rgt (low)
|
|
kActionTwoHandParry, // hold sword up to parry
|
|
|
|
// One-handed weapon use
|
|
kActionSwingHigh, // one-handed swing (high)
|
|
kActionSwingLow, // one-handed swing (low)
|
|
kActionParryHigh, // one-handed parry (high)
|
|
kActionParryLow, // one-handed parry (low)
|
|
kActionShieldParry, // parry with shield
|
|
|
|
kActionThrowObject, // throw
|
|
|
|
// Other combat actions
|
|
kActionFireBow, // fire an arrow
|
|
kActionCastSpell, // cast a magic spell
|
|
kActionUseWand, // cast a magic spell w/wand
|
|
kActionUseStaff, // cast a magic spell w/staff
|
|
kActionHit, // show impact of blow
|
|
kActionKnockedDown, // knocked down by opponent
|
|
kActionDie, // death agony
|
|
|
|
// Passive actions
|
|
kActionSleep, // sleeping
|
|
kActionDead, // dead body on ground
|
|
kActionSit, // sitting at table
|
|
|
|
// Misc actions built from other frames
|
|
kActionListenAtDoor, // listening at doors
|
|
kActionShoveDoor, // try to force a door open
|
|
kActionSpecial1, // special Action
|
|
kActionSpecial2, // special Action
|
|
kActionSpecial3, // special Action
|
|
kActionSpecial4, // special Action
|
|
kActionSpecial5, // special Action
|
|
kActionSpecial6, // special Action
|
|
kActionSpecial7, // special Action
|
|
kActionSpecial8 // special Action
|
|
};
|
|
|
|
enum ActorGoalTypes {
|
|
kActorGoalFollowAssignment,
|
|
kActorGoalPreserveSelf,
|
|
kActorGoalAttackEnemy,
|
|
kActorGoalFollowLeader,
|
|
kActorGoalAvoidEnemies
|
|
};
|
|
|
|
// The actor structure will be divided into two parts. The
|
|
// ResourceActor structure defines the data as it is stored in the
|
|
// resource file. The Actor structure has a copy of all of the
|
|
// ResourceActor data members, plus data members which will be
|
|
// initialized and used during run time.
|
|
|
|
struct ResourceActor : public ResourceGameObject {
|
|
|
|
// Social loyalty
|
|
uint8 faction; // actor's faction
|
|
|
|
// Appearance attribute
|
|
uint8 colorScheme; // indirect color map
|
|
|
|
int32 appearanceID; // appearnce of this actor
|
|
|
|
// Personality attributes
|
|
int8 attitude, // cooperativeness
|
|
mood; // happiness
|
|
uint8 disposition; // actor disposition
|
|
// 0 = friendly, 1 = enemy,
|
|
// 2 = Julian, 3 = Philip,
|
|
// 4 = Kevin
|
|
|
|
// Character orientation
|
|
Direction currentFacing; // current facing direction
|
|
|
|
// Tether info
|
|
int16 tetherLocU; // tether U coordinate
|
|
int16 tetherLocV; // tether V coordinate
|
|
int16 tetherDist; // length of tether
|
|
|
|
// Held objects
|
|
ObjectID leftHandObject, // object held in left hand.
|
|
rightHandObject; // object held in right hand.
|
|
|
|
// Knowledge packets
|
|
uint16 knowledge[16];
|
|
|
|
// Schedule script ID
|
|
uint16 schedule;
|
|
|
|
// Pad bytes
|
|
uint8 reserved[18];
|
|
|
|
ResourceActor(Common::SeekableReadStream *stream);
|
|
};
|
|
|
|
class Actor : public GameObject {
|
|
friend class ActorProto;
|
|
friend class MotionTask;
|
|
friend class Task;
|
|
friend class TaskStack;
|
|
|
|
public:
|
|
|
|
// Resource fields
|
|
|
|
// Social loyalty
|
|
uint8 _faction; // actor's faction
|
|
|
|
// Appearance attribute
|
|
uint8 _colorScheme; // indirect color map
|
|
|
|
int32 _appearanceID; // appearnce of this actor
|
|
|
|
// Personality attributes
|
|
int8 _attitude, // cooperativeness
|
|
_mood; // happiness
|
|
uint8 _disposition; // actor disposition
|
|
// 0 = friendly, 1 = enemy,
|
|
// 2 = Julian, 3 = Philip,
|
|
// 4 = Kevin
|
|
|
|
// Character orientation
|
|
Direction _currentFacing; // current facing direction
|
|
|
|
// Tether info
|
|
int16 _tetherLocU; // tether U coordinate
|
|
int16 _tetherLocV; // tether V coordinate
|
|
int16 _tetherDist; // length of tether
|
|
|
|
// Held objects
|
|
ObjectID _leftHandObject, // object held in left hand.
|
|
_rightHandObject; // object held in right hand.
|
|
|
|
// Knowledge packets
|
|
uint16 _knowledge[16];
|
|
|
|
// Schedule script ID
|
|
uint16 _schedule;
|
|
|
|
// Run-time fields
|
|
|
|
uint8 _conversationMemory[4];// last things talked about
|
|
|
|
// Sprite animation variables
|
|
uint8 _currentAnimation, // current action sequence
|
|
_currentPose, // current pose in sequence
|
|
_animationFlags; // current posing flags
|
|
|
|
// Various actor flags
|
|
enum {
|
|
kAFLobotomized = (1 << 0),
|
|
kAFTemporary = (1 << 1),
|
|
kAFAfraid = (1 << 2),
|
|
kAFHasAssignment = (1 << 3),
|
|
kAFSpecialAttack = (1 << 4),
|
|
kAFFightStance = (1 << 5)
|
|
};
|
|
|
|
uint8 _flags;
|
|
|
|
// Contains sprite index and positioning info for the current
|
|
// actor state.
|
|
ActorPose _poseInfo; // current animation state
|
|
|
|
// Pointer to the appearance record (sprite array) for this actor.
|
|
ActorAppearance *_appearance; // appearance structs
|
|
|
|
int16 _cycleCount; // misc counter for actions
|
|
int16 _kludgeCount; // another misc counter
|
|
|
|
uint32 _enchantmentFlags; // flags indicating racial
|
|
// abilities and enchantments
|
|
|
|
// Movement attributes
|
|
MotionTask *_moveTask;
|
|
|
|
// Current task
|
|
TaskStack *_curTask;
|
|
|
|
// Current goal type
|
|
uint8 _currentGoal;
|
|
|
|
// Used for deltayed deactivation (and also to word-align struct)
|
|
uint8 _deactivationCounter;
|
|
|
|
// Assignment
|
|
ActorAssignment *_assignment;
|
|
// assignments
|
|
|
|
// Current effective stats
|
|
ActorAttributes _effectiveStats;
|
|
|
|
uint8 _actionCounter; // coordinate moves in combat
|
|
|
|
uint16 _effectiveResistance; // resistances (see EFFECTS.H)
|
|
uint16 _effectiveImmunity; // immunities (see EFFECTS.H)
|
|
|
|
int16 _recPointsPerUpdate; // fractional vitality recovery
|
|
|
|
int16 _currentRecoveryPoints; // fraction left from last recovery
|
|
|
|
enum vitalityRecovery {
|
|
kRecPointsPerVitality = 10
|
|
};
|
|
|
|
|
|
Actor *_leader; // This actor's leader
|
|
ObjectID _leaderID;
|
|
Band *_followers; // This actor's band of followers
|
|
BandID _followersID;
|
|
|
|
ObjectID _armorObjects[ARMOR_COUNT]; // armor objects being worn
|
|
|
|
GameObject *_currentTarget;
|
|
ObjectID _currentTargetID;
|
|
|
|
int16 _scriptVar[kActorScriptVars]; // scratch variables for scripter use
|
|
|
|
// Member functions
|
|
|
|
private:
|
|
// Initialize actor record
|
|
void init(
|
|
int16 protoIndex,
|
|
uint16 nameIndex,
|
|
uint16 scriptIndex,
|
|
int32 appearanceNum,
|
|
uint8 colorSchemeIndex,
|
|
uint8 factionNum,
|
|
uint8 initFlags);
|
|
|
|
public:
|
|
// Default constructor
|
|
Actor();
|
|
|
|
// Constructor - initial actor construction
|
|
Actor(const ResourceActor &res);
|
|
|
|
Actor(Common::InSaveFile *in);
|
|
|
|
// Destructor
|
|
~Actor();
|
|
|
|
// Return the number of bytes needed to archive this actor
|
|
int32 archiveSize();
|
|
|
|
void write(Common::MemoryWriteStreamDynamic *out);
|
|
|
|
static Actor *newActor(
|
|
int16 protoNum,
|
|
uint16 nameIndex,
|
|
uint16 scriptIndex,
|
|
int32 appearanceNum,
|
|
uint8 colorSchemeIndex,
|
|
uint8 factionNum,
|
|
uint8 initFlags);
|
|
|
|
// Delete this actor
|
|
void deleteActor();
|
|
|
|
private:
|
|
// Turn incrementally
|
|
void turn(Direction targetDir) {
|
|
Direction relativeDir = (targetDir - _currentFacing) & 0x7;
|
|
|
|
_currentFacing =
|
|
(relativeDir < 4
|
|
? _currentFacing + 1
|
|
: _currentFacing - 1)
|
|
& 0x7;
|
|
}
|
|
public:
|
|
|
|
// Cause the actor to stop his current motion task is he is
|
|
// interruptable
|
|
void stopMoving();
|
|
|
|
// Cause this actor to die
|
|
void die();
|
|
|
|
// Cause this actor to return from the dead
|
|
void imNotQuiteDead();
|
|
|
|
// makes the actor do a vitality change test
|
|
void vitalityUpdate();
|
|
|
|
// Perform actor specific activation tasks
|
|
void activateActor();
|
|
|
|
// Perform actor specific deactivation tasks
|
|
void deactivateActor();
|
|
|
|
// De-lobotomize this actor
|
|
void delobotomize();
|
|
|
|
// Lobotomize this actor
|
|
void lobotomize();
|
|
|
|
// Return a pointer to the actor's current assignment
|
|
ActorAssignment *getAssignment() {
|
|
return _flags & kAFHasAssignment
|
|
? _assignment
|
|
: nullptr;
|
|
}
|
|
|
|
// determine whether this actor has a specified property
|
|
bool hasProperty(const ActorProperty &actorProp) {
|
|
// The function call operator is used explicitly because
|
|
// Visual C++ 4.0 doesn't like it otherwise.
|
|
return actorProp.operator()(this);
|
|
}
|
|
|
|
// Determine if specified point is within actor's arms' reach
|
|
bool inReach(const TilePoint &tp);
|
|
|
|
// Determine if specified point is within an objects use range
|
|
bool inUseRange(const TilePoint &tp, GameObject *obj);
|
|
|
|
// Determine if actor is dead
|
|
bool isDead() {
|
|
return _effectiveStats.vitality <= 0;
|
|
}
|
|
|
|
// Determine if actor is immobile (i.e. can't walk)
|
|
bool isImmobile();
|
|
|
|
// Return a pointer to this actor's currently readied offensive
|
|
// object
|
|
GameObject *offensiveObject();
|
|
|
|
// Returns pointers to this actor's readied primary defensive object
|
|
// and optionally their scondary defensive object
|
|
void defensiveObject(GameObject **priPtr, GameObject **secPtr = NULL);
|
|
|
|
// Returns a pointer to the object with which this actor is
|
|
// currently blocking, if any
|
|
GameObject *blockingObject(Actor *attacker);
|
|
|
|
// Return the total used armor attributes
|
|
void totalArmorAttributes(ArmorAttributes &armorAttribs);
|
|
|
|
// Determine if specified point is within actor's attack range
|
|
bool inAttackRange(const TilePoint &tp);
|
|
|
|
// Attack the specified object with the currently selected weapon
|
|
void attack(GameObject *obj);
|
|
|
|
// Stop any attack on the specified object
|
|
void stopAttack(GameObject *obj);
|
|
|
|
// Determine if this actor can block an attack with objects
|
|
// currently being held
|
|
bool canDefend();
|
|
|
|
// Return a numeric value which roughly estimates this actor's
|
|
// offensive strength
|
|
int16 offenseScore();
|
|
|
|
// Return a numeric value which roughly estimates this actor's
|
|
// defensive strenght
|
|
int16 defenseScore();
|
|
|
|
// Handle the effect of a successful hit on an opponent in combat
|
|
void handleSuccessfulStrike(GameObject *weapon) {
|
|
weapon->proto()->applySkillGrowth(thisID());
|
|
}
|
|
|
|
// Return the value of this actor's disposition
|
|
int16 getDisposition() {
|
|
return _disposition;
|
|
}
|
|
|
|
// Give the actor a new disposition
|
|
int16 setDisposition(int16 newDisp) {
|
|
int16 oldDisp = _disposition;
|
|
if (newDisp < kDispositionPlayer)
|
|
_disposition = newDisp;
|
|
return oldDisp;
|
|
}
|
|
|
|
// Return a pointer to the effective stats
|
|
ActorAttributes *getStats() {
|
|
return &_effectiveStats;
|
|
}
|
|
|
|
// Return a pointer to this actor's base stats
|
|
ActorAttributes *getBaseStats();
|
|
|
|
// Return the color remapping table
|
|
void getColorTranslation(ColorTable map);
|
|
|
|
// Determine if this actor is interruptable
|
|
bool isInterruptable() {
|
|
return _actionCounter == 0;
|
|
}
|
|
|
|
// Determine if this actor is permanently uninterruptable
|
|
bool isPermanentlyUninterruptable() {
|
|
return _actionCounter == maxuint8;
|
|
}
|
|
|
|
// Set the inturruptability for this actor
|
|
void setInterruptablity(bool val) {
|
|
_actionCounter = val ? 0 : maxuint8;
|
|
}
|
|
|
|
// Set action time counter for this actor
|
|
// REM: the action points will eventually need to be scaled based
|
|
// upon enchantments and abilities
|
|
void setActionPoints(uint8 points) {
|
|
_actionCounter = points;
|
|
}
|
|
|
|
// Drop the all of the actor's inventory
|
|
void dropInventory();
|
|
|
|
// Place an object into this actor's right or left hand
|
|
void holdInRightHand(ObjectID objID);
|
|
void holdInLeftHand(ObjectID objID);
|
|
|
|
// Wear a piece of armor
|
|
void wear(ObjectID objID, uint8 where);
|
|
|
|
// Update the appearance of an actor with no motion task.
|
|
void updateAppearance(int32 deltaTime);
|
|
|
|
// Used To Find Wait State When Preffered Not Available
|
|
bool setAvailableAction(int16 action1, int16 action2, int16 action3, int16 actiondefault);
|
|
|
|
// Set the current animation sequence that the actor is doing.
|
|
// Returns the number of poses in the sequence, or 0 if there
|
|
// are no poses in the sequence.
|
|
int16 setAction(int16 newState, int16 flags);
|
|
|
|
// returns true if the action is available in the current
|
|
// direction.
|
|
bool isActionAvailable(int16 newState, bool anyDir = false);
|
|
|
|
// Return the number of animation frames in the specified action
|
|
// for the specified direction
|
|
int16 animationFrames(int16 actionType, Direction dir);
|
|
|
|
// Update the current animation sequence to the next frame
|
|
bool nextAnimationFrame();
|
|
|
|
// calculate which sprite frames to show. Return false if
|
|
// sprite frames are not loaded.
|
|
bool calcSpriteFrames();
|
|
|
|
// Calculate the frame list entry, given the current actor's
|
|
// body state, and facing direction.
|
|
// FrameListEntry *calcFrameState( int16 bodyState );
|
|
|
|
// Returns 0 if not moving, 1 if path being calculated,
|
|
// 2 if path being followed.
|
|
int pathFindState();
|
|
|
|
// High level actor behavior functions
|
|
private:
|
|
void setGoal(uint8 newGoal);
|
|
|
|
public:
|
|
void evaluateNeeds();
|
|
|
|
// Called every frame to update the state of this actor
|
|
void updateState();
|
|
|
|
void handleTaskCompletion(TaskResult result);
|
|
void handleOffensiveAct(Actor *attacker);
|
|
void handleDamageTaken(uint8 damage);
|
|
void handleSuccessfulStrike(Actor *target, int8 damage);
|
|
void handleSuccessfulKill(Actor *target);
|
|
|
|
private:
|
|
static bool canBlockWith(GameObject *defenseObj, Direction relativeDir);
|
|
public:
|
|
void evaluateMeleeAttack(Actor *attacker);
|
|
|
|
// Banding related functions
|
|
void bandWith(Actor *newLeader);
|
|
void disband();
|
|
|
|
bool inBandingRange() {
|
|
assert(_leader != NULL);
|
|
|
|
return _leader->IDParent() == IDParent()
|
|
&& (_leader->getLocation() - getLocation()).quickHDistance()
|
|
<= kBandingDist;
|
|
}
|
|
|
|
private:
|
|
bool addFollower(Actor *newBandMember);
|
|
void removeFollower(Actor *bandMember);
|
|
|
|
TaskStack *createFollowerTask(Actor *bandMember);
|
|
uint8 evaluateFollowerNeeds(Actor *follower);
|
|
|
|
public:
|
|
// Knowledge-related member functions
|
|
bool addKnowledge(uint16 kID);
|
|
bool removeKnowledge(uint16 kID);
|
|
void clearKnowledge();
|
|
void useKnowledge(scriptCallFrame &scf);
|
|
|
|
bool canSenseProtaganistIndirectly(SenseInfo &info, int16 range);
|
|
bool canSenseSpecificActorIndirectly(
|
|
SenseInfo &info,
|
|
int16 range,
|
|
Actor *a);
|
|
bool canSenseSpecificObjectIndirectly(
|
|
SenseInfo &info,
|
|
int16 range,
|
|
ObjectID obj);
|
|
bool canSenseActorPropertyIndirectly(
|
|
SenseInfo &info,
|
|
int16 range,
|
|
ActorPropertyID prop);
|
|
bool canSenseObjectPropertyIndirectly(
|
|
SenseInfo &info,
|
|
int16 range,
|
|
ObjectPropertyID prop);
|
|
|
|
// Take mana from actor's mana pool (if possible)
|
|
bool takeMana(ActorManaID i, int8 dMana);
|
|
|
|
bool hasMana(ActorManaID i, int8 dMana);
|
|
|
|
uint32 getBaseEnchantmentEffects();
|
|
uint16 getBaseResistance();
|
|
uint16 getBaseImmunity();
|
|
uint16 getBaseRecovery();
|
|
|
|
bool resists(effectResistTypes r) {
|
|
return _effectiveResistance & (1 << r);
|
|
}
|
|
bool isImmuneTo(effectImmuneTypes r) {
|
|
return _effectiveImmunity & (1 << r);
|
|
}
|
|
bool hasEffect(effectOthersTypes e) {
|
|
return (_enchantmentFlags & (1 << e)) != 0;
|
|
}
|
|
|
|
void setResist(effectResistTypes r, bool on) {
|
|
_effectiveResistance = on ?
|
|
_effectiveResistance | (1 << r) :
|
|
_effectiveResistance & ~(1 << r);
|
|
}
|
|
|
|
void setImmune(effectImmuneTypes r, bool on) {
|
|
_effectiveImmunity = on ?
|
|
_effectiveImmunity | (1 << r) :
|
|
_effectiveImmunity & ~(1 << r);
|
|
}
|
|
|
|
void setEffect(effectOthersTypes e, bool on) {
|
|
_enchantmentFlags = on ?
|
|
_enchantmentFlags | (1 << e) :
|
|
_enchantmentFlags & ~(1 << e);
|
|
}
|
|
|
|
bool makeSavingThrow();
|
|
|
|
void setFightStance(bool val) {
|
|
if (val)
|
|
_flags |= kAFFightStance;
|
|
else
|
|
_flags &= ~kAFFightStance;
|
|
}
|
|
};
|
|
|
|
inline bool isPlayerActor(Actor *a) {
|
|
return a->_disposition >= kDispositionPlayer;
|
|
}
|
|
|
|
inline bool isPlayerActor(ObjectID obj) {
|
|
return isActor(obj)
|
|
&& isPlayerActor((Actor *)GameObject::objectAddress(obj));
|
|
}
|
|
|
|
inline bool isEnemy(Actor *a) {
|
|
return !a->isDead() && a->_disposition == kDispositionEnemy;
|
|
}
|
|
|
|
inline bool isEnemy(ObjectID obj) {
|
|
return isActor(obj)
|
|
&& isEnemy((Actor *)GameObject::objectAddress(obj));
|
|
}
|
|
|
|
void updateActorStates();
|
|
|
|
void pauseActorStates();
|
|
void resumeActorStates();
|
|
|
|
void setCombatBehavior(bool enabled);
|
|
|
|
// Determine if the actors are currently initialized
|
|
bool areActorsInitialized();
|
|
|
|
void clearEnchantments(Actor *a);
|
|
void addEnchantment(Actor *a, uint16 enchantmentID);
|
|
|
|
/* ============================================================================ *
|
|
Actor factions table
|
|
* ============================================================================ */
|
|
|
|
enum factionTallyTypes {
|
|
kFactionNumKills = 0, // # of times faction member killed by PC
|
|
kFactionNumThefts, // # of times PC steals from faction member
|
|
kFactionNumFavors, // accumulated by SAGA script.
|
|
|
|
kFactionNumColumns
|
|
};
|
|
|
|
// Get the attitude a particular faction has for a char.
|
|
int16 GetFactionTally(int faction, enum factionTallyTypes act);
|
|
|
|
// Increment / Decrement faction attitude
|
|
// Whenever an actor is killed, call:
|
|
// AddFactionAttitude( actor.faction, kFactionNumKills, 1 );
|
|
// Whenever an actor is robbed, call:
|
|
// AddFactionAttitude( actor.faction, kFactionNumThefts, 1 );
|
|
int16 AddFactionTally(int faction, enum factionTallyTypes act, int amt);
|
|
|
|
// Initialize the faction tally table
|
|
void initFactionTallies();
|
|
|
|
// Save the faction tallies to a save file
|
|
void saveFactionTallies(Common::OutSaveFile *outS);
|
|
|
|
// Load the faction tallies from a save file
|
|
void loadFactionTallies(Common::InSaveFile *in);
|
|
|
|
// Cleanup the faction tally table
|
|
inline void cleanupFactionTallies() { /* Nothing to do */ }
|
|
|
|
class ActorManager {
|
|
public:
|
|
|
|
enum {
|
|
kEvalRate = 8,
|
|
kEvalRateMask = kEvalRate - 1
|
|
};
|
|
|
|
Common::Array<Actor *> _actorList;
|
|
|
|
int32 _updatesViaScript;
|
|
int32 _baseActorIndex;
|
|
int16 _factionTable[kMaxFactions][kFactionNumColumns];
|
|
bool _actorStatesPaused;
|
|
bool _combatBehaviorEnabled;
|
|
|
|
ActorManager() {
|
|
_updatesViaScript = 0;
|
|
_baseActorIndex = kEvalRateMask;
|
|
|
|
memset(_factionTable, 0, sizeof(_factionTable));
|
|
|
|
_actorStatesPaused = false;
|
|
_combatBehaviorEnabled = false;
|
|
}
|
|
};
|
|
|
|
} // end of namespace Saga2
|
|
|
|
#endif
|