Implement get*Target combat routines

This commit is contained in:
Vsevolod Kremianskii 2021-03-23 19:59:16 +07:00
parent 581984f7c0
commit 8a7885e19e
9 changed files with 131 additions and 13 deletions

View file

@ -630,6 +630,7 @@ set(GAME_SOURCES
src/game/script/routines.cpp
src/game/script/routines_actions.cpp
src/game/script/routines_ai.cpp
src/game/script/routines_combat.cpp
src/game/script/routines_common.cpp
src/game/script/routines_effects.cpp
src/game/script/routines_enginetypes.cpp

View file

@ -185,15 +185,15 @@ void ActionExecutor::executeStartConversation(const shared_ptr<Object> &actor, S
}
void ActionExecutor::executeAttack(const shared_ptr<Object> &actor, AttackAction &action, float dt) {
auto target = action.target();
shared_ptr<SpatialObject> target(action.target());
if (target->isDead()) {
action.complete();
return;
}
glm::vec3 dest(target->position());
auto creatureActor = static_pointer_cast<Creature>(actor);
navigateCreature(creatureActor, dest, true, action.range(), dt);
if (navigateCreature(creatureActor, target->position(), true, action.range(), dt)) {
// TODO: start a combat round
}
}
bool ActionExecutor::navigateCreature(const shared_ptr<Creature> &creature, const glm::vec3 &dest, bool run, float distance, float dt) {

View file

@ -57,6 +57,13 @@ static constexpr int kStrRefRemains = 38151;
static string g_headHookNode("headhook");
static string g_talkDummyNode("talkdummy");
void Creature::Combat::reset() {
attackTarget.reset();
attemptedAttackTarget.reset();
spellTarget.reset();
attemptedSpellTarget.reset();
}
Creature::Creature(
uint32_t id,
ObjectFactory *objectFactory,

View file

@ -90,6 +90,15 @@ public:
std::shared_ptr<SpatialObject> lastPerceived;
};
struct Combat {
std::shared_ptr<SpatialObject> attackTarget;
std::shared_ptr<SpatialObject> attemptedAttackTarget;
std::shared_ptr<SpatialObject> spellTarget;
std::shared_ptr<SpatialObject> attemptedSpellTarget;
void reset();
};
Creature(
uint32_t id,
ObjectFactory *objectFactory,
@ -130,6 +139,7 @@ public:
int xp() const { return _xp; }
RacialType racialType() const { return _racialType; }
NPCAIStyle aiStyle() const { return _aiStyle; }
Combat &combat() { return _combat; }
void setMovementType(MovementType type);
void setFaction(Faction faction);
@ -217,6 +227,7 @@ private:
Perception _perception;
RacialType _racialType { RacialType::Unknown };
NPCAIStyle _aiStyle { NPCAIStyle::MeleeAttack };
Combat _combat;
// Animation

View file

@ -505,6 +505,15 @@ private:
// END Perception
// Combat
script::Variable getAttackTarget(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getAttemptedAttackTarget(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getSpellTarget(const VariablesList &args, script::ExecutionContext &ctx);
script::Variable getAttemptedSpellTarget(const VariablesList &args, script::ExecutionContext &ctx);
// END Combat
// AI
script::Variable getNPCAIStyle(const VariablesList &args, script::ExecutionContext &ctx);

View file

@ -338,7 +338,7 @@ Variable Routines::actionAttack(const VariablesList &args, ExecutionContext &ctx
warn("Script: actionAttack: attackee is invalid");
return Variable();
}
auto action = make_unique<AttackAction>(attackee);
auto action = make_unique<AttackAction>(attackee, caller->getAttackRange());
caller->actionQueue().add(move(action));
return Variable();

View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2020-2021 The reone project contributors
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include "routines.h"
#include "../../common/log.h"
#include "../object/creature.h"
using namespace std;
using namespace reone::script;
namespace reone {
namespace game {
Variable Routines::getAttackTarget(const VariablesList &args, ExecutionContext &ctx) {
Variable result;
result.type = VariableType::Object;
auto creature = getCreatureOrCaller(args, 0, ctx);
if (creature) {
result.object = creature->combat().attackTarget;
} else {
warn("Script: getAttackTarget: creature is invalid");
}
return move(result);
}
Variable Routines::getAttemptedAttackTarget(const VariablesList &args, ExecutionContext &ctx) {
Variable result;
result.type = VariableType::Object;
auto caller = getCallerAsCreature(ctx);
if (caller) {
result.object = caller->combat().attemptedAttackTarget;
} else {
warn("Script: getAttemptedAttackTarget: caller is invalid");
}
return move(result);
}
Variable Routines::getSpellTarget(const VariablesList &args, ExecutionContext &ctx) {
Variable result;
result.type = VariableType::Object;
auto creature = getCreatureOrCaller(args, 0, ctx);
if (creature) {
result.object = creature->combat().spellTarget;
} else {
warn("Script: getSpellTarget: creature is invalid");
}
return move(result);
}
Variable Routines::getAttemptedSpellTarget(const VariablesList &args, ExecutionContext &ctx) {
Variable result;
result.type = VariableType::Object;
auto caller = getCallerAsCreature(ctx);
if (caller) {
result.object = caller->combat().attemptedSpellTarget;
} else {
warn("Script: getAttemptedSpellTarget: caller is invalid");
}
return move(result);
}
} // namespace game
} // namespace reone

View file

@ -354,7 +354,7 @@ void Routines::addKotorRoutines() {
add("JumpToLocation", Void, { Location }, &Routines::jumpToLocation);
add("EffectTemporaryHitpoints", Effect, { Int }, &Routines::effectTemporaryHitpoints);
add("GetSkillRank", Int, { Int, Object }, &Routines::getSkillRank);
add("GetAttackTarget", Object, { Object });
add("GetAttackTarget", Object, { Object }, &Routines::getAttackTarget);
add("GetLastAttackType", Int, { Object });
add("GetLastAttackMode", Int, { Object });
add("GetDistanceBetween2D", Float, { Object, Object }, &Routines::getDistanceBetween2D);
@ -399,7 +399,7 @@ void Routines::addKotorRoutines() {
add("GetGender", Int, { Object }, &Routines::getGender);
add("GetIsTalentValid", Int, { Talent });
add("ActionMoveAwayFromLocation", Void, { Location, Int, Float }, &Routines::actionMoveAwayFromLocation);
add("GetAttemptedAttackTarget", Object, { });
add("GetAttemptedAttackTarget", Object, { }, &Routines::getAttemptedAttackTarget);
add("GetTypeFromTalent", Int, { Talent });
add("GetIdFromTalent", Int, { Talent });
add("PlayPazaak", Void, { Int, String, Int, Int, Object });
@ -413,7 +413,7 @@ void Routines::addKotorRoutines() {
add("EffectDamageForcePoints", Effect, { Int }, &Routines::effectDamageForcePoints);
add("EffectHealForcePoints", Effect, { Int }, &Routines::effectHealForcePoints);
add("SendMessageToPC", Void, { Object, String });
add("GetAttemptedSpellTarget", Object, { });
add("GetAttemptedSpellTarget", Object, { }, &Routines::getAttemptedSpellTarget);
add("GetLastOpenedBy", Object, { }, &Routines::getLastOpenedBy);
add("GetHasSpell", Int, { Int, Object });
add("OpenStore", Void, { Object, Object, Int, Int });
@ -800,7 +800,7 @@ void Routines::addKotorRoutines() {
add("ResetDialogState", Void, { });
add("SetGoodEvilValue", Void, { Object, Int });
add("GetIsPoisoned", Int, { Object });
add("GetSpellTarget", Object, { Object });
add("GetSpellTarget", Object, { Object }, &Routines::getSpellTarget);
add("SetSoloMode", Void, { Int });
add("EffectCutSceneHorrified", Effect, { }, &Routines::effectCutSceneHorrified);
add("EffectCutSceneParalyze", Effect, { }, &Routines::effectCutSceneParalyze);

View file

@ -355,7 +355,7 @@ void Routines::addTslRoutines() {
add("JumpToLocation", Void, { Location }, &Routines::jumpToLocation);
add("EffectTemporaryHitpoints", Effect, { Int }, &Routines::effectTemporaryHitpoints);
add("GetSkillRank", Int, { Int, Object }, &Routines::getSkillRank);
add("GetAttackTarget", Object, { Object });
add("GetAttackTarget", Object, { Object }, &Routines::getAttackTarget);
add("GetLastAttackType", Int, { Object });
add("GetLastAttackMode", Int, { Object });
add("GetDistanceBetween2D", Float, { Object, Object }, &Routines::getDistanceBetween2D);
@ -400,7 +400,7 @@ void Routines::addTslRoutines() {
add("GetGender", Int, { Object }, &Routines::getGender);
add("GetIsTalentValid", Int, { Talent });
add("ActionMoveAwayFromLocation", Void, { Location, Int, Float }, &Routines::actionMoveAwayFromLocation);
add("GetAttemptedAttackTarget", Object, { });
add("GetAttemptedAttackTarget", Object, { }, &Routines::getAttemptedAttackTarget);
add("GetTypeFromTalent", Int, { Talent });
add("GetIdFromTalent", Int, { Talent });
add("PlayPazaak", Void, { Int, String, Int, Int, Object });
@ -414,7 +414,7 @@ void Routines::addTslRoutines() {
add("EffectDamageForcePoints", Effect, { Int }, &Routines::effectDamageForcePoints);
add("EffectHealForcePoints", Effect, { Int }, &Routines::effectHealForcePoints);
add("SendMessageToPC", Void, { Object, String });
add("GetAttemptedSpellTarget", Object, { });
add("GetAttemptedSpellTarget", Object, { }, &Routines::getAttemptedSpellTarget);
add("GetLastOpenedBy", Object, { }, &Routines::getLastOpenedBy);
add("GetHasSpell", Int, { Int, Object });
add("OpenStore", Void, { Object, Object, Int, Int });
@ -799,7 +799,7 @@ void Routines::addTslRoutines() {
add("ResetDialogState", Void, { });
add("SetGoodEvilValue", Void, { Object, Int });
add("GetIsPoisoned", Int, { Object });
add("GetSpellTarget", Object, { Object });
add("GetSpellTarget", Object, { Object }, &Routines::getSpellTarget);
add("SetSoloMode", Void, { Int });
add("EffectCutSceneHorrified", Effect, { }, &Routines::effectCutSceneHorrified);
add("EffectCutSceneParalyze", Effect, { }, &Routines::effectCutSceneParalyze);