2015-09-25 21:07:16 +08:00
|
|
|
/*
|
2024-01-03 01:21:08 +01:00
|
|
|
* Copyright (c) 2010-2015, Argon Sun (Fluorohydride)
|
2026-01-15 20:22:01 +01:00
|
|
|
* Copyright (c) 2016-2026, Edoardo Lolletti (edo9300) <edoardo762@gmail.com>
|
2015-09-25 21:07:16 +08:00
|
|
|
*
|
2024-01-03 01:21:08 +01:00
|
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
2015-09-25 21:07:16 +08:00
|
|
|
*/
|
2024-01-05 12:17:47 +01:00
|
|
|
#include <algorithm> //std::min, std::find
|
|
|
|
|
#include <numeric> //std::iota
|
|
|
|
|
#include <utility> //std::move, std::swap
|
2015-09-25 21:07:16 +08:00
|
|
|
#include "card.h"
|
2024-01-05 12:17:47 +01:00
|
|
|
#include "bit.h"
|
|
|
|
|
#include "duel.h"
|
2015-09-25 21:07:16 +08:00
|
|
|
#include "effect.h"
|
2024-01-05 12:17:47 +01:00
|
|
|
#include "field.h"
|
2015-09-25 21:07:16 +08:00
|
|
|
#include "group.h"
|
2024-01-05 12:17:47 +01:00
|
|
|
#include "scriptlib.h"
|
2015-09-25 21:07:16 +08:00
|
|
|
|
2022-05-14 20:25:01 +02:00
|
|
|
#define LUA_MODULE Duel
|
|
|
|
|
#include "function_array_helper.h"
|
|
|
|
|
|
2021-10-13 17:29:29 +02:00
|
|
|
namespace {
|
2025-07-05 19:50:36 +02:00
|
|
|
namespace LUA_NAMESPACE {
|
2021-10-13 17:29:29 +02:00
|
|
|
|
|
|
|
|
using namespace scriptlib;
|
|
|
|
|
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(EnableGlobalFlag) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2024-11-04 22:38:08 +01:00
|
|
|
// noop
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetLP) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto p = lua_get<int8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(p != 0 && p != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->player[p].lp);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SetLP) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto p = lua_get<int8_t>(L, 1);
|
|
|
|
|
auto lp = lua_get<int32_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(lp < 0) lp = 0;
|
|
|
|
|
if(p != 0 && p != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
pduel->game_field->player[p].lp = lp;
|
2019-07-16 00:57:53 +02:00
|
|
|
auto message = pduel->new_message(MSG_LPUPDATE);
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint8_t>(p);
|
|
|
|
|
message->write<uint32_t>(lp);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetTurnPlayer) {
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, pduel->game_field->infos.turn_player);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-12-02 07:08:36 -03:00
|
|
|
LUA_STATIC_FUNCTION(IsTurnPlayer) {
|
|
|
|
|
check_param_count(L, 1);
|
|
|
|
|
const auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->infos.turn_player == playerid);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetTurnCount) {
|
2016-11-19 17:08:04 +09:00
|
|
|
if(lua_gettop(L) > 0) {
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2016-11-19 17:08:04 +09:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->infos.turn_id_by_player[playerid]);
|
|
|
|
|
} else
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->infos.turn_id);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetDrawCount) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->get_draw_count(playerid));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(RegisterEffect) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto peffect = lua_get<effect*, true>(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
pduel->game_field->add_effect(peffect, playerid);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(RegisterFlagEffect) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 5);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = (lua_get<uint32_t>(L, 2) & 0xfffffff) | 0x10000000;
|
|
|
|
|
auto reset = lua_get<uint32_t>(L, 3);
|
|
|
|
|
auto flag = lua_get<uint32_t>(L, 4);
|
|
|
|
|
auto count = lua_get<uint16_t>(L, 5);
|
|
|
|
|
auto lab = lua_get<uint32_t, 0>(L, 6);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(count == 0)
|
|
|
|
|
count = 1;
|
|
|
|
|
if(reset & (RESET_PHASE) && !(reset & (RESET_SELF_TURN | RESET_OPPO_TURN)))
|
|
|
|
|
reset |= (RESET_SELF_TURN | RESET_OPPO_TURN);
|
|
|
|
|
effect* peffect = pduel->new_effect();
|
|
|
|
|
peffect->effect_owner = playerid;
|
|
|
|
|
peffect->owner = pduel->game_field->temp_card;
|
2024-01-13 16:10:22 +01:00
|
|
|
peffect->handler = nullptr;
|
2015-09-25 21:07:16 +08:00
|
|
|
peffect->type = EFFECT_TYPE_FIELD;
|
|
|
|
|
peffect->code = code;
|
|
|
|
|
peffect->reset_flag = reset;
|
2015-10-31 15:50:37 +09:00
|
|
|
peffect->flag[0] = flag | EFFECT_FLAG_CANNOT_DISABLE | EFFECT_FLAG_PLAYER_TARGET | EFFECT_FLAG_FIELD_ONLY;
|
2015-09-25 21:07:16 +08:00
|
|
|
peffect->s_range = 1;
|
|
|
|
|
peffect->o_range = 0;
|
2017-08-14 08:02:43 +09:00
|
|
|
peffect->reset_count = count;
|
2019-06-19 22:51:12 +08:00
|
|
|
peffect->label.push_back(lab);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->add_effect(peffect, playerid);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, peffect);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetFlagEffect) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = (lua_get<uint32_t>(L, 2) & 0xfffffff) | 0x10000000;
|
2015-09-25 21:07:16 +08:00
|
|
|
effect_set eset;
|
|
|
|
|
pduel->game_field->filter_player_effect(playerid, code, &eset);
|
|
|
|
|
lua_pushinteger(L, eset.size());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ResetFlagEffect) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = (lua_get<uint32_t>(L, 2) & 0xfffffff) | 0x10000000;
|
2016-05-07 06:13:42 +09:00
|
|
|
auto pr = pduel->game_field->effects.aura_effect.equal_range(code);
|
2015-09-25 21:07:16 +08:00
|
|
|
for(; pr.first != pr.second; ) {
|
|
|
|
|
auto rm = pr.first++;
|
2016-05-07 06:13:42 +09:00
|
|
|
effect* peffect = rm->second;
|
2017-10-28 11:10:54 +09:00
|
|
|
if(peffect->code == code && peffect->is_target_player(playerid))
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->remove_effect(peffect);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SetFlagEffectLabel) {
|
2017-10-28 11:10:54 +09:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2017-10-28 11:10:54 +09:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = (lua_get<uint32_t>(L, 2) & 0xfffffff) | 0x10000000;
|
|
|
|
|
auto lab = lua_get<int32_t>(L, 3);
|
2017-10-28 11:10:54 +09:00
|
|
|
effect_set eset;
|
|
|
|
|
pduel->game_field->filter_player_effect(playerid, code, &eset);
|
|
|
|
|
if(!eset.size())
|
|
|
|
|
lua_pushboolean(L, FALSE);
|
|
|
|
|
else {
|
2019-06-19 22:51:12 +08:00
|
|
|
eset[0]->label.clear();
|
|
|
|
|
eset[0]->label.push_back(lab);
|
2017-10-28 11:10:54 +09:00
|
|
|
lua_pushboolean(L, TRUE);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetFlagEffectLabel) {
|
2017-10-28 11:10:54 +09:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2017-10-28 11:10:54 +09:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = (lua_get<uint32_t>(L, 2) & 0xfffffff) | 0x10000000;
|
2017-10-28 11:10:54 +09:00
|
|
|
effect_set eset;
|
|
|
|
|
pduel->game_field->filter_player_effect(playerid, code, &eset);
|
2022-10-06 13:11:11 +02:00
|
|
|
if(eset.empty()) {
|
2017-10-28 11:10:54 +09:00
|
|
|
lua_pushnil(L);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(eset.size()), nullptr);
|
2019-06-19 22:51:12 +08:00
|
|
|
for(auto& eff : eset)
|
|
|
|
|
lua_pushinteger(L, eff->label.size() ? eff->label[0] : 0);
|
2023-02-07 16:43:27 +01:00
|
|
|
return static_cast<int32_t>(eset.size());
|
2017-10-28 11:10:54 +09:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(Destroy) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto reason = lua_get<uint32_t>(L, 2);
|
|
|
|
|
auto dest = lua_get<uint16_t, LOCATION_GRAVE>(L, 3);
|
2023-02-26 15:23:20 -03:00
|
|
|
const auto reasonplayer = lua_get<uint8_t>(L, 4, pduel->game_field->core.reason_player);
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [pcard, pgroup] = lua_get_card_or_group(L, 1); pcard)
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->destroy(pcard, pduel->game_field->core.reason_effect, reason, reasonplayer, PLAYER_NONE, dest, 0);
|
2015-09-25 21:07:16 +08:00
|
|
|
else
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->destroy(pgroup->container, pduel->game_field->core.reason_effect, reason, reasonplayer, PLAYER_NONE, dest, 0);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(Remove) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto pos = lua_get<uint8_t, 0>(L, 2);
|
|
|
|
|
auto reason = lua_get<uint32_t>(L, 3);
|
|
|
|
|
auto playerid = lua_get<uint8_t, PLAYER_NONE>(L, 4);
|
2023-02-26 15:23:20 -03:00
|
|
|
const auto reasonplayer = lua_get<uint8_t>(L, 5, pduel->game_field->core.reason_player);
|
2023-12-03 11:34:38 +01:00
|
|
|
if (auto [pcard, pgroup] = lua_get_card_or_group(L, 1); pcard)
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->send_to(pcard, pduel->game_field->core.reason_effect, reason, reasonplayer, playerid, LOCATION_REMOVED, 0, pos);
|
2015-09-25 21:07:16 +08:00
|
|
|
else
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->send_to(pgroup->container, pduel->game_field->core.reason_effect, reason, reasonplayer, playerid, LOCATION_REMOVED, 0, pos);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SendtoGrave) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto reason = lua_get<uint32_t>(L, 2);
|
|
|
|
|
auto playerid = lua_get<uint8_t, PLAYER_NONE>(L, 3);
|
2023-02-26 15:23:20 -03:00
|
|
|
const auto reasonplayer = lua_get<uint8_t>(L, 4, pduel->game_field->core.reason_player);
|
2023-12-03 11:34:38 +01:00
|
|
|
if (auto [pcard, pgroup] = lua_get_card_or_group(L, 1); pcard)
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->send_to(pcard, pduel->game_field->core.reason_effect, reason, reasonplayer, playerid, LOCATION_GRAVE, 0, POS_FACEUP);
|
2015-09-25 21:07:16 +08:00
|
|
|
else
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->send_to(pgroup->container, pduel->game_field->core.reason_effect, reason, reasonplayer, playerid, LOCATION_GRAVE, 0, POS_FACEUP);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(Summon) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 4);
|
2020-10-30 17:05:28 +01:00
|
|
|
if(pduel->game_field->core.effect_damage_step)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
2020-07-21 00:08:06 +02:00
|
|
|
bool ignore_count = lua_get<bool>(L, 3);
|
2020-10-30 17:05:28 +01:00
|
|
|
auto peffect = lua_get<effect*>(L, 4);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto min_tribute = lua_get<uint8_t, 0>(L, 5);
|
|
|
|
|
auto zone = lua_get<uint32_t, 0x1f>(L, 6);
|
2016-12-04 09:36:52 +08:00
|
|
|
pduel->game_field->core.summon_cancelable = FALSE;
|
2017-06-08 19:57:49 +09:00
|
|
|
pduel->game_field->summon(playerid, pcard, peffect, ignore_count, min_tribute, zone);
|
2020-07-04 23:36:42 +08:00
|
|
|
if(pduel->game_field->core.current_chain.size()) {
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->core.reserved = std::move(pduel->game_field->core.subunits.back());
|
2020-07-04 23:36:42 +08:00
|
|
|
pduel->game_field->core.subunits.pop_back();
|
|
|
|
|
pduel->game_field->core.summoning_card = pcard;
|
|
|
|
|
}
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SpecialSummonRule) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2020-10-30 17:05:28 +01:00
|
|
|
if(pduel->game_field->core.effect_damage_step)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint32_t, 0>(L, 3);
|
2016-12-04 09:36:52 +08:00
|
|
|
pduel->game_field->core.summon_cancelable = FALSE;
|
2018-01-12 14:36:02 +08:00
|
|
|
pduel->game_field->special_summon_rule(playerid, pcard, sumtype);
|
2020-07-04 23:36:42 +08:00
|
|
|
if(pduel->game_field->core.current_chain.size()) {
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->core.reserved = std::move(pduel->game_field->core.subunits.back());
|
2020-07-04 23:36:42 +08:00
|
|
|
pduel->game_field->core.subunits.pop_back();
|
|
|
|
|
pduel->game_field->core.summoning_card = pcard;
|
|
|
|
|
}
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
inline int32_t spsummon_rule(lua_State* L, uint32_t summon_type, uint32_t offset) {
|
2021-10-13 17:29:29 +02:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2020-10-30 17:05:28 +01:00
|
|
|
const auto pduel = lua_get<duel*>(L);
|
|
|
|
|
if(pduel->game_field->core.effect_damage_step)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
owned_lua<group> must = nullptr;
|
2020-07-23 23:50:09 +02:00
|
|
|
if(auto _pcard = lua_get<card*>(L, 3 + offset)) {
|
|
|
|
|
must = pduel->new_group(_pcard);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
must->is_readonly = true;
|
2020-07-23 23:50:09 +02:00
|
|
|
} else if(auto pgroup = lua_get<group*>(L, 3 + offset)) {
|
2020-10-18 16:48:15 +02:00
|
|
|
must = pduel->new_group(pgroup);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
must->is_readonly = true;
|
2020-02-27 20:26:09 +01:00
|
|
|
}
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
owned_lua<group> materials = nullptr;
|
2020-07-23 23:50:09 +02:00
|
|
|
if(auto _pcard = lua_get<card*>(L, 4 + offset)) {
|
|
|
|
|
materials = pduel->new_group(_pcard);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
materials->is_readonly = true;
|
2020-07-23 23:50:09 +02:00
|
|
|
} else if(auto pgroup = lua_get<group*>(L, 4 + offset)) {
|
2020-10-18 16:48:15 +02:00
|
|
|
materials = pduel->new_group(pgroup);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
materials->is_readonly = true;
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
auto minc = lua_get<uint16_t, 0>(L, 5 + offset);
|
|
|
|
|
auto maxc = lua_get<uint16_t, 0>(L, 6 + offset);
|
2020-02-27 20:26:09 +01:00
|
|
|
pduel->game_field->core.must_use_mats = must;
|
|
|
|
|
pduel->game_field->core.only_use_mats = materials;
|
2019-06-20 20:50:57 +02:00
|
|
|
pduel->game_field->core.forced_summon_minc = minc;
|
|
|
|
|
pduel->game_field->core.forced_summon_maxc = maxc;
|
2016-12-04 09:36:52 +08:00
|
|
|
pduel->game_field->core.summon_cancelable = FALSE;
|
2020-02-27 20:26:09 +01:00
|
|
|
pduel->game_field->special_summon_rule(playerid, pcard, summon_type);
|
2020-07-04 23:36:42 +08:00
|
|
|
if(pduel->game_field->core.current_chain.size()) {
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->core.reserved = std::move(pduel->game_field->core.subunits.back());
|
2020-07-04 23:36:42 +08:00
|
|
|
pduel->game_field->core.subunits.pop_back();
|
|
|
|
|
pduel->game_field->core.summoning_card = pcard;
|
|
|
|
|
}
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SynchroSummon) {
|
2020-05-19 14:15:25 +02:00
|
|
|
return spsummon_rule(L, SUMMON_TYPE_SYNCHRO, 0);
|
2020-02-27 20:26:09 +01:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(XyzSummon) {
|
2020-05-19 14:15:25 +02:00
|
|
|
return spsummon_rule(L, SUMMON_TYPE_XYZ, 0);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(LinkSummon) {
|
2020-05-19 14:15:25 +02:00
|
|
|
return spsummon_rule(L, SUMMON_TYPE_LINK, 0);
|
2020-02-28 12:18:52 +01:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ProcedureSummon) {
|
2021-10-13 17:29:29 +02:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint32_t>(L, 3);
|
2020-05-19 14:15:25 +02:00
|
|
|
return spsummon_rule(L, sumtype, 1);
|
2018-01-11 21:45:27 +01:00
|
|
|
}
|
2023-11-25 11:15:21 +01:00
|
|
|
inline int32_t spsummon_rule_group(lua_State* L, uint32_t summon_type, [[maybe_unused]] uint32_t offset) {
|
2021-10-13 17:29:29 +02:00
|
|
|
check_param_count(L, 1);
|
2021-01-21 19:15:31 +01:00
|
|
|
const auto pduel = lua_get<duel*>(L);
|
2021-09-04 22:04:14 +02:00
|
|
|
const auto playerid = lua_get<uint8_t>(L, 1);
|
2021-01-21 19:15:31 +01:00
|
|
|
pduel->game_field->core.summon_cancelable = FALSE;
|
|
|
|
|
pduel->game_field->special_summon_rule_group(playerid, summon_type);
|
|
|
|
|
if(pduel->game_field->core.current_chain.size()) {
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->core.reserved = std::move(pduel->game_field->core.subunits.back());
|
2021-01-21 19:15:31 +01:00
|
|
|
pduel->game_field->core.subunits.pop_back();
|
|
|
|
|
pduel->game_field->core.summoning_proc_group_type = summon_type;
|
|
|
|
|
}
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2021-01-21 19:15:31 +01:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(PendulumSummon) {
|
2021-01-21 19:15:31 +01:00
|
|
|
return spsummon_rule_group(L, SUMMON_TYPE_PENDULUM, 0);
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ProcedureSummonGroup) {
|
2021-10-13 17:29:29 +02:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint32_t>(L, 2);
|
2021-01-21 19:15:31 +01:00
|
|
|
return spsummon_rule_group(L, sumtype, 1);
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(MSet) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 4);
|
2020-10-30 17:05:28 +01:00
|
|
|
if(pduel->game_field->core.effect_damage_step)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2020-07-21 00:08:06 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
2020-07-23 23:50:09 +02:00
|
|
|
auto ignore_count = lua_get<bool>(L, 3);
|
2020-10-30 17:05:28 +01:00
|
|
|
auto peffect = lua_get<effect*>(L, 4);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto min_tribute = lua_get<uint8_t, 0>(L, 5);
|
|
|
|
|
auto zone = lua_get<uint32_t, 0x1f>(L, 6);
|
2016-12-04 09:36:52 +08:00
|
|
|
pduel->game_field->core.summon_cancelable = FALSE;
|
2017-06-09 09:44:04 +09:00
|
|
|
pduel->game_field->mset(playerid, pcard, peffect, ignore_count, min_tribute, zone);
|
2020-07-04 23:36:42 +08:00
|
|
|
if(pduel->game_field->core.current_chain.size()) {
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->core.reserved = std::move(pduel->game_field->core.subunits.back());
|
2020-07-04 23:36:42 +08:00
|
|
|
pduel->game_field->core.subunits.pop_back();
|
|
|
|
|
pduel->game_field->core.summoning_card = pcard;
|
|
|
|
|
}
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SSet) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto toplayer = lua_get<uint8_t>(L, 3, playerid);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(toplayer != 0 && toplayer != 1)
|
|
|
|
|
toplayer = playerid;
|
2020-07-23 23:50:09 +02:00
|
|
|
bool confirm = lua_get<bool, true>(L, 4);
|
2023-12-03 11:34:38 +01:00
|
|
|
auto [pcard, pgroup] = lua_get_card_or_group(L, 2);
|
2020-10-30 17:05:28 +01:00
|
|
|
if(pcard) {
|
2019-12-10 21:15:36 +08:00
|
|
|
pgroup = pduel->new_group(pcard);
|
2020-10-30 17:05:28 +01:00
|
|
|
} else if(pgroup->container.empty()) {
|
2023-11-25 11:15:21 +01:00
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2023-09-24 16:45:39 +02:00
|
|
|
return 1;
|
2020-10-30 17:05:28 +01:00
|
|
|
}
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SpellSetGroup>(playerid, toplayer, pgroup, confirm, pduel->game_field->core.reason_effect);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-12-12 11:01:55 +09:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CreateToken) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2021-01-04 23:29:28 +01:00
|
|
|
if(playerid >= PLAYER_NONE) {
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = lua_get<uint32_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
card* pcard = pduel->new_card(code);
|
|
|
|
|
pcard->owner = playerid;
|
|
|
|
|
pcard->current.location = 0;
|
|
|
|
|
pcard->current.controler = playerid;
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pcard);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SpecialSummon) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 7);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint32_t>(L, 2);
|
|
|
|
|
auto sumplayer = lua_get<uint8_t>(L, 3);
|
2021-01-04 23:29:28 +01:00
|
|
|
if(sumplayer >= PLAYER_NONE)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 4);
|
2020-07-21 00:08:06 +02:00
|
|
|
auto nocheck = lua_get<bool>(L, 5);
|
|
|
|
|
auto nolimit = lua_get<bool>(L, 6);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto positions = lua_get<uint8_t>(L, 7);
|
|
|
|
|
auto zone = lua_get<uint32_t, 0xff>(L, 8);
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [pcard, pgroup] = lua_get_card_or_group(L, 1); pcard) {
|
2022-03-13 19:51:18 +01:00
|
|
|
pduel->game_field->special_summon(card_set{ pcard }, sumtype, sumplayer, playerid, nocheck, nolimit, positions, zone);
|
2015-09-25 21:07:16 +08:00
|
|
|
} else
|
2022-03-13 19:51:18 +01:00
|
|
|
pduel->game_field->special_summon(pgroup->container, sumtype, sumplayer, playerid, nocheck, nolimit, positions, zone);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SpecialSummonStep) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 7);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint32_t>(L, 2);
|
|
|
|
|
auto sumplayer = lua_get<uint8_t>(L, 3);
|
2021-01-04 23:29:28 +01:00
|
|
|
if(sumplayer >= PLAYER_NONE)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 4);
|
2020-07-21 00:08:06 +02:00
|
|
|
auto nocheck = lua_get<bool>(L, 5);
|
|
|
|
|
auto nolimit = lua_get<bool>(L, 6);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto positions = lua_get<uint8_t>(L, 7);
|
|
|
|
|
auto zone = lua_get<uint32_t, 0xff>(L, 8);
|
2017-03-26 19:50:07 +09:00
|
|
|
pduel->game_field->special_summon_step(pcard, sumtype, sumplayer, playerid, nocheck, nolimit, positions, zone);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SpecialSummonComplete) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
2021-12-13 00:01:00 +01:00
|
|
|
auto& core = pduel->game_field->core;
|
|
|
|
|
if(core.special_summoning.empty() && core.ss_tograve_set.empty()) {
|
|
|
|
|
core.operated_set.clear();
|
|
|
|
|
lua_pushinteger(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
pduel->game_field->special_summon_complete(core.reason_effect, core.reason_player);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SendtoHand) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t, PLAYER_NONE>(L, 2);
|
2021-01-04 23:29:28 +01:00
|
|
|
if(playerid > PLAYER_NONE)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto reason = lua_get<uint32_t>(L, 3);
|
2023-02-26 15:23:20 -03:00
|
|
|
const auto reasonplayer = lua_get<uint8_t>(L, 4, pduel->game_field->core.reason_player);
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [pcard, pgroup] = lua_get_card_or_group(L, 1); pcard)
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->send_to(pcard, pduel->game_field->core.reason_effect, reason, reasonplayer, playerid, LOCATION_HAND, 0, POS_FACEUP);
|
2015-09-25 21:07:16 +08:00
|
|
|
else
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->send_to(pgroup->container, pduel->game_field->core.reason_effect, reason, reasonplayer, playerid, LOCATION_HAND, 0, POS_FACEUP);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SendtoDeck) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 4);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t, PLAYER_NONE>(L, 2);
|
2021-01-04 23:29:28 +01:00
|
|
|
if(playerid > PLAYER_NONE)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sequence = lua_get<int32_t>(L, 3);
|
|
|
|
|
auto reason = lua_get<uint32_t>(L, 4);
|
2023-02-26 15:23:20 -03:00
|
|
|
const auto reasonplayer = lua_get<uint8_t>(L, 5, pduel->game_field->core.reason_player);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint16_t location = (sequence == -2) ? 0 : LOCATION_DECK;
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [pcard, pgroup] = lua_get_card_or_group(L, 1); pcard)
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->send_to(pcard, pduel->game_field->core.reason_effect, reason, reasonplayer, playerid, location, sequence, POS_FACEUP);
|
2015-09-25 21:07:16 +08:00
|
|
|
else
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->send_to(pgroup->container, pduel->game_field->core.reason_effect, reason, reasonplayer, playerid, location, sequence, POS_FACEUP);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SendtoExtraP) {
|
2015-10-22 13:13:10 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t, PLAYER_NONE>(L, 2);
|
2021-01-04 23:29:28 +01:00
|
|
|
if(playerid > PLAYER_NONE)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto reason = lua_get<uint32_t>(L, 3);
|
2023-02-26 15:23:20 -03:00
|
|
|
const auto reasonplayer = lua_get<uint8_t>(L, 4, pduel->game_field->core.reason_player);
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [pcard, pgroup] = lua_get_card_or_group(L, 1); pcard)
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->send_to(pcard, pduel->game_field->core.reason_effect, reason, reasonplayer, playerid, LOCATION_EXTRA, 0, POS_FACEUP);
|
2015-10-22 13:13:10 +08:00
|
|
|
else
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->send_to(pgroup->container, pduel->game_field->core.reason_effect, reason, reasonplayer, playerid, LOCATION_EXTRA, 0, POS_FACEUP);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-10-22 13:13:10 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(Sendto) {
|
2017-10-02 22:28:39 +02:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto location = lua_get<uint16_t>(L, 2);
|
|
|
|
|
auto reason = lua_get<uint32_t>(L, 3);
|
|
|
|
|
auto pos = lua_get<uint8_t, POS_FACEUP>(L, 4);
|
|
|
|
|
auto playerid = lua_get<uint8_t, PLAYER_NONE>(L, 5);
|
2021-01-04 23:29:28 +01:00
|
|
|
if(playerid > PLAYER_NONE)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sequence = lua_get<uint32_t, 0>(L, 6);
|
2023-02-26 15:23:20 -03:00
|
|
|
const auto reasonplayer = lua_get<uint8_t>(L, 7, pduel->game_field->core.reason_player);
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [pcard, pgroup] = lua_get_card_or_group(L, 1); pcard)
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->send_to(pcard, pduel->game_field->core.reason_effect, reason, reasonplayer, playerid, location, sequence, pos, TRUE);
|
2017-10-02 22:28:39 +02:00
|
|
|
else
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->send_to(pgroup->container, pduel->game_field->core.reason_effect, reason, reasonplayer, playerid, location, sequence, pos, TRUE);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2017-10-02 22:28:39 +02:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(RemoveCards) {
|
2019-09-06 12:35:05 +02:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [pcard, pgroup] = lua_get_card_or_group(L, 1); pcard) {
|
2022-09-17 12:49:23 +02:00
|
|
|
auto message = pduel->new_message(MSG_REMOVE_CARDS);
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint32_t>(1);
|
2019-09-06 12:35:05 +02:00
|
|
|
message->write(pcard->get_info_location());
|
|
|
|
|
pcard->enable_field_effect(false);
|
|
|
|
|
pcard->cancel_field_effect();
|
|
|
|
|
pduel->game_field->remove_card(pcard);
|
|
|
|
|
} else {
|
2022-09-17 12:49:23 +02:00
|
|
|
auto message = pduel->new_message(MSG_REMOVE_CARDS);
|
|
|
|
|
auto tot = pgroup->container.size();
|
|
|
|
|
auto cur = std::min<size_t>(tot, 255);
|
|
|
|
|
message->write<uint32_t>(cur);
|
2019-09-06 12:35:05 +02:00
|
|
|
for(auto& card : pgroup->container) {
|
|
|
|
|
message->write(card->get_info_location());
|
2022-09-17 12:49:23 +02:00
|
|
|
--tot;
|
|
|
|
|
--cur;
|
|
|
|
|
if(cur == 0 && tot > 0) {
|
|
|
|
|
message = pduel->new_message(MSG_REMOVE_CARDS);
|
|
|
|
|
cur = std::min<size_t>(tot, 255);
|
|
|
|
|
message->write<uint32_t>(cur);
|
|
|
|
|
}
|
2019-09-06 12:35:05 +02:00
|
|
|
card->enable_field_effect(false);
|
|
|
|
|
card->cancel_field_effect();
|
|
|
|
|
}
|
|
|
|
|
for(auto& card : pgroup->container)
|
|
|
|
|
pduel->game_field->remove_card(card);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetOperatedGroup) {
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group(pduel->game_field->core.operated_set);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsCanAddCounter) {
|
2019-05-07 18:22:32 +09:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2016-06-05 21:58:38 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2019-05-07 18:22:32 +09:00
|
|
|
if(lua_gettop(L) == 1)
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_action(playerid, EFFECT_CANNOT_PLACE_COUNTER));
|
|
|
|
|
else {
|
|
|
|
|
check_param_count(L, 4);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto countertype = lua_get<uint16_t>(L, 2);
|
|
|
|
|
auto count = lua_get<uint32_t>(L, 3);
|
2020-07-21 00:08:06 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 4);
|
2019-05-07 18:22:32 +09:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_place_counter(playerid, pcard, countertype, count));
|
|
|
|
|
}
|
2016-06-05 21:58:38 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(RemoveCounter) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 6);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto rplayer = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(rplayer != 0 && rplayer != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto self = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto oppo = lua_get<uint8_t>(L, 3);
|
|
|
|
|
auto countertype = lua_get<uint16_t>(L, 4);
|
|
|
|
|
auto count = lua_get<uint32_t>(L, 5);
|
|
|
|
|
auto reason = lua_get<uint32_t>(L, 6);
|
2024-01-13 16:10:22 +01:00
|
|
|
pduel->game_field->remove_counter(reason, nullptr, rplayer, self, oppo, countertype, count);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsCanRemoveCounter) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 6);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto rplayer = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(rplayer != 0 && rplayer != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto self = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto oppo = lua_get<uint8_t>(L, 3);
|
|
|
|
|
auto countertype = lua_get<uint16_t>(L, 4);
|
|
|
|
|
auto count = lua_get<uint32_t>(L, 5);
|
|
|
|
|
auto reason = lua_get<uint32_t>(L, 6);
|
2024-01-13 16:10:22 +01:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_remove_counter(rplayer, nullptr, self, oppo, countertype, count, reason));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetCounter) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 4);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto self = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto oppo = lua_get<uint8_t>(L, 3);
|
|
|
|
|
auto countertype = lua_get<uint16_t>(L, 4);
|
2020-07-21 00:08:06 +02:00
|
|
|
lua_pushinteger(L, pduel->game_field->get_field_counter(playerid, self, oppo, countertype));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ChangePosition) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto au = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto ad = lua_get<uint8_t>(L, 3, au);
|
|
|
|
|
auto du = lua_get<uint8_t>(L, 4, au);
|
|
|
|
|
auto dd = lua_get<uint8_t>(L, 5, au);
|
|
|
|
|
uint32_t flag = 0;
|
2020-07-23 23:50:09 +02:00
|
|
|
if(lua_get<bool, false>(L, 6)) flag |= NO_FLIP_EFFECT;
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [pcard, pgroup] = lua_get_card_or_group(L, 1); pcard) {
|
2022-03-13 19:51:18 +01:00
|
|
|
pduel->game_field->change_position(card_set{ pcard }, pduel->game_field->core.reason_effect, pduel->game_field->core.reason_player, au, ad, du, dd, flag, TRUE);
|
2015-09-25 21:07:16 +08:00
|
|
|
} else
|
2022-03-13 19:51:18 +01:00
|
|
|
pduel->game_field->change_position(pgroup->container, pduel->game_field->core.reason_effect, pduel->game_field->core.reason_player, au, ad, du, dd, flag, TRUE);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(Release) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto reason = lua_get<uint32_t>(L, 2);
|
2023-02-26 15:23:20 -03:00
|
|
|
const auto reasonplayer = lua_get<uint8_t>(L, 3, pduel->game_field->core.reason_player);
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [pcard, pgroup] = lua_get_card_or_group(L, 1); pcard)
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->release(pcard, pduel->game_field->core.reason_effect, reason, reasonplayer);
|
2015-09-25 21:07:16 +08:00
|
|
|
else
|
2023-02-26 15:23:20 -03:00
|
|
|
pduel->game_field->release(pgroup->container, pduel->game_field->core.reason_effect, reason, reasonplayer);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(MoveToField) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 6);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto move_player = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto playerid = lua_get<uint8_t>(L, 3);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto destination = lua_get<uint16_t>(L, 4);
|
|
|
|
|
auto positions = lua_get<uint8_t>(L, 5);
|
2020-07-21 00:08:06 +02:00
|
|
|
auto enable = lua_get<bool>(L, 6);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto zone = lua_get<uint32_t, 0xff>(L, 7);
|
2016-04-08 19:38:51 +08:00
|
|
|
pcard->enable_field_effect(false);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->adjust_instant();
|
2020-06-16 12:26:59 +02:00
|
|
|
pduel->game_field->move_to_field(pcard, move_player, playerid, destination, positions, enable, 0, zone);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ReturnToField) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(!(pcard->current.reason & REASON_TEMPORARY))
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto pos = lua_get<uint8_t>(L, 2, pcard->previous.position);
|
|
|
|
|
auto zone = lua_get<uint32_t, 0xff>(L, 3);
|
2016-04-08 19:38:51 +08:00
|
|
|
pcard->enable_field_effect(false);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->adjust_instant();
|
|
|
|
|
pduel->game_field->refresh_location_info_instant();
|
2020-06-16 12:26:59 +02:00
|
|
|
pduel->game_field->move_to_field(pcard, pcard->previous.controler, pcard->previous.controler, pcard->previous.location, pos, TRUE, 1, zone, FALSE, LOCATION_REASON_TOFIELD | LOCATION_REASON_RETURN);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(MoveSequence) {
|
2020-10-30 20:57:44 +01:00
|
|
|
check_action_permission(L);
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto seq = lua_get<uint8_t>(L, 2);
|
2022-01-13 18:16:04 +01:00
|
|
|
uint16_t cur_loc = pcard->current.location;
|
2022-03-05 00:04:08 +01:00
|
|
|
bool cur_pzone = pcard->current.pzone;
|
2022-01-13 18:16:04 +01:00
|
|
|
auto location = lua_get<uint16_t>(L, 3, cur_loc);
|
|
|
|
|
|
|
|
|
|
auto& field = *pduel->game_field;
|
|
|
|
|
|
|
|
|
|
bool pzone = false;
|
2022-03-04 19:43:26 +01:00
|
|
|
bool fzone = false;
|
2022-01-13 18:16:04 +01:00
|
|
|
if(location == LOCATION_PZONE) {
|
|
|
|
|
if(!field.is_flag(DUEL_PZONE))
|
2022-06-23 11:47:00 +02:00
|
|
|
lua_error(L, "LOCATION_PZONE passed with pendulum zones disabled");
|
2022-01-13 18:16:04 +01:00
|
|
|
pzone = true;
|
|
|
|
|
location = LOCATION_SZONE;
|
2022-03-04 19:43:26 +01:00
|
|
|
} else if(location == LOCATION_FZONE) {
|
|
|
|
|
fzone = true;
|
|
|
|
|
location = LOCATION_SZONE;
|
2022-01-13 18:16:04 +01:00
|
|
|
}
|
|
|
|
|
|
2020-07-21 00:08:06 +02:00
|
|
|
auto playerid = pcard->current.controler;
|
2022-01-13 18:16:04 +01:00
|
|
|
|
|
|
|
|
if(location != cur_loc)
|
2022-06-23 11:47:00 +02:00
|
|
|
lua_error(L, "The new location doesn't match the current one");
|
2022-01-13 18:16:04 +01:00
|
|
|
|
|
|
|
|
if(pzone) {
|
|
|
|
|
if(seq > 1)
|
2022-06-23 11:47:00 +02:00
|
|
|
lua_error(L, "Invalid sequence");
|
2022-01-13 18:16:04 +01:00
|
|
|
seq = field.get_pzone_index(seq, playerid);
|
2022-03-04 19:43:26 +01:00
|
|
|
} else if(fzone) {
|
|
|
|
|
if(seq != 0)
|
2022-06-23 11:47:00 +02:00
|
|
|
lua_error(L, "Invalid sequence");
|
2022-03-04 19:43:26 +01:00
|
|
|
seq = 5;
|
2022-02-13 12:58:07 +01:00
|
|
|
} else if(location == LOCATION_MZONE && field.is_flag(DUEL_EMZONE)) {
|
|
|
|
|
if(seq > 6)
|
2022-06-23 11:47:00 +02:00
|
|
|
lua_error(L, "Invalid sequence");
|
2022-02-13 12:58:07 +01:00
|
|
|
} else if ((location == LOCATION_MZONE || location == LOCATION_SZONE) && seq > 4)
|
2022-06-23 11:47:00 +02:00
|
|
|
lua_error(L, "Invalid sequence");
|
2022-01-13 18:16:04 +01:00
|
|
|
|
|
|
|
|
auto& core = field.core;
|
2024-01-03 13:34:39 +01:00
|
|
|
bool res = false;
|
2022-01-13 18:16:04 +01:00
|
|
|
if(pcard->is_affect_by_effect(core.reason_effect)) {
|
2022-01-14 00:53:19 +01:00
|
|
|
const auto previous_loc_info = pcard->get_info_location();
|
|
|
|
|
const auto previous_code = pcard->data.code;
|
2024-01-03 13:34:39 +01:00
|
|
|
if(res = field.move_card(playerid, pcard, pcard->current.location, seq, pzone); res) {
|
2022-01-14 00:53:19 +01:00
|
|
|
if(cur_pzone != pzone) {
|
|
|
|
|
auto message = pduel->new_message(MSG_MOVE);
|
|
|
|
|
message->write<uint32_t>(previous_code);
|
|
|
|
|
message->write(previous_loc_info);
|
|
|
|
|
message->write(pcard->get_info_location());
|
|
|
|
|
message->write<uint32_t>(pcard->current.reason);
|
|
|
|
|
}
|
2024-01-13 16:10:22 +01:00
|
|
|
field.raise_single_event(pcard, nullptr, EVENT_MOVE, core.reason_effect, 0, core.reason_player, playerid, 0);
|
2022-01-13 18:16:04 +01:00
|
|
|
field.raise_event(pcard, EVENT_MOVE, core.reason_effect, 0, core.reason_player, playerid, 0);
|
|
|
|
|
field.process_single_event();
|
|
|
|
|
field.process_instant_event();
|
|
|
|
|
}
|
2021-03-31 10:17:54 +08:00
|
|
|
}
|
2022-01-13 18:16:04 +01:00
|
|
|
lua_pushboolean(L, res);
|
|
|
|
|
return 1;
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SwapSequence) {
|
2020-10-30 20:57:44 +01:00
|
|
|
check_action_permission(L);
|
2017-03-30 08:29:18 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard1 = lua_get<card*, true>(L, 1);
|
|
|
|
|
auto pcard2 = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t player = pcard1->current.controler;
|
|
|
|
|
uint8_t location = pcard1->current.location;
|
2017-03-30 08:29:18 +08:00
|
|
|
if(pcard2->current.controler == player
|
2017-04-23 23:41:04 +02:00
|
|
|
&& (location == LOCATION_MZONE || location == LOCATION_SZONE) && pcard2->current.location == location
|
2017-03-30 08:29:18 +08:00
|
|
|
&& pcard1->is_affect_by_effect(pduel->game_field->core.reason_effect)
|
|
|
|
|
&& pcard2->is_affect_by_effect(pduel->game_field->core.reason_effect)) {
|
2020-01-08 12:45:00 +08:00
|
|
|
pduel->game_field->swap_card(pcard1, pcard2);
|
2024-01-13 16:10:22 +01:00
|
|
|
pduel->game_field->raise_single_event(pcard1, nullptr, EVENT_MOVE, pduel->game_field->core.reason_effect, 0, pduel->game_field->core.reason_player, player, 0);
|
|
|
|
|
pduel->game_field->raise_single_event(pcard2, nullptr, EVENT_MOVE, pduel->game_field->core.reason_effect, 0, pduel->game_field->core.reason_player, player, 0);
|
2024-03-08 11:03:06 +01:00
|
|
|
pduel->game_field->raise_event({ pcard1, pcard2 }, EVENT_MOVE, pduel->game_field->core.reason_effect, 0, pduel->game_field->core.reason_player, player, 0);
|
2018-03-07 23:44:18 +09:00
|
|
|
pduel->game_field->process_single_event();
|
|
|
|
|
pduel->game_field->process_instant_event();
|
2017-03-30 08:29:18 +08:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(Activate) {
|
2017-07-01 23:51:49 +09:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2020-07-21 00:08:06 +02:00
|
|
|
auto peffect = lua_get<effect*, true>(L, 1);
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::ActivateEffect>(peffect);
|
2017-07-01 23:51:49 +09:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SetChainLimit) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2022-06-11 12:59:38 +02:00
|
|
|
auto f = interpreter::get_function_handle(L, lua_get<function, true>(L, 1));
|
2018-03-07 09:59:57 +09:00
|
|
|
pduel->game_field->core.chain_limit.emplace_back(f, pduel->game_field->core.reason_player);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SetChainLimitTillChainEnd) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2022-06-11 12:59:38 +02:00
|
|
|
auto f = interpreter::get_function_handle(L, lua_get<function, true>(L, 1));
|
2018-03-07 09:59:57 +09:00
|
|
|
pduel->game_field->core.chain_limit_p.emplace_back(f, pduel->game_field->core.reason_player);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetChainMaterial) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
effect_set eset;
|
|
|
|
|
pduel->game_field->filter_player_effect(playerid, EFFECT_CHAIN_MATERIAL, &eset);
|
|
|
|
|
if(!eset.size())
|
|
|
|
|
return 0;
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, eset[0]);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ConfirmDecktop) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto count = lua_get<uint32_t>(L, 2);
|
2022-03-05 12:24:38 +01:00
|
|
|
const auto& player = pduel->game_field->player[playerid];
|
|
|
|
|
const auto& list_main = player.list_main;
|
|
|
|
|
if(count >= list_main.size())
|
2023-02-07 16:43:27 +01:00
|
|
|
count = static_cast<uint32_t>(list_main.size());
|
2022-03-05 12:24:38 +01:00
|
|
|
else if(list_main.size() > count) {
|
2024-11-04 22:36:40 +01:00
|
|
|
if(pduel->game_field->core.deck_reversed) {
|
2022-03-05 12:24:38 +01:00
|
|
|
card* pcard = *(list_main.rbegin() + count);
|
|
|
|
|
auto message = pduel->new_message(MSG_DECK_TOP);
|
|
|
|
|
message->write<uint8_t>(playerid);
|
|
|
|
|
message->write<uint32_t>(count);
|
|
|
|
|
message->write<uint32_t>(pcard->data.code);
|
|
|
|
|
message->write<uint32_t>(pcard->current.position);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
}
|
2019-07-16 00:57:53 +02:00
|
|
|
auto message = pduel->new_message(MSG_CONFIRM_DECKTOP);
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint8_t>(playerid);
|
|
|
|
|
message->write<uint32_t>(count);
|
2022-03-05 12:24:38 +01:00
|
|
|
for(auto cit = list_main.rbegin(), end = cit + count; cit != end; ++cit) {
|
|
|
|
|
const auto& pcard = *cit;
|
|
|
|
|
message->write<uint32_t>(pcard->data.code);
|
|
|
|
|
message->write<uint8_t>(pcard->current.controler);
|
|
|
|
|
message->write<uint8_t>(pcard->current.location);
|
|
|
|
|
message->write<uint32_t>(pcard->current.sequence);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ConfirmExtratop) {
|
2017-11-17 18:44:31 +01:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2017-11-17 18:44:31 +01:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto count = lua_get<uint32_t>(L, 2);
|
2022-03-05 12:24:38 +01:00
|
|
|
const auto& player = pduel->game_field->player[playerid];
|
|
|
|
|
const auto& list_extra = player.list_extra;
|
2023-02-07 16:43:27 +01:00
|
|
|
const uint32_t max_count = static_cast<uint32_t>(list_extra.size()) - player.extra_p_count;
|
2022-03-05 12:24:38 +01:00
|
|
|
count = std::min(max_count, count);
|
2019-07-16 00:57:53 +02:00
|
|
|
auto message = pduel->new_message(MSG_CONFIRM_EXTRATOP);
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint8_t>(playerid);
|
|
|
|
|
message->write<uint32_t>(count);
|
2022-03-05 12:24:38 +01:00
|
|
|
for(auto cit = list_extra.rbegin() + player.extra_p_count, end = cit + count; cit != end; ++cit) {
|
|
|
|
|
const auto& pcard = *cit;
|
|
|
|
|
message->write<uint32_t>(pcard->data.code);
|
|
|
|
|
message->write<uint8_t>(pcard->current.controler);
|
|
|
|
|
message->write<uint8_t>(pcard->current.location);
|
|
|
|
|
message->write<uint32_t>(pcard->current.sequence);
|
2017-11-17 18:44:31 +01:00
|
|
|
}
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2017-11-17 18:44:31 +01:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ConfirmCards) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2023-12-03 11:34:38 +01:00
|
|
|
auto [pcard, pgroup] = lua_get_card_or_group(L, 2);
|
2020-10-30 17:05:28 +01:00
|
|
|
if(pgroup && pgroup->container.empty())
|
|
|
|
|
return 0;
|
2019-07-16 00:57:53 +02:00
|
|
|
auto message = pduel->new_message(MSG_CONFIRM_CARDS);
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint8_t>(playerid);
|
2023-12-03 13:19:37 -03:00
|
|
|
|
|
|
|
|
//To raise the proper events:
|
|
|
|
|
// EVENT_CONFIRM event when a card is revealed (used by "Vanquish Soul Jiaolong")
|
|
|
|
|
// EVENT_TOHAND_CONFIRM event when a card in the hand is revealed (used by "Puppet King" and "Puppet Queen")
|
|
|
|
|
auto& field = *pduel->game_field;
|
|
|
|
|
auto reason = (field.core.chain_solving) ? REASON_EFFECT : REASON_COST;
|
|
|
|
|
auto trigeff = field.core.reason_effect;
|
|
|
|
|
uint8_t revealingplayer = 1 - playerid;
|
|
|
|
|
bool was_during_to_hand = field.check_event(EVENT_TO_HAND);
|
|
|
|
|
card_set handgroup;
|
|
|
|
|
auto raise_confirm_event = [&](card* pcard) {
|
2024-01-13 16:10:22 +01:00
|
|
|
field.raise_single_event(pcard, nullptr, EVENT_CONFIRM, trigeff, reason, field.core.reason_player, revealingplayer, 0);
|
2023-12-03 13:19:37 -03:00
|
|
|
if(was_during_to_hand && (pcard->current.location == LOCATION_HAND)) {
|
2024-01-13 16:10:22 +01:00
|
|
|
field.raise_single_event(pcard, nullptr, EVENT_TOHAND_CONFIRM, trigeff, reason, field.core.reason_player, revealingplayer, 0);
|
2023-12-03 13:19:37 -03:00
|
|
|
handgroup.insert(pcard);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2015-09-25 21:07:16 +08:00
|
|
|
if(pcard) {
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint32_t>(1);
|
|
|
|
|
message->write<uint32_t>(pcard->data.code);
|
|
|
|
|
message->write<uint8_t>(pcard->current.controler);
|
|
|
|
|
message->write<uint8_t>(pcard->current.location);
|
|
|
|
|
message->write<uint32_t>(pcard->current.sequence);
|
2023-12-03 13:19:37 -03:00
|
|
|
raise_confirm_event(pcard);
|
|
|
|
|
field.raise_event(pcard, EVENT_CONFIRM, trigeff, reason, field.core.reason_player, revealingplayer, 0);
|
2015-09-25 21:07:16 +08:00
|
|
|
} else {
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint32_t>(pgroup->container.size());
|
2020-09-16 17:12:50 +02:00
|
|
|
for(auto& _pcard : pgroup->container) {
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint32_t>(_pcard->data.code);
|
|
|
|
|
message->write<uint8_t>(_pcard->current.controler);
|
|
|
|
|
message->write<uint8_t>(_pcard->current.location);
|
|
|
|
|
message->write<uint32_t>(_pcard->current.sequence);
|
2023-12-03 13:19:37 -03:00
|
|
|
raise_confirm_event(_pcard);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2024-03-08 11:03:06 +01:00
|
|
|
field.raise_event(pgroup->container, EVENT_CONFIRM, trigeff, reason, field.core.reason_player, revealingplayer, 0);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-12-03 13:19:37 -03:00
|
|
|
if(handgroup.size())
|
2024-03-08 11:03:06 +01:00
|
|
|
field.raise_event(std::move(handgroup), EVENT_TOHAND_CONFIRM, trigeff, reason, field.core.reason_player, revealingplayer, 0);
|
2023-12-03 13:19:37 -03:00
|
|
|
field.process_single_event();
|
|
|
|
|
field.process_instant_event();
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SortDecktop) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sort_player = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto target_player = lua_get<uint8_t>(L, 2);
|
2024-01-08 20:46:41 +01:00
|
|
|
auto count = lua_get<uint16_t>(L, 3);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(sort_player != 0 && sort_player != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
if(target_player != 0 && target_player != 1)
|
|
|
|
|
return 0;
|
2019-02-03 13:00:47 +01:00
|
|
|
if(count < 1 || count > 64)
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SortDeck>(sort_player, target_player, count, false);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2020-04-19 19:38:54 +02:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SortDeckbottom) {
|
2020-04-19 19:38:54 +02:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sort_player = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto target_player = lua_get<uint8_t>(L, 2);
|
2024-01-08 20:46:41 +01:00
|
|
|
auto count = lua_get<uint16_t>(L, 3);
|
2020-04-19 19:38:54 +02:00
|
|
|
if(sort_player != 0 && sort_player != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
if(target_player != 0 && target_player != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
if(count < 1 || count > 64)
|
|
|
|
|
return 0;
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SortDeck>(sort_player, target_player, count, true);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CheckEvent) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto ev = lua_get<uint32_t>(L, 1);
|
2020-09-02 14:59:30 +02:00
|
|
|
if(!/*bool get_info = */lua_get<bool, false>(L, 2)) {
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, pduel->game_field->check_event(ev));
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
tevent pe;
|
|
|
|
|
if(pduel->game_field->check_event(ev, &pe)) {
|
|
|
|
|
lua_pushboolean(L, 1);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pe.event_cards);
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, pe.event_player);
|
|
|
|
|
lua_pushinteger(L, pe.event_value);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pe.reason_effect);
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, pe.reason);
|
|
|
|
|
lua_pushinteger(L, pe.reason_player);
|
|
|
|
|
return 7;
|
|
|
|
|
} else {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(RaiseEvent) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 7);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = lua_get<uint32_t>(L, 2);
|
2024-01-13 16:10:22 +01:00
|
|
|
effect* peffect = nullptr;
|
2020-12-26 00:31:31 +01:00
|
|
|
if(!lua_isnoneornil(L, 3))
|
2020-07-21 00:08:06 +02:00
|
|
|
peffect = lua_get<effect*, true>(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto r = lua_get<uint32_t>(L, 4);
|
|
|
|
|
auto rp = lua_get<uint8_t>(L, 5);
|
|
|
|
|
auto ep = lua_get<uint8_t>(L, 6);
|
|
|
|
|
auto ev = lua_get<uint32_t>(L, 7);
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [pcard, pgroup] = lua_get_card_or_group(L, 1); pcard)
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->raise_event(pcard, code, peffect, r, rp, ep, ev);
|
|
|
|
|
else
|
2024-03-08 11:03:06 +01:00
|
|
|
pduel->game_field->raise_event(pgroup->container, code, peffect, r, rp, ep, ev);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->process_instant_event();
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(RaiseSingleEvent) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 7);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = lua_get<uint32_t>(L, 2);
|
2020-10-30 17:05:28 +01:00
|
|
|
auto peffect = lua_get<effect*>(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto r = lua_get<uint32_t>(L, 4);
|
|
|
|
|
auto rp = lua_get<uint8_t>(L, 5);
|
|
|
|
|
auto ep = lua_get<uint8_t>(L, 6);
|
|
|
|
|
auto ev = lua_get<uint32_t>(L, 7);
|
2024-01-13 16:10:22 +01:00
|
|
|
pduel->game_field->raise_single_event(pcard, nullptr, code, peffect, r, rp, ep, ev);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->process_single_event();
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CheckTiming) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto tm = lua_get<uint32_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, (pduel->game_field->core.hint_timing[0]&tm) || (pduel->game_field->core.hint_timing[1]&tm));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetEnvironment) {
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t code = 0;
|
|
|
|
|
uint8_t p = 2;
|
2021-02-02 18:09:49 +01:00
|
|
|
auto IsEnabled = [&](card* pcard) {
|
|
|
|
|
if(pcard && pcard->is_position(POS_FACEUP) && pcard->get_status(STATUS_EFFECT_ENABLED)) {
|
|
|
|
|
code = pcard->get_code();
|
|
|
|
|
p = pcard->current.controler;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
if(!IsEnabled(pduel->game_field->player[0].list_szone[5]) && !IsEnabled(pduel->game_field->player[1].list_szone[5])) {
|
|
|
|
|
effect_set eset;
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->filter_field_effect(EFFECT_CHANGE_ENVIRONMENT, &eset);
|
|
|
|
|
if(eset.size()) {
|
2021-02-02 18:09:49 +01:00
|
|
|
const auto peffect = eset.back();
|
2015-09-25 21:07:16 +08:00
|
|
|
code = peffect->get_value();
|
|
|
|
|
p = peffect->get_handler_player();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lua_pushinteger(L, code);
|
|
|
|
|
lua_pushinteger(L, p);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsEnvironment) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = lua_get<uint32_t>(L, 1);
|
|
|
|
|
auto playerid = lua_get<uint8_t, PLAYER_ALL>(L, 2);
|
|
|
|
|
auto loc = lua_get<uint16_t, LOCATION_FZONE + LOCATION_ONFIELD>(L, 3);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1 && playerid != PLAYER_ALL)
|
|
|
|
|
return 0;
|
2021-02-02 18:09:49 +01:00
|
|
|
auto RetTrue = [L] {
|
|
|
|
|
lua_pushboolean(L, TRUE);
|
|
|
|
|
return 1;
|
|
|
|
|
};
|
|
|
|
|
auto IsEnabled = [](card* pcard) { return pcard && pcard->is_position(POS_FACEUP) && pcard->get_status(STATUS_EFFECT_ENABLED); };
|
2021-09-04 22:04:14 +02:00
|
|
|
auto CheckFzone = [&](uint8_t player) {
|
2021-02-02 18:09:49 +01:00
|
|
|
if(playerid == player || playerid == PLAYER_ALL) {
|
|
|
|
|
const auto& pcard = pduel->game_field->player[player].list_szone[5];
|
|
|
|
|
if(IsEnabled(pcard) && code == pcard->get_code())
|
|
|
|
|
return true;
|
2017-09-07 22:59:40 +08:00
|
|
|
}
|
2021-02-02 18:09:49 +01:00
|
|
|
return false;
|
|
|
|
|
};
|
2021-09-04 22:04:14 +02:00
|
|
|
auto CheckSzone = [&](uint8_t player) {
|
2021-02-02 18:09:49 +01:00
|
|
|
if(playerid == player || playerid == PLAYER_ALL) {
|
|
|
|
|
for(auto& pcard : pduel->game_field->player[player].list_szone) {
|
|
|
|
|
if(IsEnabled(pcard) && code == pcard->get_code())
|
|
|
|
|
return true;
|
2017-09-07 22:59:40 +08:00
|
|
|
}
|
|
|
|
|
}
|
2021-02-02 18:09:49 +01:00
|
|
|
return false;
|
|
|
|
|
};
|
2021-09-04 22:04:14 +02:00
|
|
|
auto CheckMzone = [&](uint8_t player) {
|
2021-02-02 18:09:49 +01:00
|
|
|
if(playerid == player || playerid == PLAYER_ALL) {
|
|
|
|
|
for(auto& pcard : pduel->game_field->player[player].list_mzone) {
|
|
|
|
|
if(IsEnabled(pcard) && code == pcard->get_code())
|
|
|
|
|
return true;
|
2017-09-07 22:59:40 +08:00
|
|
|
}
|
|
|
|
|
}
|
2021-02-02 18:09:49 +01:00
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
auto ShouldApplyChangeEnv = [&]() {
|
|
|
|
|
if((loc & (LOCATION_FZONE | LOCATION_SZONE)) == 0)
|
|
|
|
|
return false;
|
|
|
|
|
return !(IsEnabled(pduel->game_field->player[0].list_szone[5]) || IsEnabled(pduel->game_field->player[1].list_szone[5]));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if(loc & LOCATION_FZONE && (CheckFzone(0) || CheckFzone(1)))
|
|
|
|
|
return RetTrue();
|
|
|
|
|
|
|
|
|
|
if(loc & LOCATION_SZONE && (CheckSzone(0) || CheckSzone(1)))
|
|
|
|
|
return RetTrue();
|
|
|
|
|
|
|
|
|
|
if(loc & LOCATION_MZONE && (CheckMzone(0) || CheckMzone(1)))
|
|
|
|
|
return RetTrue();
|
|
|
|
|
|
|
|
|
|
if(ShouldApplyChangeEnv()) {
|
2015-09-25 21:07:16 +08:00
|
|
|
effect_set eset;
|
|
|
|
|
pduel->game_field->filter_field_effect(EFFECT_CHANGE_ENVIRONMENT, &eset);
|
|
|
|
|
if(eset.size()) {
|
2021-02-02 18:09:49 +01:00
|
|
|
const auto& peffect = eset.back();
|
2021-09-04 22:04:14 +02:00
|
|
|
if((playerid == PLAYER_ALL || playerid == peffect->get_handler_player()) && code == (uint32_t)peffect->get_value())
|
2021-02-02 18:09:49 +01:00
|
|
|
return RetTrue();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
}
|
2021-02-02 18:09:49 +01:00
|
|
|
lua_pushboolean(L, FALSE);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(Win) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto reason = lua_get<uint32_t>(L, 2);
|
2016-07-17 22:21:43 +02:00
|
|
|
if (playerid != 0 && playerid != 1 && playerid != 2)
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
2016-07-17 22:21:43 +02:00
|
|
|
if (playerid == 0) {
|
|
|
|
|
if (pduel->game_field->is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_EFFECT))
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else if (playerid == 1) {
|
|
|
|
|
if (pduel->game_field->is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_EFFECT))
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (pduel->game_field->is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_EFFECT) && pduel->game_field->is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_EFFECT))
|
|
|
|
|
return 0;
|
|
|
|
|
else if (pduel->game_field->is_player_affected_by_effect(0, EFFECT_CANNOT_LOSE_EFFECT))
|
|
|
|
|
playerid = 0;
|
|
|
|
|
else if (pduel->game_field->is_player_affected_by_effect(1, EFFECT_CANNOT_LOSE_EFFECT))
|
|
|
|
|
playerid = 1;
|
|
|
|
|
}
|
|
|
|
|
if (pduel->game_field->core.win_player == 5) {
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->core.win_player = playerid;
|
|
|
|
|
pduel->game_field->core.win_reason = reason;
|
2018-01-11 18:57:17 -02:00
|
|
|
} else if ((pduel->game_field->core.win_player == 0 && playerid == 1) || (pduel->game_field->core.win_player == 1 && playerid == 0)) {
|
|
|
|
|
pduel->game_field->core.win_player = 2;
|
|
|
|
|
pduel->game_field->core.win_reason = reason;
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(Draw) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto count = lua_get<uint32_t>(L, 2);
|
|
|
|
|
auto reason = lua_get<uint32_t>(L, 3);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->draw(pduel->game_field->core.reason_effect, reason, pduel->game_field->core.reason_player, playerid, count);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(Damage) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2022-03-31 18:33:31 +02:00
|
|
|
auto amount = lua_get<int64_t>(L, 2);
|
|
|
|
|
uint32_t actual_amount = 0;
|
|
|
|
|
if(amount > 0)
|
|
|
|
|
actual_amount = static_cast<uint32_t>(amount);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto reason = lua_get<uint32_t>(L, 3);
|
2020-07-23 23:50:09 +02:00
|
|
|
bool is_step = lua_get<bool, false>(L, 4);
|
2023-05-31 12:17:50 -03:00
|
|
|
auto reason_player = lua_get<uint8_t>(L, 5, pduel->game_field->core.reason_player);
|
|
|
|
|
if (reason_player > PLAYER_NONE)
|
|
|
|
|
reason_player = pduel->game_field->core.reason_player;
|
2024-01-13 16:10:22 +01:00
|
|
|
pduel->game_field->damage(pduel->game_field->core.reason_effect, reason, reason_player, nullptr, playerid, actual_amount, is_step);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<uint32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(Recover) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2022-03-31 18:33:31 +02:00
|
|
|
auto amount = lua_get<int64_t>(L, 2);
|
|
|
|
|
uint32_t actual_amount = 0;
|
|
|
|
|
if(amount > 0)
|
|
|
|
|
actual_amount = static_cast<uint32_t>(amount);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto reason = lua_get<uint32_t>(L, 3);
|
2020-07-23 23:50:09 +02:00
|
|
|
bool is_step = lua_get<bool, false>(L, 4);
|
2023-05-31 12:17:50 -03:00
|
|
|
auto reason_player = lua_get<uint8_t>(L, 5, pduel->game_field->core.reason_player);
|
|
|
|
|
if (reason_player > PLAYER_NONE)
|
|
|
|
|
reason_player = pduel->game_field->core.reason_player;
|
|
|
|
|
pduel->game_field->recover(pduel->game_field->core.reason_effect, reason, reason_player, playerid, actual_amount, is_step);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<uint32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(RDComplete) {
|
2016-05-17 19:00:41 +09:00
|
|
|
pduel->game_field->core.subunits.splice(pduel->game_field->core.subunits.end(), pduel->game_field->core.recover_damage_reserve);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2016-05-17 19:00:41 +09:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(Equip) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto equip_card = lua_get<card*, true>(L, 2);
|
|
|
|
|
auto target = lua_get<card*, true>(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2020-07-23 23:50:09 +02:00
|
|
|
bool up = lua_get<bool, true>(L, 4);
|
|
|
|
|
bool step = lua_get<bool, false>(L, 5);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->equip(playerid, equip_card, target, up, step);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(EquipComplete) {
|
2023-03-16 19:56:53 +01:00
|
|
|
const auto& field = pduel->game_field;
|
|
|
|
|
auto& core = field->core;
|
2021-09-04 20:46:43 +02:00
|
|
|
card_set etargets;
|
2023-03-16 19:56:53 +01:00
|
|
|
for(auto& equip_card : core.equiping_cards) {
|
2015-09-25 21:07:16 +08:00
|
|
|
if(equip_card->is_position(POS_FACEUP))
|
2016-04-08 19:38:51 +08:00
|
|
|
equip_card->enable_field_effect(true);
|
2015-09-25 21:07:16 +08:00
|
|
|
etargets.insert(equip_card->equiping_target);
|
|
|
|
|
}
|
2023-03-16 19:56:53 +01:00
|
|
|
if (etargets.size() == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
field->adjust_instant();
|
|
|
|
|
for(auto& equip_target : etargets) {
|
|
|
|
|
field->raise_single_event(equip_target, &core.equiping_cards, EVENT_EQUIP,
|
|
|
|
|
core.reason_effect, 0, core.reason_player, PLAYER_NONE, 0);
|
|
|
|
|
}
|
2024-03-08 11:03:06 +01:00
|
|
|
field->raise_event(core.equiping_cards, EVENT_EQUIP,
|
2023-03-16 19:56:53 +01:00
|
|
|
core.reason_effect, 0, core.reason_player, PLAYER_NONE, 0);
|
|
|
|
|
core.hint_timing[0] |= TIMING_EQUIP;
|
|
|
|
|
core.hint_timing[1] |= TIMING_EQUIP;
|
|
|
|
|
field->process_single_event();
|
|
|
|
|
field->process_instant_event();
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetControl) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint16_t reset_phase = lua_get<uint16_t, 0>(L, 3) & 0x3ff;
|
|
|
|
|
auto reset_count = lua_get<uint8_t, 0>(L, 4);
|
|
|
|
|
auto zone = lua_get<uint32_t, 0xff>(L, 5);
|
|
|
|
|
auto chose_player = lua_get<uint8_t>(L, 6, pduel->game_field->core.reason_player);
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [pcard, pgroup] = lua_get_card_or_group(L, 1); pcard)
|
2020-07-05 20:35:33 +02:00
|
|
|
pduel->game_field->get_control(pcard, pduel->game_field->core.reason_effect, chose_player, playerid, reset_phase, reset_count, zone);
|
2016-05-15 23:31:22 +09:00
|
|
|
else
|
2022-03-13 19:51:18 +01:00
|
|
|
pduel->game_field->get_control(pgroup->container, pduel->game_field->core.reason_effect, chose_player, playerid, reset_phase, reset_count, zone);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SwapControl) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint16_t reset_phase = lua_get<uint16_t, 0>(L, 3) & 0x3ff;
|
|
|
|
|
auto reset_count = lua_get<uint8_t, 0>(L, 4);
|
2023-12-08 19:52:46 +01:00
|
|
|
auto& field = *pduel->game_field;
|
|
|
|
|
if(auto [pcard1, pgroup1] = lua_get_card_or_group(L, 1); pcard1) {
|
|
|
|
|
auto pcard2 = lua_get<card*, true>(L, 2);
|
|
|
|
|
field.swap_control(field.core.reason_effect, field.core.reason_player, pcard1, pcard2, reset_phase, reset_count);
|
|
|
|
|
} else {
|
|
|
|
|
auto pgroup2 = lua_get<group*, true>(L, 2);
|
|
|
|
|
field.swap_control(field.core.reason_effect, field.core.reason_player, pgroup1->container, pgroup2->container, reset_phase, reset_count);
|
|
|
|
|
}
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CheckLPCost) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto cost = lua_get<uint32_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, pduel->game_field->check_lp_cost(playerid, cost));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(PayLPCost) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto cost = lua_get<uint32_t>(L, 2);
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::PayLPCost>(playerid, cost);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(DiscardDeck) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto count = lua_get<uint16_t>(L, 2);
|
|
|
|
|
auto reason = lua_get<uint32_t>(L, 3);
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::DiscardDeck>(playerid, count, reason);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(DiscardHand) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 5);
|
2022-06-11 12:59:38 +02:00
|
|
|
const auto findex = lua_get<function>(L, 2);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* pexception = nullptr;
|
|
|
|
|
group* pexgroup = nullptr;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t extraargs = 0;
|
2015-09-25 21:07:16 +08:00
|
|
|
if(lua_gettop(L) >= 6) {
|
2020-09-16 17:12:50 +02:00
|
|
|
if((pexception = lua_get<card*>(L, 6)) == nullptr)
|
2020-07-12 14:57:26 +02:00
|
|
|
pexgroup = lua_get<group*>(L, 6);
|
2015-09-25 21:07:16 +08:00
|
|
|
extraargs = lua_gettop(L) - 6;
|
|
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto min = lua_get<uint16_t>(L, 3);
|
|
|
|
|
auto max = lua_get<uint16_t>(L, 4);
|
|
|
|
|
auto reason = lua_get<uint32_t>(L, 5);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group();
|
2022-06-11 12:59:38 +02:00
|
|
|
pduel->game_field->filter_matching_card(findex, playerid, LOCATION_HAND, 0, pgroup, pexception, pexgroup, extraargs);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->core.select_cards.assign(pgroup->container.begin(), pgroup->container.end());
|
|
|
|
|
if(pduel->game_field->core.select_cards.size() == 0) {
|
|
|
|
|
lua_pushinteger(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::DiscardHand>(playerid, min, max, reason);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(DisableShuffleCheck) {
|
2020-07-23 23:50:09 +02:00
|
|
|
bool disable = lua_get<bool, true>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->core.shuffle_check_disabled = disable;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(DisableSelfDestroyCheck) {
|
2020-10-26 10:17:12 +08:00
|
|
|
bool disable = lua_get<bool, true>(L, 1);
|
|
|
|
|
pduel->game_field->core.selfdes_disabled = disable;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ShuffleDeck) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
pduel->game_field->shuffle(playerid, LOCATION_DECK);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ShuffleExtra) {
|
2017-11-17 18:44:31 +01:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2017-11-17 18:44:31 +01:00
|
|
|
if (playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
pduel->game_field->shuffle(playerid, LOCATION_EXTRA);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2017-11-17 18:44:31 +01:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ShuffleHand) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
pduel->game_field->shuffle(playerid, LOCATION_HAND);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ShuffleSetCard) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pgroup = lua_get<group*, true>(L, 1);
|
2017-11-14 05:16:24 +08:00
|
|
|
if(pgroup->container.size() <= 0)
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
2017-03-19 23:33:20 +09:00
|
|
|
card* ms[7];
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t seq[7];
|
2021-12-04 16:06:41 +01:00
|
|
|
auto it = pgroup->container.begin();
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t ct = 0;
|
2021-12-04 16:06:41 +01:00
|
|
|
ms[ct] = *it;
|
|
|
|
|
uint8_t loc = ms[ct]->current.location;
|
|
|
|
|
if(loc != LOCATION_MZONE && loc != LOCATION_SZONE)
|
|
|
|
|
return 0;
|
|
|
|
|
uint8_t tp = ms[ct]->current.controler;
|
|
|
|
|
if(tp > 1)
|
|
|
|
|
return 0;
|
|
|
|
|
if(ms[ct]->current.position & POS_FACEUP)
|
|
|
|
|
return 0;
|
|
|
|
|
if(ms[ct]->current.sequence > 4)
|
|
|
|
|
return 0;
|
|
|
|
|
seq[ct] = ms[ct]->current.sequence;
|
2022-03-05 13:56:43 +01:00
|
|
|
++it;
|
|
|
|
|
++ct;
|
|
|
|
|
for(auto end = pgroup->container.end(); it != end; ++it, ++ct) {
|
2021-12-04 16:06:41 +01:00
|
|
|
auto pcard = *it;
|
|
|
|
|
const auto& current = pcard->current;
|
|
|
|
|
if(current.location != loc)
|
|
|
|
|
return 0;
|
|
|
|
|
if(current.position & POS_FACEUP)
|
|
|
|
|
return 0;
|
|
|
|
|
if(current.sequence > 4)
|
|
|
|
|
return 0;
|
|
|
|
|
if(current.controler != tp)
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
ms[ct] = pcard;
|
2021-12-04 16:06:41 +01:00
|
|
|
seq[ct] = current.sequence;
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
for(int32_t i = ct - 1; i > 0; --i) {
|
|
|
|
|
int32_t s = pduel->get_next_integer(0, i);
|
2016-05-06 22:50:22 +09:00
|
|
|
std::swap(ms[i], ms[s]);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2021-09-04 20:26:09 +02:00
|
|
|
auto& field = pduel->game_field;
|
|
|
|
|
auto& list = (loc == LOCATION_MZONE) ? field->player[tp].list_mzone : field->player[tp].list_szone;
|
2019-07-16 00:57:53 +02:00
|
|
|
auto message = pduel->new_message(MSG_SHUFFLE_SET_CARD);
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint8_t>(loc);
|
|
|
|
|
message->write<uint8_t>(ct);
|
|
|
|
|
for(uint32_t i = 0; i < ct; ++i) {
|
2018-03-07 23:44:18 +09:00
|
|
|
card* pcard = ms[i];
|
2019-07-16 00:57:53 +02:00
|
|
|
message->write(pcard->get_info_location());
|
2021-09-04 20:26:09 +02:00
|
|
|
list[seq[i]] = pcard;
|
2018-03-07 23:44:18 +09:00
|
|
|
pcard->current.sequence = seq[i];
|
2024-01-13 16:10:22 +01:00
|
|
|
field->raise_single_event(pcard, nullptr, EVENT_MOVE, pcard->current.reason_effect, pcard->current.reason, pcard->current.reason_player, tp, 0);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2024-03-08 11:03:06 +01:00
|
|
|
field->raise_event(pgroup->container, EVENT_MOVE, field->core.reason_effect, 0, field->core.reason_player, tp, 0);
|
2021-09-04 20:26:09 +02:00
|
|
|
field->process_single_event();
|
|
|
|
|
field->process_instant_event();
|
2021-09-04 22:04:14 +02:00
|
|
|
for(uint32_t i = 0; i < ct; ++i) {
|
2018-08-18 20:19:07 +02:00
|
|
|
if(ms[i]->xyz_materials.size()) {
|
2019-07-16 00:57:53 +02:00
|
|
|
message->write(ms[i]->get_info_location());
|
2018-08-18 20:19:07 +02:00
|
|
|
} else {
|
2019-09-06 12:34:10 +02:00
|
|
|
message->write(loc_info{});
|
2018-08-18 20:19:07 +02:00
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ChangeAttacker) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2022-03-05 13:56:43 +01:00
|
|
|
auto new_attacker = lua_get<card*, true>(L, 1);
|
|
|
|
|
auto& attacker = pduel->game_field->core.attacker;
|
|
|
|
|
if(attacker == new_attacker)
|
2017-09-07 05:40:56 +09:00
|
|
|
return 0;
|
2020-10-30 17:05:28 +01:00
|
|
|
auto ignore_count = lua_get<bool, false>(L, 2);
|
2018-08-21 19:04:34 +08:00
|
|
|
card* attack_target = pduel->game_field->core.attack_target;
|
2022-03-05 13:56:43 +01:00
|
|
|
++attacker->announce_count;
|
|
|
|
|
attacker->announced_cards.addcard(attack_target);
|
2018-08-21 17:51:57 +08:00
|
|
|
pduel->game_field->attack_all_target_check();
|
2022-03-05 13:56:43 +01:00
|
|
|
attacker = new_attacker;
|
2017-09-07 05:40:56 +09:00
|
|
|
attacker->attack_controler = attacker->current.controler;
|
|
|
|
|
pduel->game_field->core.pre_field[0] = attacker->fieldid_r;
|
|
|
|
|
if(!ignore_count) {
|
2022-03-05 13:56:43 +01:00
|
|
|
++attacker->attack_announce_count;
|
2017-09-07 05:40:56 +09:00
|
|
|
if(pduel->game_field->infos.phase == PHASE_DAMAGE) {
|
2022-03-05 13:56:43 +01:00
|
|
|
++attacker->attacked_count;
|
2017-09-07 05:40:56 +09:00
|
|
|
attacker->attacked_cards.addcard(attack_target);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ChangeAttackTarget) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2020-10-30 17:05:28 +01:00
|
|
|
auto target = lua_get<card*>(L, 1);
|
2020-07-23 23:50:09 +02:00
|
|
|
auto ignore = lua_get<bool, false>(L, 2);
|
2016-05-03 22:21:06 +08:00
|
|
|
card* attacker = pduel->game_field->core.attacker;
|
|
|
|
|
if(!attacker || !attacker->is_capable_attack() || attacker->is_status(STATUS_ATTACK_CANCELED)) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2021-09-04 20:46:43 +02:00
|
|
|
card_vector cv;
|
2016-05-16 02:11:21 +08:00
|
|
|
pduel->game_field->get_attack_target(attacker, &cv, pduel->game_field->core.chain_attack);
|
2018-02-06 17:19:35 -04:00
|
|
|
if(((target && std::find(cv.begin(), cv.end(), target) != cv.end()) || ignore) ||
|
|
|
|
|
(!target && !attacker->is_affected_by_effect(EFFECT_CANNOT_DIRECT_ATTACK))) {
|
2016-05-16 02:11:21 +08:00
|
|
|
pduel->game_field->core.attack_target = target;
|
2024-01-03 13:34:39 +01:00
|
|
|
pduel->game_field->core.attack_rollback = false;
|
2017-10-15 23:15:42 +08:00
|
|
|
pduel->game_field->core.opp_mzone.clear();
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t turnp = pduel->game_field->infos.turn_player;
|
2018-08-21 19:04:34 +08:00
|
|
|
for(auto& pcard : pduel->game_field->player[1 - turnp].list_mzone) {
|
2017-03-19 23:33:20 +09:00
|
|
|
if(pcard)
|
2017-10-15 23:15:42 +08:00
|
|
|
pduel->game_field->core.opp_mzone.insert(pcard->fieldid_r);
|
2016-05-16 02:11:21 +08:00
|
|
|
}
|
2019-07-16 00:57:53 +02:00
|
|
|
auto message = pduel->new_message(MSG_ATTACK);
|
|
|
|
|
message->write(attacker->get_info_location());
|
2016-05-16 02:11:21 +08:00
|
|
|
if(target) {
|
2017-01-04 16:12:05 +01:00
|
|
|
if(target->current.controler != turnp) {
|
2024-01-13 16:10:22 +01:00
|
|
|
pduel->game_field->raise_single_event(target, nullptr, EVENT_BE_BATTLE_TARGET, nullptr, REASON_REPLACE, 0, turnp, 0);
|
|
|
|
|
pduel->game_field->raise_event(target, EVENT_BE_BATTLE_TARGET, nullptr, REASON_REPLACE, 0, turnp, 0);
|
2016-10-03 19:53:54 +02:00
|
|
|
}else{
|
2024-01-13 16:10:22 +01:00
|
|
|
pduel->game_field->raise_single_event(target, nullptr, EVENT_BE_BATTLE_TARGET, nullptr, REASON_REPLACE, 0, 1 - turnp, 0);
|
|
|
|
|
pduel->game_field->raise_event(target, EVENT_BE_BATTLE_TARGET, nullptr, REASON_REPLACE, 0, 1 - turnp, 0);
|
2016-10-03 19:53:54 +02:00
|
|
|
}
|
2016-05-16 02:11:21 +08:00
|
|
|
pduel->game_field->process_single_event();
|
|
|
|
|
pduel->game_field->process_instant_event();
|
2019-07-16 00:57:53 +02:00
|
|
|
message->write(target->get_info_location());
|
2018-08-21 19:04:34 +08:00
|
|
|
} else {
|
2016-05-17 22:59:05 +08:00
|
|
|
pduel->game_field->core.attack_player = TRUE;
|
2019-09-06 12:34:10 +02:00
|
|
|
message->write(loc_info{});
|
2018-08-21 19:04:34 +08:00
|
|
|
}
|
2016-05-03 22:21:06 +08:00
|
|
|
lua_pushboolean(L, 1);
|
|
|
|
|
} else
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(AttackCostPaid) {
|
2021-09-04 22:04:14 +02:00
|
|
|
auto paid = lua_get<uint8_t, 1>(L, 1);
|
2017-09-14 21:35:59 +02:00
|
|
|
pduel->game_field->core.attack_cost_paid = paid;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ForceAttack) {
|
2018-12-16 16:02:16 +01:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto attacker = lua_get<card*, true>(L, 1);
|
|
|
|
|
auto attack_target = lua_get<card*, true>(L, 2);
|
2018-12-16 16:02:16 +01:00
|
|
|
pduel->game_field->core.set_forced_attack = true;
|
|
|
|
|
pduel->game_field->core.forced_attacker = attacker;
|
|
|
|
|
pduel->game_field->core.forced_attack_target = attack_target;
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2018-12-16 16:02:16 +01:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CalculateDamage) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto attacker = lua_get<card*, true>(L, 1);
|
2020-10-30 17:05:28 +01:00
|
|
|
auto attack_target = lua_get<card*>(L, 2);
|
2020-07-23 23:50:09 +02:00
|
|
|
auto new_attack = lua_get<bool, false>(L, 3);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(attacker == attack_target)
|
|
|
|
|
return 0;
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::DamageStep>(attacker, attack_target, new_attack);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetBattleDamage) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->core.battle_damage[playerid]);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ChangeBattleDamage) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto dam = lua_get<uint32_t>(L, 2);
|
2020-07-23 23:50:09 +02:00
|
|
|
bool check = lua_get<bool, true>(L, 3);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(check && pduel->game_field->core.battle_damage[playerid] == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
pduel->game_field->core.battle_damage[playerid] = dam;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ChangeTargetCard) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto count = lua_get<uint8_t>(L, 1);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pgroup = lua_get<group*, true>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->change_target(count, pgroup);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ChangeTargetPlayer) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto count = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->change_target_player(count, playerid);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ChangeTargetParam) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto count = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto param = lua_get<int32_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->change_target_param(count, param);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(BreakEffect) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
pduel->game_field->break_effect();
|
2024-03-08 11:12:46 +01:00
|
|
|
pduel->game_field->raise_event(nullptr, EVENT_BREAK_EFFECT, nullptr, 0, PLAYER_NONE, PLAYER_NONE, 0);
|
2020-08-24 08:27:44 +08:00
|
|
|
pduel->game_field->process_instant_event();
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ChangeChainOperation) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2022-06-11 12:59:38 +02:00
|
|
|
auto f = interpreter::get_function_handle(L, lua_get<function, true>(L, 2));
|
|
|
|
|
pduel->game_field->change_chain_effect(lua_get<uint8_t>(L, 1), f);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(NegateActivation) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
lua_pushboolean(L, pduel->game_field->negate_chain(lua_get<uint8_t>(L, 1)));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(NegateEffect) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
lua_pushboolean(L, pduel->game_field->disable_chain(lua_get<uint8_t>(L, 1)));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(NegateRelatedChain) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto reset_flag = lua_get<uint32_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(pduel->game_field->core.current_chain.size() < 2)
|
2017-01-05 16:38:51 +08:00
|
|
|
return 0;
|
2015-09-25 21:07:16 +08:00
|
|
|
if(!pcard->is_affect_by_effect(pduel->game_field->core.reason_effect))
|
|
|
|
|
return 0;
|
2016-07-21 22:42:10 +08:00
|
|
|
for(auto it = pduel->game_field->core.current_chain.rbegin(); it != pduel->game_field->core.current_chain.rend(); ++it) {
|
2016-11-16 19:52:12 +09:00
|
|
|
if(it->triggering_effect->get_handler() == pcard && pcard->is_has_relation(*it)) {
|
2016-07-21 22:42:10 +08:00
|
|
|
effect* negeff = pduel->new_effect();
|
2016-11-16 19:52:12 +09:00
|
|
|
negeff->owner = pduel->game_field->core.reason_effect->get_handler();
|
2016-07-21 22:42:10 +08:00
|
|
|
negeff->type = EFFECT_TYPE_SINGLE;
|
|
|
|
|
negeff->code = EFFECT_DISABLE_CHAIN;
|
|
|
|
|
negeff->value = it->chain_id;
|
|
|
|
|
negeff->reset_flag = RESET_CHAIN | RESET_EVENT | reset_flag;
|
|
|
|
|
pcard->add_effect(negeff);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(NegateSummon) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t sumplayer = PLAYER_NONE;
|
2023-12-03 11:34:38 +01:00
|
|
|
auto [pcard, pgroup] = lua_get_card_or_group(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(pcard) {
|
2022-10-30 11:08:18 +01:00
|
|
|
sumplayer = pcard->summon.player;
|
2015-09-25 21:07:16 +08:00
|
|
|
pcard->set_status(STATUS_SUMMONING, FALSE);
|
|
|
|
|
pcard->set_status(STATUS_SUMMON_DISABLED, TRUE);
|
2022-10-30 11:08:18 +01:00
|
|
|
if((pcard->summon.type & SUMMON_TYPE_PENDULUM) != SUMMON_TYPE_PENDULUM)
|
2015-09-25 21:07:16 +08:00
|
|
|
pcard->set_status(STATUS_PROC_COMPLETE, FALSE);
|
|
|
|
|
} else {
|
2020-09-16 17:12:50 +02:00
|
|
|
for(auto& _pcard : pgroup->container) {
|
2022-10-30 11:08:18 +01:00
|
|
|
sumplayer = _pcard->summon.player;
|
2020-09-16 17:12:50 +02:00
|
|
|
_pcard->set_status(STATUS_SUMMONING, FALSE);
|
|
|
|
|
_pcard->set_status(STATUS_SUMMON_DISABLED, TRUE);
|
2022-10-30 11:08:18 +01:00
|
|
|
if((_pcard->summon.type & SUMMON_TYPE_PENDULUM) != SUMMON_TYPE_PENDULUM)
|
2020-09-16 17:12:50 +02:00
|
|
|
_pcard->set_status(STATUS_PROC_COMPLETE, FALSE);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t event_code = 0;
|
2018-09-15 20:20:25 +08:00
|
|
|
if(pduel->game_field->check_event(EVENT_SUMMON))
|
|
|
|
|
event_code = EVENT_SUMMON_NEGATED;
|
|
|
|
|
else if(pduel->game_field->check_event(EVENT_FLIP_SUMMON))
|
|
|
|
|
event_code = EVENT_FLIP_SUMMON_NEGATED;
|
|
|
|
|
else if(pduel->game_field->check_event(EVENT_SPSUMMON))
|
|
|
|
|
event_code = EVENT_SPSUMMON_NEGATED;
|
|
|
|
|
effect* reason_effect = pduel->game_field->core.reason_effect;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t reason_player = pduel->game_field->core.reason_player;
|
2018-09-15 20:20:25 +08:00
|
|
|
if(pcard)
|
|
|
|
|
pduel->game_field->raise_event(pcard, event_code, reason_effect, REASON_EFFECT, reason_player, sumplayer, 0);
|
|
|
|
|
else
|
2024-03-08 11:03:06 +01:00
|
|
|
pduel->game_field->raise_event(pgroup->container, event_code, reason_effect, REASON_EFFECT, reason_player, sumplayer, 0);
|
2018-09-15 20:20:25 +08:00
|
|
|
pduel->game_field->process_instant_event();
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IncreaseSummonedCount) {
|
2024-01-13 16:10:22 +01:00
|
|
|
card* pcard = nullptr;
|
|
|
|
|
effect* pextra = nullptr;
|
2020-07-21 01:21:25 +02:00
|
|
|
if(lua_gettop(L) > 0)
|
|
|
|
|
pcard = lua_get<card*, true>(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t playerid = pduel->game_field->core.reason_player;
|
2020-09-16 17:12:50 +02:00
|
|
|
if(pcard && (pextra = pcard->is_affected_by_effect(EFFECT_EXTRA_SUMMON_COUNT)) != nullptr)
|
2015-09-25 21:07:16 +08:00
|
|
|
pextra->get_value(pcard);
|
|
|
|
|
else
|
2022-03-05 13:56:43 +01:00
|
|
|
++pduel->game_field->core.summon_count[playerid];
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CheckSummonedCount) {
|
2024-01-13 16:10:22 +01:00
|
|
|
card* pcard = nullptr;
|
2020-07-21 01:21:25 +02:00
|
|
|
if(lua_gettop(L) > 0)
|
|
|
|
|
pcard = lua_get<card*, true>(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t playerid = pduel->game_field->core.reason_player;
|
2015-09-25 21:07:16 +08:00
|
|
|
if((pcard && pcard->is_affected_by_effect(EFFECT_EXTRA_SUMMON_COUNT))
|
|
|
|
|
|| pduel->game_field->core.summon_count[playerid] < pduel->game_field->get_summon_count_limit(playerid))
|
|
|
|
|
lua_pushboolean(L, 1);
|
|
|
|
|
else
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetLocationCount) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto location = lua_get<uint8_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto uplayer = lua_get<uint8_t>(L, 3, pduel->game_field->core.reason_player);
|
|
|
|
|
auto reason = lua_get<uint32_t, LOCATION_REASON_TOFIELD>(L, 4);
|
|
|
|
|
auto zone = lua_get<uint32_t, 0xff>(L, 5);
|
|
|
|
|
uint32_t list = 0;
|
2021-12-13 14:07:51 +01:00
|
|
|
lua_pushinteger(L, pduel->game_field->get_useable_count(nullptr, playerid, location, uplayer, reason, zone, &list));
|
2018-07-05 17:20:22 +08:00
|
|
|
lua_pushinteger(L, list);
|
2018-05-01 08:49:03 +08:00
|
|
|
return 2;
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetMZoneCount) {
|
2017-10-21 16:28:35 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2017-10-21 16:28:35 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
bool swapped = false;
|
2022-10-18 00:32:27 +02:00
|
|
|
const uint32_t default_loc = 0x1111 * pduel->game_field->is_flag(DUEL_3_COLUMNS_FIELD);
|
|
|
|
|
uint32_t used_location[2] = { default_loc, default_loc };
|
2021-09-04 20:46:43 +02:00
|
|
|
card_vector list_mzone[2];
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [mcard, mgroup] = lua_get_card_or_group<true>(L, 2); mcard || mgroup) {
|
2023-11-26 15:11:50 +01:00
|
|
|
for(size_t p = 0; p < 2; ++p) {
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t digit = 1;
|
2018-09-03 16:36:45 +08:00
|
|
|
for(auto& pcard : pduel->game_field->player[p].list_mzone) {
|
2020-10-30 17:05:28 +01:00
|
|
|
if(pcard && pcard != mcard && !(mgroup && mgroup->has_card(pcard))) {
|
2017-10-21 16:28:35 +08:00
|
|
|
used_location[p] |= digit;
|
|
|
|
|
list_mzone[p].push_back(pcard);
|
|
|
|
|
} else
|
2024-01-13 16:10:22 +01:00
|
|
|
list_mzone[p].push_back(nullptr);
|
2017-10-21 16:28:35 +08:00
|
|
|
digit <<= 1;
|
|
|
|
|
}
|
|
|
|
|
used_location[p] |= pduel->game_field->player[p].used_location & 0xff00;
|
|
|
|
|
std::swap(used_location[p], pduel->game_field->player[p].used_location);
|
|
|
|
|
pduel->game_field->player[p].list_mzone.swap(list_mzone[p]);
|
|
|
|
|
}
|
|
|
|
|
swapped = true;
|
|
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
auto uplayer = lua_get<uint8_t>(L, 3, pduel->game_field->core.reason_player);
|
|
|
|
|
auto reason = lua_get<uint32_t, LOCATION_REASON_TOFIELD>(L, 4);
|
|
|
|
|
auto zone = lua_get<uint32_t, 0xff>(L, 5);
|
|
|
|
|
uint32_t list = 0;
|
2021-12-13 14:07:51 +01:00
|
|
|
lua_pushinteger(L, pduel->game_field->get_useable_count(nullptr, playerid, LOCATION_MZONE, uplayer, reason, zone, &list));
|
2018-05-01 08:49:03 +08:00
|
|
|
lua_pushinteger(L, list);
|
2017-10-21 16:28:35 +08:00
|
|
|
if(swapped) {
|
|
|
|
|
pduel->game_field->player[0].used_location = used_location[0];
|
|
|
|
|
pduel->game_field->player[1].used_location = used_location[1];
|
|
|
|
|
pduel->game_field->player[0].list_mzone.swap(list_mzone[0]);
|
|
|
|
|
pduel->game_field->player[1].list_mzone.swap(list_mzone[1]);
|
|
|
|
|
}
|
2018-05-01 08:49:03 +08:00
|
|
|
return 2;
|
2017-10-21 16:28:35 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetLocationCountFromEx) {
|
2017-04-14 14:02:15 +09:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2017-04-14 14:02:15 +09:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto uplayer = lua_get<uint8_t>(L, 2, pduel->game_field->core.reason_player);
|
2017-05-12 21:27:36 +09:00
|
|
|
bool swapped = false;
|
2022-10-18 00:32:27 +02:00
|
|
|
const uint32_t default_loc = 0x1111 * pduel->game_field->is_flag(DUEL_3_COLUMNS_FIELD);
|
|
|
|
|
uint32_t used_location[2] = { default_loc, default_loc };
|
2021-09-04 20:46:43 +02:00
|
|
|
card_vector list_mzone[2];
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [mcard, mgroup] = lua_get_card_or_group<true>(L, 3); mcard || mgroup) {
|
2023-11-26 15:11:50 +01:00
|
|
|
for(size_t p = 0; p < 2; ++p) {
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t digit = 1;
|
2018-09-03 16:36:45 +08:00
|
|
|
for(auto& pcard : pduel->game_field->player[p].list_mzone) {
|
2020-10-30 17:05:28 +01:00
|
|
|
if(pcard && pcard != mcard && !(mgroup && mgroup->has_card(pcard))) {
|
2017-05-23 16:19:37 +09:00
|
|
|
used_location[p] |= digit;
|
|
|
|
|
list_mzone[p].push_back(pcard);
|
|
|
|
|
} else
|
2024-01-13 16:10:22 +01:00
|
|
|
list_mzone[p].push_back(nullptr);
|
2017-05-23 16:19:37 +09:00
|
|
|
digit <<= 1;
|
|
|
|
|
}
|
|
|
|
|
used_location[p] |= pduel->game_field->player[p].used_location & 0xff00;
|
|
|
|
|
std::swap(used_location[p], pduel->game_field->player[p].used_location);
|
|
|
|
|
pduel->game_field->player[p].list_mzone.swap(list_mzone[p]);
|
2017-04-19 22:06:14 +09:00
|
|
|
}
|
2017-05-12 21:27:36 +09:00
|
|
|
swapped = true;
|
2017-04-19 22:06:14 +09:00
|
|
|
}
|
2020-01-04 15:54:38 +08:00
|
|
|
bool use_temp_card = false;
|
2024-01-13 16:10:22 +01:00
|
|
|
card* scard = nullptr;
|
2020-12-26 00:31:31 +01:00
|
|
|
if(!lua_isnoneornil(L, 4)) {
|
2020-09-16 17:12:50 +02:00
|
|
|
if((scard = lua_get<card*>(L, 4)) == nullptr) {
|
2020-01-04 15:54:38 +08:00
|
|
|
use_temp_card = true;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto type = lua_get<uint32_t>(L, 4);
|
2020-01-04 15:54:38 +08:00
|
|
|
scard = pduel->game_field->temp_card;
|
|
|
|
|
scard->current.location = LOCATION_EXTRA;
|
|
|
|
|
scard->data.type = TYPE_MONSTER | type;
|
|
|
|
|
if(type & TYPE_PENDULUM)
|
|
|
|
|
scard->current.position = POS_FACEUP_DEFENSE;
|
|
|
|
|
else
|
|
|
|
|
scard->current.position = POS_FACEDOWN_DEFENSE;
|
|
|
|
|
}
|
2017-04-20 00:10:40 +09:00
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
auto zone = lua_get<uint32_t, 0xff>(L, 5);
|
|
|
|
|
uint32_t list = 0;
|
2018-05-01 08:49:03 +08:00
|
|
|
lua_pushinteger(L, pduel->game_field->get_useable_count_fromex(scard, playerid, uplayer, zone, &list));
|
|
|
|
|
lua_pushinteger(L, list);
|
2017-05-12 21:27:36 +09:00
|
|
|
if(swapped) {
|
2017-05-23 16:19:37 +09:00
|
|
|
pduel->game_field->player[0].used_location = used_location[0];
|
|
|
|
|
pduel->game_field->player[1].used_location = used_location[1];
|
|
|
|
|
pduel->game_field->player[0].list_mzone.swap(list_mzone[0]);
|
|
|
|
|
pduel->game_field->player[1].list_mzone.swap(list_mzone[1]);
|
2017-04-19 22:06:14 +09:00
|
|
|
}
|
2020-01-04 15:54:38 +08:00
|
|
|
if(use_temp_card) {
|
|
|
|
|
scard->current.location = 0;
|
|
|
|
|
scard->data.type = 0;
|
|
|
|
|
scard->current.position = 0;
|
|
|
|
|
}
|
2018-05-01 08:49:03 +08:00
|
|
|
return 2;
|
2017-04-14 15:38:48 +09:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetUsableMZoneCount) {
|
2017-04-14 16:12:03 +09:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2017-04-14 15:38:48 +09:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto uplayer = lua_get<uint8_t>(L, 2, pduel->game_field->core.reason_player);
|
|
|
|
|
uint32_t zone = 0xff;
|
|
|
|
|
uint32_t flag1, flag2;
|
2021-12-13 14:07:51 +01:00
|
|
|
int32_t ct1 = pduel->game_field->get_tofield_count(nullptr, playerid, LOCATION_MZONE, uplayer, LOCATION_REASON_TOFIELD, zone, &flag1);
|
|
|
|
|
int32_t ct2 = pduel->game_field->get_spsummonable_count_fromex(nullptr, playerid, uplayer, zone, &flag2);
|
2021-09-04 22:04:14 +02:00
|
|
|
int32_t ct3 = field::field_used_count[~(flag1 | flag2) & 0x1f];
|
|
|
|
|
int32_t count = ct1 + ct2 - ct3;
|
|
|
|
|
int32_t limit = pduel->game_field->get_mzone_limit(playerid, uplayer, LOCATION_REASON_TOFIELD);
|
2018-03-14 22:21:06 +09:00
|
|
|
if(count > limit)
|
|
|
|
|
count = limit;
|
|
|
|
|
lua_pushinteger(L, count);
|
2017-04-14 15:38:48 +09:00
|
|
|
return 1;
|
2017-04-14 14:02:15 +09:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetLinkedGroup) {
|
2017-06-13 22:45:14 +09:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto rplayer = lua_get<uint8_t>(L, 1);
|
2017-06-13 22:45:14 +09:00
|
|
|
if(rplayer != 0 && rplayer != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto location1 = lua_get<uint16_t>(L, 2);
|
2018-10-13 00:50:37 +02:00
|
|
|
if(location1 == 1)
|
|
|
|
|
location1 = LOCATION_MZONE;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto location2 = lua_get<uint16_t>(L, 3);
|
2018-10-13 00:50:37 +02:00
|
|
|
if(location2 == 1)
|
|
|
|
|
location2 = LOCATION_MZONE;
|
2021-09-04 20:46:43 +02:00
|
|
|
card_set cset;
|
2018-10-13 00:50:37 +02:00
|
|
|
pduel->game_field->get_linked_cards(rplayer, location1, location2, &cset);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group(std::move(cset));
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2017-06-13 22:45:14 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetLinkedGroupCount) {
|
2017-06-13 22:45:14 +09:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto rplayer = lua_get<uint8_t>(L, 1);
|
2017-06-13 22:45:14 +09:00
|
|
|
if(rplayer != 0 && rplayer != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto location1 = lua_get<uint16_t>(L, 2);
|
2018-10-13 00:50:37 +02:00
|
|
|
if(location1 == 1)
|
|
|
|
|
location1 = LOCATION_MZONE;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto location2 = lua_get<uint16_t>(L, 3);
|
2018-10-13 00:50:37 +02:00
|
|
|
if(location2 == 1)
|
|
|
|
|
location2 = LOCATION_MZONE;
|
2021-09-04 20:46:43 +02:00
|
|
|
card_set cset;
|
2018-10-13 00:50:37 +02:00
|
|
|
pduel->game_field->get_linked_cards(rplayer, location1, location2, &cset);
|
2017-06-13 22:45:14 +09:00
|
|
|
lua_pushinteger(L, cset.size());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetLinkedZone) {
|
2017-04-14 14:29:13 +09:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2017-04-14 14:29:13 +09:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->get_linked_zone(playerid));
|
|
|
|
|
return 1;
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetFreeLinkedZone) {
|
2019-10-17 17:34:08 +02:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2019-10-17 17:34:08 +02:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->get_linked_zone(playerid, true));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetFieldCard) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto location = lua_get<uint16_t>(L, 2);
|
|
|
|
|
auto sequence = lua_get<uint32_t>(L, 3);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
card* pcard = pduel->game_field->get_field_card(playerid, location, sequence);
|
2017-01-02 18:08:00 +08:00
|
|
|
if(!pcard || pcard->get_status(STATUS_SUMMONING | STATUS_SPSUMMON_STEP))
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pcard);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CheckLocation) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto location = lua_get<uint16_t>(L, 2);
|
|
|
|
|
auto sequence = lua_get<uint32_t>(L, 3);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2017-10-21 16:28:35 +08:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_location_useable(playerid, location, sequence));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetCurrentChain) {
|
2021-02-02 18:09:11 +01:00
|
|
|
const auto real = lua_get<bool, false>(L, 1);
|
|
|
|
|
const auto& core = pduel->game_field->core;
|
|
|
|
|
lua_pushinteger(L, real ? core.real_chain_count : core.current_chain.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetChainInfo) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
chain* ch = pduel->game_field->get_chain(lua_get<uint8_t>(L, 1));
|
2017-08-06 17:12:07 +09:00
|
|
|
if(!ch)
|
|
|
|
|
return 0;
|
2022-10-26 18:13:11 +02:00
|
|
|
auto top = lua_gettop(L);
|
2025-02-24 20:51:49 +01:00
|
|
|
auto args = static_cast<int32_t>(lua_istable(L, 2) ? lua_rawlen(L, 2) : top - 1);
|
2022-10-06 13:11:11 +02:00
|
|
|
luaL_checkstack(L, args, nullptr);
|
2022-10-28 20:03:11 +02:00
|
|
|
lua_iterate_table_or_stack(L, 2, top, [L, ch, pduel]() -> int {
|
2023-12-08 10:45:08 +01:00
|
|
|
auto flag = lua_get<CHAININFO>(L, -1);
|
2015-09-25 21:07:16 +08:00
|
|
|
switch(flag) {
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_EFFECT:
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, ch->triggering_effect);
|
2015-09-25 21:07:16 +08:00
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_PLAYER:
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, ch->triggering_player);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_CONTROLER:
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, ch->triggering_controler);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_LOCATION:
|
2022-10-28 20:03:11 +02:00
|
|
|
lua_pushinteger(L, ch->triggering_location & ~(LOCATION_STZONE | LOCATION_MMZONE | LOCATION_EMZONE));
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_LOCATION_SYMBOLIC:
|
2022-10-28 20:03:11 +02:00
|
|
|
lua_pushinteger(L, ch->triggering_location & ~(LOCATION_MZONE | LOCATION_SZONE));
|
2015-09-25 21:07:16 +08:00
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_SEQUENCE:
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, ch->triggering_sequence);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_SEQUENCE_SYMBOLIC:
|
2022-10-30 11:00:48 +01:00
|
|
|
if(pduel->game_field->is_flag(DUEL_3_COLUMNS_FIELD) && (ch->triggering_location & ~(LOCATION_STZONE | LOCATION_MMZONE)))
|
2022-10-28 20:03:11 +02:00
|
|
|
lua_pushinteger(L, ch->triggering_sequence + 1);
|
|
|
|
|
else if(ch->triggering_location & LOCATION_PZONE) {
|
|
|
|
|
if(ch->triggering_sequence == pduel->game_field->get_pzone_index(0, ch->triggering_controler))
|
|
|
|
|
lua_pushinteger(L, 0);
|
|
|
|
|
else
|
|
|
|
|
lua_pushinteger(L, 1);
|
2023-12-09 11:04:56 -03:00
|
|
|
} else if(ch->triggering_location & LOCATION_FZONE) {
|
2022-10-28 20:03:11 +02:00
|
|
|
lua_pushinteger(L, 0);
|
2023-12-09 11:04:56 -03:00
|
|
|
} else if(ch->triggering_location & LOCATION_EMZONE) {
|
2022-10-28 20:03:11 +02:00
|
|
|
lua_pushinteger(L, ch->triggering_sequence - 5);
|
|
|
|
|
} else
|
|
|
|
|
lua_pushinteger(L, ch->triggering_sequence);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_POSITION:
|
2017-08-12 11:06:14 +09:00
|
|
|
lua_pushinteger(L, ch->triggering_position);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_CODE:
|
2019-03-14 22:15:36 +08:00
|
|
|
lua_pushinteger(L, ch->triggering_state.code);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_CODE2:
|
2019-03-14 22:15:36 +08:00
|
|
|
lua_pushinteger(L, ch->triggering_state.code2);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_TYPE:
|
2023-12-08 10:04:31 +01:00
|
|
|
lua_pushinteger(L, ch->triggering_state.type);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_LEVEL:
|
2019-03-14 22:15:36 +08:00
|
|
|
lua_pushinteger(L, ch->triggering_state.level);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_RANK:
|
2019-03-14 22:15:36 +08:00
|
|
|
lua_pushinteger(L, ch->triggering_state.rank);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_ATTRIBUTE:
|
2019-03-14 22:15:36 +08:00
|
|
|
lua_pushinteger(L, ch->triggering_state.attribute);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_RACE:
|
2019-03-14 22:15:36 +08:00
|
|
|
lua_pushinteger(L, ch->triggering_state.race);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_ATTACK:
|
2019-03-14 22:15:36 +08:00
|
|
|
lua_pushinteger(L, ch->triggering_state.attack);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TRIGGERING_DEFENSE:
|
2019-03-14 22:15:36 +08:00
|
|
|
lua_pushinteger(L, ch->triggering_state.defense);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TARGET_CARDS:
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, ch->target_cards);
|
2015-09-25 21:07:16 +08:00
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TARGET_PLAYER:
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, ch->target_player);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TARGET_PARAM:
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, ch->target_param);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::DISABLE_REASON:
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, ch->disable_reason);
|
2015-09-25 21:07:16 +08:00
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::DISABLE_PLAYER:
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, ch->disable_player);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::CHAIN_ID:
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, ch->chain_id);
|
|
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::TYPE:
|
2020-01-02 13:45:19 +08:00
|
|
|
if((ch->triggering_effect->card_type & (TYPE_MONSTER | TYPE_SPELL | TYPE_TRAP)) == (TYPE_TRAP | TYPE_MONSTER))
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, TYPE_MONSTER);
|
2020-01-02 13:45:19 +08:00
|
|
|
else lua_pushinteger(L, (ch->triggering_effect->card_type & (TYPE_MONSTER | TYPE_SPELL | TYPE_TRAP)));
|
2015-09-25 21:07:16 +08:00
|
|
|
break;
|
2023-12-08 10:45:08 +01:00
|
|
|
case CHAININFO::EXTTYPE:
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, ch->triggering_effect->card_type);
|
|
|
|
|
break;
|
2023-12-09 11:04:56 -03:00
|
|
|
case CHAININFO::TRIGGERING_STATUS:
|
|
|
|
|
lua_pushinteger(L, ch->triggering_status);
|
|
|
|
|
break;
|
|
|
|
|
case CHAININFO::TRIGGERING_SUMMON_LOCATION:
|
|
|
|
|
lua_pushinteger(L, ch->triggering_summon_location);
|
|
|
|
|
break;
|
|
|
|
|
case CHAININFO::TRIGGERING_SUMMON_TYPE:
|
|
|
|
|
lua_pushinteger(L, ch->triggering_summon_type);
|
|
|
|
|
break;
|
|
|
|
|
case CHAININFO::TRIGGERING_SUMMON_PROC_COMPLETE:
|
|
|
|
|
lua_pushboolean(L, ch->triggering_summon_proc_complete);
|
|
|
|
|
break;
|
|
|
|
|
case CHAININFO::TRIGGERING_SETCODES: {
|
|
|
|
|
const auto& setcodes = ch->triggering_state.setcodes;
|
2024-04-15 22:39:25 +02:00
|
|
|
lua_createtable(L, static_cast<int>(setcodes.size()), 0);
|
2023-12-09 11:04:56 -03:00
|
|
|
int i = 1;
|
|
|
|
|
for(const auto& setcode : setcodes) {
|
|
|
|
|
lua_pushinteger(L, i++);
|
|
|
|
|
lua_pushinteger(L, setcode);
|
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
default:
|
2022-10-06 13:11:11 +02:00
|
|
|
lua_error(L, "Passed invalid CHAININFO flag.");
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2022-10-26 18:13:11 +02:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
return args;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetChainEvent) {
|
2017-10-28 11:10:54 +09:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto count = lua_get<uint8_t>(L, 1);
|
2017-10-28 11:10:54 +09:00
|
|
|
chain* ch = pduel->game_field->get_chain(count);
|
|
|
|
|
if(!ch)
|
|
|
|
|
return 0;
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, ch->evt.event_cards);
|
2017-10-28 11:10:54 +09:00
|
|
|
lua_pushinteger(L, ch->evt.event_player);
|
|
|
|
|
lua_pushinteger(L, ch->evt.event_value);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, ch->evt.reason_effect);
|
2017-10-28 11:10:54 +09:00
|
|
|
lua_pushinteger(L, ch->evt.reason);
|
|
|
|
|
lua_pushinteger(L, ch->evt.reason_player);
|
|
|
|
|
return 6;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetFirstTarget) {
|
2017-07-01 23:51:49 +09:00
|
|
|
chain* ch = pduel->game_field->get_chain(0);
|
|
|
|
|
if(!ch || !ch->target_cards || ch->target_cards->container.size() == 0)
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
2022-10-06 13:11:11 +02:00
|
|
|
const auto& cset = ch->target_cards->container;
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(cset.size()), nullptr);
|
2022-10-06 13:11:11 +02:00
|
|
|
for(auto& pcard : cset)
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pcard);
|
2023-02-07 16:43:27 +01:00
|
|
|
return static_cast<int32_t>(cset.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetCurrentPhase) {
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, pduel->game_field->infos.phase);
|
|
|
|
|
return 1;
|
2023-12-02 07:08:36 -03:00
|
|
|
}
|
|
|
|
|
LUA_STATIC_FUNCTION(IsMainPhase) {
|
|
|
|
|
const auto phase = pduel->game_field->infos.phase;
|
|
|
|
|
lua_pushboolean(L, (phase == PHASE_MAIN1 || phase == PHASE_MAIN2));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
LUA_STATIC_FUNCTION(IsBattlePhase) {
|
|
|
|
|
const auto phase = pduel->game_field->infos.phase;
|
|
|
|
|
lua_pushboolean(L, (phase >= PHASE_BATTLE_START) && (phase <= PHASE_BATTLE));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
LUA_STATIC_FUNCTION(IsPhase) {
|
|
|
|
|
check_param_count(L, 1);
|
|
|
|
|
const auto phase = lua_get<uint16_t>(L, 1);
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->infos.phase == phase);
|
|
|
|
|
return 1;
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SkipPhase) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 4);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto phase = lua_get<uint16_t>(L, 2);
|
|
|
|
|
auto reset = lua_get<uint32_t>(L, 3);
|
|
|
|
|
auto count = lua_get<uint16_t>(L, 4);
|
|
|
|
|
auto value = lua_get<uint32_t, 0>(L, 5);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(count <= 0)
|
|
|
|
|
count = 1;
|
2021-09-04 22:04:14 +02:00
|
|
|
int32_t code = 0;
|
2015-09-25 21:07:16 +08:00
|
|
|
if(phase == PHASE_DRAW)
|
|
|
|
|
code = EFFECT_SKIP_DP;
|
|
|
|
|
else if(phase == PHASE_STANDBY)
|
|
|
|
|
code = EFFECT_SKIP_SP;
|
|
|
|
|
else if(phase == PHASE_MAIN1)
|
|
|
|
|
code = EFFECT_SKIP_M1;
|
|
|
|
|
else if(phase == PHASE_BATTLE)
|
|
|
|
|
code = EFFECT_SKIP_BP;
|
|
|
|
|
else if(phase == PHASE_MAIN2)
|
|
|
|
|
code = EFFECT_SKIP_M2;
|
2019-04-25 13:35:03 +02:00
|
|
|
else if(phase == PHASE_END)
|
|
|
|
|
code = EFFECT_SKIP_EP;
|
2015-09-25 21:07:16 +08:00
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
effect* peffect = pduel->new_effect();
|
|
|
|
|
peffect->owner = pduel->game_field->temp_card;
|
|
|
|
|
peffect->effect_owner = playerid;
|
|
|
|
|
peffect->type = EFFECT_TYPE_FIELD;
|
|
|
|
|
peffect->code = code;
|
2015-12-21 21:58:27 +08:00
|
|
|
peffect->reset_flag = (reset & 0x3ff) | RESET_PHASE | RESET_SELF_TURN;
|
2015-10-31 15:50:37 +09:00
|
|
|
peffect->flag[0] = EFFECT_FLAG_CANNOT_DISABLE | EFFECT_FLAG_PLAYER_TARGET;
|
2015-09-25 21:07:16 +08:00
|
|
|
peffect->s_range = 1;
|
|
|
|
|
peffect->o_range = 0;
|
2017-08-14 08:02:43 +09:00
|
|
|
peffect->reset_count = count;
|
2015-09-25 21:07:16 +08:00
|
|
|
peffect->value = value;
|
|
|
|
|
pduel->game_field->add_effect(peffect, playerid);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsAttackCostPaid) {
|
2017-09-14 21:35:59 +02:00
|
|
|
lua_pushinteger(L, pduel->game_field->core.attack_cost_paid);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsDamageCalculated) {
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, pduel->game_field->core.damage_calculated);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetAttacker) {
|
2015-09-25 21:07:16 +08:00
|
|
|
card* pcard = pduel->game_field->core.attacker;
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pcard);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetAttackTarget) {
|
2015-09-25 21:07:16 +08:00
|
|
|
card* pcard = pduel->game_field->core.attack_target;
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pcard);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetBattleMonster) {
|
2020-03-19 11:10:24 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2020-03-19 11:10:24 +08:00
|
|
|
card* attacker = pduel->game_field->core.attacker;
|
|
|
|
|
card* defender = pduel->game_field->core.attack_target;
|
2022-03-05 13:56:43 +01:00
|
|
|
for(int32_t i = 0; i < 2; ++i) {
|
2020-03-19 11:10:24 +08:00
|
|
|
if(attacker && attacker->current.controler == playerid)
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, attacker);
|
2020-03-19 11:10:24 +08:00
|
|
|
else if(defender && defender->current.controler == playerid)
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, defender);
|
2020-03-19 11:10:24 +08:00
|
|
|
else
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
playerid = 1 - playerid;
|
|
|
|
|
}
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(NegateAttack) {
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::AttackDisable>();
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ChainAttack) {
|
2024-05-30 12:20:55 +02:00
|
|
|
auto* attacker = pduel->game_field->core.attacker;
|
2024-07-11 20:09:44 +02:00
|
|
|
if(!attacker || !attacker->is_affect_by_effect(pduel->game_field->core.reason_effect))
|
2024-05-30 12:20:55 +02:00
|
|
|
return 0;
|
|
|
|
|
pduel->game_field->core.chain_attack = true;
|
|
|
|
|
pduel->game_field->core.chain_attacker_id = attacker->fieldid;
|
2020-07-21 01:21:25 +02:00
|
|
|
if(lua_gettop(L) > 0)
|
|
|
|
|
pduel->game_field->core.chain_attack_target = lua_get<card*, true>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(Readjust) {
|
2016-11-16 19:52:12 +09:00
|
|
|
card* adjcard = pduel->game_field->core.reason_effect->get_handler();
|
2022-03-05 13:56:43 +01:00
|
|
|
auto& readj_map = pduel->game_field->core.readjust_map[adjcard];
|
|
|
|
|
++readj_map;
|
|
|
|
|
if(readj_map > 3) {
|
2024-01-13 16:10:22 +01:00
|
|
|
pduel->game_field->send_to(adjcard, nullptr, REASON_RULE, pduel->game_field->core.reason_player, PLAYER_NONE, LOCATION_GRAVE, 0, POS_FACEUP);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2024-01-03 13:34:39 +01:00
|
|
|
pduel->game_field->core.re_adjust = true;
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(AdjustInstantly) {
|
2015-09-25 21:07:16 +08:00
|
|
|
if(lua_gettop(L) > 0) {
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
pcard->filter_disable_related_cards();
|
|
|
|
|
}
|
|
|
|
|
pduel->game_field->adjust_instant();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* \brief Duel.GetFieldGroup
|
|
|
|
|
* \param playerid, location1, location2
|
|
|
|
|
* \return Group
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetFieldGroup) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto location1 = lua_get<uint16_t>(L, 2);
|
|
|
|
|
auto location2 = lua_get<uint16_t>(L, 3);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group();
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->filter_field_card(playerid, location1, location2, pgroup);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* \brief Duel.GetFieldGroupCount
|
|
|
|
|
* \param playerid, location1, location2
|
|
|
|
|
* \return Integer
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetFieldGroupCount) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto location1 = lua_get<uint16_t>(L, 2);
|
|
|
|
|
auto location2 = lua_get<uint16_t>(L, 3);
|
2024-01-13 16:10:22 +01:00
|
|
|
uint32_t count = pduel->game_field->filter_field_card(playerid, location1, location2, nullptr);
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, count);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* \brief Duel.GetDeckTop
|
|
|
|
|
* \param playerid, count
|
|
|
|
|
* \return Group
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetDecktopGroup) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2022-09-22 13:36:13 +02:00
|
|
|
auto& main = pduel->game_field->player[playerid].list_main;
|
2023-02-07 16:43:27 +01:00
|
|
|
const auto count = std::min<size_t>(lua_get<uint32_t>(L, 2), main.size());
|
2022-09-22 13:36:13 +02:00
|
|
|
const auto offset = main.size() - count;
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group(main.begin() + offset, main.end());
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetDeckbottomGroup) {
|
2022-09-22 13:36:22 +02:00
|
|
|
check_param_count(L, 2);
|
|
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto& main = pduel->game_field->player[playerid].list_main;
|
2023-02-07 16:43:27 +01:00
|
|
|
const auto count = std::min<size_t>(lua_get<uint32_t>(L, 2), main.size());
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group(main.begin(), main.begin() + count);
|
2022-09-22 13:36:22 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2017-11-17 18:44:31 +01:00
|
|
|
/**
|
|
|
|
|
* \brief Duel.GetExtraTopGroup
|
|
|
|
|
* \param playerid, count
|
|
|
|
|
* \return Group
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetExtraTopGroup) {
|
2017-11-17 18:44:31 +01:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto count = lua_get<uint32_t>(L, 2);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group();
|
2017-11-17 18:44:31 +01:00
|
|
|
auto cit = pduel->game_field->player[playerid].list_extra.rbegin() + pduel->game_field->player[playerid].extra_p_count;
|
2021-09-04 22:04:14 +02:00
|
|
|
for(uint32_t i = 0; i < count && cit != pduel->game_field->player[playerid].list_extra.rend(); ++i, ++cit)
|
2017-11-17 18:44:31 +01:00
|
|
|
pgroup->container.insert(*cit);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2017-11-17 18:44:31 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
/**
|
|
|
|
|
* \brief Duel.GetMatchingGroup
|
|
|
|
|
* \param filter_func, self, location1, location2, exception card, (extraargs...)
|
|
|
|
|
* \return Group
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetMatchingGroup) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 5);
|
2022-06-11 12:59:38 +02:00
|
|
|
const auto findex = lua_get<function>(L, 1);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* pexception = nullptr;
|
|
|
|
|
group* pexgroup = nullptr;
|
2020-09-16 17:12:50 +02:00
|
|
|
if((pexception = lua_get<card*>(L, 5)) == nullptr)
|
2020-07-12 14:57:26 +02:00
|
|
|
pexgroup = lua_get<group*>(L, 5);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t extraargs = lua_gettop(L) - 5;
|
|
|
|
|
auto self = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto location1 = lua_get<uint16_t>(L, 3);
|
|
|
|
|
auto location2 = lua_get<uint16_t>(L, 4);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group();
|
2022-06-11 12:59:38 +02:00
|
|
|
pduel->game_field->filter_matching_card(findex, self, location1, location2, pgroup, pexception, pexgroup, extraargs);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* \brief Duel.GetMatchingGroupCount
|
|
|
|
|
* \param filter_func, self, location1, location2, exception card, (extraargs...)
|
|
|
|
|
* \return Integer
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetMatchingGroupCount) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 5);
|
2022-06-11 12:59:38 +02:00
|
|
|
const auto findex = lua_get<function>(L, 1);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* pexception = nullptr;
|
|
|
|
|
group* pexgroup = nullptr;
|
2020-09-16 17:12:50 +02:00
|
|
|
if((pexception = lua_get<card*>(L, 5)) == nullptr)
|
2020-07-12 14:57:26 +02:00
|
|
|
pexgroup = lua_get<group*>(L, 5);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t extraargs = lua_gettop(L) - 5;
|
|
|
|
|
auto self = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto location1 = lua_get<uint16_t>(L, 3);
|
|
|
|
|
auto location2 = lua_get<uint16_t>(L, 4);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group();
|
2022-06-11 12:59:38 +02:00
|
|
|
pduel->game_field->filter_matching_card(findex, self, location1, location2, pgroup, pexception, pexgroup, extraargs);
|
2023-02-07 16:43:27 +01:00
|
|
|
lua_pushinteger(L, pgroup->container.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* \brief Duel.GetFirstMatchingCard
|
|
|
|
|
* \param filter_func, self, location1, location2, exception card, (extraargs...)
|
|
|
|
|
* \return Card | nil
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetFirstMatchingCard) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 5);
|
2022-06-11 12:59:38 +02:00
|
|
|
const auto findex = lua_get<function>(L, 1);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* pexception = nullptr;
|
|
|
|
|
group* pexgroup = nullptr;
|
2020-09-16 17:12:50 +02:00
|
|
|
if((pexception = lua_get<card*>(L, 5)) == nullptr)
|
2020-07-12 14:57:26 +02:00
|
|
|
pexgroup = lua_get<group*>(L, 5);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t extraargs = lua_gettop(L) - 5;
|
|
|
|
|
auto self = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto location1 = lua_get<uint16_t>(L, 3);
|
|
|
|
|
auto location2 = lua_get<uint16_t>(L, 4);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* pret = nullptr;
|
|
|
|
|
pduel->game_field->filter_matching_card(findex, self, location1, location2, nullptr, pexception, pexgroup, extraargs, &pret);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(pret)
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pret);
|
2015-09-25 21:07:16 +08:00
|
|
|
else lua_pushnil(L);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* \brief Duel.IsExistingMatchingCard
|
|
|
|
|
* \param filter_func, self, location1, location2, count, exception card, (extraargs...)
|
|
|
|
|
* \return boolean
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsExistingMatchingCard) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 6);
|
2022-06-11 12:59:38 +02:00
|
|
|
const auto findex = lua_get<function>(L, 1);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* pexception = nullptr;
|
|
|
|
|
group* pexgroup = nullptr;
|
2020-09-16 17:12:50 +02:00
|
|
|
if((pexception = lua_get<card*>(L, 6)) == nullptr)
|
2020-07-12 14:57:26 +02:00
|
|
|
pexgroup = lua_get<group*>(L, 6);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t extraargs = lua_gettop(L) - 6;
|
|
|
|
|
auto self = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto location1 = lua_get<uint16_t>(L, 3);
|
|
|
|
|
auto location2 = lua_get<uint16_t>(L, 4);
|
|
|
|
|
auto fcount = lua_get<uint32_t>(L, 5);
|
2024-01-13 16:10:22 +01:00
|
|
|
lua_pushboolean(L, pduel->game_field->filter_matching_card(findex, self, location1, location2, nullptr, pexception, pexgroup, extraargs, nullptr, fcount));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* \brief Duel.SelectMatchingCards
|
|
|
|
|
* \param playerid, filter_func, self, location1, location2, min, max, exception card, (extraargs...)
|
|
|
|
|
* \return Group
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SelectMatchingCard) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 8);
|
2022-06-11 12:59:38 +02:00
|
|
|
const auto findex = lua_get<function>(L, 2);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* pexception = nullptr;
|
|
|
|
|
group* pexgroup = nullptr;
|
2020-09-07 23:24:10 +02:00
|
|
|
bool cancelable = false;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t lastarg = 8;
|
2020-07-24 00:16:34 +02:00
|
|
|
if(lua_isboolean(L, lastarg)) {
|
2020-07-23 23:50:09 +02:00
|
|
|
check_param_count(L, 9);
|
2020-09-07 23:24:10 +02:00
|
|
|
cancelable = lua_get<bool, false>(L, lastarg);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2020-03-14 18:40:09 +01:00
|
|
|
}
|
2020-09-16 17:12:50 +02:00
|
|
|
if((pexception = lua_get<card*>(L, lastarg)) == nullptr)
|
2020-07-12 14:57:26 +02:00
|
|
|
pexgroup = lua_get<group*>(L, lastarg);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t extraargs = lua_gettop(L) - lastarg;
|
|
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto self = lua_get<uint8_t>(L, 3);
|
|
|
|
|
auto location1 = lua_get<uint16_t>(L, 4);
|
|
|
|
|
auto location2 = lua_get<uint16_t>(L, 5);
|
|
|
|
|
auto min = lua_get<uint16_t>(L, 6);
|
|
|
|
|
auto max = lua_get<uint16_t>(L, 7);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group();
|
2022-06-11 12:59:38 +02:00
|
|
|
pduel->game_field->filter_matching_card(findex, self, location1, location2, pgroup, pexception, pexgroup, extraargs);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->core.select_cards.assign(pgroup->container.begin(), pgroup->container.end());
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SelectCard>(playerid, cancelable, min, max);
|
2023-11-25 11:15:21 +01:00
|
|
|
return push_return_cards(L, cancelable);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SelectCardsFromCodes) {
|
2020-08-21 22:24:48 +02:00
|
|
|
check_action_permission(L);
|
2020-09-02 15:03:13 +02:00
|
|
|
check_param_count(L, 6);
|
2021-12-07 22:13:34 +01:00
|
|
|
pduel->game_field->core.select_cards_codes.clear();
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2020-08-21 22:24:48 +02:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto min = lua_get<uint16_t>(L, 2);
|
|
|
|
|
auto max = lua_get<uint16_t>(L, 3);
|
2020-08-21 22:24:48 +02:00
|
|
|
bool cancelable = lua_get<bool>(L, 4);
|
2024-03-07 16:36:12 +01:00
|
|
|
check_param<LuaParam::BOOLEAN>(L, 5);
|
2022-10-26 18:13:11 +02:00
|
|
|
lua_iterate_table_or_stack(L, 6, lua_gettop(L), [L, &select_codes = pduel->game_field->core.select_cards_codes]{
|
2023-02-07 16:43:27 +01:00
|
|
|
select_codes.emplace_back(lua_get<uint32_t>(L, -1), static_cast<uint32_t>(select_codes.size() + 1));
|
2022-10-26 18:13:11 +02:00
|
|
|
});
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SelectCardCodes>(playerid, cancelable, min, max);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
2021-04-19 12:04:28 +02:00
|
|
|
int ret = 1;
|
2022-10-06 13:11:11 +02:00
|
|
|
const auto& ret_codes = pduel->game_field->return_card_codes;
|
|
|
|
|
if(!ret_codes.canceled) {
|
2020-09-02 15:03:13 +02:00
|
|
|
bool ret_index = lua_get<bool>(L, 5);
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(ret_codes.list.size() + (3 * ret_index) /* account for table creation */), nullptr);
|
2022-10-06 13:11:11 +02:00
|
|
|
for(const auto& obj : ret_codes.list) {
|
2020-09-02 15:03:13 +02:00
|
|
|
if(ret_index) {
|
2023-12-08 12:30:10 +01:00
|
|
|
lua_createtable(L, 2, 0);
|
2020-09-02 15:03:13 +02:00
|
|
|
lua_pushinteger(L, 1);
|
|
|
|
|
}
|
2021-12-07 22:13:34 +01:00
|
|
|
lua_pushinteger(L, obj.first);
|
2020-09-02 15:03:13 +02:00
|
|
|
if(ret_index) {
|
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
lua_pushinteger(L, 2);
|
2021-12-07 22:13:34 +01:00
|
|
|
lua_pushinteger(L, obj.second);
|
2020-09-02 15:03:13 +02:00
|
|
|
lua_settable(L, -3);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-06 13:11:11 +02:00
|
|
|
ret = (int)ret_codes.list.size();
|
2021-04-19 12:04:28 +02:00
|
|
|
} else
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
return ret;
|
2020-08-21 22:24:48 +02:00
|
|
|
});
|
|
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
/**
|
|
|
|
|
* \brief Duel.GetReleaseGroup
|
|
|
|
|
* \param playerid
|
|
|
|
|
* \return Group
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetReleaseGroup) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2020-07-23 23:50:09 +02:00
|
|
|
bool hand = lua_get<bool, false>(L, 2);
|
|
|
|
|
bool oppo = lua_get<bool, false>(L, 3);
|
2023-11-21 11:56:23 +01:00
|
|
|
const auto reason = lua_get<uint32_t, REASON_COST>(L, 4);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group();
|
2024-01-13 16:10:22 +01:00
|
|
|
pduel->game_field->get_release_list(playerid, &pgroup->container, &pgroup->container, &pgroup->container, hand, 0, 0, nullptr, nullptr, oppo, reason);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* \brief Duel.GetReleaseGroupCount
|
|
|
|
|
* \param playerid
|
|
|
|
|
* \return Integer
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetReleaseGroupCount) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2020-07-23 23:50:09 +02:00
|
|
|
bool hand = lua_get<bool, false>(L, 2);
|
|
|
|
|
bool oppo = lua_get<bool, false>(L, 3);
|
2023-11-12 13:04:20 -03:00
|
|
|
const auto reason = lua_get<uint32_t, REASON_COST>(L, 4);
|
2024-01-13 16:10:22 +01:00
|
|
|
lua_pushinteger(L, pduel->game_field->get_release_list(playerid, nullptr, nullptr, nullptr, hand, 0, 0, nullptr, nullptr, oppo, reason));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2021-09-26 00:21:15 +02:00
|
|
|
static int32_t check_release_group(lua_State* L, uint8_t use_hand) {
|
2021-10-13 17:29:29 +02:00
|
|
|
check_param_count(L, 4);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2022-06-11 12:59:38 +02:00
|
|
|
const auto findex = lua_get<function>(L, 2);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* pexception = nullptr;
|
|
|
|
|
group* pexgroup = nullptr;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t lastarg = 4;
|
2020-10-30 17:05:28 +01:00
|
|
|
const auto pduel = lua_get<duel*>(L);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto min = lua_get<uint16_t>(L, 3);
|
2020-07-21 00:08:06 +02:00
|
|
|
auto max = min;
|
2020-07-23 23:50:09 +02:00
|
|
|
bool check_field = false;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t zone = 0xff;
|
2020-03-20 19:50:16 +01:00
|
|
|
card* to_check = nullptr;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t toplayer = playerid;
|
2020-07-23 23:50:09 +02:00
|
|
|
bool use_oppo = false;
|
2020-07-24 00:16:34 +02:00
|
|
|
if(lua_isboolean(L, lastarg)) {
|
2020-07-12 14:57:26 +02:00
|
|
|
use_hand = lua_get<bool>(L, lastarg);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2021-09-04 22:04:14 +02:00
|
|
|
max = lua_get<uint16_t>(L, lastarg, min);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2020-07-23 23:50:09 +02:00
|
|
|
check_field = lua_get<bool, false>(L, lastarg);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2020-07-21 15:03:03 +02:00
|
|
|
to_check = lua_get<card*>(L, lastarg);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2021-09-04 22:04:14 +02:00
|
|
|
toplayer = lua_get<uint8_t>(L, lastarg, playerid);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2021-09-04 22:04:14 +02:00
|
|
|
zone = lua_get<uint32_t, 0xff>(L, lastarg);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2020-07-23 23:50:09 +02:00
|
|
|
use_oppo = lua_get<bool, false>(L, lastarg);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2020-03-14 18:40:09 +01:00
|
|
|
}
|
2020-09-16 17:12:50 +02:00
|
|
|
if((pexception = lua_get<card*>(L, lastarg)) == nullptr)
|
2020-07-12 14:57:26 +02:00
|
|
|
pexgroup = lua_get<group*>(L, lastarg);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t extraargs = lua_gettop(L) - lastarg;
|
2023-11-12 13:04:20 -03:00
|
|
|
int32_t result = pduel->game_field->check_release_list(playerid, min, max, use_hand, findex, extraargs, pexception, pexgroup, check_field, toplayer, zone, to_check, use_oppo, REASON_EFFECT);
|
2018-03-12 02:10:40 +09:00
|
|
|
pduel->game_field->core.must_select_cards.clear();
|
|
|
|
|
lua_pushboolean(L, result);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
2020-03-20 19:50:16 +01:00
|
|
|
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CheckReleaseGroup) {
|
2020-03-20 19:50:16 +01:00
|
|
|
return check_release_group(L, FALSE);
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CheckReleaseGroupEx) {
|
2020-03-20 19:50:16 +01:00
|
|
|
return check_release_group(L, TRUE);
|
|
|
|
|
}
|
2021-09-26 00:21:15 +02:00
|
|
|
static int32_t select_release_group(lua_State* L, uint8_t use_hand) {
|
2021-10-13 17:29:29 +02:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 5);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2022-06-11 12:59:38 +02:00
|
|
|
const auto findex = lua_get<function>(L, 2);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* pexception = nullptr;
|
|
|
|
|
group* pexgroup = nullptr;
|
2020-07-23 23:50:09 +02:00
|
|
|
bool cancelable = false;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t lastarg = 5;
|
2020-07-23 23:50:09 +02:00
|
|
|
bool check_field = false;
|
2020-03-20 19:50:16 +01:00
|
|
|
card* to_check = nullptr;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t toplayer = playerid;
|
|
|
|
|
uint8_t zone = 0xff;
|
2020-07-23 23:50:09 +02:00
|
|
|
bool use_oppo = false;
|
2020-07-24 00:16:34 +02:00
|
|
|
if(lua_isboolean(L, lastarg)) {
|
2020-07-12 14:57:26 +02:00
|
|
|
use_hand = lua_get<bool>(L, lastarg);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2020-07-23 23:50:09 +02:00
|
|
|
cancelable = lua_get<bool, false>(L, lastarg);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2020-07-23 23:50:09 +02:00
|
|
|
check_field = lua_get<bool, false>(L, lastarg);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2020-07-21 15:03:03 +02:00
|
|
|
to_check = lua_get<card*>(L, lastarg);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2021-09-04 22:04:14 +02:00
|
|
|
toplayer = lua_get<uint8_t>(L, lastarg, playerid);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2021-09-04 22:04:14 +02:00
|
|
|
zone = lua_get<uint32_t, 0xff>(L, lastarg);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2020-07-23 23:50:09 +02:00
|
|
|
use_oppo = lua_get<bool, false>(L, lastarg);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2020-03-14 18:40:09 +01:00
|
|
|
}
|
2020-09-16 17:12:50 +02:00
|
|
|
if((pexception = lua_get<card*>(L, lastarg)) == nullptr)
|
2020-07-12 14:57:26 +02:00
|
|
|
pexgroup = lua_get<group*>(L, lastarg);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t extraargs = lua_gettop(L) - lastarg;
|
2020-10-30 17:05:28 +01:00
|
|
|
const auto pduel = lua_get<duel*>(L);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto min = lua_get<uint16_t>(L, 3);
|
|
|
|
|
auto max = lua_get<uint16_t>(L, 4);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->core.release_cards.clear();
|
|
|
|
|
pduel->game_field->core.release_cards_ex.clear();
|
2018-03-11 17:51:46 +09:00
|
|
|
pduel->game_field->core.release_cards_ex_oneof.clear();
|
2023-11-12 13:04:20 -03:00
|
|
|
pduel->game_field->get_release_list(playerid, &pduel->game_field->core.release_cards, &pduel->game_field->core.release_cards_ex, &pduel->game_field->core.release_cards_ex_oneof, use_hand, findex, extraargs, pexception, pexgroup, use_oppo, REASON_EFFECT);
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SelectRelease>(playerid, cancelable, min, max, check_field, to_check, toplayer, zone);
|
2023-11-25 11:15:21 +01:00
|
|
|
return push_return_cards(L, cancelable);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SelectReleaseGroup) {
|
2020-07-23 23:50:09 +02:00
|
|
|
return select_release_group(L, false);
|
2020-03-20 19:50:16 +01:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SelectReleaseGroupEx) {
|
2020-07-23 23:50:09 +02:00
|
|
|
return select_release_group(L, true);
|
2020-03-20 19:50:16 +01:00
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
/**
|
|
|
|
|
* \brief Duel.GetTributeGroup
|
|
|
|
|
* \param targetcard
|
|
|
|
|
* \return Group
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetTributeGroup) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto target = lua_get<card*, true>(L, 1);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group();
|
2018-09-07 17:52:07 +02:00
|
|
|
pduel->game_field->get_summon_release_list(target, &(pgroup->container), &(pgroup->container), &(pgroup->container));
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* \brief Duel.GetTributeCount
|
|
|
|
|
* \param targetcard
|
|
|
|
|
* \return Integer
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetTributeCount) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto target = lua_get<card*, true>(L, 1);
|
2024-01-13 16:10:22 +01:00
|
|
|
group* mg = nullptr;
|
2020-12-26 00:31:31 +01:00
|
|
|
if(!lua_isnoneornil(L, 2))
|
2020-07-21 01:21:25 +02:00
|
|
|
mg = lua_get<group*, true>(L, 2);
|
2020-07-23 23:50:09 +02:00
|
|
|
bool ex = lua_get<bool, false>(L, 3);
|
2021-12-13 14:07:51 +01:00
|
|
|
lua_pushinteger(L, pduel->game_field->get_summon_release_list(target, nullptr, nullptr, nullptr, mg, ex));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CheckTribute) {
|
2016-12-18 22:11:15 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto target = lua_get<card*, true>(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto min = lua_get<uint16_t>(L, 2);
|
|
|
|
|
auto max = lua_get<uint16_t>(L, 3, min);
|
2024-01-13 16:10:22 +01:00
|
|
|
group* mg = nullptr;
|
2020-12-26 00:31:31 +01:00
|
|
|
if(!lua_isnoneornil(L, 4))
|
2020-07-21 01:21:25 +02:00
|
|
|
mg = lua_get<group*, true>(L, 4);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto toplayer = lua_get<uint8_t>(L, 5, target->current.controler);
|
|
|
|
|
auto zone = lua_get<uint32_t, 0x1f>(L, 6);
|
2019-07-21 12:58:15 +02:00
|
|
|
lua_pushboolean(L, pduel->game_field->check_tribute(target, min, max, mg, toplayer, zone));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SelectTribute) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 4);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto target = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto min = lua_get<uint16_t>(L, 3);
|
|
|
|
|
auto max = lua_get<uint16_t>(L, 4);
|
2024-01-13 16:10:22 +01:00
|
|
|
group* mg = nullptr;
|
2020-12-26 00:31:31 +01:00
|
|
|
if(!lua_isnoneornil(L, 5))
|
2020-07-21 01:21:25 +02:00
|
|
|
mg = lua_get<group*, true>(L, 5);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto toplayer = lua_get<uint8_t>(L, 6, playerid);
|
2017-10-14 17:21:47 +08:00
|
|
|
if(toplayer != 0 && toplayer != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t ex = FALSE;
|
2017-10-14 17:21:47 +08:00
|
|
|
if(toplayer != playerid)
|
|
|
|
|
ex = TRUE;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto zone = lua_get<uint32_t, 0x1f>(L, 7);
|
2020-07-23 23:50:09 +02:00
|
|
|
auto cancelable = lua_get<bool, false>(L, 8);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->core.release_cards.clear();
|
|
|
|
|
pduel->game_field->core.release_cards_ex.clear();
|
2018-03-11 17:51:46 +09:00
|
|
|
pduel->game_field->core.release_cards_ex_oneof.clear();
|
2019-07-21 12:58:15 +02:00
|
|
|
pduel->game_field->get_summon_release_list(target, &pduel->game_field->core.release_cards, &pduel->game_field->core.release_cards_ex, &pduel->game_field->core.release_cards_ex_oneof, mg, ex);
|
2024-01-13 16:10:22 +01:00
|
|
|
pduel->game_field->select_tribute_cards(nullptr, playerid, cancelable, min, max, toplayer, zone);
|
2023-11-25 11:15:21 +01:00
|
|
|
return push_return_cards(L, cancelable);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* \brief Duel.GetTargetCount
|
|
|
|
|
* \param filter_func, self, location1, location2, exception card, (extraargs...)
|
|
|
|
|
* \return Group
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetTargetCount) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 5);
|
2022-06-11 12:59:38 +02:00
|
|
|
const auto findex = lua_get<function>(L, 1);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* pexception = nullptr;
|
|
|
|
|
group* pexgroup = nullptr;
|
2020-09-16 17:12:50 +02:00
|
|
|
if((pexception = lua_get<card*>(L, 5)) == nullptr)
|
2020-07-12 14:57:26 +02:00
|
|
|
pexgroup = lua_get<group*>(L, 5);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t extraargs = lua_gettop(L) - 5;
|
|
|
|
|
auto self = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto location1 = lua_get<uint16_t>(L, 3);
|
|
|
|
|
auto location2 = lua_get<uint16_t>(L, 4);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group();
|
2024-01-03 13:34:39 +01:00
|
|
|
pduel->game_field->filter_matching_card(findex, self, location1, location2, pgroup, pexception, pexgroup, extraargs, nullptr, 0, true);
|
2023-02-07 16:43:27 +01:00
|
|
|
lua_pushinteger(L, pgroup->container.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* \brief Duel.IsExistingTarget
|
|
|
|
|
* \param filter_func, self, location1, location2, count, exception card, (extraargs...)
|
|
|
|
|
* \return boolean
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsExistingTarget) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 6);
|
2022-06-11 12:59:38 +02:00
|
|
|
const auto findex = lua_get<function>(L, 1);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* pexception = nullptr;
|
|
|
|
|
group* pexgroup = nullptr;
|
2020-09-16 17:12:50 +02:00
|
|
|
if((pexception = lua_get<card*>(L, 6)) == nullptr)
|
2020-07-12 14:57:26 +02:00
|
|
|
pexgroup = lua_get<group*>(L, 6);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t extraargs = lua_gettop(L) - 6;
|
|
|
|
|
auto self = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto location1 = lua_get<uint16_t>(L, 3);
|
|
|
|
|
auto location2 = lua_get<uint16_t>(L, 4);
|
|
|
|
|
auto count = lua_get<uint16_t>(L, 5);
|
2024-01-03 13:34:39 +01:00
|
|
|
lua_pushboolean(L, pduel->game_field->filter_matching_card(findex, self, location1, location2, nullptr, pexception, pexgroup, extraargs, nullptr, count, true));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* \brief Duel.SelectTarget
|
|
|
|
|
* \param playerid, filter_func, self, location1, location2, min, max, exception card, (extraargs...)
|
|
|
|
|
* \return Group
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SelectTarget) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 8);
|
2022-06-11 12:59:38 +02:00
|
|
|
const auto findex = lua_get<function>(L, 2);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* pexception = nullptr;
|
|
|
|
|
group* pexgroup = nullptr;
|
2020-07-23 23:50:09 +02:00
|
|
|
bool cancelable = false;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t lastarg = 8;
|
2020-07-24 00:16:34 +02:00
|
|
|
if(lua_isboolean(L, lastarg)) {
|
2020-07-23 23:50:09 +02:00
|
|
|
check_param_count(L, 9);
|
|
|
|
|
cancelable = lua_get<bool, false>(L, lastarg);
|
2022-03-05 13:56:43 +01:00
|
|
|
++lastarg;
|
2020-03-14 18:40:09 +01:00
|
|
|
}
|
2020-09-16 17:12:50 +02:00
|
|
|
if((pexception = lua_get<card*>(L, lastarg)) == nullptr)
|
2020-07-12 14:57:26 +02:00
|
|
|
pexgroup = lua_get<group*>(L, lastarg);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t extraargs = lua_gettop(L) - lastarg;
|
|
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto self = lua_get<uint8_t>(L, 3);
|
|
|
|
|
auto location1 = lua_get<uint16_t>(L, 4);
|
|
|
|
|
auto location2 = lua_get<uint16_t>(L, 5);
|
|
|
|
|
auto min = lua_get<uint16_t>(L, 6);
|
|
|
|
|
auto max = lua_get<uint16_t>(L, 7);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(pduel->game_field->core.current_chain.size() == 0)
|
|
|
|
|
return 0;
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group();
|
2024-01-03 13:34:39 +01:00
|
|
|
pduel->game_field->filter_matching_card(findex, self, location1, location2, pgroup, pexception, pexgroup, extraargs, nullptr, 0, true);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->core.select_cards.assign(pgroup->container.begin(), pgroup->container.end());
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SelectCard>(playerid, cancelable, min, max);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
2020-03-14 18:40:09 +01:00
|
|
|
if(pduel->game_field->return_cards.canceled) {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2019-06-23 14:15:19 +08:00
|
|
|
chain* ch = pduel->game_field->get_chain(0);
|
|
|
|
|
if(ch) {
|
|
|
|
|
if(!ch->target_cards) {
|
|
|
|
|
ch->target_cards = pduel->new_group();
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
ch->target_cards->is_readonly = true;
|
2019-06-23 14:15:19 +08:00
|
|
|
}
|
2019-07-16 01:57:22 +02:00
|
|
|
ch->target_cards->container.insert(pduel->game_field->return_cards.list.begin(), pduel->game_field->return_cards.list.end());
|
2019-06-23 14:15:19 +08:00
|
|
|
effect* peffect = ch->triggering_effect;
|
|
|
|
|
if(peffect->type & EFFECT_TYPE_CONTINUOUS) {
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, ch->target_cards);
|
2019-06-23 14:15:19 +08:00
|
|
|
} else {
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pret = pduel->new_group(pduel->game_field->return_cards.list);
|
2019-06-23 14:15:19 +08:00
|
|
|
for(auto& pcard : pret->container) {
|
|
|
|
|
pcard->create_relation(*ch);
|
|
|
|
|
if(peffect->is_flag(EFFECT_FLAG_CARD_TARGET)) {
|
2019-07-16 00:57:53 +02:00
|
|
|
auto message = pduel->new_message(MSG_BECOME_TARGET);
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint32_t>(1);
|
2019-07-16 00:57:53 +02:00
|
|
|
message->write(pcard->get_info_location());
|
2019-06-23 14:15:19 +08:00
|
|
|
}
|
|
|
|
|
}
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pret);
|
2019-06-23 14:15:19 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SelectFusionMaterial) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
|
|
|
|
auto pgroup = lua_get<group*, true>(L, 3);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
owned_lua<group> forced_materials = nullptr;
|
2024-01-08 20:46:41 +01:00
|
|
|
if(auto pcard_ = lua_get<card*>(L, 4))
|
|
|
|
|
forced_materials = pduel->new_group(pcard_);
|
2020-07-23 23:50:09 +02:00
|
|
|
else
|
2024-01-08 20:46:41 +01:00
|
|
|
forced_materials = lua_get<group*>(L, 4);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto chkf = lua_get<uint32_t, PLAYER_NONE>(L, 5);
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SelectFusion>(playerid, pgroup, chkf, forced_materials, pcard);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group(pduel->game_field->core.fusion_materials);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SetFusionMaterial) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pgroup = lua_get<group*, true>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->core.fusion_materials = pgroup->container;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetRitualMaterial) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2020-07-23 23:50:09 +02:00
|
|
|
bool check_level = lua_get<bool, true>(L, 2);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group();
|
2020-07-14 22:49:49 +02:00
|
|
|
pduel->game_field->get_ritual_material(playerid, pduel->game_field->core.reason_effect, &pgroup->container, check_level);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ReleaseRitualMaterial) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pgroup = lua_get<group*, true>(L, 1);
|
2022-03-13 00:04:26 +01:00
|
|
|
pduel->game_field->ritual_release(pgroup->container);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetFusionMaterial) {
|
2016-12-20 00:58:50 +09:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2016-12-20 00:58:50 +09:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group();
|
2016-12-20 00:58:50 +09:00
|
|
|
pduel->game_field->get_fusion_material(playerid, &pgroup->container);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2016-12-20 00:58:50 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsSummonCancelable) {
|
2020-05-13 21:28:45 +08:00
|
|
|
lua_pushboolean(L, pduel->game_field->core.summon_cancelable);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SetSelectedCard) {
|
2016-03-18 00:48:52 +09:00
|
|
|
check_param_count(L, 1);
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [pcard, pgroup] = lua_get_card_or_group(L, 1); pcard)
|
2020-10-30 17:05:28 +01:00
|
|
|
pduel->game_field->core.must_select_cards = { pcard };
|
2022-06-23 11:47:00 +02:00
|
|
|
else
|
2016-03-18 00:48:52 +09:00
|
|
|
pduel->game_field->core.must_select_cards.assign(pgroup->container.begin(), pgroup->container.end());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GrabSelectedCard) {
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group(pduel->game_field->core.must_select_cards);
|
2018-11-28 21:05:58 +08:00
|
|
|
pduel->game_field->core.must_select_cards.clear();
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2018-11-28 21:05:58 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SetTargetCard) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2023-12-03 11:34:38 +01:00
|
|
|
auto [pcard, pgroup] = lua_get_card_or_group(L, 1);
|
2017-07-01 23:51:49 +09:00
|
|
|
chain* ch = pduel->game_field->get_chain(0);
|
|
|
|
|
if(!ch)
|
|
|
|
|
return 0;
|
|
|
|
|
if(!ch->target_cards) {
|
|
|
|
|
ch->target_cards = pduel->new_group();
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
ch->target_cards->is_readonly = true;
|
2017-07-01 23:51:49 +09:00
|
|
|
}
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto targets = ch->target_cards;
|
2017-07-01 23:51:49 +09:00
|
|
|
effect* peffect = ch->triggering_effect;
|
|
|
|
|
if(peffect->type & EFFECT_TYPE_CONTINUOUS) {
|
2015-09-25 21:07:16 +08:00
|
|
|
if(pcard)
|
2017-07-01 23:51:49 +09:00
|
|
|
targets->container.insert(pcard);
|
2015-09-25 21:07:16 +08:00
|
|
|
else
|
2017-07-01 23:51:49 +09:00
|
|
|
targets->container = pgroup->container;
|
2017-07-03 18:20:47 +09:00
|
|
|
} else {
|
2015-09-25 21:07:16 +08:00
|
|
|
if(pcard) {
|
|
|
|
|
targets->container.insert(pcard);
|
2017-07-03 18:20:47 +09:00
|
|
|
pcard->create_relation(*ch);
|
2015-09-25 21:07:16 +08:00
|
|
|
} else {
|
|
|
|
|
targets->container.insert(pgroup->container.begin(), pgroup->container.end());
|
2020-09-16 17:12:50 +02:00
|
|
|
for(auto& _pcard : pgroup->container)
|
|
|
|
|
_pcard->create_relation(*ch);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2015-10-31 15:50:37 +09:00
|
|
|
if(peffect->is_flag(EFFECT_FLAG_CARD_TARGET)) {
|
2020-03-18 11:51:55 +01:00
|
|
|
auto message = pduel->new_message(MSG_BECOME_TARGET);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(pcard) {
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint32_t>(1);
|
2019-07-16 00:57:53 +02:00
|
|
|
message->write(pcard->get_info_location());
|
2015-09-25 21:07:16 +08:00
|
|
|
} else {
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint32_t>(pgroup->container.size());
|
2020-09-16 17:12:50 +02:00
|
|
|
for(auto& _pcard : pgroup->container)
|
|
|
|
|
message->write(_pcard->get_info_location());
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ClearTargetCard) {
|
2017-07-01 23:51:49 +09:00
|
|
|
chain* ch = pduel->game_field->get_chain(0);
|
|
|
|
|
if(ch && ch->target_cards)
|
|
|
|
|
ch->target_cards->container.clear();
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SetTargetPlayer) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2017-07-01 23:51:49 +09:00
|
|
|
chain* ch = pduel->game_field->get_chain(0);
|
|
|
|
|
if(ch)
|
|
|
|
|
ch->target_player = playerid;
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SetTargetParam) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto param = lua_get<uint32_t>(L, 1);
|
2017-07-01 23:51:49 +09:00
|
|
|
chain* ch = pduel->game_field->get_chain(0);
|
|
|
|
|
if(ch)
|
|
|
|
|
ch->target_param = param;
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* \brief Duel.SetOperationInfo
|
|
|
|
|
* \param target_group, target_count, target_player, targ
|
|
|
|
|
* \return N/A
|
|
|
|
|
*/
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SetOperationInfo) {
|
2021-10-13 17:29:29 +02:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 6);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto ct = lua_get<uint32_t>(L, 1);
|
2026-01-15 20:22:01 +01:00
|
|
|
auto cate = lua_get<uint64_t>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto count = lua_get<uint8_t>(L, 4);
|
|
|
|
|
auto playerid = lua_get<uint8_t>(L, 5);
|
|
|
|
|
auto param = lua_get<int32_t>(L, 6);
|
2020-10-30 17:05:28 +01:00
|
|
|
auto pobj = lua_get<lua_obj*>(L, 3);
|
2017-07-01 23:51:49 +09:00
|
|
|
chain* ch = pduel->game_field->get_chain(ct);
|
|
|
|
|
if(!ch)
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
2020-10-30 17:05:28 +01:00
|
|
|
optarget opt{ nullptr, count, playerid, param };
|
2023-12-08 19:53:35 +01:00
|
|
|
if(pobj && (pobj->lua_type == LuaParam::CARD || pobj->lua_type == LuaParam::GROUP)) {
|
2020-10-30 17:05:28 +01:00
|
|
|
opt.op_cards = pduel->new_group(pobj);
|
2021-01-02 22:43:15 +01:00
|
|
|
// spear creting and similar stuff, they set CATEGORY_SPECIAL_SUMMON with PLAYER_ALL to increase the summon counters
|
|
|
|
|
// and the core always assume the group is exactly 2 cards
|
2022-06-23 11:47:00 +02:00
|
|
|
if(cate == 0x200 && playerid == PLAYER_ALL && opt.op_cards->container.size() != 2)
|
|
|
|
|
lua_error(L, "Called Duel.SetOperationInfo with CATEGORY_SPECIAL_SUMMON and PLAYER_ALL but the group size wasn't exactly 2.");
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
opt.op_cards->is_readonly = true;
|
2020-10-30 17:05:28 +01:00
|
|
|
}
|
2021-03-24 20:18:51 +01:00
|
|
|
ch->opinfos[cate] = std::move(opt);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetOperationInfo) {
|
2021-10-13 17:29:29 +02:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto ct = lua_get<uint32_t>(L, 1);
|
2026-01-15 20:22:01 +01:00
|
|
|
auto cate = lua_get<uint64_t>(L, 2);
|
2017-07-01 23:51:49 +09:00
|
|
|
chain* ch = pduel->game_field->get_chain(ct);
|
|
|
|
|
if(!ch)
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
2020-10-30 19:01:04 +01:00
|
|
|
auto oit = ch->opinfos.find(cate);
|
2017-07-01 23:51:49 +09:00
|
|
|
if(oit != ch->opinfos.end()) {
|
|
|
|
|
optarget& opt = oit->second;
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, 1);
|
|
|
|
|
if(opt.op_cards)
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, opt.op_cards);
|
2015-09-25 21:07:16 +08:00
|
|
|
else
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
lua_pushinteger(L, opt.op_count);
|
|
|
|
|
lua_pushinteger(L, opt.op_player);
|
|
|
|
|
lua_pushinteger(L, opt.op_param);
|
|
|
|
|
return 5;
|
2017-07-01 23:51:49 +09:00
|
|
|
} else {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SetPossibleOperationInfo) {
|
2021-10-13 17:29:29 +02:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 6);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto ct = lua_get<uint32_t>(L, 1);
|
2026-01-15 20:22:01 +01:00
|
|
|
auto cate = lua_get<uint64_t>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto count = lua_get<uint8_t>(L, 4);
|
|
|
|
|
auto playerid = lua_get<uint8_t>(L, 5);
|
|
|
|
|
auto param = lua_get<int32_t>(L, 6);
|
2021-03-24 20:18:51 +01:00
|
|
|
auto pobj = lua_get<lua_obj*>(L, 3);
|
|
|
|
|
chain* ch = pduel->game_field->get_chain(ct);
|
|
|
|
|
if(!ch)
|
|
|
|
|
return 0;
|
|
|
|
|
optarget opt{ nullptr, count, playerid, param };
|
2023-12-08 19:53:35 +01:00
|
|
|
if(pobj && (pobj->lua_type == LuaParam::CARD || pobj->lua_type == LuaParam::GROUP)) {
|
2021-03-24 20:18:51 +01:00
|
|
|
opt.op_cards = pduel->new_group(pobj);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
opt.op_cards->is_readonly = true;
|
2021-03-24 20:18:51 +01:00
|
|
|
}
|
|
|
|
|
ch->possibleopinfos[cate] = std::move(opt);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetPossibleOperationInfo) {
|
2021-10-13 17:29:29 +02:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto ct = lua_get<uint32_t>(L, 1);
|
2026-01-15 20:22:01 +01:00
|
|
|
auto cate = lua_get<uint64_t>(L, 2);
|
2021-03-24 20:18:51 +01:00
|
|
|
chain* ch = pduel->game_field->get_chain(ct);
|
|
|
|
|
if(!ch)
|
|
|
|
|
return 0;
|
|
|
|
|
auto oit = ch->possibleopinfos.find(cate);
|
|
|
|
|
if(oit != ch->possibleopinfos.end()) {
|
|
|
|
|
optarget& opt = oit->second;
|
|
|
|
|
lua_pushboolean(L, 1);
|
|
|
|
|
if(opt.op_cards)
|
|
|
|
|
interpreter::pushobject(L, opt.op_cards);
|
|
|
|
|
else
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
lua_pushinteger(L, opt.op_count);
|
|
|
|
|
lua_pushinteger(L, opt.op_player);
|
|
|
|
|
lua_pushinteger(L, opt.op_param);
|
|
|
|
|
return 5;
|
|
|
|
|
} else {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetOperationCount) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto ct = lua_get<uint32_t>(L, 1);
|
2017-07-01 23:51:49 +09:00
|
|
|
chain* ch = pduel->game_field->get_chain(ct);
|
|
|
|
|
if(!ch)
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
2017-07-01 23:51:49 +09:00
|
|
|
lua_pushinteger(L, ch->opinfos.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(ClearOperationInfo) {
|
2019-12-18 08:35:06 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto ct = lua_get<uint32_t>(L, 1);
|
2019-12-18 08:35:06 +08:00
|
|
|
chain* ch = pduel->game_field->get_chain(ct);
|
|
|
|
|
if(!ch)
|
|
|
|
|
return 0;
|
|
|
|
|
ch->opinfos.clear();
|
2021-03-24 20:18:51 +01:00
|
|
|
ch->possibleopinfos.clear();
|
2019-12-18 08:35:06 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(Overlay) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto target = lua_get<card*, true>(L, 1);
|
2022-06-23 11:47:00 +02:00
|
|
|
if(target->overlay_target != nullptr)
|
|
|
|
|
lua_error(L, "Attempt to overlay materials to a card that is an overlay material.");
|
2023-12-03 11:34:38 +01:00
|
|
|
auto [pcard, pgroup] = lua_get_card_or_group(L, 2);
|
2022-11-05 16:48:29 +01:00
|
|
|
bool send_materials_to_grave = lua_get<bool, false>(L, 3);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(pcard) {
|
2022-06-23 11:47:00 +02:00
|
|
|
if(pcard == target)
|
|
|
|
|
lua_error(L, "Attempt to overlay a card with itself.");
|
2022-11-05 16:48:29 +01:00
|
|
|
pduel->game_field->xyz_overlay(target, pcard, send_materials_to_grave);
|
2021-10-31 16:56:46 +01:00
|
|
|
} else {
|
2022-06-23 11:47:00 +02:00
|
|
|
if(pgroup->has_card(target))
|
|
|
|
|
lua_error(L, "Attempt to overlay a card with itself.");
|
2022-11-05 16:48:29 +01:00
|
|
|
pduel->game_field->xyz_overlay(target, pgroup->container, send_materials_to_grave);
|
2021-10-31 16:56:46 +01:00
|
|
|
}
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetOverlayGroup) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto rplayer = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(rplayer != 0 && rplayer != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto self = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto oppo = lua_get<uint8_t>(L, 3);
|
2020-07-21 15:03:03 +02:00
|
|
|
group* targetsgroup = lua_get<group*>(L, 4);
|
Move Group's lifetime management to Lua (#166)
No longer manage a Group's lifetime explicitly in native code, but instead leverage Lua's garbage collector to handle it's lifetime.
In this change, Groups will be stored internally in the core inside a weak table, so that they will still be reference-able when needed, but if no reference were to exist in Lua code, they will be subject to garbage collection.
Whenever a Group is used by native code, its wrapped by a owned_lua template class, this is akin to std::shared_ptr--It reference counts the usages of that group internally in the core, including managing it in the Lua registry index when in use, so that it won't be collected.
With this approach, the exponential memory usage growth caused by long running procedures due to the creation hundredths of thousands of groups per iteration, is mitigated, since the temporary groups will be reaped more frequently, as opposed to the old approach of them being cleared only after the topmost Lua function had finished executing.
For now a single GC step is triggered whenever the total number of groups is more than 2048--an arbitrary value that seems to work well enough, but which can be changed/optimized after proper profiling.
A major upgrade with this approach is the removal of the concept of Groups "kept alive" and having to "explicitly delete" them to make them outlive a Lua function execution, since they will now follow Lua's variables lifetime properly.
2025-05-30 23:20:22 +02:00
|
|
|
auto pgroup = pduel->new_group();
|
2020-07-21 00:08:06 +02:00
|
|
|
pduel->game_field->get_overlay_group(rplayer, self, oppo, &pgroup->container, targetsgroup);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetOverlayCount) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto rplayer = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(rplayer != 0 && rplayer != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto self = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto oppo = lua_get<uint8_t>(L, 3);
|
2020-07-21 15:03:03 +02:00
|
|
|
group* pgroup = lua_get<group*>(L, 4);
|
2020-07-21 00:08:06 +02:00
|
|
|
lua_pushinteger(L, pduel->game_field->get_overlay_count(rplayer, self, oppo, pgroup));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CheckRemoveOverlayCard) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 5);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto self = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto oppo = lua_get<uint8_t>(L, 3);
|
|
|
|
|
auto count = lua_get<uint16_t>(L, 4);
|
|
|
|
|
auto reason = lua_get<uint32_t>(L, 5);
|
2020-07-21 15:03:03 +02:00
|
|
|
group* pgroup = lua_get<group*>(L, 6);
|
2020-07-21 00:08:06 +02:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_remove_overlay_card(playerid, pgroup, self, oppo, count, reason));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(RemoveOverlayCard) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 6);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto self = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto oppo = lua_get<uint8_t>(L, 3);
|
|
|
|
|
auto min = lua_get<uint16_t>(L, 4);
|
|
|
|
|
auto max = lua_get<uint16_t>(L, 5);
|
|
|
|
|
auto reason = lua_get<uint32_t>(L, 6);
|
2020-07-21 15:03:03 +02:00
|
|
|
group* pgroup = lua_get<group*>(L, 7);
|
2020-07-21 00:08:06 +02:00
|
|
|
pduel->game_field->remove_overlay_card(reason, pgroup, playerid, self, oppo, min, max);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(Hint) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto htype = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto desc = lua_get<uint64_t>(L, 3);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(htype == HINT_OPSELECTED)
|
|
|
|
|
playerid = 1 - playerid;
|
2019-07-16 00:57:53 +02:00
|
|
|
auto message = pduel->new_message(MSG_HINT);
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint8_t>(htype);
|
|
|
|
|
message->write<uint8_t>(playerid);
|
|
|
|
|
message->write<uint64_t>(desc);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(HintSelection) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2025-02-10 20:51:38 +01:00
|
|
|
auto [pcard, pgroup] = lua_get_card_or_group(L, 1);
|
2025-04-13 15:07:49 +02:00
|
|
|
bool selection = lua_get<bool, true>(L, 2);
|
2020-03-18 11:51:55 +01:00
|
|
|
auto message = pduel->new_message(selection ? MSG_CARD_SELECTED : MSG_BECOME_TARGET);
|
2025-02-10 20:51:38 +01:00
|
|
|
if(pcard) {
|
2021-10-10 11:00:08 +02:00
|
|
|
message->write<uint32_t>(1);
|
2019-07-16 00:57:53 +02:00
|
|
|
message->write(pcard->get_info_location());
|
2021-10-10 11:00:08 +02:00
|
|
|
} else {
|
|
|
|
|
message->write<uint32_t>(pgroup->container.size());
|
2022-06-23 11:47:00 +02:00
|
|
|
for(auto& _pcard : pgroup->container)
|
|
|
|
|
message->write(_pcard->get_info_location());
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SelectEffectYesNo) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto desc = lua_get<uint64_t, 95>(L, 3);
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SelectEffectYesNo>(playerid, desc, pcard);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SelectYesNo) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto desc = lua_get<uint64_t>(L, 2);
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SelectYesNo>(playerid, desc);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SelectOption) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
pduel->game_field->core.select_options.clear();
|
2022-10-26 18:13:11 +02:00
|
|
|
lua_iterate_table_or_stack(L, 2 + lua_isboolean(L, 2), lua_gettop(L), [L, &select_options = pduel->game_field->core.select_options] {
|
|
|
|
|
select_options.push_back(lua_get<uint64_t>(L, -1));
|
|
|
|
|
});
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SelectOption>(playerid);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2020-07-23 23:50:09 +02:00
|
|
|
bool sel_hint = lua_get<bool, true>(L, 2);
|
2021-01-21 19:16:13 +01:00
|
|
|
if(sel_hint && !pduel->game_field->core.select_options.empty()) {
|
2019-08-22 16:56:30 +02:00
|
|
|
auto message = pduel->new_message(MSG_HINT);
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint8_t>(HINT_OPSELECTED);
|
|
|
|
|
message->write<uint8_t>(playerid);
|
|
|
|
|
message->write<uint64_t>(pduel->game_field->core.select_options[pduel->game_field->returns.at<int32_t>(0)]);
|
2019-08-22 16:56:30 +02:00
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SelectPosition) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto positions = lua_get<uint8_t>(L, 3);
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SelectPosition>(playerid, pcard->data.code, positions);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SelectDisableField) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 5);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto count = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto location1 = lua_get<uint16_t>(L, 3);
|
|
|
|
|
auto location2 = lua_get<uint16_t>(L, 4);
|
2020-07-23 23:50:09 +02:00
|
|
|
bool all_field = lua_get<bool, false>(L, 6);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t filter = 0xe0e0e0e0;
|
2020-04-20 17:07:38 +02:00
|
|
|
if(all_field){
|
|
|
|
|
filter = pduel->game_field->is_flag(DUEL_EMZONE) ? 0x800080 : 0xE000E0;
|
2021-09-28 11:55:44 +02:00
|
|
|
filter |= pduel->game_field->get_pzone_zones_flag();
|
2020-04-20 17:07:38 +02:00
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
filter |= lua_get<uint32_t>(L, 5, filter);
|
|
|
|
|
uint32_t ct1 = 0, ct2 = 0, ct3 = 0, ct4 = 0, plist = 0, flag = 0xffffffff;
|
2015-09-25 21:07:16 +08:00
|
|
|
if(location1 & LOCATION_MZONE) {
|
2021-12-13 14:07:51 +01:00
|
|
|
ct1 = pduel->game_field->get_useable_count(nullptr, playerid, LOCATION_MZONE, PLAYER_NONE, 0, 0xff, &plist);
|
2017-04-02 18:43:10 +02:00
|
|
|
if (all_field) {
|
2020-04-20 17:07:38 +02:00
|
|
|
plist &= ~0x60;
|
2017-04-02 18:43:10 +02:00
|
|
|
if (!pduel->game_field->is_location_useable(playerid, LOCATION_MZONE, 5))
|
|
|
|
|
plist |= 0x20;
|
|
|
|
|
else
|
2022-03-05 13:56:43 +01:00
|
|
|
++ct1;
|
2017-04-02 18:43:10 +02:00
|
|
|
if (!pduel->game_field->is_location_useable(playerid, LOCATION_MZONE, 6))
|
|
|
|
|
plist |= 0x40;
|
|
|
|
|
else
|
2022-03-05 13:56:43 +01:00
|
|
|
++ct1;
|
2017-04-02 18:43:10 +02:00
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
flag = (flag & 0xffffff00) | plist;
|
|
|
|
|
}
|
|
|
|
|
if(location1 & LOCATION_SZONE) {
|
2021-12-13 14:07:51 +01:00
|
|
|
ct2 = pduel->game_field->get_useable_count(nullptr, playerid, LOCATION_SZONE, PLAYER_NONE, 0, 0xff, &plist);
|
2017-04-02 18:43:10 +02:00
|
|
|
if (all_field) {
|
2020-04-20 17:07:38 +02:00
|
|
|
plist &= ~0xe0;
|
2017-04-02 18:43:10 +02:00
|
|
|
if (!pduel->game_field->is_location_useable(playerid, LOCATION_SZONE, 5))
|
|
|
|
|
plist |= 0x20;
|
|
|
|
|
else
|
2022-03-05 13:56:43 +01:00
|
|
|
++ct2;
|
2017-04-02 18:43:10 +02:00
|
|
|
if (!pduel->game_field->is_location_useable(playerid, LOCATION_SZONE, 6))
|
|
|
|
|
plist |= 0x40;
|
|
|
|
|
else
|
2022-03-05 13:56:43 +01:00
|
|
|
++ct2;
|
2017-04-02 18:43:10 +02:00
|
|
|
if (!pduel->game_field->is_location_useable(playerid, LOCATION_SZONE, 7))
|
|
|
|
|
plist |= 0x80;
|
|
|
|
|
else
|
2022-03-05 13:56:43 +01:00
|
|
|
++ct2;
|
2017-04-02 18:43:10 +02:00
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
flag = (flag & 0xffff00ff) | (plist << 8);
|
|
|
|
|
}
|
|
|
|
|
if(location2 & LOCATION_MZONE) {
|
2021-12-13 14:07:51 +01:00
|
|
|
ct3 = pduel->game_field->get_useable_count(nullptr, 1 - playerid, LOCATION_MZONE, PLAYER_NONE, 0, 0xff, &plist);
|
2017-04-02 18:43:10 +02:00
|
|
|
if (all_field) {
|
2020-04-20 17:07:38 +02:00
|
|
|
plist &= ~0x60;
|
2017-04-02 18:43:10 +02:00
|
|
|
if (!pduel->game_field->is_location_useable(1 - playerid, LOCATION_MZONE, 5))
|
|
|
|
|
plist |= 0x20;
|
|
|
|
|
else
|
2022-03-05 13:56:43 +01:00
|
|
|
++ct3;
|
2017-04-02 18:43:10 +02:00
|
|
|
if (!pduel->game_field->is_location_useable(1 - playerid, LOCATION_MZONE, 6))
|
|
|
|
|
plist |= 0x40;
|
|
|
|
|
else
|
2022-03-05 13:56:43 +01:00
|
|
|
++ct3;
|
2017-04-02 18:43:10 +02:00
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
flag = (flag & 0xff00ffff) | (plist << 16);
|
|
|
|
|
}
|
|
|
|
|
if(location2 & LOCATION_SZONE) {
|
2021-12-13 14:07:51 +01:00
|
|
|
ct4 = pduel->game_field->get_useable_count(nullptr, 1 - playerid, LOCATION_SZONE, PLAYER_NONE, 0, 0xff, &plist);
|
2017-04-02 18:43:10 +02:00
|
|
|
if (all_field) {
|
2020-04-20 17:07:38 +02:00
|
|
|
plist &= ~0xe0;
|
2017-04-02 18:43:10 +02:00
|
|
|
if (!pduel->game_field->is_location_useable(1 - playerid, LOCATION_SZONE, 5))
|
|
|
|
|
plist |= 0x20;
|
|
|
|
|
else
|
2022-03-05 13:56:43 +01:00
|
|
|
++ct4;
|
2017-04-02 18:43:10 +02:00
|
|
|
if (!pduel->game_field->is_location_useable(1 - playerid, LOCATION_SZONE, 6))
|
|
|
|
|
plist |= 0x40;
|
|
|
|
|
else
|
2022-03-05 13:56:43 +01:00
|
|
|
++ct4;
|
2017-04-02 18:43:10 +02:00
|
|
|
if (!pduel->game_field->is_location_useable(1 - playerid, LOCATION_SZONE, 7))
|
|
|
|
|
plist |= 0x80;
|
|
|
|
|
else
|
2022-03-05 13:56:43 +01:00
|
|
|
++ct4;
|
2017-04-02 18:43:10 +02:00
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
flag = (flag & 0xffffff) | (plist << 24);
|
|
|
|
|
}
|
2017-04-02 18:43:10 +02:00
|
|
|
flag |= filter | ((all_field) ? 0x800080 : 0xe0e0e0e0);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(count > ct1 + ct2 + ct3 + ct4)
|
|
|
|
|
count = ct1 + ct2 + ct3 + ct4;
|
|
|
|
|
if(count == 0)
|
|
|
|
|
return 0;
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SelectDisField>(playerid, flag, count);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto count = lua_get<uint8_t>(L, 2);
|
|
|
|
|
uint32_t dfflag = 0;
|
|
|
|
|
uint8_t pa = 0;
|
|
|
|
|
for(uint32_t i = 0; i < count; ++i) {
|
|
|
|
|
uint8_t p = pduel->game_field->returns.at<int8_t>(pa);
|
|
|
|
|
uint8_t l = pduel->game_field->returns.at<int8_t>(pa + 1);
|
|
|
|
|
uint8_t s = pduel->game_field->returns.at<int8_t>(pa + 2);
|
2019-06-23 14:15:19 +08:00
|
|
|
dfflag |= 0x1u << (s + (p == playerid ? 0 : 16) + (l == LOCATION_MZONE ? 0 : 8));
|
|
|
|
|
pa += 3;
|
|
|
|
|
}
|
|
|
|
|
lua_pushinteger(L, dfflag);
|
|
|
|
|
return 1;
|
|
|
|
|
});
|
2017-10-02 21:26:24 +02:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SelectFieldZone) {
|
2017-10-02 21:26:24 +02:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 4);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2017-10-02 21:26:24 +02:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto count = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto location1 = lua_get<uint16_t>(L, 3);
|
|
|
|
|
auto location2 = lua_get<uint16_t>(L, 4);
|
|
|
|
|
auto filter = lua_get<uint32_t, 0xe0e0e0e0>(L, 5);
|
2020-04-20 17:07:38 +02:00
|
|
|
filter |= pduel->game_field->is_flag(DUEL_EMZONE) ? 0x800080 : 0xE000E0;
|
2021-09-28 11:55:44 +02:00
|
|
|
filter |= pduel->game_field->get_pzone_zones_flag();
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t flag = 0xffffffff;
|
2017-10-02 21:26:24 +02:00
|
|
|
if(location1 & LOCATION_MZONE)
|
|
|
|
|
flag &= 0xffffff00;
|
|
|
|
|
if(location1 & LOCATION_SZONE)
|
|
|
|
|
flag &= 0xffff00ff;
|
|
|
|
|
if(location2 & LOCATION_MZONE)
|
|
|
|
|
flag &= 0xff00ffff;
|
2020-04-20 18:29:05 +02:00
|
|
|
if(location2 & LOCATION_SZONE)
|
2017-10-02 21:26:24 +02:00
|
|
|
flag &= 0xffffff;
|
|
|
|
|
flag |= filter;
|
|
|
|
|
if (flag == 0xffffffff)
|
|
|
|
|
return 0;
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SelectDisField>(playerid, flag, count);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto count = lua_get<uint8_t>(L, 2);
|
|
|
|
|
uint32_t dfflag = 0;
|
|
|
|
|
uint8_t pa = 0;
|
|
|
|
|
for(uint32_t i = 0; i < count; ++i) {
|
|
|
|
|
uint8_t p = pduel->game_field->returns.at<int8_t>(pa);
|
|
|
|
|
uint8_t l = pduel->game_field->returns.at<int8_t>(pa + 1);
|
|
|
|
|
uint8_t s = pduel->game_field->returns.at<int8_t>(pa + 2);
|
2019-06-23 14:15:19 +08:00
|
|
|
dfflag |= 0x1u << (s + (p == playerid ? 0 : 16) + (l == LOCATION_MZONE ? 0 : 8));
|
|
|
|
|
pa += 3;
|
|
|
|
|
}
|
|
|
|
|
lua_pushinteger(L, dfflag);
|
|
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(AnnounceRace) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2022-06-11 12:59:38 +02:00
|
|
|
auto available = lua_get<uint64_t>(L, 3);
|
2023-04-23 21:34:36 +02:00
|
|
|
if(bit::has_invalid_bits(available, RACE_ALL))
|
|
|
|
|
lua_error(L, "Passed an invalid race.");
|
|
|
|
|
auto count = std::min(lua_get<uint8_t>(L, 2), bit::popcnt(available));
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::AnnounceRace>(playerid, count, available);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<uint64_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(AnnounceAttribute) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto available = lua_get<uint32_t>(L, 3);
|
2023-04-23 21:34:36 +02:00
|
|
|
if(bit::has_invalid_bits(available, ATTRIBUTE_ALL))
|
|
|
|
|
lua_error(L, "Passed an invalid attribute.");
|
|
|
|
|
auto count = std::min(lua_get<uint8_t>(L, 2), bit::popcnt(available));
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::AnnounceAttribute>(playerid, count, available);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(AnnounceNumberRange) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto min = lua_get<uint32_t, 1>(L, 2);
|
|
|
|
|
auto max = lua_get<uint32_t, 12>(L, 3);
|
2020-07-23 23:50:09 +02:00
|
|
|
if(min > max)
|
|
|
|
|
std::swap(min, max);
|
2023-01-28 22:58:02 +01:00
|
|
|
std::set<uint32_t> excluded;
|
|
|
|
|
lua_iterate_table_or_stack(L, 4, lua_gettop(L), [L, &excluded, min, max] {
|
|
|
|
|
if(!lua_isnil(L, -1)) {
|
|
|
|
|
auto val = lua_get<uint32_t>(L, -1);
|
|
|
|
|
if(val >= min && val <= max)
|
|
|
|
|
excluded.insert(val);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
auto& select_options = pduel->game_field->core.select_options;
|
|
|
|
|
if(excluded.empty()) {
|
|
|
|
|
select_options.resize((max - min) + 1);
|
|
|
|
|
std::iota(select_options.begin(), select_options.end(), min);
|
|
|
|
|
} else {
|
|
|
|
|
select_options.clear();
|
|
|
|
|
auto it = excluded.cbegin();
|
|
|
|
|
const auto cend = excluded.cend();
|
|
|
|
|
uint32_t i = min;
|
|
|
|
|
for(; i <= max; ++i) {
|
|
|
|
|
if(it == cend)
|
|
|
|
|
break;
|
|
|
|
|
if(*it == i) {
|
2022-03-05 13:56:43 +01:00
|
|
|
++it;
|
2020-07-21 00:08:06 +02:00
|
|
|
continue;
|
2017-10-07 06:04:10 -03:00
|
|
|
}
|
2023-01-28 22:58:02 +01:00
|
|
|
select_options.push_back(i);
|
2017-10-07 06:04:10 -03:00
|
|
|
}
|
2023-01-28 22:58:02 +01:00
|
|
|
for(; i <= max; ++i)
|
|
|
|
|
select_options.push_back(i);
|
2017-10-07 06:04:10 -03:00
|
|
|
}
|
2023-01-28 22:58:02 +01:00
|
|
|
if(select_options.empty())
|
2017-10-07 06:04:10 -03:00
|
|
|
return 0;
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::AnnounceNumber>(playerid);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
2021-09-04 22:04:14 +02:00
|
|
|
lua_pushinteger(L, pduel->game_field->core.select_options[pduel->game_field->returns.at<int32_t>(0)]);
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 2;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2022-11-05 16:45:42 +01:00
|
|
|
LUA_FUNCTION_ALIAS(AnnounceLevel);
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(AnnounceCard) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2024-01-06 21:52:34 +01:00
|
|
|
auto& options = pduel->game_field->core.select_options;
|
2016-09-25 09:47:06 +09:00
|
|
|
pduel->game_field->core.select_options.clear();
|
2024-04-01 00:05:57 +02:00
|
|
|
if(auto paramcount = lua_gettop(L); paramcount > 2 || lua_istable(L, 2)) {
|
|
|
|
|
lua_iterate_table_or_stack(L, 2, paramcount, [&options, L] {
|
|
|
|
|
options.push_back(lua_get<uint64_t>(L, -1));
|
|
|
|
|
});
|
|
|
|
|
} else {
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t ttype = TYPE_MONSTER | TYPE_SPELL | TYPE_TRAP;
|
2020-07-21 00:08:06 +02:00
|
|
|
if(paramcount == 2)
|
2021-09-04 22:04:14 +02:00
|
|
|
ttype = lua_get<uint32_t>(L, 2);
|
2024-01-06 21:52:34 +01:00
|
|
|
options.push_back(ttype);
|
|
|
|
|
options.push_back(OPCODE_ISTYPE);
|
2019-07-16 01:57:22 +02:00
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
int32_t stack_size = 0;
|
2020-10-17 23:34:04 +02:00
|
|
|
bool has_opcodes = false;
|
2024-01-06 21:52:34 +01:00
|
|
|
for(auto& opcode : options) {
|
|
|
|
|
if(opcode != OPCODE_ALLOW_ALIASES && opcode != OPCODE_ALLOW_TOKENS)
|
2020-10-17 23:34:04 +02:00
|
|
|
has_opcodes = true;
|
2024-01-06 21:52:34 +01:00
|
|
|
switch(opcode) {
|
2020-04-12 15:41:54 +08:00
|
|
|
case OPCODE_ADD:
|
|
|
|
|
case OPCODE_SUB:
|
|
|
|
|
case OPCODE_MUL:
|
|
|
|
|
case OPCODE_DIV:
|
|
|
|
|
case OPCODE_AND:
|
|
|
|
|
case OPCODE_OR:
|
2020-04-12 12:23:26 +02:00
|
|
|
case OPCODE_BAND:
|
|
|
|
|
case OPCODE_BOR:
|
|
|
|
|
case OPCODE_BXOR:
|
|
|
|
|
case OPCODE_LSHIFT:
|
|
|
|
|
case OPCODE_RSHIFT:
|
2020-04-12 15:41:54 +08:00
|
|
|
stack_size -= 1;
|
|
|
|
|
break;
|
|
|
|
|
case OPCODE_NEG:
|
|
|
|
|
case OPCODE_NOT:
|
2020-04-12 12:23:26 +02:00
|
|
|
case OPCODE_BNOT:
|
2020-04-12 15:41:54 +08:00
|
|
|
case OPCODE_ISCODE:
|
|
|
|
|
case OPCODE_ISSETCARD:
|
|
|
|
|
case OPCODE_ISTYPE:
|
|
|
|
|
case OPCODE_ISRACE:
|
|
|
|
|
case OPCODE_ISATTRIBUTE:
|
2020-10-17 23:34:04 +02:00
|
|
|
case OPCODE_ALLOW_ALIASES:
|
|
|
|
|
case OPCODE_ALLOW_TOKENS:
|
2020-04-12 15:41:54 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
stack_size += 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if(stack_size <= 0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-06-23 11:47:00 +02:00
|
|
|
if(stack_size != 1 && has_opcodes)
|
|
|
|
|
lua_error(L, "Parameters are invalid.");
|
2020-10-17 23:34:04 +02:00
|
|
|
if(!has_opcodes) {
|
2024-01-06 21:52:34 +01:00
|
|
|
options.push_back(TYPE_MONSTER | TYPE_SPELL | TYPE_TRAP);
|
|
|
|
|
options.push_back(OPCODE_ISTYPE);
|
2020-10-17 23:34:04 +02:00
|
|
|
}
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::AnnounceCard>(playerid);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2016-09-25 09:47:06 +09:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(AnnounceType) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->core.select_options.clear();
|
|
|
|
|
pduel->game_field->core.select_options.push_back(70);
|
|
|
|
|
pduel->game_field->core.select_options.push_back(71);
|
|
|
|
|
pduel->game_field->core.select_options.push_back(72);
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SelectOption>(playerid);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2019-07-16 00:57:53 +02:00
|
|
|
auto message = pduel->new_message(MSG_HINT);
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint8_t>(HINT_OPSELECTED);
|
|
|
|
|
message->write<uint8_t>(playerid);
|
|
|
|
|
message->write<uint64_t>(pduel->game_field->core.select_options[pduel->game_field->returns.at<int32_t>(0)]);
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(AnnounceNumber) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->core.select_options.clear();
|
2022-10-26 18:13:11 +02:00
|
|
|
lua_iterate_table_or_stack(L, 2, lua_gettop(L), [L, &select_options = pduel->game_field->core.select_options] {
|
|
|
|
|
select_options.push_back(lua_get<uint64_t>(L, -1));
|
|
|
|
|
});
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::AnnounceNumber>(playerid);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
2021-09-04 22:04:14 +02:00
|
|
|
lua_pushinteger(L, pduel->game_field->core.select_options[pduel->game_field->returns.at<int32_t>(0)]);
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 2;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(AnnounceCoin) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2022-10-15 16:12:16 +02:00
|
|
|
auto desc = lua_get<uint64_t, 552>(L, 2);
|
|
|
|
|
auto message = pduel->new_message(MSG_HINT);
|
|
|
|
|
message->write<uint8_t>(HINT_SELECTMSG);
|
|
|
|
|
message->write<uint8_t>(playerid);
|
|
|
|
|
message->write<uint64_t>(desc);
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->core.select_options.clear();
|
|
|
|
|
pduel->game_field->core.select_options.push_back(60);
|
|
|
|
|
pduel->game_field->core.select_options.push_back(61);
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::SelectOption>(playerid);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
2022-10-13 19:29:51 +02:00
|
|
|
if(/*bool sel_hint = */lua_get<bool, true>(L, 2)) {
|
|
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto message = pduel->new_message(MSG_HINT);
|
|
|
|
|
message->write<uint8_t>(HINT_OPSELECTED);
|
|
|
|
|
message->write<uint8_t>(playerid);
|
|
|
|
|
message->write<uint64_t>(pduel->game_field->core.select_options[pduel->game_field->returns.at<int32_t>(0)]);
|
|
|
|
|
}
|
|
|
|
|
lua_pushinteger(L, 1 - pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(TossCoin) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto count = lua_get<uint8_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
if((playerid != 0 && playerid != 1) || count <= 0)
|
|
|
|
|
return 0;
|
|
|
|
|
if(count > 5)
|
|
|
|
|
count = 5;
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::TossCoin>(pduel->game_field->core.reason_effect, pduel->game_field->core.reason_player, playerid, count);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
2022-10-13 16:12:52 +02:00
|
|
|
const auto& coin_results = pduel->game_field->core.coin_results;
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(coin_results.size()), nullptr);
|
2024-01-05 15:50:25 +01:00
|
|
|
for(const auto result : coin_results)
|
2022-10-13 16:12:52 +02:00
|
|
|
lua_pushinteger(L, static_cast<int8_t>(result));
|
2023-02-07 16:43:27 +01:00
|
|
|
return static_cast<int32_t>(coin_results.size());
|
2019-06-23 14:15:19 +08:00
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(TossDice) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto count1 = lua_get<uint8_t>(L, 2);
|
2022-10-13 16:12:52 +02:00
|
|
|
if(playerid != 0 && playerid != 1)
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto count2 = lua_get<uint8_t, 0>(L, 3);
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::TossDice>(pduel->game_field->core.reason_effect, pduel->game_field->core.reason_player, playerid, count1, count2);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
2022-10-13 16:12:52 +02:00
|
|
|
const auto& dice_results = pduel->game_field->core.dice_results;
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(dice_results.size()), nullptr);
|
2022-10-13 16:12:52 +02:00
|
|
|
for(const auto& result : dice_results)
|
|
|
|
|
lua_pushinteger(L, result);
|
2023-02-07 16:43:27 +01:00
|
|
|
return static_cast<int32_t>(dice_results.size());
|
2019-06-23 14:15:19 +08:00
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(RockPaperScissors) {
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t repeat = lua_get<bool, true>(L, 1);
|
2024-01-08 20:46:41 +01:00
|
|
|
pduel->game_field->emplace_process<Processors::RockPaperScissors>(repeat);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->returns.at<int32_t>(0));
|
2019-06-23 14:15:19 +08:00
|
|
|
return 1;
|
|
|
|
|
});
|
2017-04-13 22:57:49 +02:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetCoinResult) {
|
2023-11-25 11:15:21 +01:00
|
|
|
const auto& coin_results = pduel->game_field->core.coin_results;
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(coin_results.size()), nullptr);
|
2024-01-05 15:50:25 +01:00
|
|
|
for(const auto coin : coin_results)
|
2022-10-13 16:12:52 +02:00
|
|
|
lua_pushinteger(L, static_cast<int>(coin));
|
2023-02-07 16:43:27 +01:00
|
|
|
return static_cast<int32_t>(coin_results.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetDiceResult) {
|
2023-11-25 11:15:21 +01:00
|
|
|
const auto& dice_results = pduel->game_field->core.dice_results;
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(dice_results.size()), nullptr);
|
2022-10-13 16:12:52 +02:00
|
|
|
for(const auto& dice : dice_results)
|
2020-07-21 16:55:37 +02:00
|
|
|
lua_pushinteger(L, dice);
|
2023-02-07 16:43:27 +01:00
|
|
|
return static_cast<int32_t>(dice_results.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SetCoinResult) {
|
2023-11-25 11:15:21 +01:00
|
|
|
auto& coin_results = pduel->game_field->core.coin_results;
|
2022-10-13 16:12:52 +02:00
|
|
|
if(lua_gettop(L) != (int)coin_results.size())
|
|
|
|
|
lua_error(L, "The number of coin results passed didn't match the expected amount of %d. (Passed %d)", coin_results.size(), lua_gettop(L));
|
|
|
|
|
for(size_t i = 0; i < coin_results.size(); ++i)
|
2023-02-07 16:43:27 +01:00
|
|
|
coin_results[i] = static_cast<bool>(lua_get<uint8_t>(L, static_cast<int>(i + 1)));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SetDiceResult) {
|
2023-11-25 11:15:21 +01:00
|
|
|
auto& dice_results = pduel->game_field->core.dice_results;
|
2022-10-13 16:12:52 +02:00
|
|
|
if(lua_gettop(L) != (int)dice_results.size())
|
|
|
|
|
lua_error(L, "The number of dice results passed didn't match the expected amount of %d. (Passed %d)", dice_results.size(), lua_gettop(L));
|
|
|
|
|
for(size_t i = 0; i < dice_results.size(); ++i)
|
2023-02-07 16:43:27 +01:00
|
|
|
dice_results[i] = lua_get<uint8_t>(L, static_cast<int>(i + 1));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsDuelType) {
|
2016-09-26 20:09:50 +02:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto duel_type = lua_get<uint64_t>(L, 1);
|
2020-07-21 00:08:06 +02:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_flag(duel_type));
|
2016-09-26 20:09:50 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetDuelType) {
|
2023-02-16 16:40:12 -03:00
|
|
|
lua_pushinteger(L, pduel->game_field->core.duel_options);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerAffectedByEffect) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = lua_get<uint32_t>(L, 2);
|
2017-05-02 20:06:41 +02:00
|
|
|
effect* peffect = pduel->game_field->is_player_affected_by_effect(playerid, code);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, peffect);
|
2017-05-02 20:06:41 +02:00
|
|
|
return 1;
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetPlayerEffect) {
|
2017-06-17 22:53:23 +02:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2017-05-02 21:17:15 +02:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = lua_get<uint32_t, 0>(L, 2);
|
2022-10-06 12:24:16 +02:00
|
|
|
effect_set eset;
|
|
|
|
|
pduel->game_field->get_player_effect(playerid, code, &eset);
|
2022-10-06 13:11:11 +02:00
|
|
|
if(eset.empty()) {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(eset.size()), nullptr);
|
2022-10-06 12:24:16 +02:00
|
|
|
for(const auto& peff : eset)
|
|
|
|
|
interpreter::pushobject(L, peff);
|
2023-02-07 16:43:27 +01:00
|
|
|
return static_cast<int32_t>(eset.size());
|
2017-05-02 21:17:15 +02:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanDraw) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
auto count = lua_get<uint32_t, 0>(L, 2);
|
2023-12-21 21:58:07 +01:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_draw(playerid)
|
|
|
|
|
&& (pduel->game_field->player[playerid].list_main.size() >= count));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanDiscardDeck) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto count = lua_get<uint32_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_discard_deck(playerid, count));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanDiscardDeckAsCost) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto count = lua_get<uint32_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_discard_deck_as_cost(playerid, count));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanSummon) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if(lua_gettop(L) == 1)
|
2019-05-07 18:22:32 +09:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_action(playerid, EFFECT_CANNOT_SUMMON));
|
2015-09-25 21:07:16 +08:00
|
|
|
else {
|
|
|
|
|
check_param_count(L, 3);
|
2020-07-21 00:08:06 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint32_t>(L, 2);
|
2018-08-23 20:20:27 +08:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_summon(sumtype, playerid, pcard, playerid));
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CanPlayerSetMonster) {
|
2019-12-02 09:55:51 +09:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2019-12-02 09:55:51 +09:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if(lua_gettop(L) == 1)
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_action(playerid, EFFECT_CANNOT_MSET));
|
|
|
|
|
else {
|
|
|
|
|
check_param_count(L, 3);
|
2020-07-21 00:08:06 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint32_t>(L, 2);
|
2019-12-02 09:55:51 +09:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_mset(sumtype, playerid, pcard, playerid));
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CanPlayerSetSpellTrap) {
|
2019-12-02 09:55:51 +09:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2019-12-02 09:55:51 +09:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if(lua_gettop(L) == 1)
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_action(playerid, EFFECT_CANNOT_SSET));
|
|
|
|
|
else {
|
|
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
2019-12-02 09:55:51 +09:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_sset(playerid, pcard));
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanSpecialSummon) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if(lua_gettop(L) == 1)
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_spsummon(playerid));
|
|
|
|
|
else {
|
|
|
|
|
check_param_count(L, 5);
|
2020-07-21 00:08:06 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 5);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint32_t>(L, 2);
|
|
|
|
|
auto sumpos = lua_get<uint8_t>(L, 3);
|
|
|
|
|
auto toplayer = lua_get<uint8_t>(L, 4);
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_spsummon(pduel->game_field->core.reason_effect, sumtype, sumpos, playerid, toplayer, pcard));
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanFlipSummon) {
|
2019-05-07 18:22:32 +09:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2019-05-07 18:22:32 +09:00
|
|
|
if(lua_gettop(L) == 1)
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_action(playerid, EFFECT_CANNOT_FLIP_SUMMON));
|
|
|
|
|
else {
|
|
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
2019-05-07 18:22:32 +09:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_flipsummon(playerid, pcard));
|
|
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanSpecialSummonMonster) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 9);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = lua_get<uint32_t>(L, 2);
|
2021-11-06 16:23:19 +01:00
|
|
|
card_data dat = pduel->read_card(code);
|
2015-09-25 21:07:16 +08:00
|
|
|
dat.code = code;
|
|
|
|
|
dat.alias = 0;
|
2020-12-26 00:31:31 +01:00
|
|
|
if(!lua_isnoneornil(L, 3)) {
|
2024-01-06 21:52:34 +01:00
|
|
|
lua_iterate_table_or_stack(L, 3, 3, [&setcodes = dat.setcodes, &L]{
|
|
|
|
|
setcodes.insert(lua_get<uint16_t>(L, -1));
|
|
|
|
|
});
|
2020-01-13 20:03:14 +01:00
|
|
|
}
|
2020-12-26 00:31:31 +01:00
|
|
|
if(!lua_isnoneornil(L, 4))
|
2021-09-04 22:04:14 +02:00
|
|
|
dat.type = lua_get<uint32_t>(L, 4);
|
2020-12-26 00:31:31 +01:00
|
|
|
if(!lua_isnoneornil(L, 5))
|
2021-09-04 22:04:14 +02:00
|
|
|
dat.attack = lua_get<int32_t>(L, 5);
|
2020-12-26 00:31:31 +01:00
|
|
|
if(!lua_isnoneornil(L, 6))
|
2021-09-04 22:04:14 +02:00
|
|
|
dat.defense = lua_get<int32_t>(L, 6);
|
2020-12-26 00:31:31 +01:00
|
|
|
if(!lua_isnoneornil(L, 7))
|
2021-09-04 22:04:14 +02:00
|
|
|
dat.level = lua_get<uint32_t>(L, 7);
|
2020-12-26 00:31:31 +01:00
|
|
|
if(!lua_isnoneornil(L, 8))
|
2022-06-11 12:59:38 +02:00
|
|
|
dat.race = lua_get<uint64_t>(L, 8);
|
2020-12-26 00:31:31 +01:00
|
|
|
if(!lua_isnoneornil(L, 9))
|
2021-09-04 22:04:14 +02:00
|
|
|
dat.attribute = lua_get<uint32_t>(L, 9);
|
|
|
|
|
auto pos = lua_get<uint8_t, POS_FACEUP>(L, 10);
|
|
|
|
|
auto toplayer = lua_get<uint8_t>(L, 11, playerid);
|
|
|
|
|
auto sumtype = lua_get<uint32_t, 0>(L, 12);
|
2016-06-30 23:46:47 +09:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_spsummon_monster(playerid, toplayer, pos, sumtype, &dat));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanSpecialSummonCount) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
|
|
|
|
auto count = lua_get<uint32_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_spsummon_count(playerid, count));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanRelease) {
|
2019-05-07 18:22:32 +09:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2019-05-07 18:22:32 +09:00
|
|
|
if(lua_gettop(L) == 1)
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_action(playerid, EFFECT_CANNOT_RELEASE));
|
|
|
|
|
else {
|
|
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
2023-11-12 13:04:20 -03:00
|
|
|
const auto reason = lua_get<uint32_t, REASON_COST>(L, 3);
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_release(playerid, pcard, reason));
|
2019-05-07 18:22:32 +09:00
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanRemove) {
|
2019-05-07 18:22:32 +09:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2019-05-07 18:22:32 +09:00
|
|
|
if(lua_gettop(L) == 1)
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_action(playerid, EFFECT_CANNOT_REMOVE));
|
|
|
|
|
else {
|
|
|
|
|
check_param_count(L, 2);
|
2020-07-21 00:08:06 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto reason = lua_get<uint32_t, REASON_EFFECT>(L, 3);
|
2019-11-29 08:55:07 +09:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_remove(playerid, pcard, reason));
|
2019-05-07 18:22:32 +09:00
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanSendtoHand) {
|
2020-07-21 00:08:06 +02:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2019-05-07 18:22:32 +09:00
|
|
|
if(lua_gettop(L) == 1)
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_action(playerid, EFFECT_CANNOT_TO_HAND));
|
|
|
|
|
else {
|
|
|
|
|
check_param_count(L, 2);
|
2020-07-21 00:08:06 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
2019-05-07 18:22:32 +09:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_send_to_hand(playerid, pcard));
|
|
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanSendtoGrave) {
|
2020-07-21 00:08:06 +02:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2019-05-07 18:22:32 +09:00
|
|
|
if(lua_gettop(L) == 1)
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_action(playerid, EFFECT_CANNOT_TO_GRAVE));
|
|
|
|
|
else {
|
|
|
|
|
check_param_count(L, 2);
|
2020-07-21 00:08:06 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
2019-05-07 18:22:32 +09:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_send_to_grave(playerid, pcard));
|
|
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanSendtoDeck) {
|
2023-06-30 12:52:51 -03:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2019-05-07 18:22:32 +09:00
|
|
|
if(lua_gettop(L) == 1)
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_action(playerid, EFFECT_CANNOT_TO_DECK));
|
|
|
|
|
else {
|
|
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
2019-05-07 18:22:32 +09:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_send_to_deck(playerid, pcard));
|
|
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanAdditionalSummon) {
|
2018-07-18 21:46:32 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2018-07-18 21:46:32 +08:00
|
|
|
if(playerid != 0 && playerid != 1) {
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2020-07-21 15:03:03 +02:00
|
|
|
lua_pushboolean(L, pduel->game_field->core.extra_summon[playerid] == 0);
|
2018-07-18 21:46:32 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-25 11:15:21 +01:00
|
|
|
inline int32_t is_player_can_procedure_summon_group(lua_State* L, uint32_t summon_type, [[maybe_unused]] uint32_t offset) {
|
2021-10-13 17:29:29 +02:00
|
|
|
check_param_count(L, 1);
|
2021-01-21 19:15:31 +01:00
|
|
|
const auto pduel = lua_get<duel*>(L);
|
2021-09-04 22:04:14 +02:00
|
|
|
const auto playerid = lua_get<uint8_t>(L, 1);
|
2021-01-21 19:15:31 +01:00
|
|
|
effect_set eset;
|
|
|
|
|
pduel->game_field->filter_field_effect(EFFECT_SPSUMMON_PROC_G, &eset);
|
|
|
|
|
for(const auto& peff : eset) {
|
|
|
|
|
if(peff->get_value() != summon_type)
|
|
|
|
|
continue;
|
|
|
|
|
card* pcard = peff->get_handler();
|
|
|
|
|
if(pcard->current.controler != playerid && !peff->is_flag(EFFECT_FLAG_BOTH_SIDE))
|
|
|
|
|
continue;
|
|
|
|
|
auto& core = pduel->game_field->core;
|
|
|
|
|
effect* oreason = core.reason_effect;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t op = core.reason_player;
|
2021-01-21 19:15:31 +01:00
|
|
|
core.reason_effect = peff;
|
|
|
|
|
core.reason_player = pcard->current.controler;
|
|
|
|
|
pduel->game_field->save_lp_cost();
|
2023-12-08 19:53:35 +01:00
|
|
|
pduel->lua->add_param<LuaParam::EFFECT>(peff);
|
|
|
|
|
pduel->lua->add_param<LuaParam::CARD>(pcard);
|
|
|
|
|
pduel->lua->add_param<LuaParam::BOOLEAN>(TRUE);
|
|
|
|
|
pduel->lua->add_param<LuaParam::EFFECT>(oreason);
|
|
|
|
|
pduel->lua->add_param<LuaParam::INT>(playerid);
|
2021-01-21 19:15:31 +01:00
|
|
|
if(pduel->lua->check_condition(peff->condition, 5)) {
|
|
|
|
|
pduel->game_field->restore_lp_cost();
|
|
|
|
|
core.reason_effect = oreason;
|
|
|
|
|
core.reason_player = op;
|
|
|
|
|
lua_pushboolean(L, TRUE);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
pduel->game_field->restore_lp_cost();
|
|
|
|
|
core.reason_effect = oreason;
|
|
|
|
|
core.reason_player = op;
|
|
|
|
|
}
|
|
|
|
|
lua_pushboolean(L, FALSE);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanPendulumSummon) {
|
2021-01-21 19:15:31 +01:00
|
|
|
return is_player_can_procedure_summon_group(L, SUMMON_TYPE_PENDULUM, 0);
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsPlayerCanProcedureSummonGroup) {
|
2021-10-13 17:29:29 +02:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint32_t>(L, 2);
|
2021-01-21 19:15:31 +01:00
|
|
|
return is_player_can_procedure_summon_group(L, sumtype, 1);
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsChainNegatable) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2020-04-20 11:50:10 +08:00
|
|
|
lua_pushboolean(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsChainDisablable) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto chaincount = lua_get<uint8_t>(L, 1);
|
2018-07-26 14:49:14 +08:00
|
|
|
if(pduel->game_field->core.chain_solving) {
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->is_chain_disablable(chaincount));
|
|
|
|
|
return 1;
|
2016-12-28 21:53:13 +08:00
|
|
|
}
|
2020-04-20 11:50:10 +08:00
|
|
|
lua_pushboolean(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsChainSolving) {
|
2023-11-25 11:15:21 +01:00
|
|
|
lua_pushboolean(L, pduel->game_field->core.chain_solving);
|
2022-03-04 19:39:59 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CheckChainTarget) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto chaincount = lua_get<uint8_t>(L, 1);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 2);
|
2020-10-30 17:05:28 +01:00
|
|
|
lua_pushboolean(L, pduel->game_field->check_chain_target(chaincount, pcard));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CheckChainUniqueness) {
|
2015-09-25 21:07:16 +08:00
|
|
|
if(pduel->game_field->core.current_chain.size() == 0) {
|
|
|
|
|
lua_pushboolean(L, 1);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
std::set<uint32_t> er;
|
2018-09-03 16:36:45 +08:00
|
|
|
for(const auto& ch : pduel->game_field->core.current_chain)
|
|
|
|
|
er.insert(ch.triggering_effect->get_handler()->get_code());
|
2020-07-21 15:03:03 +02:00
|
|
|
lua_pushboolean(L, er.size() == pduel->game_field->core.current_chain.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetActivityCount) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
2022-10-26 18:13:11 +02:00
|
|
|
auto top = lua_gettop(L);
|
2023-02-07 16:43:27 +01:00
|
|
|
int32_t retct = static_cast<int32_t>(lua_istable(L, 2) ? lua_rawlen(L, 2) : top - 1);
|
2022-10-06 13:11:11 +02:00
|
|
|
luaL_checkstack(L, retct, nullptr);
|
2022-10-26 18:13:11 +02:00
|
|
|
lua_iterate_table_or_stack(L, 2, top, [L, &core = pduel->game_field->core, playerid]() -> int {
|
|
|
|
|
auto activity_type = static_cast<ActivityType>(lua_get<uint8_t>(L, -1));
|
2015-09-25 21:07:16 +08:00
|
|
|
switch(activity_type) {
|
2022-10-26 18:13:11 +02:00
|
|
|
case ACTIVITY_SUMMON:
|
|
|
|
|
lua_pushinteger(L, core.summon_state_count[playerid]);
|
|
|
|
|
break;
|
|
|
|
|
case ACTIVITY_NORMALSUMMON:
|
|
|
|
|
lua_pushinteger(L, core.normalsummon_state_count[playerid]);
|
|
|
|
|
break;
|
|
|
|
|
case ACTIVITY_SPSUMMON:
|
|
|
|
|
lua_pushinteger(L, core.spsummon_state_count[playerid]);
|
|
|
|
|
break;
|
|
|
|
|
case ACTIVITY_FLIPSUMMON:
|
|
|
|
|
lua_pushinteger(L, core.flipsummon_state_count[playerid]);
|
|
|
|
|
break;
|
|
|
|
|
case ACTIVITY_ATTACK:
|
|
|
|
|
lua_pushinteger(L, core.attack_state_count[playerid]);
|
|
|
|
|
break;
|
|
|
|
|
case ACTIVITY_BATTLE_PHASE:
|
|
|
|
|
lua_pushinteger(L, core.battle_phase_count[playerid]);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
lua_error(L, "Passed invalid ACTIVITY flag.");
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2022-10-26 18:13:11 +02:00
|
|
|
return 1;
|
|
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
return retct;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(CheckPhaseActivity) {
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, pduel->game_field->core.phase_action);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(AddCustomActivityCounter) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2022-06-11 12:59:38 +02:00
|
|
|
const auto findex = lua_get<function, true>(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto counter_id = lua_get<uint32_t>(L, 1);
|
2021-09-26 00:21:15 +02:00
|
|
|
auto activity_type = static_cast<ActivityType>(lua_get<uint8_t>(L, 2));
|
2022-06-23 11:47:00 +02:00
|
|
|
if(activity_type == ACTIVITY_BATTLE_PHASE || activity_type > ACTIVITY_CHAIN)
|
|
|
|
|
lua_error(L, "Passed invalid ACTIVITY counter.");
|
2022-06-11 12:59:38 +02:00
|
|
|
int32_t counter_filter = interpreter::get_function_handle(L, findex);
|
2022-03-21 19:06:32 +01:00
|
|
|
auto& counter_map = pduel->game_field->core.get_counter_map(activity_type);
|
2021-09-26 00:21:15 +02:00
|
|
|
if(counter_map.find(counter_id) != counter_map.end())
|
|
|
|
|
return 0;
|
2022-05-14 20:00:15 +02:00
|
|
|
counter_map.emplace(counter_id, processor::action_value_t{ counter_filter, { 0, 0 } });
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetCustomActivityCount) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto counter_id = lua_get<uint32_t>(L, 1);
|
|
|
|
|
auto playerid = lua_get<uint8_t>(L, 2);
|
2021-09-26 00:21:15 +02:00
|
|
|
auto activity_type = static_cast<ActivityType>(lua_get<uint8_t>(L, 3));
|
2022-06-23 11:47:00 +02:00
|
|
|
if(activity_type == ACTIVITY_BATTLE_PHASE || activity_type > ACTIVITY_CHAIN || activity_type == 0)
|
|
|
|
|
lua_error(L, "Passed invalid ACTIVITY counter.");
|
2022-03-21 19:06:32 +01:00
|
|
|
auto& counter_map = pduel->game_field->core.get_counter_map(activity_type);
|
2021-09-26 00:21:15 +02:00
|
|
|
int32_t val = 0;
|
|
|
|
|
auto it = counter_map.find(counter_id);
|
|
|
|
|
if(it != counter_map.end())
|
2022-03-21 19:05:26 +01:00
|
|
|
val = it->second.player_amount[playerid];
|
|
|
|
|
lua_pushinteger(L, val);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2016-06-03 23:20:47 +08:00
|
|
|
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetBattledCount) {
|
2016-06-03 23:20:47 +08:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2016-06-03 23:20:47 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->core.battled_count[playerid]);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsAbleToEnterBP) {
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_able_to_enter_bp());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetRandomNumber) {
|
2020-07-21 00:08:06 +02:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
int32_t min = 0;
|
|
|
|
|
int32_t max = 1;
|
2018-02-01 22:50:41 +01:00
|
|
|
if (lua_gettop(L) > 1) {
|
2021-09-04 22:04:14 +02:00
|
|
|
min = lua_get<uint32_t>(L, 1);
|
|
|
|
|
max = lua_get<uint32_t>(L, 2);
|
2018-02-01 22:50:41 +01:00
|
|
|
} else
|
2021-09-04 22:04:14 +02:00
|
|
|
max = lua_get<uint32_t>(L, 1);
|
2018-02-01 22:50:41 +01:00
|
|
|
lua_pushinteger(L, pduel->get_next_integer(min, max));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(AssumeReset) {
|
2023-11-25 11:15:21 +01:00
|
|
|
pduel->restore_assumes();
|
2021-07-26 19:27:24 +02:00
|
|
|
return 0;
|
2018-02-01 22:50:41 +01:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetCardFromCardID) {
|
2019-03-16 20:12:51 +01:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto id = lua_get<uint32_t>(L, 1);
|
2019-03-16 20:12:51 +01:00
|
|
|
for(auto& pcard : pduel->cards) {
|
2020-03-14 10:38:29 +01:00
|
|
|
if(pcard->cardid == id) {
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pcard);
|
2019-03-16 20:12:51 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(LoadScript) {
|
2020-08-13 01:24:04 +02:00
|
|
|
check_param_count(L, 1);
|
2024-09-21 10:36:53 +02:00
|
|
|
check_param<LuaParam::STRING>(L, 1);
|
2025-07-12 22:28:56 +02:00
|
|
|
size_t len;
|
|
|
|
|
const auto* string = lua_tolstring(L, 1, &len);
|
|
|
|
|
if(len == 0)
|
2023-07-29 13:48:31 +02:00
|
|
|
lua_error(L, "Parameter 1 should be a non empty \"String\".");
|
2025-07-12 22:28:56 +02:00
|
|
|
if(auto begin = string, end = string + len;
|
|
|
|
|
std::find_if(begin, end, [](auto ch) {
|
|
|
|
|
return ch == '/' || ch == '\\';
|
|
|
|
|
}) != end) {
|
|
|
|
|
lua_error(L, "Passed script name containing a path separator");
|
2023-07-29 13:48:31 +02:00
|
|
|
}
|
2020-08-13 01:24:04 +02:00
|
|
|
if(/*auto check_cache = */lua_get<bool, true>(L, 2)) {
|
2025-07-12 22:28:56 +02:00
|
|
|
enum SCRIPT_LOAD_STATUS {
|
|
|
|
|
LOAD_SUCCEDED,
|
|
|
|
|
LOAD_FAILED,
|
|
|
|
|
LOADING,
|
|
|
|
|
};
|
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, pduel->lua->loaded_scripts_table);
|
|
|
|
|
auto table_index = lua_absindex(L, -1);
|
|
|
|
|
lua_pushvalue(L, 1);
|
|
|
|
|
lua_gettable(L, table_index);
|
|
|
|
|
if(lua_isnil(L, -1)) {
|
|
|
|
|
auto set_load_status = [&](auto load_status) {
|
|
|
|
|
lua_pushvalue(L, 1);
|
|
|
|
|
lua_pushinteger(L, load_status);
|
|
|
|
|
lua_settable(L, table_index);
|
|
|
|
|
};
|
|
|
|
|
set_load_status(LOADING);
|
2021-01-07 13:39:12 +01:00
|
|
|
auto res = pduel->read_script(string);
|
2020-08-13 01:24:04 +02:00
|
|
|
lua_pushboolean(L, res);
|
2025-07-12 22:28:56 +02:00
|
|
|
set_load_status(res ? LOAD_SUCCEDED : LOAD_FAILED);
|
|
|
|
|
} else {
|
|
|
|
|
auto load_status = lua_tointeger(L, -1);
|
|
|
|
|
if(load_status == LOADING)
|
|
|
|
|
lua_error(L, "Recursive script loading detected.");
|
|
|
|
|
lua_pushboolean(L, load_status == LOAD_SUCCEDED);
|
2020-08-13 01:24:04 +02:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2021-01-07 13:39:12 +01:00
|
|
|
lua_pushboolean(L, pduel->read_script(string));
|
2020-08-13 01:24:04 +02:00
|
|
|
lua_getglobal(L, "edopro_exports");
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
lua_setglobal(L, "edopro_exports");
|
|
|
|
|
return 2;
|
2019-04-22 01:30:55 +02:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(TagSwap) {
|
2016-11-01 20:10:45 +01:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2017-01-15 15:45:11 +01:00
|
|
|
if (playerid != 0 && playerid != 1)
|
2016-11-01 20:10:45 +01:00
|
|
|
return 0;
|
|
|
|
|
pduel->game_field->tag_swap(playerid);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yield();
|
2016-11-01 20:10:45 +01:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetPlayersCount) {
|
2019-08-22 16:57:28 +02:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2019-08-22 16:57:28 +02:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->get_player_count(playerid));
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(SwapDeckAndGrave) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_action_permission(L);
|
|
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
pduel->game_field->swap_deck_and_grave(playerid);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(MajesticCopy) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 1);
|
|
|
|
|
auto ccard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t resv = 0;
|
|
|
|
|
uint16_t resc = 0;
|
2024-03-01 17:53:08 +01:00
|
|
|
if(check_param<LuaParam::INT, true>(L, 3)) {
|
2021-09-04 22:04:14 +02:00
|
|
|
resv = lua_get<uint32_t>(L, 3);
|
|
|
|
|
resc = lua_get<uint16_t, 1>(L, 4);
|
2017-10-07 20:40:36 +02:00
|
|
|
} else {
|
|
|
|
|
resv = RESET_EVENT + 0x1fe0000 + RESET_PHASE + PHASE_END + RESET_SELF_TURN + RESET_OPPO_TURN;
|
|
|
|
|
resc = 0x1;
|
|
|
|
|
}
|
|
|
|
|
if(resv & (RESET_PHASE) && !(resv & (RESET_SELF_TURN | RESET_OPPO_TURN)))
|
|
|
|
|
resv |= (RESET_SELF_TURN | RESET_OPPO_TURN);
|
2016-05-07 06:13:42 +09:00
|
|
|
for(auto eit = ccard->single_effect.begin(); eit != ccard->field_effect.end(); ++eit) {
|
2015-09-25 21:07:16 +08:00
|
|
|
if(eit == ccard->single_effect.end()) {
|
|
|
|
|
eit = ccard->field_effect.begin();
|
|
|
|
|
if(eit == ccard->field_effect.end())
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
effect* peffect = eit->second;
|
2017-10-07 20:40:36 +02:00
|
|
|
if (!(peffect->type & 0x7c) && !peffect->is_flag(EFFECT_FLAG2_MAJESTIC_MUST_COPY)) continue;
|
2016-03-18 16:14:56 +08:00
|
|
|
if(!peffect->is_flag(EFFECT_FLAG_INITIAL)) continue;
|
2017-10-07 20:40:36 +02:00
|
|
|
effect* ceffect = peffect->clone(true);
|
2015-09-25 21:07:16 +08:00
|
|
|
ceffect->owner = pcard;
|
2015-10-31 15:50:37 +09:00
|
|
|
ceffect->flag[0] &= ~EFFECT_FLAG_INITIAL;
|
2015-09-25 21:07:16 +08:00
|
|
|
ceffect->effect_owner = PLAYER_NONE;
|
2017-10-07 20:40:36 +02:00
|
|
|
ceffect->reset_flag = resv;
|
|
|
|
|
ceffect->reset_count = resc;
|
2015-09-25 21:07:16 +08:00
|
|
|
ceffect->recharge();
|
|
|
|
|
if(ceffect->type & EFFECT_TYPE_TRIGGER_F) {
|
|
|
|
|
ceffect->type &= ~EFFECT_TYPE_TRIGGER_F;
|
|
|
|
|
ceffect->type |= EFFECT_TYPE_TRIGGER_O;
|
2015-10-31 15:50:37 +09:00
|
|
|
ceffect->flag[0] |= EFFECT_FLAG_DELAY;
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
if(ceffect->type & EFFECT_TYPE_QUICK_F) {
|
|
|
|
|
ceffect->type &= ~EFFECT_TYPE_QUICK_F;
|
|
|
|
|
ceffect->type |= EFFECT_TYPE_QUICK_O;
|
|
|
|
|
}
|
|
|
|
|
pcard->add_effect(ceffect);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetStartingHand) {
|
2020-06-26 23:56:52 +02:00
|
|
|
check_param_count(L, 1);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 1);
|
2020-06-26 23:56:52 +02:00
|
|
|
if(playerid != 0 && playerid != 1)
|
|
|
|
|
return 0;
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->player[playerid].start_count);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2025-05-29 22:27:08 +02:00
|
|
|
LUA_STATIC_FUNCTION(GetReasonPlayer) {
|
|
|
|
|
lua_pushinteger(L, pduel->game_field->core.reason_player);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
LUA_STATIC_FUNCTION(GetReasonEffect) {
|
|
|
|
|
interpreter::pushobject(L, pduel->game_field->core.reason_effect);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-31 20:40:42 +02:00
|
|
|
#define INFO_FUNC_FROM_CODE(lua_name,attr) \
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetCard ##lua_name ##FromCode) { \
|
2022-05-31 20:40:42 +02:00
|
|
|
check_param_count(L, 1); \
|
2023-05-16 10:24:28 +02:00
|
|
|
auto code = lua_get<uint32_t>(L, 1); \
|
2023-11-25 11:15:21 +01:00
|
|
|
const auto& data = pduel->read_card(code); \
|
2022-05-31 20:40:42 +02:00
|
|
|
if(data.code == 0) \
|
|
|
|
|
return 0; \
|
|
|
|
|
lua_pushinteger(L, data.attr); \
|
|
|
|
|
return 1; \
|
|
|
|
|
}
|
|
|
|
|
INFO_FUNC_FROM_CODE(Alias, alias)
|
|
|
|
|
INFO_FUNC_FROM_CODE(Type, type)
|
|
|
|
|
INFO_FUNC_FROM_CODE(Level, level)
|
|
|
|
|
INFO_FUNC_FROM_CODE(Attribute, attribute)
|
|
|
|
|
INFO_FUNC_FROM_CODE(Race, race)
|
|
|
|
|
INFO_FUNC_FROM_CODE(Attack, attack)
|
|
|
|
|
INFO_FUNC_FROM_CODE(Defense, defense)
|
|
|
|
|
INFO_FUNC_FROM_CODE(Rscale, rscale)
|
|
|
|
|
INFO_FUNC_FROM_CODE(Lscale, lscale)
|
|
|
|
|
INFO_FUNC_FROM_CODE(LinkMarker, link_marker)
|
|
|
|
|
#undef INFO_FUNC_FROM_CODE
|
|
|
|
|
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(GetCardSetcodeFromCode) {
|
2022-05-31 20:40:42 +02:00
|
|
|
check_param_count(L, 1);
|
|
|
|
|
auto code = lua_get<uint32_t>(L, 1);
|
2023-11-25 11:15:21 +01:00
|
|
|
const auto& data = pduel->read_card(code);
|
2022-05-31 20:40:42 +02:00
|
|
|
if(data.code == 0)
|
|
|
|
|
return 0;
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(data.setcodes.size()), nullptr);
|
2022-05-31 20:40:42 +02:00
|
|
|
for(auto& setcode : data.setcodes)
|
|
|
|
|
lua_pushinteger(L, setcode);
|
2023-02-07 16:43:27 +01:00
|
|
|
return static_cast<int32_t>(data.setcodes.size());
|
2022-05-31 20:40:42 +02:00
|
|
|
}
|
2021-10-13 17:29:29 +02:00
|
|
|
}
|
2025-07-05 19:50:36 +02:00
|
|
|
}
|
2021-10-13 17:29:29 +02:00
|
|
|
|
|
|
|
|
void scriptlib::push_duel_lib(lua_State* L) {
|
2022-05-14 20:25:01 +02:00
|
|
|
static constexpr auto duellib = GET_LUA_FUNCTIONS_ARRAY();
|
2023-11-26 14:47:09 +01:00
|
|
|
static_assert(duellib.back().name == nullptr);
|
2023-02-07 16:43:27 +01:00
|
|
|
lua_createtable(L, 0, static_cast<int>(duellib.size() - 1));
|
2024-04-13 10:34:09 +02:00
|
|
|
ensure_luaL_stack(luaL_setfuncs, L, duellib.data(), 0);
|
2021-10-13 17:29:29 +02:00
|
|
|
lua_setglobal(L, "Duel");
|
|
|
|
|
}
|