2015-09-25 21:07:16 +08:00
|
|
|
/*
|
2024-01-03 01:21:08 +01:00
|
|
|
* Copyright (c) 2010-2015, Argon Sun (Fluorohydride)
|
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
|
|
|
* Copyright (c) 2017-2025, 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-10-06 14:46:28 +02:00
|
|
|
#include <algorithm> //std::any_of, std::max
|
2024-01-05 12:17:47 +01:00
|
|
|
#include <iterator> //std::distance
|
|
|
|
|
#include <set>
|
2015-09-25 21:07:16 +08:00
|
|
|
#include "card.h"
|
2024-01-05 12:17:47 +01:00
|
|
|
#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-15 13:19:29 +02:00
|
|
|
#define LUA_MODULE Card
|
2025-07-05 15:03:10 +02:00
|
|
|
#define LUA_CLASS card
|
2022-05-15 13:19:29 +02:00
|
|
|
#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;
|
|
|
|
|
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetCode) {
|
2018-03-04 18:31:08 +01:00
|
|
|
if (lua_gettop(L) > 1) {
|
2024-01-13 16:10:22 +01:00
|
|
|
card* scard = nullptr;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t playerid = PLAYER_NONE;
|
2022-10-19 15:04:27 +02:00
|
|
|
if (!lua_isnoneornil(L, 2))
|
2020-07-21 01:21:25 +02:00
|
|
|
scard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint64_t, 0>(L, 3);
|
2018-03-04 18:31:08 +01:00
|
|
|
if (lua_gettop(L) > 3)
|
2021-09-04 22:04:14 +02:00
|
|
|
playerid = lua_get<uint8_t>(L, 4);
|
2018-03-04 18:31:08 +01:00
|
|
|
else if (sumtype == SUMMON_TYPE_FUSION)
|
2020-10-30 17:05:28 +01:00
|
|
|
playerid = pduel->game_field->core.reason_player;
|
2022-10-06 13:11:11 +02:00
|
|
|
std::set<uint32_t> codes;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->get_summon_code(codes, scard, sumtype, playerid);
|
2022-10-06 13:11:11 +02:00
|
|
|
if (codes.empty()) {
|
2018-03-04 18:31:08 +01:00
|
|
|
lua_pushnil(L);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(codes.size()), nullptr);
|
2022-10-06 13:11:11 +02:00
|
|
|
for(uint32_t code : codes)
|
|
|
|
|
lua_pushinteger(pduel->lua->current_state, code);
|
2023-02-07 16:43:27 +01:00
|
|
|
return static_cast<int32_t>(codes.size());
|
2018-03-04 18:31:08 +01:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->get_code());
|
|
|
|
|
uint32_t otcode = self->get_another_code();
|
2015-09-25 21:07:16 +08:00
|
|
|
if(otcode) {
|
|
|
|
|
lua_pushinteger(L, otcode);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
// GetOriginalCode(): get the original code printed on card
|
|
|
|
|
// return: 1 int
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOriginalCode) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->data.alias) {
|
|
|
|
|
int32_t dif = self->data.code - self->data.alias;
|
2015-09-25 21:07:16 +08:00
|
|
|
if(dif > -10 && dif < 10)
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->data.alias);
|
2015-09-25 21:07:16 +08:00
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->data.code);
|
2015-09-25 21:07:16 +08:00
|
|
|
} else
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->data.code);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
// GetOriginalCodeRule(): get the original code in duel (can be different from printed code)
|
|
|
|
|
// return: 1-2 int
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOriginalCodeRule) {
|
2015-09-25 21:07:16 +08:00
|
|
|
effect_set eset;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->filter_effect(EFFECT_ADD_CODE, &eset);
|
|
|
|
|
if(self->data.alias && !eset.size())
|
|
|
|
|
lua_pushinteger(L, self->data.alias);
|
2015-09-25 21:07:16 +08:00
|
|
|
else {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->data.code);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(eset.size()) {
|
2023-11-21 11:56:23 +01:00
|
|
|
uint32_t otcode = eset.back()->get_value(self);
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, otcode);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetSetCard) {
|
2022-10-06 13:11:11 +02:00
|
|
|
std::set<uint16_t> setcodes;
|
2018-03-04 18:31:08 +01:00
|
|
|
if (lua_gettop(L) > 1) {
|
2024-01-13 16:10:22 +01:00
|
|
|
card* scard = nullptr;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t playerid = PLAYER_NONE;
|
2022-10-19 15:04:27 +02:00
|
|
|
if (!lua_isnoneornil(L, 2))
|
2020-07-21 01:21:25 +02:00
|
|
|
scard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint64_t, 0>(L, 3);
|
2018-03-04 18:31:08 +01:00
|
|
|
if (lua_gettop(L) > 3)
|
2021-09-04 22:04:14 +02:00
|
|
|
playerid = lua_get<uint8_t>(L, 4);
|
2018-03-04 18:31:08 +01:00
|
|
|
else if (sumtype == SUMMON_TYPE_FUSION)
|
2020-10-30 17:05:28 +01:00
|
|
|
playerid = pduel->game_field->core.reason_player;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->get_summon_set_card(setcodes, scard, sumtype, playerid);
|
2022-10-06 13:11:11 +02:00
|
|
|
} else {
|
2023-11-21 11:56:23 +01:00
|
|
|
self->get_set_card(setcodes);
|
2018-03-04 18:31:08 +01:00
|
|
|
}
|
2022-10-06 13:11:11 +02:00
|
|
|
if (setcodes.empty()) {
|
2017-09-07 02:31:01 +02:00
|
|
|
lua_pushnil(L);
|
|
|
|
|
return 1;
|
2017-09-06 19:18:33 -04:00
|
|
|
}
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(setcodes.size()), nullptr);
|
2022-10-06 13:11:11 +02:00
|
|
|
for(const auto setcode : setcodes)
|
|
|
|
|
lua_pushinteger(L, setcode);
|
2023-02-07 16:43:27 +01:00
|
|
|
return static_cast<int32_t>(setcodes.size());
|
2017-09-06 19:18:33 -04:00
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOriginalSetCard) {
|
2023-11-21 11:56:23 +01:00
|
|
|
const auto& setcodes = self->get_origin_set_card();
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(setcodes.size()), nullptr);
|
2022-10-06 13:11:11 +02:00
|
|
|
for(auto& setcode : setcodes)
|
2020-01-13 20:03:14 +01:00
|
|
|
lua_pushinteger(L, setcode);
|
2023-02-07 16:43:27 +01:00
|
|
|
return static_cast<int32_t>(setcodes.size());
|
2017-09-06 19:18:33 -04:00
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPreviousSetCard) {
|
2022-10-06 13:11:11 +02:00
|
|
|
std::set<uint16_t> setcodes;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->get_pre_set_card(setcodes);
|
2022-10-06 13:11:11 +02:00
|
|
|
if (setcodes.empty()) {
|
2017-09-07 02:31:01 +02:00
|
|
|
lua_pushnil(L);
|
|
|
|
|
return 1;
|
2017-09-06 19:18:33 -04:00
|
|
|
}
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(setcodes.size()), nullptr);
|
2022-10-06 13:11:11 +02:00
|
|
|
for(auto& setcode : setcodes)
|
|
|
|
|
lua_pushinteger(L, setcode);
|
2023-02-07 16:43:27 +01:00
|
|
|
return static_cast<int32_t>(setcodes.size());
|
2017-09-06 19:18:33 -04:00
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetType) {
|
2024-01-13 16:10:22 +01:00
|
|
|
card* scard = nullptr;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t playerid = PLAYER_NONE;
|
2020-12-26 00:31:31 +01:00
|
|
|
if (lua_gettop(L) > 1 && !lua_isnoneornil(L, 2))
|
2020-07-21 01:21:25 +02:00
|
|
|
scard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint64_t, 0>(L, 3);
|
2017-09-07 14:44:18 +02:00
|
|
|
if (lua_gettop(L) > 3)
|
2021-09-04 22:04:14 +02:00
|
|
|
playerid = lua_get<uint8_t>(L, 4);
|
2017-09-07 14:44:18 +02:00
|
|
|
else if (sumtype == SUMMON_TYPE_FUSION)
|
2020-10-30 17:05:28 +01:00
|
|
|
playerid = pduel->game_field->core.reason_player;
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->get_type(scard, sumtype, playerid));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOriginalType) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->data.type);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetLevel) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->get_level());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetRank) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->get_rank());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetLink) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->get_link());
|
2017-03-25 18:06:16 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetSynchroLevel) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto scard = lua_get<card*, true>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->get_synchro_level(scard));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetRitualLevel) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto scard = lua_get<card*, true>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->get_ritual_level(scard));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOriginalLevel) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if((self->data.type & (TYPE_XYZ | TYPE_LINK)) || (self->status & STATUS_NO_LEVEL))
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, 0);
|
|
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->data.level);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOriginalRank) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if(!(self->data.type & TYPE_XYZ))
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, 0);
|
|
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->data.level);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsXyzLevel) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto xyzcard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto lv = lua_get<uint32_t>(L, 3);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->check_xyz_level(xyzcard, lv));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetLeftScale) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->get_lscale());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOriginalLeftScale) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->data.lscale);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetRightScale) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->get_rscale());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOriginalRightScale) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->data.rscale);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetLinkMarker) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->get_link_marker());
|
2018-01-12 18:44:24 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsLinkMarker) {
|
2017-03-25 18:06:16 +09:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto dir = lua_get<uint32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_link_marker(dir));
|
2017-03-25 18:06:16 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetLinkedGroup) {
|
2021-09-04 20:46:43 +02:00
|
|
|
card_set cset;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->get_linked_cards(&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(cset);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2017-03-25 18:06:16 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetLinkedGroupCount) {
|
2021-09-04 20:46:43 +02:00
|
|
|
card_set cset;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->get_linked_cards(&cset);
|
2017-03-25 18:06:16 +09:00
|
|
|
lua_pushinteger(L, cset.size());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetLinkedZone) {
|
2023-11-21 11:56:23 +01:00
|
|
|
uint32_t zone = self->get_linked_zone();
|
|
|
|
|
auto cp = lua_get<uint8_t>(L, 2, self->current.controler);
|
|
|
|
|
if(cp == 1 - self->current.controler)
|
2017-10-16 14:42:37 +08:00
|
|
|
lua_pushinteger(L, (((zone & 0xffff) << 16) | (zone >> 16)));
|
2019-10-17 17:34:08 +02:00
|
|
|
else
|
|
|
|
|
lua_pushinteger(L, zone);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetFreeLinkedZone) {
|
2023-11-21 11:56:23 +01:00
|
|
|
uint32_t zone = self->get_linked_zone(true);
|
|
|
|
|
auto cp = lua_get<uint8_t>(L, 2, self->current.controler);
|
|
|
|
|
if(cp == 1 - self->current.controler)
|
2019-10-17 17:34:08 +02:00
|
|
|
lua_pushinteger(L, (((zone & 0xffff) << 16) | (zone >> 16)));
|
2017-10-16 14:42:37 +08:00
|
|
|
else
|
|
|
|
|
lua_pushinteger(L, zone);
|
2017-03-27 07:51:24 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetMutualLinkedGroup) {
|
2021-09-04 20:46:43 +02:00
|
|
|
card_set cset;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->get_mutual_linked_cards(&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(cset);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2017-07-24 10:46:39 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetMutualLinkedGroupCount) {
|
2021-09-04 20:46:43 +02:00
|
|
|
card_set cset;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->get_mutual_linked_cards(&cset);
|
2017-07-24 10:46:39 +08:00
|
|
|
lua_pushinteger(L, cset.size());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetMutualLinkedZone) {
|
2023-11-21 11:56:23 +01:00
|
|
|
uint32_t zone = self->get_mutual_linked_zone();
|
|
|
|
|
auto cp = lua_get<uint8_t>(L, 2, self->current.controler);
|
|
|
|
|
if(cp == 1 - self->current.controler)
|
2017-10-16 14:42:37 +08:00
|
|
|
lua_pushinteger(L, (((zone & 0xffff) << 16) | (zone >> 16)));
|
|
|
|
|
else
|
|
|
|
|
lua_pushinteger(L, zone);
|
2017-07-24 10:46:39 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsLinked) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_link_state());
|
2017-06-13 22:45:14 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsExtraLinked) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_extra_link_state());
|
2018-04-27 22:17:24 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetColumnGroup) {
|
2021-09-04 22:04:14 +02:00
|
|
|
auto left = lua_get<uint8_t, 0>(L, 2);
|
|
|
|
|
auto right = lua_get<uint8_t, 0>(L, 3);
|
2021-09-04 20:46:43 +02:00
|
|
|
card_set cset;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->get_column_cards(&cset, left, right);
|
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(cset);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2017-07-24 11:46:59 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetColumnGroupCount) {
|
2021-09-04 22:04:14 +02:00
|
|
|
auto left = lua_get<uint8_t, 0>(L, 2);
|
|
|
|
|
auto right = lua_get<uint8_t, 0>(L, 3);
|
2021-09-04 20:46:43 +02:00
|
|
|
card_set cset;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->get_column_cards(&cset, left, right);
|
2017-07-24 11:46:59 +08:00
|
|
|
lua_pushinteger(L, cset.size());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetColumnZone) {
|
2017-09-19 18:22:38 +09:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto loc = lua_get<uint16_t>(L, 2);
|
|
|
|
|
auto left = lua_get<uint8_t, 0>(L, 3);
|
|
|
|
|
auto right = lua_get<uint8_t, 0>(L, 4);
|
2023-11-21 11:56:23 +01:00
|
|
|
auto cp = lua_get<uint8_t>(L, 5, self->current.controler);
|
|
|
|
|
uint32_t zone = self->get_column_zone(loc, left, right);
|
|
|
|
|
if(cp == 1 - self->current.controler)
|
2017-10-16 14:42:37 +08:00
|
|
|
lua_pushinteger(L, (((zone & 0xffff) << 16) | (zone >> 16)));
|
|
|
|
|
else
|
|
|
|
|
lua_pushinteger(L, zone);
|
2017-09-19 18:22:38 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAllColumn) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_all_column());
|
2017-07-24 11:46:59 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetAttribute) {
|
2024-01-13 16:10:22 +01:00
|
|
|
card* scard = nullptr;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t playerid = PLAYER_NONE;
|
2020-12-26 00:31:31 +01:00
|
|
|
if (lua_gettop(L) > 1 && !lua_isnoneornil(L, 2))
|
2020-07-21 01:21:25 +02:00
|
|
|
scard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint64_t, 0>(L, 3);
|
2017-09-07 00:09:10 +02:00
|
|
|
if (lua_gettop(L) > 3)
|
2021-09-04 22:04:14 +02:00
|
|
|
playerid = lua_get<uint8_t>(L, 4);
|
2017-09-07 00:09:10 +02:00
|
|
|
else if (sumtype == SUMMON_TYPE_FUSION)
|
2020-10-30 17:05:28 +01:00
|
|
|
playerid = pduel->game_field->core.reason_player;
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->get_attribute(scard, sumtype, playerid));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOriginalAttribute) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->status & STATUS_NO_LEVEL)
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, 0);
|
|
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->data.attribute);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetRace) {
|
2024-01-13 16:10:22 +01:00
|
|
|
card* scard = nullptr;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t playerid = PLAYER_NONE;
|
2020-12-26 00:31:31 +01:00
|
|
|
if (lua_gettop(L) > 1 && !lua_isnoneornil(L, 2))
|
2020-07-21 01:21:25 +02:00
|
|
|
scard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint64_t, 0>(L, 3);
|
2017-09-07 00:09:10 +02:00
|
|
|
if (lua_gettop(L) > 3)
|
2021-09-04 22:04:14 +02:00
|
|
|
playerid = lua_get<uint8_t>(L, 4);
|
2017-09-07 00:09:10 +02:00
|
|
|
else if (sumtype == SUMMON_TYPE_FUSION)
|
2020-10-30 17:05:28 +01:00
|
|
|
playerid = pduel->game_field->core.reason_player;
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->get_race(scard, sumtype, playerid));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOriginalRace) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->status & STATUS_NO_LEVEL)
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, 0);
|
|
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->data.race);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetAttack) {
|
2024-10-06 14:46:28 +02:00
|
|
|
lua_pushinteger(L, std::max(0, self->get_attack()));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetBaseAttack) {
|
2024-10-06 14:46:28 +02:00
|
|
|
lua_pushinteger(L, std::max(0, self->get_base_attack()));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetTextAttack) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->status & STATUS_NO_LEVEL)
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, 0);
|
|
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->data.attack);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetDefense) {
|
2024-10-06 14:46:28 +02:00
|
|
|
lua_pushinteger(L, std::max(0, self->get_defense()));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetBaseDefense) {
|
2024-10-06 14:46:28 +02:00
|
|
|
lua_pushinteger(L, std::max(0, self->get_base_defense()));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetTextDefense) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->status & STATUS_NO_LEVEL)
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, 0);
|
|
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->data.defense);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPreviousCodeOnField) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->previous.code);
|
|
|
|
|
if(self->previous.code2) {
|
|
|
|
|
lua_pushinteger(L, self->previous.code2);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPreviousTypeOnField) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->previous.type);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPreviousLevelOnField) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->previous.level);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPreviousRankOnField) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->previous.rank);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPreviousAttributeOnField) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->previous.attribute);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPreviousRaceOnField) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->previous.race);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPreviousAttackOnField) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->previous.attack);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPreviousDefenseOnField) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->previous.defense);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOwner) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->owner);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetControler) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->current.controler);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPreviousControler) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->previous.controler);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetReason) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->current.reason);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetReasonCard) {
|
2023-11-21 11:56:23 +01:00
|
|
|
interpreter::pushobject(L, self->current.reason_card);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetReasonPlayer) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->current.reason_player);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetReasonEffect) {
|
2023-11-21 11:56:23 +01:00
|
|
|
interpreter::pushobject(L, self->current.reason_effect);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(SetReason) {
|
2017-11-13 19:22:43 -02:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto reason = lua_get<uint32_t>(L, 2);
|
2020-07-23 23:50:09 +02:00
|
|
|
if (lua_get<bool, false>(L, 3))
|
2023-11-21 11:56:23 +01:00
|
|
|
self->current.reason |= reason;
|
2017-11-13 19:22:43 -02:00
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
self->current.reason = reason;
|
2017-11-13 19:22:43 -02:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(SetReasonCard) {
|
2017-11-13 19:22:43 -02:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto rcard = lua_get<card*, true>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->current.reason_card = rcard;
|
2017-11-13 19:22:43 -02:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(SetReasonPlayer) {
|
2017-11-13 19:22:43 -02:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto rp = lua_get<uint8_t>(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
if (rp <= (unsigned)PLAYER_ALL)
|
2023-11-21 11:56:23 +01:00
|
|
|
self->current.reason_player = rp;
|
2017-11-13 19:22:43 -02:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(SetReasonEffect) {
|
2017-11-13 19:22:43 -02:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto re = lua_get<effect*, true>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->current.reason_effect = re;
|
2017-11-13 19:22:43 -02:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPosition) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->current.position);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPreviousPosition) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->previous.position);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetBattlePosition) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->temp.position);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetLocation) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->get_status(STATUS_SUMMONING | STATUS_SUMMON_DISABLED | STATUS_ACTIVATE_DISABLED | STATUS_SPSUMMON_STEP))
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, 0);
|
|
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->current.location);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPreviousLocation) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->previous.location);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetSequence) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->current.sequence);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPreviousSequence) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->previous.sequence);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetSummonType) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->summon.type & 0xff00ffff);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetSummonLocation) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->summon.location);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetSummonPlayer) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->summon.player);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetDestination) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->sendto_param.location);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetLeaveFieldDest) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->leave_field_redirect(REASON_EFFECT));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetTurnID) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->turnid);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetFieldID) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->fieldid);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetRealFieldID) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->fieldid_r);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetCardID) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->cardid);
|
2020-03-14 10:38:29 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsOriginalCodeRule) {
|
2019-03-30 09:56:54 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t code1 = 0;
|
|
|
|
|
uint32_t code2 = 0;
|
2019-03-30 09:56:54 +08:00
|
|
|
effect_set eset;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->filter_effect(EFFECT_ADD_CODE, &eset);
|
|
|
|
|
if(self->data.alias && !eset.size()){
|
|
|
|
|
code1 = self->data.alias;
|
2019-03-30 09:56:54 +08:00
|
|
|
code2 = 0;
|
2020-07-21 15:03:03 +02:00
|
|
|
} else {
|
2023-11-21 11:56:23 +01:00
|
|
|
code1 = self->data.code;
|
2019-03-30 09:56:54 +08:00
|
|
|
if(eset.size())
|
2023-11-21 11:56:23 +01:00
|
|
|
code2 = eset.back()->get_value(self);
|
2019-03-30 09:56:54 +08:00
|
|
|
}
|
2022-10-26 18:13:11 +02:00
|
|
|
bool found = lua_find_in_table_or_in_stack(L, 2, lua_gettop(L), [L, code1, code2] {
|
|
|
|
|
if(lua_isnoneornil(L, -1))
|
|
|
|
|
return false;
|
|
|
|
|
uint32_t tcode = lua_get<uint32_t>(L, -1);
|
|
|
|
|
return code1 == tcode || (code2 && code2 == tcode);
|
|
|
|
|
});
|
|
|
|
|
lua_pushboolean(L, found);
|
2022-10-19 14:37:41 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
LUA_FUNCTION(IsOriginalCode) {
|
|
|
|
|
check_param_count(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
const auto original_code = [self]() {
|
|
|
|
|
if(self->data.alias) {
|
|
|
|
|
int32_t dif = self->data.code - self->data.alias;
|
2022-10-19 14:37:41 +02:00
|
|
|
if(dif > -10 && dif < 10)
|
2023-11-21 11:56:23 +01:00
|
|
|
return self->data.alias;
|
2022-10-19 14:37:41 +02:00
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
return self->data.code;
|
2022-10-19 14:37:41 +02:00
|
|
|
} else
|
2023-11-21 11:56:23 +01:00
|
|
|
return self->data.code;
|
2022-10-19 14:37:41 +02:00
|
|
|
}();
|
2022-10-26 18:13:11 +02:00
|
|
|
bool found = lua_find_in_table_or_in_stack(L, 2, lua_gettop(L), [L, original_code] {
|
|
|
|
|
if(lua_isnoneornil(L, -1))
|
|
|
|
|
return false;
|
|
|
|
|
return original_code == lua_get<uint32_t>(L, -1);
|
|
|
|
|
});
|
|
|
|
|
lua_pushboolean(L, found);
|
2019-03-30 09:56:54 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsCode) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
uint32_t code1 = self->get_code();
|
|
|
|
|
uint32_t code2 = self->get_another_code();
|
2022-10-26 18:13:11 +02:00
|
|
|
bool found = lua_find_in_table_or_in_stack(L, 2, lua_gettop(L), [L, code1, code2] {
|
|
|
|
|
if(lua_isnoneornil(L, -1))
|
|
|
|
|
return false;
|
|
|
|
|
uint32_t tcode = lua_get<uint32_t>(L, -1);
|
|
|
|
|
return code1 == tcode || (code2 && code2 == tcode);
|
|
|
|
|
});
|
|
|
|
|
lua_pushboolean(L, found);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsSummonCode) {
|
2018-03-04 18:11:19 +01:00
|
|
|
check_param_count(L, 5);
|
2020-10-30 17:05:28 +01:00
|
|
|
auto scard = lua_get<card*>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint64_t>(L, 3);
|
|
|
|
|
auto playerid = lua_get<uint8_t, PLAYER_NONE>(L, 4);
|
2020-10-30 17:05:28 +01:00
|
|
|
effect_set eset;
|
2021-09-04 22:04:14 +02:00
|
|
|
std::set<uint32_t> codes;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->filter_effect(EFFECT_ADD_CODE, &eset, FALSE);
|
|
|
|
|
self->filter_effect(EFFECT_REMOVE_CODE, &eset, FALSE);
|
|
|
|
|
self->filter_effect(EFFECT_CHANGE_CODE, &eset);
|
|
|
|
|
uint32_t code1 = self->get_code();
|
|
|
|
|
uint32_t code2 = self->get_another_code();
|
2018-03-04 18:11:19 +01:00
|
|
|
codes.insert(code1);
|
|
|
|
|
if (code2)
|
|
|
|
|
codes.insert(code2);
|
2020-07-21 16:41:40 +02:00
|
|
|
for (const auto& peff : eset) {
|
|
|
|
|
if (!peff->operation)
|
2018-03-04 18:11:19 +01:00
|
|
|
continue;
|
2023-12-08 19:53:35 +01:00
|
|
|
pduel->lua->add_param<LuaParam::CARD>(scard);
|
|
|
|
|
pduel->lua->add_param<LuaParam::INT>(sumtype);
|
|
|
|
|
pduel->lua->add_param<LuaParam::INT>(playerid);
|
2020-07-21 16:41:40 +02:00
|
|
|
if (!pduel->lua->check_condition(peff->operation, 3))
|
2018-03-04 18:11:19 +01:00
|
|
|
continue;
|
2020-07-21 16:41:40 +02:00
|
|
|
if (peff->code == EFFECT_ADD_CODE)
|
2023-11-21 11:56:23 +01:00
|
|
|
codes.insert(peff->get_value(self));
|
2020-07-21 16:41:40 +02:00
|
|
|
else if (peff->code == EFFECT_REMOVE_CODE) {
|
2023-11-21 11:56:23 +01:00
|
|
|
auto cit = codes.find(peff->get_value(self));
|
2018-03-04 18:11:19 +01:00
|
|
|
if (cit != codes.end())
|
|
|
|
|
codes.erase(cit);
|
|
|
|
|
} else {
|
|
|
|
|
codes.clear();
|
2023-11-21 11:56:23 +01:00
|
|
|
codes.insert(peff->get_value(self));
|
2018-03-04 18:11:19 +01:00
|
|
|
}
|
|
|
|
|
}
|
2022-10-26 18:13:11 +02:00
|
|
|
bool found = lua_find_in_table_or_in_stack(L, 5, lua_gettop(L), [L, &codes] {
|
|
|
|
|
if(lua_isnoneornil(L, -1))
|
|
|
|
|
return false;
|
|
|
|
|
uint32_t tcode = lua_get<uint32_t>(L, -1);
|
|
|
|
|
return codes.find(tcode) != codes.end();
|
|
|
|
|
});
|
|
|
|
|
lua_pushboolean(L, found);
|
2018-03-04 18:11:19 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-03-15 22:07:31 +01:00
|
|
|
inline bool set_contains_setcode(const std::set<uint16_t>& setcodes, uint16_t to_match_setcode) {
|
|
|
|
|
return std::any_of(setcodes.cbegin(), setcodes.cend(), [to_match_setcode](uint16_t setcode) {
|
|
|
|
|
return card::match_setcode(to_match_setcode, setcode);
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsSetCard) {
|
2018-03-04 18:11:19 +01:00
|
|
|
check_param_count(L, 2);
|
2022-10-26 18:13:11 +02:00
|
|
|
std::set<uint16_t> setcodes;
|
2018-03-04 18:11:19 +01:00
|
|
|
if (lua_gettop(L) > 2) {
|
2024-01-13 16:10:22 +01:00
|
|
|
card* scard = nullptr;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t playerid = PLAYER_NONE;
|
2022-10-19 15:04:27 +02:00
|
|
|
if (!lua_isnoneornil(L, 3))
|
2020-07-21 01:21:25 +02:00
|
|
|
scard = lua_get<card*, true>(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint64_t, 0>(L, 4);
|
|
|
|
|
playerid = lua_get<uint8_t, PLAYER_NONE>(L, 5);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->get_summon_set_card(setcodes, scard, sumtype, playerid);
|
2018-03-04 18:11:19 +01:00
|
|
|
} else
|
2023-11-21 11:56:23 +01:00
|
|
|
self->get_set_card(setcodes);
|
2022-10-26 18:13:11 +02:00
|
|
|
bool found = lua_find_in_table_or_in_stack(L, 2, 2, [L, &setcodes] {
|
2023-03-15 22:07:31 +01:00
|
|
|
return set_contains_setcode(setcodes, lua_get<uint16_t>(L, -1));
|
2022-10-26 18:13:11 +02:00
|
|
|
});
|
|
|
|
|
lua_pushboolean(L, found);
|
2018-03-04 18:11:19 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsOriginalSetCard) {
|
2018-03-04 18:11:19 +01:00
|
|
|
check_param_count(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
const auto& setcodes = self->get_origin_set_card();
|
2022-10-26 18:13:11 +02:00
|
|
|
bool found = lua_find_in_table_or_in_stack(L, 2, lua_gettop(L), [L, &setcodes] {
|
2023-03-15 22:07:31 +01:00
|
|
|
return set_contains_setcode(setcodes, lua_get<uint16_t>(L, -1));
|
2022-10-26 18:13:11 +02:00
|
|
|
});
|
|
|
|
|
lua_pushboolean(L, found);
|
2018-03-04 18:11:19 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsPreviousSetCard) {
|
2018-03-04 18:11:19 +01:00
|
|
|
check_param_count(L, 2);
|
2022-10-26 18:13:11 +02:00
|
|
|
std::set<uint16_t> setcodes;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->get_pre_set_card(setcodes);
|
2022-10-26 18:13:11 +02:00
|
|
|
bool found = lua_find_in_table_or_in_stack(L, 2, 2, [L, &setcodes] {
|
2023-03-15 22:07:31 +01:00
|
|
|
return set_contains_setcode(setcodes, lua_get<uint16_t>(L, -1));
|
2022-10-26 18:13:11 +02:00
|
|
|
});
|
|
|
|
|
lua_pushboolean(L, found);
|
2018-03-04 18:11:19 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsType) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto ttype = lua_get<uint32_t>(L, 2);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* scard = nullptr;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t playerid = PLAYER_NONE;
|
2020-12-26 00:31:31 +01:00
|
|
|
if (lua_gettop(L) > 2 && !lua_isnoneornil(L, 3))
|
2020-07-21 01:21:25 +02:00
|
|
|
scard = lua_get<card*, true>(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint64_t, 0>(L, 4);
|
2017-09-07 14:44:18 +02:00
|
|
|
if (lua_gettop(L) > 4)
|
2021-09-04 22:04:14 +02:00
|
|
|
playerid = lua_get<uint8_t>(L, 5);
|
2017-09-07 14:44:18 +02:00
|
|
|
else if (sumtype == SUMMON_TYPE_FUSION)
|
2020-10-30 17:05:28 +01:00
|
|
|
playerid = pduel->game_field->core.reason_player;
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->get_type(scard, sumtype, playerid) & ttype);
|
2017-06-27 20:32:13 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-10-19 14:37:41 +02:00
|
|
|
LUA_FUNCTION(IsExactType) {
|
|
|
|
|
check_param_count(L, 2);
|
|
|
|
|
auto ttype = lua_get<uint32_t>(L, 2);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* scard = nullptr;
|
2022-10-19 14:37:41 +02:00
|
|
|
uint8_t playerid = PLAYER_NONE;
|
|
|
|
|
if (lua_gettop(L) > 2 && !lua_isnoneornil(L, 3))
|
|
|
|
|
scard = lua_get<card*, true>(L, 3);
|
|
|
|
|
auto sumtype = lua_get<uint64_t, 0>(L, 4);
|
|
|
|
|
if (lua_gettop(L) > 4)
|
|
|
|
|
playerid = lua_get<uint8_t>(L, 5);
|
|
|
|
|
else if (sumtype == SUMMON_TYPE_FUSION)
|
|
|
|
|
playerid = pduel->game_field->core.reason_player;
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, (self->get_type(scard, sumtype, playerid) & ttype) == ttype);
|
2022-10-19 14:37:41 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
LUA_FUNCTION(IsOriginalType) {
|
|
|
|
|
check_param_count(L, 2);
|
|
|
|
|
auto ttype = lua_get<uint32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, (self->data.type & ttype) != 0);
|
2022-10-19 14:37:41 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
inline int32_t is_prop(lua_State* L, uint32_t val) {
|
2022-10-26 18:13:11 +02:00
|
|
|
bool found = lua_find_in_table_or_in_stack(L, 2, lua_gettop(L), [L, val] {
|
|
|
|
|
if(lua_isnoneornil(L, -1))
|
|
|
|
|
return false;
|
|
|
|
|
return val == lua_get<uint32_t>(L, -1);
|
|
|
|
|
});
|
|
|
|
|
lua_pushboolean(L, found);
|
2017-09-08 15:15:26 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsLevel) {
|
2020-07-21 15:03:03 +02:00
|
|
|
check_param_count(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
return is_prop(L, self->get_level());
|
2020-07-21 15:03:03 +02:00
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsRank) {
|
2017-09-08 15:15:26 +02:00
|
|
|
check_param_count(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
return is_prop(L, self->get_rank());
|
2017-09-08 15:15:26 +02:00
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsLink) {
|
2017-09-08 15:15:26 +02:00
|
|
|
check_param_count(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
return is_prop(L, self->get_link());
|
2017-10-10 14:28:49 +02:00
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAttack) {
|
2018-05-23 07:26:29 +09:00
|
|
|
check_param_count(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
if(!(self->data.type & TYPE_MONSTER) && !(self->get_type() & TYPE_MONSTER) && !self->is_affected_by_effect(EFFECT_PRE_MONSTER))
|
2018-05-23 07:26:29 +09:00
|
|
|
lua_pushboolean(L, 0);
|
2020-07-21 15:03:03 +02:00
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
is_prop(L, self->get_attack());
|
2018-05-23 07:26:29 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsDefense) {
|
2018-05-23 07:26:29 +09:00
|
|
|
check_param_count(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
if((self->data.type & TYPE_LINK)
|
|
|
|
|
|| (!(self->data.type & TYPE_MONSTER) && !(self->get_type() & TYPE_MONSTER) && !self->is_affected_by_effect(EFFECT_PRE_MONSTER)))
|
2017-09-08 15:15:26 +02:00
|
|
|
lua_pushboolean(L, 0);
|
2020-07-21 15:03:03 +02:00
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
is_prop(L, self->get_defense());
|
2017-09-08 15:15:26 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsRace) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2022-09-03 22:45:49 +02:00
|
|
|
auto trace = lua_get<uint64_t>(L, 2);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* scard = nullptr;
|
2020-07-21 01:21:25 +02:00
|
|
|
auto playerid = PLAYER_NONE;
|
2020-12-26 00:31:31 +01:00
|
|
|
if(lua_gettop(L) > 2 && !lua_isnoneornil(L, 3))
|
2020-07-21 01:21:25 +02:00
|
|
|
scard = lua_get<card*, true>(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint64_t, 0>(L, 4);
|
2017-09-07 00:09:10 +02:00
|
|
|
if(lua_gettop(L) > 4)
|
2021-09-04 22:04:14 +02:00
|
|
|
playerid = lua_get<uint8_t>(L, 5);
|
2017-09-07 00:09:10 +02:00
|
|
|
else if(sumtype==SUMMON_TYPE_FUSION)
|
2020-10-30 17:05:28 +01:00
|
|
|
playerid = pduel->game_field->core.reason_player;
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, (self->get_race(scard, sumtype, playerid) & trace) != 0);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-10-19 14:37:41 +02:00
|
|
|
LUA_FUNCTION(IsOriginalRace) {
|
|
|
|
|
check_param_count(L, 2);
|
|
|
|
|
auto trace = lua_get<uint64_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->status & STATUS_NO_LEVEL)
|
2022-10-19 14:37:41 +02:00
|
|
|
lua_pushboolean(L, FALSE);
|
|
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, (self->data.race & trace) != 0);
|
2022-10-19 14:37:41 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAttribute) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto tattrib = lua_get<uint32_t>(L, 2);
|
2024-01-13 16:10:22 +01:00
|
|
|
card* scard = nullptr;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t playerid = PLAYER_NONE;
|
2020-12-26 00:31:31 +01:00
|
|
|
if(lua_gettop(L) > 2 && !lua_isnoneornil(L, 3))
|
2020-07-21 01:21:25 +02:00
|
|
|
scard = lua_get<card*, true>(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint64_t, 0>(L, 4);
|
2017-09-07 00:09:10 +02:00
|
|
|
if(lua_gettop(L) > 4)
|
2021-09-04 22:04:14 +02:00
|
|
|
playerid = lua_get<uint8_t>(L, 5);
|
2017-09-07 00:09:10 +02:00
|
|
|
else if(sumtype==SUMMON_TYPE_FUSION)
|
2020-10-30 17:05:28 +01:00
|
|
|
playerid = pduel->game_field->core.reason_player;
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->get_attribute(scard, sumtype, playerid) & tattrib);
|
2016-11-15 18:27:37 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-10-19 14:37:41 +02:00
|
|
|
LUA_FUNCTION(IsOriginalAttribute) {
|
|
|
|
|
check_param_count(L, 2);
|
|
|
|
|
auto tattrib = lua_get<uint32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->status & STATUS_NO_LEVEL)
|
2022-10-19 14:37:41 +02:00
|
|
|
lua_pushboolean(L, FALSE);
|
|
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, (self->data.attribute & tattrib) != 0);
|
2022-10-19 14:37:41 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsReason) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto treason = lua_get<uint32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, (self->current.reason & treason) != 0);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsSummonType) {
|
2017-06-12 21:53:25 +08:00
|
|
|
check_param_count(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
bool found = lua_find_in_table_or_in_stack(L, 2, lua_gettop(L), [L, summon_info = self->summon.type & 0xff00ffff] {
|
2022-10-26 18:13:11 +02:00
|
|
|
if(lua_isnoneornil(L, -1))
|
|
|
|
|
return false;
|
|
|
|
|
auto ttype = lua_get<uint32_t>(L, -1);
|
|
|
|
|
return (summon_info & ttype) == ttype;
|
|
|
|
|
});
|
|
|
|
|
lua_pushboolean(L, found);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-10-19 14:37:41 +02:00
|
|
|
LUA_FUNCTION(IsSummonLocation) {
|
2022-10-30 11:08:18 +01:00
|
|
|
auto loc = lua_get<uint16_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, card_state::is_location(self->summon, loc));
|
2022-10-19 14:37:41 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
LUA_FUNCTION(IsSummonPlayer) {
|
|
|
|
|
auto player = lua_get<uint8_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->summon.player == player);
|
2022-10-19 14:37:41 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsStatus) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto tstatus = lua_get<uint32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, (self->status & tstatus) != 0);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsNotTuner) {
|
2017-09-06 17:46:04 +02:00
|
|
|
check_param_count(L, 3);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto scard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 3);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_not_tuner(scard, playerid));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(SetStatus) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->status & STATUS_COPYING_EFFECT)
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto tstatus = lua_get<uint32_t>(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto enable = lua_get<bool>(L, 3);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->set_status(tstatus, enable);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsGeminiState) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, !!self->is_affected_by_effect(EFFECT_GEMINI_STATUS));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(EnableGeminiState) {
|
2015-09-25 21:07:16 +08:00
|
|
|
effect* deffect = pduel->new_effect();
|
2023-11-21 11:56:23 +01:00
|
|
|
deffect->owner = self;
|
2019-07-28 17:16:09 -03:00
|
|
|
deffect->code = EFFECT_GEMINI_STATUS;
|
2015-09-25 21:07:16 +08:00
|
|
|
deffect->type = EFFECT_TYPE_SINGLE;
|
2019-08-06 12:16:05 +09:00
|
|
|
deffect->flag[0] = EFFECT_FLAG_CANNOT_DISABLE | EFFECT_FLAG_CLIENT_HINT;
|
|
|
|
|
deffect->description = 64;
|
2015-09-25 21:07:16 +08:00
|
|
|
deffect->reset_flag = RESET_EVENT + 0x1fe0000;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->add_effect(deffect);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(SetTurnCounter) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto ct = lua_get<uint16_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->count_turn(ct);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetTurnCounter) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->turn_counter);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(SetMaterial) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2023-12-03 11:34:38 +01:00
|
|
|
if(auto [pcard, pgroup] = lua_get_card_or_group<true>(L, 2); pcard) {
|
2023-11-26 15:11:50 +01:00
|
|
|
self->set_material({ pcard });
|
|
|
|
|
} else if(pgroup) {
|
|
|
|
|
self->set_material(pgroup->container);
|
|
|
|
|
} else {
|
|
|
|
|
self->set_material({});
|
|
|
|
|
}
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetMaterial) {
|
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(self->material_cards);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetMaterialCount) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->material_cards.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetEquipGroup) {
|
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(self->equiping_cards);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetEquipCount) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->equiping_cards.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetEquipTarget) {
|
2023-11-21 11:56:23 +01:00
|
|
|
interpreter::pushobject(L, self->equiping_target);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetPreviousEquipTarget) {
|
2023-11-21 11:56:23 +01:00
|
|
|
interpreter::pushobject(L, self->pre_equip_target);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CheckEquipTarget) {
|
2020-07-21 01:21:25 +02:00
|
|
|
auto target = lua_get<card*, true>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->is_affected_by_effect(EFFECT_EQUIP_LIMIT, target)
|
|
|
|
|
&& ((!self->is_affected_by_effect(EFFECT_OLDUNION_STATUS) || target->get_union_count() == 0)
|
|
|
|
|
&& (!self->is_affected_by_effect(EFFECT_UNION_STATUS) || target->get_old_union_count() == 0)))
|
2020-06-27 22:18:37 +08:00
|
|
|
lua_pushboolean(L, 1);
|
|
|
|
|
else
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CheckUnionTarget) {
|
2020-07-21 01:21:25 +02:00
|
|
|
auto target = lua_get<card*, true>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->is_affected_by_effect(EFFECT_UNION_LIMIT, target)
|
|
|
|
|
&& ((!self->is_affected_by_effect(EFFECT_OLDUNION_STATUS) || target->get_union_count() == 0)
|
|
|
|
|
&& (!self->is_affected_by_effect(EFFECT_UNION_STATUS) || target->get_old_union_count() == 0)))
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, 1);
|
|
|
|
|
else
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetUnionCount) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->get_union_count());
|
|
|
|
|
lua_pushinteger(L, self->get_old_union_count());
|
2016-09-17 14:59:30 +08:00
|
|
|
return 2;
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOverlayGroup) {
|
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(self->xyz_materials);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOverlayCount) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->xyz_materials.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOverlayTarget) {
|
2023-11-21 11:56:23 +01:00
|
|
|
interpreter::pushobject(L, self->overlay_target);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CheckRemoveOverlayCard) {
|
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, 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<uint16_t>(L, 3);
|
|
|
|
|
auto reason = lua_get<uint32_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(self);
|
2018-10-25 22:36:33 +02:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_remove_overlay_card(playerid, pgroup, 0, 0, count, reason));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(RemoveOverlayCard) {
|
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, 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 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(self);
|
2018-10-25 22:36:33 +02:00
|
|
|
pduel->game_field->remove_overlay_card(reason, pgroup, playerid, 0, 0, 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
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetAttackedGroup) {
|
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();
|
2023-11-21 11:56:23 +01:00
|
|
|
for(auto& cit : self->attacked_cards) {
|
2018-09-03 16:36:45 +08:00
|
|
|
if(cit.second.first)
|
|
|
|
|
pgroup->container.insert(cit.second.first);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetAttackedGroupCount) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->attacked_cards.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetAttackedCount) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->attacked_count);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetBattledGroup) {
|
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();
|
2023-11-21 11:56:23 +01:00
|
|
|
for(auto& cit : self->battled_cards) {
|
2018-09-03 16:36:45 +08:00
|
|
|
if(cit.second.first)
|
|
|
|
|
pgroup->container.insert(cit.second.first);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetBattledGroupCount) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->battled_cards.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetAttackAnnouncedCount) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->attack_announce_count);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsDirectAttacked) {
|
2024-01-13 16:10:22 +01:00
|
|
|
lua_pushboolean(L, self->attacked_cards.findcard(nullptr));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(SetCardTarget) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto ocard = lua_get<card*, true>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->add_card_target(ocard);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetCardTarget) {
|
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(self->effect_target_cards);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetFirstCardTarget) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->effect_target_cards.size())
|
|
|
|
|
interpreter::pushobject(L, *self->effect_target_cards.begin());
|
2015-09-25 21:07:16 +08:00
|
|
|
else lua_pushnil(L);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetCardTargetCount) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->effect_target_cards.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsHasCardTarget) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto rcard = lua_get<card*, true>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->effect_target_cards.find(rcard) != self->effect_target_cards.end());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CancelCardTarget) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto rcard = lua_get<card*, true>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->cancel_card_target(rcard);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOwnerTarget) {
|
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(self->effect_target_owner);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pgroup);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetOwnerTargetCount) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->effect_target_owner.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetActivateEffect) {
|
2022-10-06 13:11:11 +02:00
|
|
|
effect_set eset;
|
2023-11-21 11:56:23 +01:00
|
|
|
for(auto& eit : self->field_effect) {
|
2022-10-06 13:11:11 +02:00
|
|
|
if(eit.second->type & EFFECT_TYPE_ACTIVATE)
|
|
|
|
|
eset.push_back(eit.second);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(eset.size()), nullptr);
|
2022-10-06 13:11:11 +02:00
|
|
|
for(const auto& peffect : eset)
|
|
|
|
|
interpreter::pushobject(L, peffect);
|
2023-02-07 16:43:27 +01:00
|
|
|
return static_cast<int32_t>(eset.size());
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CheckActivateEffect) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 4);
|
2020-07-23 23:50:09 +02:00
|
|
|
bool neglect_con = lua_get<bool>(L, 2);
|
|
|
|
|
bool neglect_cost = lua_get<bool>(L, 3);
|
|
|
|
|
bool copy_info = lua_get<bool>(L, 4);
|
2015-09-25 21:07:16 +08:00
|
|
|
tevent pe;
|
2023-11-21 11:56:23 +01:00
|
|
|
for(const auto& eit : self->field_effect) {
|
2020-10-30 17:05:28 +01:00
|
|
|
effect* peffect = eit.second;
|
2015-09-25 21:07:16 +08:00
|
|
|
if((peffect->type & EFFECT_TYPE_ACTIVATE)
|
|
|
|
|
&& pduel->game_field->check_event_c(peffect, pduel->game_field->core.reason_player, neglect_con, neglect_cost, copy_info, &pe)) {
|
|
|
|
|
if(!copy_info || (peffect->code == EVENT_FREE_CHAIN)) {
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, peffect);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
} else {
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, peffect);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_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, 2);
|
2020-10-30 16:51:01 +01:00
|
|
|
bool forced = lua_get<bool, false>(L, 3);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(peffect->owner == pduel->game_field->temp_card)
|
|
|
|
|
return 0;
|
2023-11-21 11:56:23 +01:00
|
|
|
if(!forced && pduel->game_field->core.reason_effect && !self->is_affect_by_effect(pduel->game_field->core.reason_effect)) {
|
2015-09-25 21:07:16 +08:00
|
|
|
pduel->game_field->core.reseted_effects.insert(peffect);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
int32_t id = -1;
|
2020-07-23 23:50:09 +02:00
|
|
|
if (!peffect->handler)
|
2023-11-21 11:56:23 +01:00
|
|
|
id = self->add_effect(peffect);
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, id);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsHasEffect) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = lua_get<uint32_t>(L, 2);
|
2017-11-18 12:00:25 +09:00
|
|
|
effect_set eset;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->filter_effect(code, &eset);
|
2023-02-07 16:43:27 +01:00
|
|
|
auto size = eset.size();
|
2017-11-18 12:00:25 +09:00
|
|
|
if(!size) {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
auto check_player = lua_get<uint8_t, PLAYER_NONE>(L, 3);
|
2023-02-07 16:43:27 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(eset.size()), nullptr); // we waste a bit of stack space but keeps checking simple
|
2020-07-21 16:41:40 +02:00
|
|
|
for(const auto& peff : eset) {
|
|
|
|
|
if(check_player == PLAYER_NONE || peff->check_count_limit(check_player))
|
|
|
|
|
interpreter::pushobject(L, peff);
|
2019-03-05 14:50:22 +08:00
|
|
|
else
|
2022-03-05 13:56:43 +01:00
|
|
|
--size;
|
2019-03-05 14:50:22 +08:00
|
|
|
}
|
|
|
|
|
if(!size) {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2023-02-07 16:43:27 +01:00
|
|
|
return static_cast<int32_t>(size);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetCardEffect) {
|
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;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->get_card_effect(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-04-08 17:55:17 +02:00
|
|
|
}
|
2024-07-09 20:54:03 +02:00
|
|
|
LUA_FUNCTION(GetOwnEffects) {
|
|
|
|
|
effect_set eset;
|
|
|
|
|
self->get_own_effects(&eset);
|
|
|
|
|
if(eset.empty())
|
|
|
|
|
return 0;
|
|
|
|
|
luaL_checkstack(L, static_cast<int>(eset.size()), nullptr);
|
|
|
|
|
for(const auto& peff : eset)
|
|
|
|
|
interpreter::pushobject(L, peff);
|
|
|
|
|
return static_cast<int32_t>(eset.size());
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(ResetEffect) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = lua_get<uint32_t>(L, 2);
|
|
|
|
|
auto type = lua_get<uint32_t>(L, 3);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->reset(code, type);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetEffectCount) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = lua_get<uint32_t>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
effect_set eset;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->filter_effect(code, &eset);
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, eset.size());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(RegisterFlagEffect) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 5);
|
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);
|
2022-04-25 10:33:01 +02:00
|
|
|
auto lab = lua_get<lua_Integer, 0>(L, 6);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto desc = lua_get<uint64_t, 0>(L, 7);
|
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();
|
2023-11-21 11:56:23 +01:00
|
|
|
peffect->owner = self;
|
2024-01-13 16:10:22 +01:00
|
|
|
peffect->handler = nullptr;
|
2015-09-25 21:07:16 +08:00
|
|
|
peffect->type = EFFECT_TYPE_SINGLE;
|
|
|
|
|
peffect->code = code;
|
|
|
|
|
peffect->reset_flag = reset;
|
2015-10-31 15:50:37 +09:00
|
|
|
peffect->flag[0] = flag | EFFECT_FLAG_CANNOT_DISABLE;
|
2017-08-14 08:02:43 +09:00
|
|
|
peffect->reset_count = count;
|
2019-06-19 22:51:12 +08:00
|
|
|
peffect->label = { lab };
|
2015-09-25 21:07:16 +08:00
|
|
|
peffect->description = desc;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->add_effect(peffect);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, peffect);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetFlagEffect) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = (lua_get<uint32_t>(L, 2) & 0xfffffff) | 0x10000000;
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->single_effect.count(code));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(ResetFlagEffect) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = (lua_get<uint32_t>(L, 2) & 0xfffffff) | 0x10000000;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->reset(code, RESET_CODE);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(SetFlagEffectLabel) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = (lua_get<uint32_t>(L, 2) & 0xfffffff) | 0x10000000;
|
|
|
|
|
auto lab = lua_get<uint32_t>(L, 3);
|
2023-11-21 11:56:23 +01:00
|
|
|
auto eit = self->single_effect.find(code);
|
|
|
|
|
if(eit == self->single_effect.end())
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, FALSE);
|
|
|
|
|
else {
|
2019-06-19 22:51:12 +08:00
|
|
|
eit->second->label = { lab };
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, TRUE);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetFlagEffectLabel) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = (lua_get<uint32_t>(L, 2) & 0xfffffff) | 0x10000000;
|
2023-11-21 11:56:23 +01:00
|
|
|
auto rg = self->single_effect.equal_range(code);
|
2025-02-24 20:51:49 +01:00
|
|
|
auto count = static_cast<int32_t>(std::distance(rg.first, rg.second));
|
2016-03-26 09:37:02 +08:00
|
|
|
if(!count) {
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
return 1;
|
2016-03-25 15:22:16 +08:00
|
|
|
}
|
2022-10-06 13:11:11 +02:00
|
|
|
luaL_checkstack(L, count, nullptr);
|
|
|
|
|
for(; rg.first != rg.second; ++rg.first) {
|
|
|
|
|
const auto& label = rg.first->second->label;
|
|
|
|
|
lua_pushinteger(L, label.size() ? label[0] : 0);
|
|
|
|
|
}
|
2016-03-25 15:22:16 +08:00
|
|
|
return count;
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CreateRelation) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto rcard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto reset = lua_get<uint32_t>(L, 3);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->create_relation(rcard, reset);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(ReleaseRelation) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto rcard = lua_get<card*, true>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->release_relation(rcard);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CreateEffectRelation) {
|
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, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->create_relation(peffect);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(ReleaseEffectRelation) {
|
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, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->release_relation(peffect);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(ClearEffectRelation) {
|
2023-11-21 11:56:23 +01:00
|
|
|
self->clear_relate_effect();
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsRelateToEffect) {
|
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, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_has_relation(peffect));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsRelateToChain) {
|
2016-01-04 07:03:05 +09:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto chain_count = lua_get<uint8_t>(L, 2);
|
2016-01-04 07:03:05 +09:00
|
|
|
if(chain_count > pduel->game_field->core.current_chain.size() || chain_count < 1)
|
2021-09-04 22:04:14 +02:00
|
|
|
chain_count = (uint8_t)pduel->game_field->core.current_chain.size();
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_has_relation(pduel->game_field->core.current_chain[chain_count - 1]));
|
2016-01-04 07:03:05 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsRelateToCard) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto rcard = lua_get<card*, true>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_has_relation(rcard));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsRelateToBattle) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->fieldid_r == pduel->game_field->core.pre_field[0] || self->fieldid_r == pduel->game_field->core.pre_field[1]);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CopyEffect) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = lua_get<uint32_t>(L, 2);
|
|
|
|
|
auto reset = lua_get<uint32_t>(L, 3);
|
|
|
|
|
auto count = lua_get<uint8_t, 1>(L, 4);
|
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);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->copy_effect(code, reset, count));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(ReplaceEffect) {
|
2015-12-25 22:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = lua_get<uint32_t>(L, 2);
|
|
|
|
|
auto reset = lua_get<uint32_t>(L, 3);
|
|
|
|
|
auto count = lua_get<uint8_t, 0>(L, 4);
|
2015-12-25 22: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);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->replace_effect(code, reset, count));
|
2015-12-25 22:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(EnableUnsummonable) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if(!self->is_status(STATUS_COPYING_EFFECT)) {
|
2015-09-25 21:07:16 +08:00
|
|
|
effect* peffect = pduel->new_effect();
|
2023-11-21 11:56:23 +01:00
|
|
|
peffect->owner = self;
|
2015-09-25 21:07:16 +08:00
|
|
|
peffect->code = EFFECT_UNSUMMONABLE_CARD;
|
|
|
|
|
peffect->type = EFFECT_TYPE_SINGLE;
|
2015-10-31 15:50:37 +09:00
|
|
|
peffect->flag[0] = EFFECT_FLAG_CANNOT_DISABLE | EFFECT_FLAG_UNCOPYABLE;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->add_effect(peffect);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(EnableReviveLimit) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if(!self->is_status(STATUS_COPYING_EFFECT)) {
|
2015-09-25 21:07:16 +08:00
|
|
|
effect* peffect1 = pduel->new_effect();
|
2023-11-21 11:56:23 +01:00
|
|
|
peffect1->owner = self;
|
2015-09-25 21:07:16 +08:00
|
|
|
peffect1->code = EFFECT_UNSUMMONABLE_CARD;
|
|
|
|
|
peffect1->type = EFFECT_TYPE_SINGLE;
|
2015-10-31 15:50:37 +09:00
|
|
|
peffect1->flag[0] = EFFECT_FLAG_CANNOT_DISABLE | EFFECT_FLAG_UNCOPYABLE;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->add_effect(peffect1);
|
2015-09-25 21:07:16 +08:00
|
|
|
effect* peffect2 = pduel->new_effect();
|
2023-11-21 11:56:23 +01:00
|
|
|
peffect2->owner = self;
|
2015-09-25 21:07:16 +08:00
|
|
|
peffect2->code = EFFECT_REVIVE_LIMIT;
|
|
|
|
|
peffect2->type = EFFECT_TYPE_SINGLE;
|
2015-10-31 15:50:37 +09:00
|
|
|
peffect2->flag[0] = EFFECT_FLAG_CANNOT_DISABLE | EFFECT_FLAG_UNCOPYABLE;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->add_effect(peffect2);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CompleteProcedure) {
|
2023-11-21 11:56:23 +01:00
|
|
|
self->set_status(STATUS_PROC_COMPLETE, TRUE);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsDisabled) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_status(STATUS_DISABLED));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsDestructable) {
|
2024-01-13 16:10:22 +01:00
|
|
|
effect* peffect = nullptr;
|
2020-07-21 01:21:25 +02:00
|
|
|
if(lua_gettop(L) > 1)
|
|
|
|
|
peffect = lua_get<effect*, true>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(peffect)
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_destructable_by_effect(peffect, pduel->game_field->core.reason_player));
|
2015-09-25 21:07:16 +08:00
|
|
|
else
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_destructable());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsSummonableCard) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_summonable_card());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsSpecialSummonable) {
|
|
|
|
|
auto sumtype = lua_get<uint32_t, 0>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_special_summonable(pduel->game_field->core.reason_player, sumtype));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsFusionSummonableCard) {
|
|
|
|
|
auto summon_type = lua_get<uint32_t, 0>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_fusion_summonable_card(summon_type));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
inline int32_t spsummonable_rule(lua_State* L, uint32_t cardtype, uint32_t sumtype, uint32_t offset) {
|
2020-10-30 17:05:28 +01:00
|
|
|
const auto pduel = lua_get<duel*>(L);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto pcard = lua_get<card*, true>(L, 1);
|
2020-02-27 20:26:09 +01:00
|
|
|
if(!(pcard->data.type & cardtype))
|
2015-09-25 21:07:16 +08:00
|
|
|
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
|
|
|
owned_lua<group> must = nullptr;
|
|
|
|
|
owned_lua<group> materials = nullptr;
|
2024-04-13 10:26:42 +02:00
|
|
|
if(auto [pcard_, pgroup_] = lua_get_card_or_group<true>(L, 2 + offset); pcard_)
|
|
|
|
|
must = pduel->new_group(pcard_);
|
|
|
|
|
else if(pgroup_)
|
|
|
|
|
must = pgroup_;
|
|
|
|
|
if(auto [pcard_, pgroup_] = lua_get_card_or_group<true>(L, 3 + offset); pcard_)
|
|
|
|
|
materials = pduel->new_group(pcard_);
|
|
|
|
|
else if(pgroup_)
|
|
|
|
|
materials = pgroup_;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto minc = lua_get<uint16_t, 0>(L, 4 + offset);
|
|
|
|
|
auto maxc = lua_get<uint16_t, 0>(L, 5 + offset);
|
2020-10-30 17:05:28 +01:00
|
|
|
auto& core = pduel->game_field->core;
|
2021-09-04 22:04:14 +02:00
|
|
|
uint8_t p = core.reason_player;
|
2020-07-14 22:57:26 +02:00
|
|
|
core.must_use_mats = must;
|
|
|
|
|
core.only_use_mats = materials;
|
|
|
|
|
core.forced_summon_minc = minc;
|
|
|
|
|
core.forced_summon_maxc = maxc;
|
2020-02-27 20:26:09 +01:00
|
|
|
lua_pushboolean(L, pcard->is_special_summonable(p, sumtype));
|
2020-07-14 22:57:26 +02:00
|
|
|
core.must_use_mats = nullptr;
|
|
|
|
|
core.only_use_mats = nullptr;
|
|
|
|
|
core.forced_summon_minc = 0;
|
|
|
|
|
core.forced_summon_maxc = 0;
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsSynchroSummonable) {
|
2020-02-28 12:18:52 +01:00
|
|
|
return spsummonable_rule(L, TYPE_SYNCHRO, SUMMON_TYPE_SYNCHRO, 0);
|
2020-02-27 20:26:09 +01:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsXyzSummonable) {
|
2020-02-28 12:18:52 +01:00
|
|
|
return spsummonable_rule(L, TYPE_XYZ, SUMMON_TYPE_XYZ, 0);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsLinkSummonable) {
|
2020-02-28 12:18:52 +01:00
|
|
|
return spsummonable_rule(L, TYPE_LINK, SUMMON_TYPE_LINK, 0);
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
LUA_STATIC_FUNCTION(IsProcedureSummonable) {
|
2021-10-13 17:29:29 +02:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto cardtype = lua_get<uint32_t, true>(L, 2);
|
|
|
|
|
auto sumtype = lua_get<uint32_t, true>(L, 3);
|
2020-02-28 12:18:52 +01:00
|
|
|
return spsummonable_rule(L, cardtype, sumtype, 2);
|
2018-01-11 21:45:27 +01:00
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsSummonable) {
|
2023-09-19 18:17:58 +02:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto ign = lua_get<bool>(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 01:21:25 +02:00
|
|
|
peffect = lua_get<effect*, true>(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto minc = lua_get<uint16_t, 0>(L, 4);
|
|
|
|
|
auto zone = lua_get<uint16_t, 0x1f>(L, 5);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_can_be_summoned(pduel->game_field->core.reason_player, ign, peffect, minc, zone));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsMSetable) {
|
2023-09-19 18:17:58 +02:00
|
|
|
check_param_count(L, 2);
|
2022-05-15 13:19:29 +02:00
|
|
|
bool ign = lua_get<bool>(L, 2);
|
2024-01-13 16:10:22 +01:00
|
|
|
effect* peffect = nullptr;
|
2022-05-15 13:19:29 +02:00
|
|
|
if(!lua_isnoneornil(L, 3))
|
|
|
|
|
peffect = lua_get<effect*, true>(L, 3);
|
|
|
|
|
auto minc = lua_get<uint16_t, 0>(L, 4);
|
|
|
|
|
auto zone = lua_get<uint32_t, 0xff>(L, 5);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_setable_mzone(pduel->game_field->core.reason_player, ign, peffect, minc, zone));
|
2022-05-15 13:19:29 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
LUA_FUNCTION(IsSSetable) {
|
|
|
|
|
bool ign = lua_get<bool, false>(L, 2);
|
2024-12-15 08:15:21 -03:00
|
|
|
auto toplayer = lua_get<uint8_t>(L, 3, pduel->game_field->core.reason_player);
|
|
|
|
|
lua_pushboolean(L, self->is_setable_szone(toplayer, ign));
|
2022-05-15 13:19:29 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
LUA_FUNCTION(IsCanBeSpecialSummoned) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 6);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto peffect = lua_get<effect*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto sumtype = lua_get<uint32_t>(L, 3);
|
|
|
|
|
auto sumplayer = lua_get<uint8_t>(L, 4);
|
2020-07-21 01:21:25 +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 sumpos = lua_get<uint8_t, POS_FACEUP>(L, 7);
|
|
|
|
|
auto toplayer = lua_get<uint8_t>(L, 8, sumplayer);
|
|
|
|
|
auto zone = lua_get<uint32_t, 0xff>(L, 9);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_can_be_special_summoned(peffect, sumtype, sumpos, sumplayer, toplayer, nocheck, nolimit, zone));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAbleToHand) {
|
2020-12-25 23:31:28 +01:00
|
|
|
auto p = lua_get<uint8_t>(L, 2, pduel->game_field->core.reason_player);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_capable_send_to_hand(p));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAbleToDeck) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_capable_send_to_deck(pduel->game_field->core.reason_player));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAbleToExtra) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_capable_send_to_extra(pduel->game_field->core.reason_player));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAbleToGrave) {
|
2026-06-02 11:01:17 +02:00
|
|
|
auto reason = lua_get<uint32_t, REASON_EFFECT>(L, 2);
|
|
|
|
|
lua_pushboolean(L, self->is_capable_send_to_grave(pduel->game_field->core.reason_player, reason));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAbleToRemove) {
|
2021-09-04 22:04:14 +02:00
|
|
|
auto p = lua_get<uint8_t>(L, 2, pduel->game_field->core.reason_player);
|
|
|
|
|
auto pos = lua_get<uint8_t, POS_FACEUP>(L, 3);
|
|
|
|
|
auto reason = lua_get<uint32_t, REASON_EFFECT>(L, 4);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_removeable(p, pos, reason));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAbleToHandAsCost) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_capable_cost_to_hand(pduel->game_field->core.reason_player));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAbleToDeckAsCost) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_capable_cost_to_deck(pduel->game_field->core.reason_player));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAbleToExtraAsCost) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_capable_cost_to_extra(pduel->game_field->core.reason_player));
|
2018-08-13 18:33:13 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAbleToDeckOrExtraAsCost) {
|
|
|
|
|
auto p = pduel->game_field->core.reason_player;
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_extra_deck_monster() ? self->is_capable_cost_to_extra(p) : self->is_capable_cost_to_deck(p));
|
2018-08-13 18:33:13 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAbleToGraveAsCost) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_capable_cost_to_grave(pduel->game_field->core.reason_player));
|
2018-08-13 18:33:13 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAbleToRemoveAsCost) {
|
2021-09-04 22:04:14 +02:00
|
|
|
auto pos = lua_get<uint8_t, POS_FACEUP>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_removeable_as_cost(pduel->game_field->core.reason_player, pos));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsReleasable) {
|
2023-11-12 13:04:20 -03:00
|
|
|
const auto reason = lua_get<uint32_t, REASON_COST>(L, 2);
|
2024-12-21 18:01:20 -03:00
|
|
|
auto player = lua_get<uint8_t>(L, 3, pduel->game_field->core.reason_player);
|
|
|
|
|
lua_pushboolean(L, self->is_releasable_by_nonsummon(player, reason));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsReleasableByEffect) {
|
2020-10-30 17:05:28 +01:00
|
|
|
effect* re = pduel->game_field->core.reason_effect;
|
2024-12-21 18:01:20 -03:00
|
|
|
if (!lua_isnoneornil(L, 2))
|
|
|
|
|
re = lua_get<effect*, true>(L, 2);
|
|
|
|
|
auto player = lua_get<uint8_t>(L, 3, pduel->game_field->core.reason_player);
|
|
|
|
|
lua_pushboolean(L, self->is_releasable_by_nonsummon(player, REASON_EFFECT) && self->is_releasable_by_effect(player, re));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsDiscardable) {
|
2020-10-30 17:05:28 +01:00
|
|
|
effect* pe = pduel->game_field->core.reason_effect;
|
2021-09-04 22:04:14 +02:00
|
|
|
auto reason = lua_get<uint32_t, REASON_COST>(L, 2);
|
2024-12-21 18:01:20 -03:00
|
|
|
auto player = lua_get<uint8_t>(L, 3, pduel->game_field->core.reason_player);
|
2023-11-21 11:56:23 +01:00
|
|
|
if((reason != REASON_COST || !self->is_affected_by_effect(EFFECT_CANNOT_USE_AS_COST))
|
2024-12-21 18:01:20 -03:00
|
|
|
&& pduel->game_field->is_player_can_discard_hand(player, self, pe, reason))
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, 1);
|
|
|
|
|
else
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CanAttack) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_capable_attack());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CanChainAttack) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self != pduel->game_field->core.attacker) {
|
2020-10-30 19:01:32 +01:00
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2021-09-04 22:04:14 +02:00
|
|
|
auto ac = lua_get<uint8_t, 2>(L, 2);
|
2020-07-23 23:50:09 +02:00
|
|
|
bool monsteronly = lua_get<bool, false>(L, 3);
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->is_status(STATUS_BATTLE_DESTROYED)
|
|
|
|
|
|| self->current.controler != pduel->game_field->infos.turn_player
|
|
|
|
|
|| self->fieldid_r != pduel->game_field->core.pre_field[0]
|
|
|
|
|
|| !self->is_capable_attack_announce(pduel->game_field->infos.turn_player)
|
|
|
|
|
|| (ac != 0 && self->announce_count >= ac)
|
|
|
|
|
|| (ac == 2 && self->is_affected_by_effect(EFFECT_EXTRA_ATTACK))) {
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
pduel->game_field->core.select_cards.clear();
|
2024-01-03 13:34:39 +01:00
|
|
|
pduel->game_field->get_attack_target(self, &pduel->game_field->core.select_cards, true);
|
2023-11-21 11:56:23 +01:00
|
|
|
if(pduel->game_field->core.select_cards.empty() && (monsteronly || !self->direct_attackable))
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
else
|
|
|
|
|
lua_pushboolean(L, 1);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsFaceup) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_position(POS_FACEUP));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAttackPos) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_position(POS_ATTACK));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsFacedown) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_position(POS_FACEDOWN));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsDefensePos) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_position(POS_DEFENSE));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsPosition) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto pos = lua_get<uint8_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_position(pos));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsPreviousPosition) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto pos = lua_get<uint8_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, (self->previous.position & pos) != 0);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsControler) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto con = lua_get<uint8_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->current.controler == con);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-10-19 14:37:41 +02:00
|
|
|
LUA_FUNCTION(IsPreviousControler) {
|
|
|
|
|
check_param_count(L, 2);
|
|
|
|
|
auto con = lua_get<uint8_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->previous.controler == con);
|
2022-10-19 14:37:41 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsOnField) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if((self->current.location & LOCATION_ONFIELD)
|
|
|
|
|
&& !self->get_status(STATUS_SUMMONING | STATUS_SUMMON_DISABLED | STATUS_ACTIVATE_DISABLED | STATUS_SPSUMMON_STEP))
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, 1);
|
|
|
|
|
else
|
|
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsLocation) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto loc = lua_get<uint16_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->current.location == LOCATION_MZONE) {
|
|
|
|
|
if(self->current.is_location(loc) && !self->get_status(STATUS_SUMMONING | STATUS_SUMMON_DISABLED | STATUS_SPSUMMON_STEP))
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, 1);
|
|
|
|
|
else
|
|
|
|
|
lua_pushboolean(L, 0);
|
2023-11-21 11:56:23 +01:00
|
|
|
} else if(self->current.location == LOCATION_SZONE) {
|
|
|
|
|
if(self->current.is_location(loc) && !self->is_status(STATUS_ACTIVATE_DISABLED))
|
2016-09-07 09:56:14 +08:00
|
|
|
lua_pushboolean(L, 1);
|
|
|
|
|
else
|
|
|
|
|
lua_pushboolean(L, 0);
|
2015-09-25 21:07:16 +08:00
|
|
|
} else
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, (self->current.location & loc) != 0);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsPreviousLocation) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto loc = lua_get<uint16_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->previous.is_location(loc));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsLevelBelow) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto lvl = lua_get<uint32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
uint32_t plvl = self->get_level();
|
2020-07-16 10:03:19 +08:00
|
|
|
lua_pushboolean(L, plvl > 0 && plvl <= lvl);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsLevelAbove) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto lvl = lua_get<uint32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
uint32_t plvl = self->get_level();
|
2020-07-16 10:03:19 +08:00
|
|
|
lua_pushboolean(L, plvl > 0 && plvl >= lvl);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsRankBelow) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto rnk = lua_get<uint32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
uint32_t prnk = self->get_rank();
|
2020-07-16 10:03:19 +08:00
|
|
|
lua_pushboolean(L, prnk > 0 && prnk <= rnk);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsRankAbove) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto rnk = lua_get<uint32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
uint32_t prnk = self->get_rank();
|
2020-07-16 10:03:19 +08:00
|
|
|
lua_pushboolean(L, prnk > 0 && prnk >= rnk);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsLinkBelow) {
|
2017-09-05 00:14:46 +09:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto lnk = lua_get<uint32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
uint32_t plnk = self->get_link();
|
2020-07-16 10:03:19 +08:00
|
|
|
lua_pushboolean(L, plnk > 0 && plnk <= lnk);
|
2017-09-05 00:14:46 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsLinkAbove) {
|
2017-09-05 00:14:46 +09:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto lnk = lua_get<uint32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
uint32_t plnk = self->get_link();
|
2020-07-16 10:03:19 +08:00
|
|
|
lua_pushboolean(L, plnk > 0 && plnk >= lnk);
|
2017-09-05 00:14:46 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAttackBelow) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto atk = lua_get<int32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
if(!(self->data.type & TYPE_MONSTER) && !(self->get_type() & TYPE_MONSTER) && !self->is_affected_by_effect(EFFECT_PRE_MONSTER))
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
else {
|
2023-11-21 11:56:23 +01:00
|
|
|
int32_t _atk = self->get_attack();
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, _atk >= 0 && _atk <= atk);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAttackAbove) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto atk = lua_get<int32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
if(!(self->data.type & TYPE_MONSTER) && !(self->get_type() & TYPE_MONSTER) && !self->is_affected_by_effect(EFFECT_PRE_MONSTER))
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
else {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->get_attack() >= atk);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsDefenseBelow) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto def = lua_get<int32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
if((self->data.type & TYPE_LINK)
|
|
|
|
|
|| (!(self->data.type & TYPE_MONSTER) && !(self->get_type() & TYPE_MONSTER) && !(self->current.location & LOCATION_MZONE)))
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
else {
|
2023-11-21 11:56:23 +01:00
|
|
|
int32_t _def = self->get_defense();
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, _def >= 0 && _def <= def);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsDefenseAbove) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto def = lua_get<int32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
if((self->data.type & TYPE_LINK)
|
|
|
|
|
|| (!(self->data.type & TYPE_MONSTER) && !(self->get_type() & TYPE_MONSTER) && !self->is_affected_by_effect(EFFECT_PRE_MONSTER)))
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushboolean(L, 0);
|
|
|
|
|
else {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->get_defense() >= def);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsPublic) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_position(POS_FACEUP));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsForbidden) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_status(STATUS_FORBIDDEN));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsAbleToChangeControler) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_capable_change_control());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsControlerCanBeChanged) {
|
2020-07-23 23:50:09 +02:00
|
|
|
bool ign = lua_get<bool, false>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto zone = lua_get<uint32_t, 0xff>(L, 3);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_control_can_be_changed(ign, zone));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(AddCounter) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto countertype = lua_get<uint16_t>(L, 2);
|
|
|
|
|
auto count = lua_get<uint16_t>(L, 3);
|
2020-07-23 23:50:09 +02:00
|
|
|
bool singly = lua_get<bool, false>(L, 4);
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->is_affect_by_effect(pduel->game_field->core.reason_effect))
|
|
|
|
|
lua_pushboolean(L, self->add_counter(pduel->game_field->core.reason_player, countertype, count, singly));
|
2020-07-21 15:03:03 +02:00
|
|
|
else
|
|
|
|
|
lua_pushboolean(L, 0);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(RemoveCounter) {
|
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 countertype = lua_get<uint16_t>(L, 3);
|
2022-06-23 11:47:00 +02:00
|
|
|
if(countertype == 0)
|
|
|
|
|
lua_error(L, "Counter type cannot be 0, use Card.RemoveAllCounters instead");
|
2021-09-04 22:04:14 +02:00
|
|
|
auto rplayer = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto count = lua_get<uint16_t>(L, 4);
|
|
|
|
|
auto reason = lua_get<uint32_t>(L, 5);
|
2023-11-21 11:56:23 +01:00
|
|
|
pduel->game_field->remove_counter(reason, self, rplayer, 0, 0, countertype, count);
|
2023-11-25 11:15:21 +01:00
|
|
|
return yieldk({
|
|
|
|
|
lua_pushboolean(L, pduel->game_field->returns.at<int32_t>(0));
|
2021-08-05 16:52:55 +02:00
|
|
|
return 1;
|
|
|
|
|
});
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(RemoveAllCounters) {
|
2021-08-05 16:52:55 +02:00
|
|
|
check_action_permission(L);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint32_t total = 0;
|
2023-11-21 11:56:23 +01:00
|
|
|
for(const auto& cmit : self->counters) {
|
2021-08-05 16:52:55 +02:00
|
|
|
auto message = pduel->new_message(MSG_REMOVE_COUNTER);
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint16_t>(cmit.first);
|
2023-11-21 11:56:23 +01:00
|
|
|
message->write<uint8_t>(self->current.controler);
|
|
|
|
|
message->write<uint8_t>(self->current.location);
|
|
|
|
|
message->write<uint8_t>(self->current.sequence);
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint16_t>(cmit.second[0] + cmit.second[1]);
|
2021-08-05 16:52:55 +02:00
|
|
|
total += cmit.second[0] + cmit.second[1];
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
self->counters.clear();
|
2021-08-05 16:52:55 +02:00
|
|
|
lua_pushinteger(L, total);
|
|
|
|
|
return 1;
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetCounter) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto countertype = lua_get<uint16_t>(L, 2);
|
2022-06-23 11:47:00 +02:00
|
|
|
if(countertype == 0)
|
|
|
|
|
lua_error(L, "Counter type cannot be 0, use Card.GetAllCounters instead");
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->get_counter(countertype));
|
2021-08-05 17:10:28 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetAllCounters) {
|
2024-04-15 22:39:25 +02:00
|
|
|
lua_createtable(L, static_cast<int>(self->counters.size()), 0);
|
2023-11-21 11:56:23 +01:00
|
|
|
for(const auto& counter : self->counters) {
|
2021-08-05 17:10:28 +02:00
|
|
|
lua_pushinteger(L, counter.first);
|
|
|
|
|
lua_pushinteger(L, counter.second[0] + counter.second[1]);
|
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(HasCounters) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, !self->counters.empty());
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(EnableCounterPermit) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto countertype = lua_get<uint16_t>(L, 2);
|
|
|
|
|
uint16_t prange;
|
2017-03-31 12:18:34 +09:00
|
|
|
if(lua_gettop(L) > 2)
|
2021-09-04 22:04:14 +02:00
|
|
|
prange = lua_get<uint16_t>(L, 3);
|
2023-11-21 11:56:23 +01:00
|
|
|
else if(self->data.type & TYPE_MONSTER)
|
2015-09-25 21:07:16 +08:00
|
|
|
prange = LOCATION_MZONE;
|
|
|
|
|
else
|
|
|
|
|
prange = LOCATION_SZONE | LOCATION_FZONE;
|
2020-10-30 17:05:28 +01:00
|
|
|
effect* peffect = pduel->new_effect();
|
2023-11-21 11:56:23 +01:00
|
|
|
peffect->owner = self;
|
2015-09-25 21:07:16 +08:00
|
|
|
peffect->type = EFFECT_TYPE_SINGLE;
|
|
|
|
|
peffect->code = EFFECT_COUNTER_PERMIT | countertype;
|
2017-08-28 23:47:11 +02:00
|
|
|
peffect->value = prange;
|
2019-04-29 09:25:24 +09:00
|
|
|
if(lua_gettop(L) > 3 && lua_isfunction(L, 4))
|
|
|
|
|
peffect->target = interpreter::get_function_handle(L, 4);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->add_effect(peffect);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(SetCounterLimit) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto countertype = lua_get<uint16_t>(L, 2);
|
|
|
|
|
auto limit = lua_get<uint32_t>(L, 3);
|
2020-10-30 17:05:28 +01:00
|
|
|
effect* peffect = pduel->new_effect();
|
2023-11-21 11:56:23 +01:00
|
|
|
peffect->owner = self;
|
2015-09-25 21:07:16 +08:00
|
|
|
peffect->type = EFFECT_TYPE_SINGLE;
|
|
|
|
|
peffect->code = EFFECT_COUNTER_LIMIT | countertype;
|
|
|
|
|
peffect->value = limit;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->add_effect(peffect);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsCanChangePosition) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_capable_change_position_by_effect(pduel->game_field->core.reason_player));
|
2017-08-01 16:28:32 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsCanTurnSet) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_capable_turn_set(pduel->game_field->core.reason_player));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsCanAddCounter) {
|
2019-04-29 09:25:24 +09:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto countertype = lua_get<uint16_t>(L, 2);
|
|
|
|
|
auto count = lua_get<uint16_t, 0>(L, 3);
|
2020-07-23 23:50:09 +02:00
|
|
|
bool singly = lua_get<bool, false>(L, 4);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto loc = lua_get<uint16_t, 0>(L, 5);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_can_add_counter(pduel->game_field->core.reason_player, countertype, count, singly, loc));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsCanRemoveCounter) {
|
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, 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 countertype = lua_get<uint16_t>(L, 3);
|
|
|
|
|
auto count = lua_get<uint16_t>(L, 4);
|
|
|
|
|
auto reason = lua_get<uint32_t>(L, 5);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, pduel->game_field->is_player_can_remove_counter(playerid, self, 0, 0, countertype, count, reason));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsCanBeFusionMaterial) {
|
2023-11-21 11:56:23 +01:00
|
|
|
card* fcard = nullptr;
|
2020-12-26 00:31:31 +01:00
|
|
|
if(lua_gettop(L) >= 2 && !lua_isnoneornil(L, 2))
|
2020-07-21 01:21:25 +02:00
|
|
|
fcard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto summon_type = lua_get<uint64_t, SUMMON_TYPE_FUSION>(L, 3);
|
2022-07-19 19:29:30 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 4, pduel->game_field->core.reason_player);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_can_be_fusion_material(fcard, summon_type, playerid));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsCanBeSynchroMaterial) {
|
2023-11-21 11:56:23 +01:00
|
|
|
card* scard = nullptr;
|
|
|
|
|
card* tuner = nullptr;
|
2020-07-21 01:21:25 +02:00
|
|
|
if(lua_gettop(L) >= 2)
|
|
|
|
|
scard = lua_get<card*, true>(L, 2);
|
2020-12-26 00:31:31 +01:00
|
|
|
if(lua_gettop(L) >= 3 && !lua_isnoneornil(L, 3))
|
2020-07-21 01:21:25 +02:00
|
|
|
tuner = lua_get<card*, true>(L, 3);
|
2026-03-31 14:06:39 -03:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 4, pduel->game_field->core.reason_player);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_can_be_synchro_material(scard, playerid, tuner));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsCanBeRitualMaterial) {
|
2023-11-21 11:56:23 +01:00
|
|
|
card* scard = nullptr;
|
2020-12-26 00:31:31 +01:00
|
|
|
if(lua_gettop(L) >= 2 && !lua_isnoneornil(L, 2))
|
2020-07-21 01:21:25 +02:00
|
|
|
scard = lua_get<card*, true>(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 3, pduel->game_field->core.reason_player);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_can_be_ritual_material(scard, playerid));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsCanBeXyzMaterial) {
|
2022-03-23 21:54:02 +01:00
|
|
|
card* scard = nullptr;
|
|
|
|
|
if(!lua_isnoneornil(L, 2))
|
2022-03-24 21:40:34 +01:00
|
|
|
scard = lua_get<card*, true>(L, 2);
|
2023-11-25 11:15:21 +01:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 3, pduel->game_field->core.reason_player);
|
2022-03-23 21:54:02 +01:00
|
|
|
auto reason = lua_get<uint32_t, REASON_XYZ | REASON_MATERIAL>(L, 4);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_can_be_xyz_material(scard, playerid, reason));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsCanBeLinkMaterial) {
|
2024-01-13 16:10:22 +01:00
|
|
|
card* scard = nullptr;
|
2020-07-21 01:21:25 +02:00
|
|
|
if(lua_gettop(L) >= 2)
|
|
|
|
|
scard = lua_get<card*, true>(L, 2);
|
2024-07-17 13:56:39 -03:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 3, pduel->game_field->core.reason_player);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_can_be_link_material(scard, playerid));
|
2017-06-27 20:32:13 +09:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsCanBeMaterial) {
|
2018-11-17 14:51:26 +01:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
uint64_t sumtype = lua_get<uint64_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
card* scard = nullptr;
|
2020-07-21 01:21:25 +02:00
|
|
|
if(lua_gettop(L) >= 3)
|
|
|
|
|
scard = lua_get<card*, true>(L, 3);
|
2026-03-31 14:06:39 -03:00
|
|
|
auto playerid = lua_get<uint8_t>(L, 4, pduel->game_field->core.reason_player);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_can_be_material(scard, sumtype, playerid));
|
2018-11-17 14:51:26 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CheckFusionMaterial) {
|
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> pgroup = nullptr;
|
2020-12-26 00:31:31 +01:00
|
|
|
if(lua_gettop(L) > 1 && !lua_isnoneornil(L, 2))
|
2020-07-21 01:21:25 +02:00
|
|
|
pgroup = lua_get<group*, 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> cg = nullptr;
|
2020-07-24 00:07:49 +02:00
|
|
|
if(auto _pcard = lua_get<card*>(L, 3))
|
|
|
|
|
cg = pduel->new_group(_pcard);
|
|
|
|
|
else
|
|
|
|
|
cg = lua_get<group*>(L, 3);
|
2026-08-17 16:50:12 +02:00
|
|
|
auto chkf = lua_get<uint64_t, PLAYER_NONE>(L, 4);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->fusion_check(pgroup, cg, chkf));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CheckFusionSubstitute) {
|
2016-05-20 22:09:51 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto fcard = lua_get<card*, true>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->check_fusion_substitute(fcard));
|
2016-05-20 22:09:51 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsImmuneToEffect) {
|
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, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, !self->is_affect_by_effect(peffect));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2023-02-05 11:19:45 +01:00
|
|
|
LUA_FUNCTION(IsCanBeDisabledByEffect) {
|
|
|
|
|
check_param_count(L, 2);
|
|
|
|
|
auto peffect = lua_get<effect*, true>(L, 2);
|
2023-05-31 12:45:00 -03:00
|
|
|
bool is_monster_effect = lua_get<bool, true>(L, 3);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_can_be_disabled_by_effect(peffect, is_monster_effect));
|
2023-02-05 11:19:45 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsCanBeEffectTarget) {
|
2015-09-25 21:07:16 +08:00
|
|
|
effect* peffect = pduel->game_field->core.reason_effect;
|
2020-07-21 01:21:25 +02:00
|
|
|
if(lua_gettop(L) > 1)
|
|
|
|
|
peffect = lua_get<effect*, true>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_capable_be_effect_target(peffect, pduel->game_field->core.reason_player));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(IsCanBeBattleTarget) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
auto bcard = lua_get<card*, true>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->is_capable_be_battle_target(bcard));
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(AddMonsterAttribute) {
|
2016-06-27 22:02:06 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto type = lua_get<uint32_t>(L, 2);
|
|
|
|
|
auto attribute = lua_get<uint32_t, 0>(L, 3);
|
2022-09-03 22:45:49 +02:00
|
|
|
auto race = lua_get<uint64_t, 0>(L, 4);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto level = lua_get<uint32_t, 0>(L, 5);
|
|
|
|
|
auto atk = lua_get<int32_t, 0>(L, 6);
|
|
|
|
|
auto def = lua_get<int32_t, 0>(L, 7);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->set_status(STATUS_NO_LEVEL, FALSE);
|
2023-11-25 11:16:36 +01:00
|
|
|
constexpr auto resets = RESET_TURN_SET | RESET_TOGRAVE | RESET_REMOVE | RESET_TEMP_REMOVE | RESET_TOHAND | RESET_TODECK | RESET_OVERLAY;
|
2016-04-22 17:26:00 +08:00
|
|
|
// pre-monster
|
2023-11-25 11:16:36 +01:00
|
|
|
{
|
|
|
|
|
effect* peffect = pduel->new_effect();
|
2023-11-21 11:56:23 +01:00
|
|
|
peffect->owner = self;
|
2016-04-22 17:26:00 +08:00
|
|
|
peffect->type = EFFECT_TYPE_SINGLE;
|
2023-11-25 11:16:36 +01:00
|
|
|
peffect->code = EFFECT_PRE_MONSTER;
|
2016-04-22 17:26:00 +08:00
|
|
|
peffect->flag[0] = EFFECT_FLAG_CANNOT_DISABLE;
|
2023-11-25 11:16:36 +01:00
|
|
|
peffect->reset_flag = RESET_CHAIN | RESET_EVENT | resets;
|
|
|
|
|
peffect->value = type;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->add_effect(peffect);
|
2016-04-22 17:26:00 +08:00
|
|
|
}
|
2023-11-25 11:16:36 +01:00
|
|
|
|
|
|
|
|
auto register_property_effect = [&](auto value, auto effect_code) {
|
|
|
|
|
auto peffect = pduel->new_effect();
|
2023-11-21 11:56:23 +01:00
|
|
|
peffect->owner = self;
|
2016-04-22 17:26:00 +08:00
|
|
|
peffect->type = EFFECT_TYPE_SINGLE;
|
2023-11-25 11:16:36 +01:00
|
|
|
peffect->code = effect_code;
|
2016-04-22 17:26:00 +08:00
|
|
|
peffect->flag[0] = EFFECT_FLAG_CANNOT_DISABLE;
|
2023-11-25 11:16:36 +01:00
|
|
|
peffect->reset_flag = RESET_EVENT | resets;
|
|
|
|
|
peffect->value = value;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->add_effect(peffect);
|
2023-11-25 11:16:36 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if(attribute)
|
|
|
|
|
register_property_effect(attribute, EFFECT_ADD_ATTRIBUTE);
|
|
|
|
|
|
|
|
|
|
if(race)
|
|
|
|
|
register_property_effect(race, EFFECT_ADD_RACE);
|
|
|
|
|
|
|
|
|
|
if(level)
|
|
|
|
|
register_property_effect(level, EFFECT_CHANGE_LEVEL);
|
|
|
|
|
|
|
|
|
|
if(atk)
|
|
|
|
|
register_property_effect(atk, EFFECT_SET_BASE_ATTACK);
|
|
|
|
|
|
|
|
|
|
if(def)
|
|
|
|
|
register_property_effect(def, EFFECT_SET_BASE_DEFENSE);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(AddMonsterAttributeComplete) {
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CancelToGrave) {
|
2020-08-31 19:42:05 +02:00
|
|
|
bool cancel = lua_get<bool, true>(L, 2);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(cancel)
|
2023-11-21 11:56:23 +01:00
|
|
|
self->set_status(STATUS_LEAVE_CONFIRMED, FALSE);
|
2015-09-25 21:07:16 +08:00
|
|
|
else {
|
2023-11-21 11:56:23 +01:00
|
|
|
pduel->game_field->core.leave_confirmed.insert(self);
|
|
|
|
|
self->set_status(STATUS_LEAVE_CONFIRMED, TRUE);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetTributeRequirement) {
|
2023-11-21 11:56:23 +01:00
|
|
|
int32_t rcount = self->get_summon_tribute_count();
|
2015-09-25 21:07:16 +08:00
|
|
|
lua_pushinteger(L, rcount & 0xffff);
|
|
|
|
|
lua_pushinteger(L, (rcount >> 16) & 0xffff);
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetBattleTarget) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if(pduel->game_field->core.attacker == self)
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pduel->game_field->core.attack_target);
|
2023-11-21 11:56:23 +01:00
|
|
|
else if(pduel->game_field->core.attack_target == self)
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, pduel->game_field->core.attacker);
|
2015-09-25 21:07:16 +08:00
|
|
|
else lua_pushnil(L);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(GetAttackableTarget) {
|
2021-09-04 20:46:43 +02:00
|
|
|
card_vector targets;
|
2023-11-21 11:56:23 +01:00
|
|
|
bool chain_attack = pduel->game_field->core.chain_attacker_id == self->fieldid;
|
|
|
|
|
pduel->game_field->get_attack_target(self, &targets, chain_attack);
|
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 newgroup = pduel->new_group(targets);
|
2020-07-20 22:05:04 +02:00
|
|
|
interpreter::pushobject(L, newgroup);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, self->direct_attackable);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 2;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(SetHint) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto type = lua_get<uint8_t>(L, 2);
|
2022-08-31 17:04:39 +02:00
|
|
|
auto value = lua_get<uint64_t>(L, 3);
|
2015-09-25 21:07:16 +08:00
|
|
|
if(type >= CHINT_DESC_ADD)
|
|
|
|
|
return 0;
|
2019-07-16 00:57:53 +02:00
|
|
|
auto message = pduel->new_message(MSG_CARD_HINT);
|
2023-11-21 11:56:23 +01:00
|
|
|
message->write(self->get_info_location());
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint8_t>(type);
|
|
|
|
|
message->write<uint64_t>(value);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(ReverseInDeck) {
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->current.location != LOCATION_DECK)
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
2024-11-04 22:36:40 +01:00
|
|
|
pduel->game_field->core.global_flag |= GLOBALFLAG_DECK_REVERSE_CHECK;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->current.position = POS_FACEUP_DEFENSE;
|
|
|
|
|
if(self->current.sequence == pduel->game_field->player[self->current.controler].list_main.size() - 1) {
|
2019-07-16 00:57:53 +02:00
|
|
|
auto message = pduel->new_message(MSG_DECK_TOP);
|
2023-11-21 11:56:23 +01:00
|
|
|
message->write<uint8_t>(self->current.controler);
|
2021-09-04 22:04:14 +02:00
|
|
|
message->write<uint32_t>(0);
|
2023-11-21 11:56:23 +01:00
|
|
|
message->write<uint32_t>(self->data.code);
|
|
|
|
|
message->write<uint32_t>(self->current.position);
|
2015-09-25 21:07:16 +08:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(SetUniqueOnField) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 4);
|
2023-11-21 11:56:23 +01:00
|
|
|
self->unique_pos[0] = lua_get<uint8_t>(L, 2);
|
|
|
|
|
self->unique_pos[1] = lua_get<uint8_t>(L, 3);
|
2017-01-29 21:54:11 +09:00
|
|
|
if(lua_isfunction(L, 4)) {
|
2023-11-21 11:56:23 +01:00
|
|
|
self->unique_code = 1;
|
|
|
|
|
self->unique_function = interpreter::get_function_handle(L, 4);
|
2017-01-29 21:54:11 +09:00
|
|
|
} else
|
2023-11-21 11:56:23 +01:00
|
|
|
self->unique_code = lua_get<uint32_t>(L, 4);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto location = lua_get<uint8_t, LOCATION_ONFIELD>(L, 5) & LOCATION_ONFIELD;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->unique_location = location;
|
2020-10-30 17:05:28 +01:00
|
|
|
effect* peffect = pduel->new_effect();
|
2023-11-21 11:56:23 +01:00
|
|
|
peffect->owner = self;
|
2015-09-25 21:07:16 +08:00
|
|
|
peffect->type = EFFECT_TYPE_SINGLE;
|
|
|
|
|
peffect->code = EFFECT_UNIQUE_CHECK;
|
2015-10-31 15:50:37 +09:00
|
|
|
peffect->flag[0] = EFFECT_FLAG_COPY_INHERIT;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->add_effect(peffect);
|
|
|
|
|
self->unique_effect = peffect;
|
|
|
|
|
if(self->current.location & location)
|
|
|
|
|
pduel->game_field->add_unique_card(self);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(CheckUniqueOnField) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto check_player = lua_get<uint8_t>(L, 2);
|
|
|
|
|
auto check_location = lua_get<uint8_t, LOCATION_ONFIELD>(L, 3) & LOCATION_ONFIELD;
|
2020-07-24 00:07:49 +02:00
|
|
|
auto icard = lua_get<card*>(L, 4);
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushboolean(L, pduel->game_field->check_unique_onfield(self, check_player, check_location, icard) ? 0 : 1);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(ResetNegateEffect) {
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_iterate_table_or_stack(L, 2, lua_gettop(L), [L, self] {
|
|
|
|
|
self->reset(lua_get<uint32_t>(L, -1), RESET_CARD);
|
2022-10-26 18:13:11 +02:00
|
|
|
});
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(AssumeProperty) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 3);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto assume = lua_get<uint32_t>(L, 2);
|
2020-07-21 01:21:25 +02:00
|
|
|
if ((assume < ASSUME_CODE) || (assume > ASSUME_LINKMARKER))
|
2024-10-06 16:23:04 +02:00
|
|
|
lua_error(L, "Invalid ASSUME value");
|
2023-11-21 11:56:23 +01:00
|
|
|
self->assume[assume] = lua_get<uint64_t>(L, 3);
|
|
|
|
|
pduel->assumes.insert(self);
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(SetSPSummonOnce) {
|
2015-09-25 21:07:16 +08:00
|
|
|
check_param_count(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
if(self->status & STATUS_COPYING_EFFECT)
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
2023-11-21 11:56:23 +01:00
|
|
|
self->spsummon_code = lua_get<uint32_t>(L, 2);
|
2020-10-30 17:05:28 +01:00
|
|
|
pduel->game_field->core.global_flag |= GLOBALFLAG_SPSUMMON_ONCE;
|
2015-09-25 21:07:16 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
#define CARD_INFO_FUNC(lua_name,attr) \
|
|
|
|
|
LUA_FUNCTION(lua_name) { \
|
|
|
|
|
if(lua_gettop(L) > 1) { \
|
2023-11-21 11:56:23 +01:00
|
|
|
self->data.attr = lua_get<decltype(self->data.attr)>(L, 2); \
|
2022-05-15 13:19:29 +02:00
|
|
|
return 0; \
|
2019-02-09 19:59:46 +01:00
|
|
|
} else \
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->data.attr); \
|
2019-02-09 19:59:46 +01:00
|
|
|
return 1;\
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
CARD_INFO_FUNC(Code, code)
|
|
|
|
|
CARD_INFO_FUNC(Alias, alias)
|
|
|
|
|
|
|
|
|
|
LUA_FUNCTION(Setcode) {
|
2020-01-13 20:03:14 +01:00
|
|
|
if(lua_gettop(L) > 1) {
|
2023-11-21 11:56:23 +01:00
|
|
|
self->data.setcodes.clear();
|
2024-01-06 21:52:34 +01:00
|
|
|
lua_iterate_table_or_stack(L, 2, 2, [&setcodes = self->data.setcodes, L]{
|
|
|
|
|
setcodes.insert(lua_get<uint16_t>(L, -1));
|
|
|
|
|
});
|
2022-03-04 23:53:28 +01:00
|
|
|
return 0;
|
2020-01-13 20:03:14 +01:00
|
|
|
} else {
|
2023-11-21 11:56:23 +01:00
|
|
|
luaL_checkstack(L, static_cast<int>(self->data.setcodes.size()), nullptr);
|
|
|
|
|
for(auto& setcode : self->data.setcodes)
|
2020-01-13 20:03:14 +01:00
|
|
|
lua_pushinteger(L, setcode);
|
|
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
return static_cast<int32_t>(self->data.setcodes.size());
|
2020-01-13 20:03:14 +01:00
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
|
|
|
|
|
CARD_INFO_FUNC(Type, type)
|
|
|
|
|
CARD_INFO_FUNC(Level, level)
|
|
|
|
|
CARD_INFO_FUNC(Attribute, attribute)
|
|
|
|
|
CARD_INFO_FUNC(Race, race)
|
|
|
|
|
CARD_INFO_FUNC(Attack, attack)
|
|
|
|
|
CARD_INFO_FUNC(Defense, defense)
|
|
|
|
|
CARD_INFO_FUNC(Rscale, rscale)
|
|
|
|
|
CARD_INFO_FUNC(Lscale, lscale)
|
|
|
|
|
CARD_INFO_FUNC(LinkMarker, link_marker)
|
|
|
|
|
#undef CARD_INFO_FUNC
|
|
|
|
|
LUA_FUNCTION(Recreate) {
|
2017-11-21 22:00:38 +01:00
|
|
|
check_param_count(L, 2);
|
2021-09-04 22:04:14 +02:00
|
|
|
auto code = lua_get<uint32_t>(L, 2);
|
2023-11-21 11:56:23 +01:00
|
|
|
if (self->recreate(code)) {
|
|
|
|
|
self->data.alias = lua_get<uint32_t>(L, 3, self->data.alias);
|
2020-12-26 00:31:31 +01:00
|
|
|
if(lua_gettop(L) > 3 && !lua_isnoneornil(L, 4)) {
|
2024-01-06 21:52:34 +01:00
|
|
|
lua_iterate_table_or_stack(L, 4, 4, [&setcodes = self->data.setcodes, L]{
|
|
|
|
|
setcodes.insert(lua_get<uint16_t>(L, -1));
|
|
|
|
|
});
|
2020-01-13 20:03:14 +01:00
|
|
|
}
|
2023-11-21 11:56:23 +01:00
|
|
|
self->data.type = lua_get<uint32_t>(L, 5, self->data.type);
|
|
|
|
|
self->data.level = lua_get<uint32_t>(L, 6, self->data.level);
|
|
|
|
|
self->data.attribute = lua_get<uint32_t>(L, 7, self->data.attribute);
|
|
|
|
|
self->data.race = lua_get<uint64_t>(L, 8, self->data.race);
|
|
|
|
|
self->data.attack = lua_get<int32_t>(L, 9, self->data.attack);
|
|
|
|
|
self->data.defense = lua_get<int32_t>(L, 10, self->data.defense);
|
|
|
|
|
self->data.lscale = lua_get<uint32_t>(L, 11, self->data.lscale);
|
|
|
|
|
self->data.rscale = lua_get<uint32_t>(L, 12, self->data.rscale);
|
|
|
|
|
self->data.link_marker = lua_get<uint32_t>(L, 13, self->data.link_marker);
|
2020-07-24 00:07:49 +02:00
|
|
|
if (lua_get<bool, false>(L, 14))
|
2023-11-21 11:56:23 +01:00
|
|
|
self->replace_effect(code, 0, 0, true);
|
2017-11-21 22:00:38 +01:00
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION(Cover) {
|
2019-11-06 18:28:32 +01:00
|
|
|
if(lua_gettop(L) > 1) {
|
2023-11-21 11:56:23 +01:00
|
|
|
self->cover = lua_get<uint32_t>(L, 2);
|
2019-11-06 18:28:32 +01:00
|
|
|
return 0;
|
|
|
|
|
} else
|
2023-11-21 11:56:23 +01:00
|
|
|
lua_pushinteger(L, self->cover);
|
2019-11-06 18:28:32 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
2022-05-15 13:19:29 +02:00
|
|
|
LUA_FUNCTION_EXISTING(GetLuaRef, get_lua_ref<card>);
|
|
|
|
|
LUA_FUNCTION_EXISTING(FromLuaRef, from_lua_ref<card>);
|
|
|
|
|
LUA_FUNCTION_EXISTING(IsDeleted, is_deleted_object);
|
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_card_lib(lua_State* L) {
|
2022-05-15 13:19:29 +02:00
|
|
|
static constexpr auto cardlib = GET_LUA_FUNCTIONS_ARRAY();
|
2023-11-26 14:47:09 +01:00
|
|
|
static_assert(cardlib.back().name == nullptr);
|
2023-02-07 16:43:27 +01:00
|
|
|
lua_createtable(L, 0, static_cast<int>(cardlib.size() - 1));
|
2024-04-13 10:34:09 +02:00
|
|
|
ensure_luaL_stack(luaL_setfuncs, L, cardlib.data(), 0);
|
2021-10-13 17:29:29 +02:00
|
|
|
lua_pushstring(L, "__index");
|
|
|
|
|
lua_pushvalue(L, -2);
|
|
|
|
|
lua_rawset(L, -3);
|
|
|
|
|
lua_setglobal(L, "Card");
|
2023-02-07 16:43:27 +01:00
|
|
|
}
|