Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2 additional AI turn actions #718

Merged
merged 4 commits into from
Feb 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion game/game/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,9 @@ enum Action:uint32_t {
AI_PointAt,
AI_StopPointAt,
AI_PrintScreen,
AI_LookAt
AI_LookAt,
AI_WhirlToNpc,
AI_TurnAway,
};


Expand Down
16 changes: 16 additions & 0 deletions game/game/gamescript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,9 @@ void GameScript::initCommon() {
bindExternal("ai_lookatnpc", &GameScript::ai_lookatnpc);
bindExternal("ai_removeweapon", &GameScript::ai_removeweapon);
bindExternal("ai_unreadyspell", &GameScript::ai_unreadyspell);
bindExternal("ai_turnaway", &GameScript::ai_turnaway);
bindExternal("ai_turntonpc", &GameScript::ai_turntonpc);
bindExternal("ai_whirlaround", &GameScript::ai_whirlaround);
bindExternal("ai_outputsvm", &GameScript::ai_outputsvm);
bindExternal("ai_outputsvm_overlay", &GameScript::ai_outputsvm_overlay);
bindExternal("ai_startstate", &GameScript::ai_startstate);
Expand Down Expand Up @@ -2920,13 +2922,27 @@ void GameScript::ai_unreadyspell(std::shared_ptr<zenkit::INpc> npcRef) {
npc->aiPush(AiQueue::aiRemoveWeapon());
}

void GameScript::ai_turnaway(std::shared_ptr<zenkit::INpc> selfRef, std::shared_ptr<zenkit::INpc> npcRef) {
auto npc = findNpc(npcRef);
auto self = findNpc(selfRef);
if(self!=nullptr)
self->aiPush(AiQueue::aiTurnAway(npc));
}

void GameScript::ai_turntonpc(std::shared_ptr<zenkit::INpc> selfRef, std::shared_ptr<zenkit::INpc> npcRef) {
auto npc = findNpc(npcRef);
auto self = findNpc(selfRef);
if(self!=nullptr)
self->aiPush(AiQueue::aiTurnToNpc(npc));
}

void GameScript::ai_whirlaround(std::shared_ptr<zenkit::INpc> selfRef, std::shared_ptr<zenkit::INpc> npcRef) {
auto npc = findNpc(npcRef);
auto self = findNpc(selfRef);
if(self!=nullptr)
self->aiPush(AiQueue::aiWhirlToNpc(npc));
}

void GameScript::ai_outputsvm(std::shared_ptr<zenkit::INpc> selfRef, std::shared_ptr<zenkit::INpc> targetRef, std::string_view name) {
auto target = findNpc(targetRef);
auto self = findNpc(selfRef);
Expand Down
2 changes: 2 additions & 0 deletions game/game/gamescript.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,9 @@ class GameScript final {
void ai_lookatnpc (std::shared_ptr<zenkit::INpc> selfRef, std::shared_ptr<zenkit::INpc> npcRef);
void ai_removeweapon (std::shared_ptr<zenkit::INpc> npcRef);
void ai_unreadyspell (std::shared_ptr<zenkit::INpc> npcRef);
void ai_turnaway (std::shared_ptr<zenkit::INpc> selfRef, std::shared_ptr<zenkit::INpc> npcRef);
void ai_turntonpc (std::shared_ptr<zenkit::INpc> selfRef, std::shared_ptr<zenkit::INpc> npcRef);
void ai_whirlaround (std::shared_ptr<zenkit::INpc> selfRef, std::shared_ptr<zenkit::INpc> npcRef);
void ai_outputsvm (std::shared_ptr<zenkit::INpc> selfRef, std::shared_ptr<zenkit::INpc> targetRef, std::string_view name);
void ai_outputsvm_overlay(std::shared_ptr<zenkit::INpc> selfRef, std::shared_ptr<zenkit::INpc> targetRef, std::string_view name);
void ai_startstate (std::shared_ptr<zenkit::INpc> selfRef, int func, int state, std::string_view wp);
Expand Down
2 changes: 1 addition & 1 deletion game/game/playercontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1087,7 +1087,7 @@ void PlayerControl::processAutoRotate(Npc& pl, float& rot, uint64_t dt) {
float step = float(pl.world().script().guildVal().turn_speed[gl]);
if(actrl[ActGeneric])
step*=2.f;
pl.rotateTo(dp.x,dp.z,step,false,dt);
pl.rotateTo(dp.x,dp.z,step,AnimationSolver::TurnType::Std,dt);
rot = pl.rotation();
}
}
Expand Down
11 changes: 9 additions & 2 deletions game/graphics/mdlvisual.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,8 @@ const Animation::Sequence* MdlVisual::startAnimAndGet(Npc& npc, AnimationSolver:
uint8_t comb,
WeaponState st, WalkBit wlk) {
// for those use MdlVisual::setRotation
assert(a!=AnimationSolver::Anim::RotL && a!=AnimationSolver::Anim::RotR);
assert(a!=AnimationSolver::Anim::RotL && a!=AnimationSolver::Anim::RotR &&
a!=AnimationSolver::Anim::WhirlL && a!=AnimationSolver::Anim::WhirlR);

if(a==AnimationSolver::InteractIn ||
a==AnimationSolver::InteractOut ||
Expand Down Expand Up @@ -651,6 +652,8 @@ const Animation::Sequence* MdlVisual::startAnimAndGet(Npc& npc, AnimationSolver:
bs = BS_RUN;
case AnimationSolver::Anim::RotL:
case AnimationSolver::Anim::RotR:
case AnimationSolver::Anim::WhirlL:
case AnimationSolver::Anim::WhirlR:
break;
case AnimationSolver::Anim::Fall:
case AnimationSolver::Anim::FallDeep:
Expand Down Expand Up @@ -740,7 +743,11 @@ bool MdlVisual::startAnim(Npc &npc, WeaponState st) {
}

void MdlVisual::setAnimRotate(Npc &npc, int dir) {
skInst->setAnimRotate(solver,npc,fgtMode,dir);
skInst->setAnimRotate(solver,npc,fgtMode,AnimationSolver::TurnType::Std,dir);
}

void MdlVisual::setAnimWhirl(Npc &npc, int dir) {
skInst->setAnimRotate(solver,npc,fgtMode,AnimationSolver::TurnType::Whirl,dir);
}

void MdlVisual::interrupt() {
Expand Down
1 change: 1 addition & 0 deletions game/graphics/mdlvisual.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class MdlVisual final {
bool hasAnim (std::string_view scheme) const;
void stopWalkAnim (Npc &npc);
void setAnimRotate (Npc &npc, int dir);
void setAnimWhirl (Npc &npc, int dir);

void interrupt();
WeaponState fightMode() const { return fgtMode; }
Expand Down
28 changes: 28 additions & 0 deletions game/graphics/mesh/animationsolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,34 @@ const Animation::Sequence* AnimationSolver::implSolveAnim(AnimationSolver::Anim
return solveFrm("T_%sWALKWTURNR",st);
return solveFrm("T_%sRUNTURNR",st);
}
// Whirl around
if(a==WhirlL) {
// Whirling in water should not happen, but just to make sure
if(bool(wlkMode & WalkBit::WM_Dive))
return solveFrm("T_DIVETURNL");
if(bool(wlkMode & WalkBit::WM_Swim))
return solveFrm("T_SWIMTURNL");

// whirling is only used in G1, but the script function is present
// in all games. In G2 all models except the human also have the
// needed animation.
const Animation::Sequence* s = solveFrm("T_SURPRISE_CCW");
if(s==nullptr)
s = solveFrm("T_%sRUNTURNL",st);
return s;
}
if(a==WhirlR) {
// Whirling in water should not happen, but just to make sure
if(bool(wlkMode & WalkBit::WM_Dive))
return solveFrm("T_DIVETURNR");
if(bool(wlkMode & WalkBit::WM_Swim))
return solveFrm("T_SWIMTURNR");

const Animation::Sequence* s = solveFrm("T_SURPRISE_CW");
if(s==nullptr)
s = solveFrm("T_%sRUNTURNR",st);
return s;
}
// Jump regular
if(a==Jump)
return solveFrm("S_JUMP");
Expand Down
8 changes: 8 additions & 0 deletions game/graphics/mesh/animationsolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ class AnimationSolver final {
MoveR,
RotL,
RotR,
WhirlL,
WhirlR,
Fall,
FallDeep,
FallDeepA,
Expand Down Expand Up @@ -70,6 +72,12 @@ class AnimationSolver final {
MagNoMana
};

enum TurnType : uint8_t {
Std = 0,
None,
Whirl,
};

struct Overlay final {
const Skeleton* skeleton=nullptr;
uint64_t time =0;
Expand Down
12 changes: 8 additions & 4 deletions game/graphics/mesh/pose.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,7 @@ Vec2 Pose::headRotation() const {
return Vec2(headRotX,headRotY);
}

void Pose::setAnimRotate(const AnimationSolver &solver, Npc &npc, WeaponState fightMode, int dir) {
void Pose::setAnimRotate(const AnimationSolver &solver, Npc &npc, WeaponState fightMode, AnimationSolver::TurnType turn, int dir) {
const Animation::Sequence *sq = nullptr;
if(dir==0) {
if(rotation!=nullptr) {
Expand All @@ -823,11 +823,15 @@ void Pose::setAnimRotate(const AnimationSolver &solver, Npc &npc, WeaponState fi
}
if(bodyState()!=BS_STAND)
return;
if(dir<0) {
sq = solver.solveAnim(AnimationSolver::Anim::RotL,fightMode,npc.walkMode(),*this);

enum AnimationSolver::Anim ani;
if(turn==AnimationSolver::TurnType::Whirl) {
ani = (dir<0)?AnimationSolver::Anim::WhirlL:AnimationSolver::Anim::WhirlR;
} else {
sq = solver.solveAnim(AnimationSolver::Anim::RotR,fightMode,npc.walkMode(),*this);
ani = (dir<0)?AnimationSolver::Anim::RotL:AnimationSolver::Anim::RotR;
}

sq = solver.solveAnim(ani,fightMode,npc.walkMode(),*this);
if(rotation!=nullptr) {
if(sq!=nullptr && rotation->name==sq->name)
return;
Expand Down
3 changes: 2 additions & 1 deletion game/graphics/mesh/pose.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "game/constants.h"
#include "animation.h"
#include "animationsolver.h"
#include "resources.h"

class Skeleton;
Expand Down Expand Up @@ -84,7 +85,7 @@ class Pose final {

void setHeadRotation(float dx, float dz);
Tempest::Vec2 headRotation() const;
void setAnimRotate(const AnimationSolver &solver, Npc &npc, WeaponState fightMode, int dir);
void setAnimRotate(const AnimationSolver &solver, Npc &npc, WeaponState fightMode, AnimationSolver::TurnType turn, int dir);
auto setAnimItem(const AnimationSolver &solver, Npc &npc, std::string_view scheme, int state) -> const Animation::Sequence*;
bool stopItemStateAnim(const AnimationSolver &solver, uint64_t tickCount);

Expand Down
14 changes: 14 additions & 0 deletions game/world/aiqueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,27 @@ AiQueue::AiAction AiQueue::aiRemoveWeapon() {
return a;
}

AiQueue::AiAction AiQueue::aiTurnAway(Npc *other) {
AiAction a;
a.act = AI_TurnAway;
a.target = other;
return a;
}

AiQueue::AiAction AiQueue::aiTurnToNpc(Npc *other) {
AiAction a;
a.act = AI_TurnToNpc;
a.target = other;
return a;
}

AiQueue::AiAction AiQueue::aiWhirlToNpc(Npc *other) {
AiAction a;
a.act = AI_WhirlToNpc;
a.target = other;
return a;
}

AiQueue::AiAction AiQueue::aiGoToNpc(Npc *other) {
AiAction a;
a.act = AI_GoToNpc;
Expand Down
2 changes: 2 additions & 0 deletions game/world/aiqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ class AiQueue {
static AiAction aiLookAtNpc(Npc* other);
static AiAction aiStopLookAt();
static AiAction aiRemoveWeapon();
static AiAction aiTurnAway (Npc *other);
static AiAction aiTurnToNpc(Npc *other);
static AiAction aiWhirlToNpc(Npc *other);
static AiAction aiGoToNpc (Npc *other);
static AiAction aiGoToNextFp(std::string_view fp);
static AiAction aiStartState(ScriptFn stateFn, int behavior, Npc *other, Npc* victim, std::string_view wp);
Expand Down
Loading