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

Maniac Patch: Add ControlVarArray and Bit Ops for Variables #2733

Merged
merged 3 commits into from
Mar 24, 2022
Merged
Changes from 1 commit
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
Next Next commit
Maniac: Implement ControlVarArray
Ghabry committed Feb 22, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 737c4b0e9a12c08115a6fb1fefc3dfdf1840ec2d
91 changes: 89 additions & 2 deletions src/game_interpreter.cpp
Original file line number Diff line number Diff line change
@@ -3982,12 +3982,99 @@ bool Game_Interpreter::CommandManiacGetPictureInfo(lcf::rpg::EventCommand const&
return true;
}

bool Game_Interpreter::CommandManiacControlVarArray(lcf::rpg::EventCommand const&) {
bool Game_Interpreter::CommandManiacControlVarArray(lcf::rpg::EventCommand const& com) {
if (!Player::IsPatchManiac()) {
return true;
}

Output::Warning("Maniac Patch: Command ControlVarArray not supported");
int op = com.parameters[0];
int mode = com.parameters[1];
int mode_a = mode & 0xF;
int mode_size = (mode >> 4) & 0xF;
int mode_b = (mode >> 8) & 0xF;

int target_a = ValueOrVariable(mode_a, com.parameters[2]);
int length = ValueOrVariable(mode_size, com.parameters[3]);
int target_b = ValueOrVariable(mode_b, com.parameters[4]);
int last_target_a = target_a + length - 1;

if (target_a < 1 || length <= 0) {
return true;
}

switch (op) {
case 0: {
// Copy, assigns left to right, the others apply right to left
int last_target_b = target_b + length - 1;
Main_Data::game_variables->SetArray(target_b, last_target_b, target_a);
break;
}
case 1:
// Swap
Main_Data::game_variables->SwapArray(target_a, last_target_a, target_b);
break;
case 2:
// Sort asc
Main_Data::game_variables->SortRange(target_a, last_target_a, true);
break;
case 3:
// Sort desc
Main_Data::game_variables->SortRange(target_a, last_target_a, false);
break;
case 4:
// Shuffle
Main_Data::game_variables->ShuffleRange(target_a, last_target_a);
break;
case 5:
// Enumerate (target_b is a single value here, not an array)
Main_Data::game_variables->EnumerateRange(target_a, last_target_a, target_b);
break;
case 6:
// Add
Main_Data::game_variables->AddArray(target_a, last_target_a, target_b);
break;
case 7:
// Sub
Main_Data::game_variables->SubArray(target_a, last_target_a, target_b);
break;
case 8:
// Mul
Main_Data::game_variables->MultArray(target_a, last_target_a, target_b);
break;
case 9:
// Div
Main_Data::game_variables->DivArray(target_a, last_target_a, target_b);
break;
case 10:
// Mod
Main_Data::game_variables->ModArray(target_a, last_target_a, target_b);
break;
case 11:
// OR
Main_Data::game_variables->BitOrArray(target_a, last_target_a, target_b);
break;
case 12:
// AND
Main_Data::game_variables->BitAndArray(target_a, last_target_a, target_b);
break;
case 13:
// XOR
Main_Data::game_variables->BitXorArray(target_a, last_target_a, target_b);
break;
case 14:
// Shift left
Main_Data::game_variables->BitShiftLeftArray(target_a, last_target_a, target_b);
break;
case 15:
// Shift right
Main_Data::game_variables->BitShiftRightArray(target_a, last_target_a, target_b);
break;
default:
Output::Warning("ManiacControlVarArray: Unknown operation {}", op);
}

Game_Map::SetNeedRefresh(true);

return true;
}

143 changes: 143 additions & 0 deletions src/game_variables.cpp
Original file line number Diff line number Diff line change
@@ -58,6 +58,27 @@ constexpr Var_t VarDiv(Var_t n, Var_t d) {
constexpr Var_t VarMod(Var_t n, Var_t d) {
return EP_LIKELY(d != 0) ? n % d : 0;
};

constexpr Var_t VarBitOr(Var_t n, Var_t d) {
return n | d;
};

constexpr Var_t VarBitAnd(Var_t n, Var_t d) {
return n & d;
};

constexpr Var_t VarBitXor(Var_t n, Var_t d) {
return n ^ d;
};

constexpr Var_t VarBitShiftLeft(Var_t n, Var_t d) {
return n << d;
};

constexpr Var_t VarBitShiftRight(Var_t n, Var_t d) {
return n >> d;
};

}

Game_Variables::Game_Variables(Var_t minval, Var_t maxval)
@@ -104,6 +125,22 @@ void Game_Variables::PrepareRange(const int first_id, const int last_id, const c
}
}

template <typename... Args>
void Game_Variables::PrepareArray(const int first_id_a, const int last_id_a, const int first_id_b, const char* warn, Args... args) {
const int last_id_b = first_id_b + last_id_a - first_id_a;
if (EP_UNLIKELY(ShouldWarn(first_id_a, last_id_a) || ShouldWarn(first_id_b, last_id_b))) {
Output::Debug(warn, first_id_a, last_id_a, first_id_b, last_id_b, args...);
--_warnings;
}
auto& vv = _variables;
if (EP_UNLIKELY(last_id_a > static_cast<int>(vv.size()))) {
vv.resize(last_id_a, 0);
}
if (EP_UNLIKELY(last_id_b > static_cast<int>(vv.size()))) {
vv.resize(last_id_b, 0);
}
}

template <typename V, typename F>
void Game_Variables::WriteRange(const int first_id, const int last_id, V&& value, F&& op) {
auto& vv = _variables;
@@ -113,6 +150,17 @@ void Game_Variables::WriteRange(const int first_id, const int last_id, V&& value
}
}

template <typename F>
void Game_Variables::WriteArray(const int first_id_a, const int last_id_a, const int first_id_b, F&& op) {
auto& vv = _variables;
int out_b = std::max(0, first_id_b - 1);
for (int i = std::max(0, first_id_a - 1); i < last_id_a; ++i) {
auto& v_a = vv[i];
auto v_b = vv[out_b++];
v_a = Utils::Clamp(op(v_a, v_b), _min, _max);
}
}

Game_Variables::Var_t Game_Variables::Set(int variable_id, Var_t value) {
return SetOp(variable_id, value, VarSet, "Invalid write var[{}] = {}!");
}
@@ -269,6 +317,101 @@ void Game_Variables::ModRangeRandom(int first_id, int last_id, Var_t minval, Var
WriteRange(first_id, last_id, [this,minval,maxval](){ return Rand::GetRandomNumber(minval, maxval); }, VarMod);
}

void Game_Variables::EnumerateRange(int first_id, int last_id, Var_t value) {
PrepareRange(first_id, last_id, "Invalid write enumerate(var[{},{}])!");
Var_t out_value = value;
WriteRange(first_id, last_id, [&out_value](){ return out_value++; }, VarSet);
}

void Game_Variables::SortRange(int first_id, int last_id, bool asc) {
PrepareRange(first_id, last_id, "Invalid write sort(var[{},{}])!");
auto& vv = _variables;
int i = std::max(0, first_id - 1);
if (i < last_id) {
auto sorter = [&](auto&& fn) {
std::stable_sort(vv.begin() + i, vv.begin() + last_id, fn);
};
if (asc) {
sorter(std::less<>());
} else {
sorter(std::greater<>());
}
}
}

void Game_Variables::ShuffleRange(int first_id, int last_id) {
PrepareRange(first_id, last_id, "Invalid write shuffle(var[{},{}])!");
auto& vv = _variables;
for (int i = std::max(0, first_id - 1); i < last_id; ++i) {
int rnd_num = Rand::GetRandomNumber(first_id, last_id) - 1;
std::swap(vv[i], vv[rnd_num]);
}
}

void Game_Variables::SetArray(int first_id_a, int last_id_a, int first_id_b) {
PrepareArray(first_id_a, last_id_a, first_id_b, "Invalid write var[{},{}] -> var[{},{}]!");
WriteArray(first_id_a, last_id_a, first_id_b, VarSet);
}

void Game_Variables::AddArray(int first_id_a, int last_id_a, int first_id_b) {
PrepareArray(first_id_a, last_id_a, first_id_b, "Invalid write var[{},{}] += var[{},{}]!");
WriteArray(first_id_a, last_id_a, first_id_b, VarAdd);
}

void Game_Variables::SubArray(int first_id_a, int last_id_a, int first_id_b) {
PrepareArray(first_id_a, last_id_a, first_id_b, "Invalid write var[{},{}] -= var[{},{}]!");
WriteArray(first_id_a, last_id_a, first_id_b, VarSub);
}

void Game_Variables::MultArray(int first_id_a, int last_id_a, int first_id_b) {
PrepareArray(first_id_a, last_id_a, first_id_b, "Invalid write var[{},{}] *= var[{},{}]!");
WriteArray(first_id_a, last_id_a, first_id_b, VarMult);
}

void Game_Variables::DivArray(int first_id_a, int last_id_a, int first_id_b) {
PrepareArray(first_id_a, last_id_a, first_id_b, "Invalid write var[{},{}] /= var[{},{}]!");
WriteArray(first_id_a, last_id_a, first_id_b, VarDiv);
}

void Game_Variables::ModArray(int first_id_a, int last_id_a, int first_id_b) {
PrepareArray(first_id_a, last_id_a, first_id_b, "Invalid write var[{},{}] %= var[{},{}]!");
WriteArray(first_id_a, last_id_a, first_id_b, VarMod);
}

void Game_Variables::BitOrArray(int first_id_a, int last_id_a, int first_id_b) {
PrepareArray(first_id_a, last_id_a, first_id_b, "Invalid write var[{},{}] |= var[{},{}]!");
WriteArray(first_id_a, last_id_a, first_id_b, VarBitOr);
}

void Game_Variables::BitAndArray(int first_id_a, int last_id_a, int first_id_b) {
PrepareArray(first_id_a, last_id_a, first_id_b, "Invalid write var[{},{}] &= var[{},{}]!");
WriteArray(first_id_a, last_id_a, first_id_b, VarBitAnd);
}

void Game_Variables::BitXorArray(int first_id_a, int last_id_a, int first_id_b) {
PrepareArray(first_id_a, last_id_a, first_id_b, "Invalid write var[{},{}] ^= var[{},{}]!");
WriteArray(first_id_a, last_id_a, first_id_b, VarBitXor);
}

void Game_Variables::BitShiftLeftArray(int first_id_a, int last_id_a, int first_id_b) {
PrepareArray(first_id_a, last_id_a, first_id_b, "Invalid write var[{},{}] <<= var[{},{}]!");
WriteArray(first_id_a, last_id_a, first_id_b, VarBitShiftLeft);
}

void Game_Variables::BitShiftRightArray(int first_id_a, int last_id_a, int first_id_b) {
PrepareArray(first_id_a, last_id_a, first_id_b, "Invalid write var[{},{}] >>= var[{},{}]!");
WriteArray(first_id_a, last_id_a, first_id_b, VarBitShiftRight);
}

void Game_Variables::SwapArray(int first_id_a, int last_id_a, int first_id_b) {
PrepareArray(first_id_a, last_id_a, first_id_b, "Invalid write var[{},{}] <-> var[{},{}]!");
auto& vv = _variables;
int out_b = std::max(0, first_id_b - 1);
for (int i = std::max(0, first_id_a - 1); i < last_id_a; ++i) {
std::swap(vv[i], vv[out_b++]);
}
}

StringView Game_Variables::GetName(int _id) const {
const auto* var = lcf::ReaderUtil::GetElement(lcf::Data::variables, _id);

21 changes: 21 additions & 0 deletions src/game_variables.h
Original file line number Diff line number Diff line change
@@ -81,6 +81,23 @@ class Game_Variables {
void DivRangeRandom(int first_id, int last_id, Var_t minval, Var_t maxval);
void ModRangeRandom(int first_id, int last_id, Var_t minval, Var_t maxval);

void EnumerateRange(int first_id, int last_id, Var_t value);
void SortRange(int first_id, int last_id, bool asc);
void ShuffleRange(int first_id, int last_id);

void SetArray(int first_id_a, int last_id_a, int first_id_b);
void AddArray(int first_id_a, int last_id_a, int first_id_b);
void SubArray(int first_id_a, int last_id_a, int first_id_b);
void MultArray(int first_id_a, int last_id_a, int first_id_b);
void DivArray(int first_id_a, int last_id_a, int first_id_b);
void ModArray(int first_id_a, int last_id_a, int first_id_b);
void BitOrArray(int first_id_a, int last_id_a, int first_id_b);
void BitAndArray(int first_id_a, int last_id_a, int first_id_b);
void BitXorArray(int first_id_a, int last_id_a, int first_id_b);
void BitShiftLeftArray(int first_id_a, int last_id_a, int first_id_b);
void BitShiftRightArray(int first_id_a, int last_id_a, int first_id_b);
void SwapArray(int first_id_a, int last_id_a, int first_id_b);

StringView GetName(int _id) const;

int GetSize() const;
@@ -100,10 +117,14 @@ class Game_Variables {
Var_t SetOp(int variable_id, Var_t value, F&& op, const char* warn);
template <typename... Args>
void PrepareRange(const int first_id, const int last_id, const char* warn, Args... args);
template <typename... Args>
void PrepareArray(const int first_id_a, const int last_id_a, const int first_id_b, const char* warn, Args... args);
template <typename V, typename F>
void WriteRange(const int first_id, const int last_id, V&& value, F&& op);
template <typename F>
void WriteRangeVariable(const int first_id, const int last_id, int var_id, F&& op);
template <typename F>
void WriteArray(const int first_id_a, const int last_id_a, const int first_id_b, F&& op);
private:
Variables_t _variables;
Var_t _min = 0;