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

New Commands: 2050 - Call Movement Action | 2051 - Wait for Single Movement (can Detect fail cases) #3111

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
107 changes: 69 additions & 38 deletions src/game_character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,10 @@ void Game_Character::UpdateMoveRoute(int32_t& current_index, const lcf::rpg::Mov
TurnRandom();
break;
case Code::move_towards_hero:
TurnTowardHero();
TurnTowardCharacter(CharPlayer);
break;
case Code::move_away_from_hero:
TurnAwayFromHero();
TurnAwayFromCharacter(CharPlayer);
break;
case Code::move_forward:
break;
Expand Down Expand Up @@ -348,10 +348,10 @@ void Game_Character::UpdateMoveRoute(int32_t& current_index, const lcf::rpg::Mov
TurnRandom();
break;
case Code::face_hero:
TurnTowardHero();
TurnTowardCharacter(CharPlayer);
break;
case Code::face_away_from_hero:
TurnAwayFromHero();
TurnAwayFromCharacter(CharPlayer);
break;
default:
break;
Expand Down Expand Up @@ -543,20 +543,21 @@ void Game_Character::Turn90DegreeLeftOrRight() {
}
}

int Game_Character::GetDirectionToHero() {
int sx = DistanceXfromPlayer();
int sy = DistanceYfromPlayer();
int Game_Character::GetDirectionToCharacter(const Game_Character* target) {
int sx = DistanceXfromCharacter(target);
int sy = DistanceYfromCharacter(target);

if ( std::abs(sx) > std::abs(sy) ) {
if (std::abs(sx) > std::abs(sy)) {
return (sx > 0) ? Left : Right;
} else {
}
else {
return (sy > 0) ? Up : Down;
}
}

int Game_Character::GetDirectionAwayHero() {
int sx = DistanceXfromPlayer();
int sy = DistanceYfromPlayer();
int Game_Character::GetDirectionAwayCharacter(const Game_Character* target) {
int sx = DistanceXfromCharacter(target);
int sy = DistanceYfromCharacter(target);

if ( std::abs(sx) > std::abs(sy) ) {
return (sx > 0) ? Right : Left;
Expand All @@ -565,12 +566,18 @@ int Game_Character::GetDirectionAwayHero() {
}
}

void Game_Character::TurnTowardHero() {
SetDirection(GetDirectionToHero());
void Game_Character::TurnTowardCharacter(int targetID) {
Game_Character* target = GetCharacter(targetID, targetID);
if (target) {
SetDirection(GetDirectionToCharacter(target));
}
}

void Game_Character::TurnAwayFromHero() {
SetDirection(GetDirectionAwayHero());
void Game_Character::TurnAwayFromCharacter(int targetID) {
Game_Character* target = GetCharacter(targetID, targetID);
if (target) {
SetDirection(GetDirectionAwayCharacter(target));
}
}

void Game_Character::TurnRandom() {
Expand Down Expand Up @@ -606,10 +613,10 @@ bool Game_Character::BeginMoveRouteJump(int32_t& current_index, const lcf::rpg::
TurnRandom();
break;
case Code::move_towards_hero:
TurnTowardHero();
TurnTowardCharacter(CharPlayer);
break;
case Code::move_away_from_hero:
TurnAwayFromHero();
TurnAwayFromCharacter(CharPlayer);
break;
case Code::move_forward:
break;
Expand Down Expand Up @@ -650,10 +657,10 @@ bool Game_Character::BeginMoveRouteJump(int32_t& current_index, const lcf::rpg::
TurnRandom();
break;
case Code::face_hero:
TurnTowardHero();
TurnTowardCharacter(CharPlayer);
break;
case Code::face_away_from_hero:
TurnAwayFromHero();
TurnAwayFromCharacter(CharPlayer);
break;
default:
break;
Expand Down Expand Up @@ -739,32 +746,39 @@ bool Game_Character::Jump(int x, int y) {
return true;
}

int Game_Character::DistanceXfromPlayer() const {
int sx = GetX() - Main_Data::game_player->GetX();
if (Game_Map::LoopHorizontal()) {
if (std::abs(sx) > Game_Map::GetTilesX() / 2) {
if (sx > 0)
sx -= Game_Map::GetTilesX();
else
sx += Game_Map::GetTilesX();
int Game_Character::DistanceXfromCharacter(const Game_Character* target) const {
if (target) {
int sx = GetX() - target->GetX();
if (Game_Map::LoopHorizontal()) {
if (std::abs(sx) > Game_Map::GetTilesX() / 2) {
if (sx > 0)
sx -= Game_Map::GetTilesX();
else
sx += Game_Map::GetTilesX();
}
}
return sx;
}
return sx;
return 0; // Return a default value or handle the case where target is nullptr.
}

int Game_Character::DistanceYfromPlayer() const {
int sy = GetY() - Main_Data::game_player->GetY();
if (Game_Map::LoopVertical()) {
if (std::abs(sy) > Game_Map::GetTilesY() / 2) {
if (sy > 0)
sy -= Game_Map::GetTilesY();
else
sy += Game_Map::GetTilesY();
int Game_Character::DistanceYfromCharacter(const Game_Character* target) const {
if (target) {
int sy = GetY() - target->GetY();
if (Game_Map::LoopVertical()) {
if (std::abs(sy) > Game_Map::GetTilesY() / 2) {
if (sy > 0)
sy -= Game_Map::GetTilesY();
else
sy += Game_Map::GetTilesY();
}
}
return sy;
}
return sy;
return 0; // Return a default value or handle the case where target is nullptr.
}


void Game_Character::ForceMoveRoute(const lcf::rpg::MoveRoute& new_route,
int frequency) {
if (!IsMoveRouteOverwritten()) {
Expand Down Expand Up @@ -797,6 +811,23 @@ void Game_Character::CancelMoveRoute() {
SetMoveRouteFinished(false);
}

bool Game_Character::isStuck(int i) {
if(i == 0 ) i =1;
int currentPose = 500;
if (GetMoveRouteIndex() < GetMoveRoute().move_commands.size()) {
if (IsStopping() && GetMoveRoute().move_commands[GetMoveRouteIndex()].command_id < 12) {
failsMove++;
} else {
failsMove = 0;
}
} else {
failsMove = 0;
}

//Output::Warning("stuck? - {} {} {} -- {}", failsMove, IsPaused(), i, GetMaxStopCount());
return failsMove > i && (GetStopCount() == 0 || GetStopCount() > GetMaxStopCount());
}

int Game_Character::GetSpriteX() const {
int x = GetX() * SCREEN_TILE_SIZE;

Expand Down
16 changes: 9 additions & 7 deletions src/game_character.h
Original file line number Diff line number Diff line change
Expand Up @@ -628,10 +628,10 @@ class Game_Character {
void Turn90DegreeLeftOrRight();

/** @return the direction we would need to face the hero. */
int GetDirectionToHero();
int GetDirectionToCharacter(const Game_Character* target);

/** @return the direction we would need to face away from hero. */
int GetDirectionAwayHero();
int GetDirectionAwayCharacter(const Game_Character* target);

/**
* @param dir input direction
Expand Down Expand Up @@ -662,13 +662,12 @@ class Game_Character {
/**
* Character looks towards the hero.
*/
void TurnTowardHero();
void TurnTowardCharacter(int targetID);

/**
* Character looks away from the hero.
*/
void TurnAwayFromHero();

void TurnAwayFromCharacter(int targetID);
/**
* Character waits for 20 frames more.
*/
Expand Down Expand Up @@ -764,8 +763,8 @@ class Game_Character {
*/
void SetAnimationType(AnimType anim_type);

int DistanceXfromPlayer() const;
int DistanceYfromPlayer() const;
int DistanceXfromCharacter(const Game_Character* target) const;
int DistanceYfromCharacter(const Game_Character* target) const;

/**
* Tests if the character is currently on the tile at x/y or moving
Expand Down Expand Up @@ -882,6 +881,9 @@ class Game_Character {
static constexpr int GetDxFromDirection(int dir);
static constexpr int GetDyFromDirection(int dir);

int failsMove = 0;
bool isStuck(int i);

protected:
explicit Game_Character(Type type, lcf::rpg::SaveMapEventBase* d);
/** Check for and fix incorrect data after loading save game */
Expand Down
6 changes: 3 additions & 3 deletions src/game_event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ bool Game_Event::ScheduleForegroundExecution(bool by_decision_key, bool face_pla
}

if (face_player && !(IsFacingLocked() || IsSpinning())) {
SetFacing(GetDirectionToHero());
SetFacing(GetDirectionToCharacter(GetCharacter(CharPlayer, CharPlayer)));
}

data()->waiting_execution = true;
Expand Down Expand Up @@ -570,8 +570,8 @@ void Game_Event::MoveTypeTowardsOrAwayPlayer(bool towards) {
dir = Rand::GetRandomNumber(0, 3);
} else {
dir = towards
? GetDirectionToHero()
: GetDirectionAwayHero();
? GetDirectionToCharacter(GetCharacter(CharPlayer, CharPlayer))
: GetDirectionAwayCharacter(GetCharacter(CharPlayer, CharPlayer));
}
}

Expand Down
99 changes: 99 additions & 0 deletions src/game_interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,10 @@ bool Game_Interpreter::ExecuteCommand(lcf::rpg::EventCommand const& com) {
return CommandManiacControlStrings(com);
case Cmd::Maniac_CallCommand:
return CommandManiacCallCommand(com);
case static_cast<Game_Interpreter::Cmd>(2050): //Cmd::EasyRpg_CallMovement
return CommandCallMovement(com);
case static_cast<Game_Interpreter::Cmd>(2051): //Cmd::EasyRpg_WaitForMovement
return CommandWaitForMovement(com);
default:
return true;
}
Expand Down Expand Up @@ -5052,6 +5056,101 @@ bool Game_Interpreter::CommandManiacCallCommand(lcf::rpg::EventCommand const& co
return true;
}

bool Game_Interpreter::CommandCallMovement(lcf::rpg::EventCommand const& com) {
// CommandSetMovement("moveCommand",[useVarID, ID, useVarOutput, output])

int eventID = ValueOrVariable(com.parameters[0], com.parameters[1]);
int outputParam = ValueOrVariable(com.parameters[2], com.parameters[3]);
int outputParamB = ValueOrVariable(com.parameters[4], com.parameters[5]);

Game_Character* event = GetCharacter(eventID);
Game_Character* target;

std::string moveCommand = ToString(com.string);
std::string outputString = event->GetSpriteName();

std::size_t pos = moveCommand.find('/');

if (pos != std::string::npos) {
outputString = moveCommand.substr(pos + 1);
moveCommand = moveCommand.substr(0, pos);
}

if (moveCommand == "SetMoveSpeed")event->SetMoveSpeed(outputParam);
if (moveCommand == "SetMoveFrequency")event->SetMoveFrequency(outputParam);
if (moveCommand == "SetTransparency")event->SetTransparency(outputParam);
if (moveCommand == "SetAnimationType")event->SetAnimationType(static_cast<Game_Character::AnimType>(outputParam));


if (moveCommand == "Event2Event") {
target = GetCharacter(outputParam);
event->SetFacing(target->GetFacing());
event->SetDirection(target->GetDirection());
event->SetX(target->GetX());
event->SetY(target->GetY());
}

if (moveCommand == "FaceTowards"){
if(!event->IsMoving()) {
event->TurnTowardCharacter(outputParam);
event->UpdateFacing();
}
}
if (moveCommand == "FaceAway"){
if (!event->IsMoving()) {
event->TurnAwayFromCharacter(outputParam);
event->UpdateFacing();
}
}

if (moveCommand == "SetFacingLocked")event->SetFacingLocked(outputParam);
if (moveCommand == "SetLayer")event->SetLayer(outputParam);
if (moveCommand == "SetFlying")event->SetFlying(outputParam); //FIXME: I wish any event could imitate an airship, lacks more work.
if (moveCommand == "ChangeCharset")event->SetSpriteGraphic(outputString,outputParam); // syntax ChangeCharset/actor1

if (moveCommand == "JumpTo")event->Game_Character::Jump(outputParam, outputParamB);

if (moveCommand == "StopMovement")event->CancelMoveRoute();

return true;
}

bool Game_Interpreter::CommandWaitForMovement(lcf::rpg::EventCommand const& com) {
// CommandWaitForMovement(useVarID, ID, useVarTargetVariable, targetVariable, useVarFailuresAmount, failuresAmount)

int eventID = ValueOrVariable(com.parameters[0], com.parameters[1]);
if (eventID == 0) eventID = GetCurrentEventId();

int outputVariable = ValueOrVariable(com.parameters[2], com.parameters[3]);
int failuresAmount = ValueOrVariable(com.parameters[4], com.parameters[5]);

// Get the character associated with the event ID
Game_Character* ev = GetCharacter(eventID);

// Check if movement exists and if it's currently running
bool movementExists = !ev->GetMoveRoute().move_commands.empty();
bool movementIsRunning = movementExists && (ev->IsMoveRouteOverwritten() && !ev->IsMoveRouteFinished());

// failed to move X times (0 = wait till finish)
if (failuresAmount > 0)
if (ev->isStuck(failuresAmount)) {
ev->failsMove = 0;
ev->CancelMoveRoute();
Main_Data::game_variables->Set(outputVariable, 0);
Game_Map::SetNeedRefresh(true);
return true;
}

// Return false if movement is still in progress
if (!movementIsRunning) {
ev->failsMove = 0;
Main_Data::game_variables->Set(outputVariable, 1);
Game_Map::SetNeedRefresh(true);
return true;
}
return false;
}

Game_Interpreter& Game_Interpreter::GetForegroundInterpreter() {
return Game_Battle::IsBattleRunning()
? Game_Battle::GetInterpreter()
Expand Down
2 changes: 2 additions & 0 deletions src/game_interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ class Game_Interpreter
bool CommandManiacSetGameOption(lcf::rpg::EventCommand const& com);
bool CommandManiacControlStrings(lcf::rpg::EventCommand const& com);
bool CommandManiacCallCommand(lcf::rpg::EventCommand const& com);
bool CommandCallMovement(lcf::rpg::EventCommand const& com);
bool CommandWaitForMovement(lcf::rpg::EventCommand const& com);

int DecodeInt(lcf::DBArray<int32_t>::const_iterator& it);
const std::string DecodeString(lcf::DBArray<int32_t>::const_iterator& it);
Expand Down