dep-ygopro-core/ocgapi.cpp
2020-11-07 19:47:50 +01:00

291 lines
9.1 KiB
C++

#include "ocgapi.h"
#include "interpreter.h"
#include "duel.h"
#include "field.h"
#include "effect.h"
#define DUEL (static_cast<class duel*>(duel))
void DefaultLogHandler(void* payload, const char* string, int type);
void DefaultCardReaderDone(void* payload, OCG_CardData* data);
OCGAPI void OCG_GetVersion(int* major, int* minor) {
if(major)
*major = OCG_VERSION_MAJOR;
if(minor)
*minor = OCG_VERSION_MINOR;
}
OCGAPI int OCG_CreateDuel(OCG_Duel* duel, OCG_DuelOptions options) {
if(duel == nullptr)
return OCG_DUEL_CREATION_NO_OUTPUT;
if(options.cardReader == nullptr) {
*duel = nullptr;
return OCG_DUEL_CREATION_NULL_DATA_READER;
}
if(options.scriptReader == nullptr) {
*duel = nullptr;
return OCG_DUEL_CREATION_NULL_SCRIPT_READER;
}
if(options.logHandler == nullptr) {
options.logHandler = DefaultLogHandler;
options.payload3 = nullptr;
}
if(options.cardReaderDone == nullptr) {
options.cardReaderDone = DefaultCardReaderDone;
options.payload4 = nullptr;
}
auto duelPtr = new class duel(options);
if(duelPtr == nullptr)
return OCG_DUEL_CREATION_NOT_CREATED;
duelPtr->random.seed(options.seed);
duelPtr->game_field->core.duel_options = options.flags;
auto& team = options.team1;
for(int i = 0; i < 2; i++, team = options.team2) {
duelPtr->game_field->player[i].lp = team.startingLP;
duelPtr->game_field->player[i].start_lp = team.startingLP;
duelPtr->game_field->player[i].start_count = team.startingDrawCount;
duelPtr->game_field->player[i].draw_count = team.drawCountPerTurn;
}
*duel = static_cast<OCG_Duel>(duelPtr);
return OCG_DUEL_CREATION_SUCCESS;
}
OCGAPI void OCG_DestroyDuel(OCG_Duel duel) {
if(duel != nullptr)
delete DUEL;
}
OCGAPI void OCG_DuelNewCard(OCG_Duel duel, OCG_NewCardInfo info) {
auto game_field = DUEL->game_field;
if(info.duelist == 0) {
if(game_field->is_location_useable(info.con, info.loc, info.seq)) {
card* pcard = DUEL->new_card(info.code);
pcard->owner = info.team;
game_field->add_card(info.con, pcard, (uint8_t)info.loc, (uint8_t)info.seq);
pcard->current.position = info.pos;
if(!(info.loc & LOCATION_ONFIELD) || (info.pos & POS_FACEUP)) {
pcard->enable_field_effect(true);
game_field->adjust_instant();
}
if(info.loc & LOCATION_ONFIELD) {
if(info.loc == LOCATION_MZONE)
pcard->set_status(STATUS_PROC_COMPLETE, TRUE);
}
}
} else {
if(info.team > 1 || !(info.loc & (LOCATION_DECK | LOCATION_EXTRA)))
return;
info.duelist--;
card* pcard = DUEL->new_card(info.code);
auto& player = game_field->player[info.team];
if(info.duelist >= player.extra_lists_main.size()) {
player.extra_lists_main.resize(info.duelist + 1);
player.extra_lists_extra.resize(info.duelist + 1);
player.extra_lists_hand.resize(info.duelist + 1);
player.extra_extra_p_count.resize(info.duelist + 1);
}
pcard->current.location = (uint8_t)info.loc;
pcard->owner = info.team;
pcard->current.controler = info.team;
pcard->current.position = POS_FACEDOWN_DEFENSE;
if(info.loc == LOCATION_DECK){
auto& list = player.extra_lists_main[info.duelist];
list.push_back(pcard);
pcard->current.sequence = list.size() - 1;
} else {
auto& list = player.extra_lists_extra[info.duelist];
list.push_back(pcard);
pcard->current.sequence = list.size() - 1;
}
}
}
OCGAPI void OCG_StartDuel(OCG_Duel duel) {
DUEL->game_field->add_process(PROCESSOR_STARTUP, 0, 0, 0, 0, 0);
}
OCGAPI int OCG_DuelProcess(OCG_Duel duel) {
DUEL->buff.clear();
int flag = 0;
do {
flag = DUEL->game_field->process();
DUEL->generate_buffer();
} while(DUEL->buff.size() == 0 && flag == PROCESSOR_FLAG_CONTINUE);
return flag;
}
OCGAPI void* OCG_DuelGetMessage(OCG_Duel duel, uint32_t* length) {
DUEL->generate_buffer();
if(length)
*length = DUEL->buff.size();
return DUEL->buff.data();
}
OCGAPI void OCG_DuelSetResponse(OCG_Duel duel, const void* buffer, uint32_t length) {
DUEL->set_response(buffer, length);
}
OCGAPI int OCG_LoadScript(OCG_Duel duel, const char* buffer, uint32_t length, const char* name) {
return DUEL->lua->load_script(buffer, length, name);
}
OCGAPI uint32_t OCG_DuelQueryCount(OCG_Duel duel, uint8_t team, uint32_t loc) {
if(team > 1)
return 0;
auto& player = DUEL->game_field->player[team];
if(loc == LOCATION_HAND)
return player.list_hand.size();
if(loc == LOCATION_GRAVE)
return player.list_grave.size();
if(loc == LOCATION_REMOVED)
return player.list_remove.size();
if(loc == LOCATION_EXTRA)
return player.list_extra.size();
if(loc == LOCATION_DECK)
return player.list_main.size();
uint32_t count = 0;
if(loc == LOCATION_MZONE) {
for(auto& pcard : player.list_mzone)
if(pcard) count++;
}
if(loc == LOCATION_SZONE) {
for(auto& pcard : player.list_szone)
if(pcard) count++;
}
return count;
}
template<typename T>
void insert_value_int(std::vector<uint8_t>& vec, T val) {
const auto vec_size = vec.size();
const auto val_size = sizeof(T);
vec.resize(vec_size + val_size);
std::memcpy(&vec[vec_size], &val, val_size);
}
template<typename T, typename T2>
__forceinline void insert_value(std::vector<uint8_t>& vec, T2 val) {
insert_value_int<T>(vec, static_cast<T>(val));
}
OCGAPI void* OCG_DuelQuery(OCG_Duel duel, uint32_t* length, OCG_QueryInfo info) {
DUEL->query_buffer.clear();
card* pcard = nullptr;
if(info.loc & LOCATION_OVERLAY) {
auto olcard = DUEL->game_field->get_field_card(info.con, (info.loc & LOCATION_OVERLAY), info.seq);
if(olcard && olcard->xyz_materials.size() > info.overlay_seq) {
pcard = olcard->xyz_materials[info.overlay_seq];
}
} else {
pcard = DUEL->game_field->get_field_card(info.con, info.loc, info.seq);
}
if(pcard == nullptr) {
if(length)
*length = 0;
return nullptr;
} else {
pcard->get_infos(info.flags);
}
if(length)
*length = DUEL->query_buffer.size();
return DUEL->query_buffer.data();
}
OCGAPI void* OCG_DuelQueryLocation(OCG_Duel duel, uint32_t* length, OCG_QueryInfo info) {
auto& buffer = DUEL->query_buffer;
auto populate = [&flags = info.flags, &buffer](const field::card_vector& list) {
for(auto& pcard : list) {
if(pcard == nullptr) {
insert_value<int16>(buffer, 0);
} else {
pcard->get_infos(flags);
}
}
};
buffer.clear();
if(info.con <= 1u) {
if(info.loc & LOCATION_OVERLAY) {
insert_value<int16>(buffer, 0);
} else {
auto& player = DUEL->game_field->player[info.con];
if(info.loc == LOCATION_MZONE)
populate(player.list_mzone);
else if(info.loc == LOCATION_SZONE)
populate(player.list_szone);
else if(info.loc == LOCATION_HAND)
populate(player.list_hand);
else if(info.loc == LOCATION_GRAVE)
populate(player.list_grave);
else if(info.loc == LOCATION_REMOVED)
populate(player.list_remove);
else if(info.loc == LOCATION_EXTRA)
populate(player.list_extra);
else if(info.loc == LOCATION_DECK)
populate(player.list_main);
}
std::vector<uint8_t> tmp_vector;
insert_value<uint32_t>(tmp_vector, buffer.size());
buffer.insert(buffer.begin(), tmp_vector.begin(), tmp_vector.end());
}
if(length)
*length = buffer.size();
return buffer.data();
}
OCGAPI void* OCG_DuelQueryField(OCG_Duel duel, uint32_t* length) {
auto& query = DUEL->query_buffer;
query.clear();
//insert_value<int8_t>(query, MSG_RELOAD_FIELD);
insert_value<int32_t>(query, DUEL->game_field->core.duel_options);
for(int playerid = 0; playerid < 2; ++playerid) {
auto& player = DUEL->game_field->player[playerid];
insert_value<int32_t>(query, player.lp);
for(auto& pcard : player.list_mzone) {
if(pcard) {
insert_value<int8_t>(query, 1);
insert_value<int8_t>(query, pcard->current.position);
insert_value<int32_t>(query, pcard->xyz_materials.size());
} else {
insert_value<int8_t>(query, 0);
}
}
for(auto& pcard : player.list_szone) {
if(pcard) {
insert_value<int8_t>(query, 1);
insert_value<int8_t>(query, pcard->current.position);
insert_value<int32_t>(query, pcard->xyz_materials.size());
} else {
insert_value<int8_t>(query, 0);
}
}
insert_value<uint32_t>(query, player.list_main.size());
insert_value<uint32_t>(query, player.list_hand.size());
insert_value<uint32_t>(query, player.list_grave.size());
insert_value<uint32_t>(query, player.list_remove.size());
insert_value<uint32_t>(query, player.list_extra.size());
insert_value<uint32_t>(query, player.extra_p_count);
}
insert_value<int32_t>(query, DUEL->game_field->core.current_chain.size());
for(const auto& ch : DUEL->game_field->core.current_chain) {
effect* peffect = ch.triggering_effect;
insert_value<int32_t>(query, peffect->get_handler()->data.code);
loc_info info = peffect->get_handler()->get_info_location();
insert_value<uint8_t>(query, info.controler);
insert_value<uint8_t>(query, info.location);
insert_value<uint32_t>(query, info.sequence);
insert_value<uint32_t>(query, info.position);
insert_value<uint8_t>(query, ch.triggering_controler);
insert_value<uint8_t>(query, (uint8_t)ch.triggering_location);
insert_value<uint32_t>(query, ch.triggering_sequence);
insert_value<uint64_t>(query, peffect->description);
}
if(length)
*length = query.size();
return query.data();
}
void DefaultLogHandler(void* /*payload*/, const char* /*string*/, int /*type*/) {
}
void DefaultCardReaderDone(void* /*payload*/, OCG_CardData* /*data*/) {
}