mirror of
https://github.com/ErikasKontenis/SabrehavenServer.git
synced 2025-11-29 15:56:50 +01:00
Revert "commit newest tfs branch only for compare"
This reverts commit 1f7dcd7347.
This commit is contained in:
@@ -4,6 +4,7 @@ set(tfs_SRC
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/ban.cpp
|
${CMAKE_CURRENT_LIST_DIR}/ban.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/baseevents.cpp
|
${CMAKE_CURRENT_LIST_DIR}/baseevents.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/bed.cpp
|
${CMAKE_CURRENT_LIST_DIR}/bed.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/behaviourdatabase.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/chat.cpp
|
${CMAKE_CURRENT_LIST_DIR}/chat.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/combat.cpp
|
${CMAKE_CURRENT_LIST_DIR}/combat.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/condition.cpp
|
${CMAKE_CURRENT_LIST_DIR}/condition.cpp
|
||||||
@@ -16,7 +17,6 @@ set(tfs_SRC
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/database.cpp
|
${CMAKE_CURRENT_LIST_DIR}/database.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/databasemanager.cpp
|
${CMAKE_CURRENT_LIST_DIR}/databasemanager.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/databasetasks.cpp
|
${CMAKE_CURRENT_LIST_DIR}/databasetasks.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/depotchest.cpp
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/depotlocker.cpp
|
${CMAKE_CURRENT_LIST_DIR}/depotlocker.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/events.cpp
|
${CMAKE_CURRENT_LIST_DIR}/events.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/fileloader.cpp
|
${CMAKE_CURRENT_LIST_DIR}/fileloader.cpp
|
||||||
@@ -26,12 +26,10 @@ set(tfs_SRC
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/groups.cpp
|
${CMAKE_CURRENT_LIST_DIR}/groups.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/house.cpp
|
${CMAKE_CURRENT_LIST_DIR}/house.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/housetile.cpp
|
${CMAKE_CURRENT_LIST_DIR}/housetile.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/inbox.cpp
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/ioguild.cpp
|
${CMAKE_CURRENT_LIST_DIR}/ioguild.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/iologindata.cpp
|
${CMAKE_CURRENT_LIST_DIR}/iologindata.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/iomap.cpp
|
${CMAKE_CURRENT_LIST_DIR}/iomap.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/iomapserialize.cpp
|
${CMAKE_CURRENT_LIST_DIR}/iomapserialize.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/iomarket.cpp
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/item.cpp
|
${CMAKE_CURRENT_LIST_DIR}/item.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/items.cpp
|
${CMAKE_CURRENT_LIST_DIR}/items.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/luascript.cpp
|
${CMAKE_CURRENT_LIST_DIR}/luascript.cpp
|
||||||
@@ -39,7 +37,6 @@ set(tfs_SRC
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/map.cpp
|
${CMAKE_CURRENT_LIST_DIR}/map.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/monster.cpp
|
${CMAKE_CURRENT_LIST_DIR}/monster.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/monsters.cpp
|
${CMAKE_CURRENT_LIST_DIR}/monsters.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/mounts.cpp
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/movement.cpp
|
${CMAKE_CURRENT_LIST_DIR}/movement.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/networkmessage.cpp
|
${CMAKE_CURRENT_LIST_DIR}/networkmessage.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/npc.cpp
|
${CMAKE_CURRENT_LIST_DIR}/npc.cpp
|
||||||
@@ -52,29 +49,24 @@ set(tfs_SRC
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/protocol.cpp
|
${CMAKE_CURRENT_LIST_DIR}/protocol.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocolgame.cpp
|
${CMAKE_CURRENT_LIST_DIR}/protocolgame.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocollogin.cpp
|
${CMAKE_CURRENT_LIST_DIR}/protocollogin.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocolold.cpp
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/protocolstatus.cpp
|
${CMAKE_CURRENT_LIST_DIR}/protocolstatus.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/quests.cpp
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/raids.cpp
|
${CMAKE_CURRENT_LIST_DIR}/raids.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/rsa.cpp
|
${CMAKE_CURRENT_LIST_DIR}/rsa.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/scheduler.cpp
|
${CMAKE_CURRENT_LIST_DIR}/scheduler.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/scriptmanager.cpp
|
${CMAKE_CURRENT_LIST_DIR}/scriptmanager.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/script.cpp
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/server.cpp
|
${CMAKE_CURRENT_LIST_DIR}/server.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/signals.cpp
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/spawn.cpp
|
${CMAKE_CURRENT_LIST_DIR}/spawn.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/spells.cpp
|
${CMAKE_CURRENT_LIST_DIR}/spells.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/script.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/talkaction.cpp
|
${CMAKE_CURRENT_LIST_DIR}/talkaction.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/tasks.cpp
|
${CMAKE_CURRENT_LIST_DIR}/tasks.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/teleport.cpp
|
${CMAKE_CURRENT_LIST_DIR}/teleport.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/thing.cpp
|
${CMAKE_CURRENT_LIST_DIR}/thing.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/tile.cpp
|
${CMAKE_CURRENT_LIST_DIR}/tile.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/tools.cpp
|
${CMAKE_CURRENT_LIST_DIR}/tools.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/trashholder.cpp
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/vocation.cpp
|
${CMAKE_CURRENT_LIST_DIR}/vocation.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/waitlist.cpp
|
${CMAKE_CURRENT_LIST_DIR}/waitlist.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/weapons.cpp
|
|
||||||
${CMAKE_CURRENT_LIST_DIR}/wildcardtree.cpp
|
${CMAKE_CURRENT_LIST_DIR}/wildcardtree.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/xtea.cpp
|
${CMAKE_CURRENT_LIST_DIR}/xtea.cpp
|
||||||
PARENT_SCOPE)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,8 +24,6 @@
|
|||||||
|
|
||||||
struct Account {
|
struct Account {
|
||||||
std::vector<std::string> characters;
|
std::vector<std::string> characters;
|
||||||
std::string name;
|
|
||||||
std::string key;
|
|
||||||
time_t lastDay = 0;
|
time_t lastDay = 0;
|
||||||
uint32_t id = 0;
|
uint32_t id = 0;
|
||||||
uint16_t premiumDays = 0;
|
uint16_t premiumDays = 0;
|
||||||
|
|||||||
271
src/actions.cpp
271
src/actions.cpp
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -40,27 +40,29 @@ Actions::Actions() :
|
|||||||
|
|
||||||
Actions::~Actions()
|
Actions::~Actions()
|
||||||
{
|
{
|
||||||
clear(false);
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actions::clearMap(ActionUseMap& map, bool fromLua)
|
inline void Actions::clearMap(ActionUseMap& map)
|
||||||
{
|
{
|
||||||
for (auto it = map.begin(); it != map.end(); ) {
|
// Filter out duplicates to avoid double-free
|
||||||
if (fromLua == it->second.fromLua) {
|
std::unordered_set<Action*> set;
|
||||||
it = map.erase(it);
|
for (const auto& it : map) {
|
||||||
} else {
|
set.insert(it.second);
|
||||||
++it;
|
}
|
||||||
}
|
map.clear();
|
||||||
|
|
||||||
|
for (Action* action : set) {
|
||||||
|
delete action;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actions::clear(bool fromLua)
|
void Actions::clear()
|
||||||
{
|
{
|
||||||
clearMap(useItemMap, fromLua);
|
clearMap(useItemMap);
|
||||||
clearMap(uniqueItemMap, fromLua);
|
clearMap(actionItemMap);
|
||||||
clearMap(actionItemMap, fromLua);
|
|
||||||
|
|
||||||
reInitState(fromLua);
|
scriptInterface.reInitState();
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaScriptInterface& Actions::getScriptInterface()
|
LuaScriptInterface& Actions::getScriptInterface()
|
||||||
@@ -73,23 +75,23 @@ std::string Actions::getScriptBaseName() const
|
|||||||
return "actions";
|
return "actions";
|
||||||
}
|
}
|
||||||
|
|
||||||
Event_ptr Actions::getEvent(const std::string& nodeName)
|
Event* Actions::getEvent(const std::string& nodeName)
|
||||||
{
|
{
|
||||||
if (strcasecmp(nodeName.c_str(), "action") != 0) {
|
if (strcasecmp(nodeName.c_str(), "action") != 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return Event_ptr(new Action(&scriptInterface));
|
return new Action(&scriptInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Actions::registerEvent(Event_ptr event, const pugi::xml_node& node)
|
bool Actions::registerEvent(Event* event, const pugi::xml_node& node)
|
||||||
{
|
{
|
||||||
Action_ptr action{static_cast<Action*>(event.release())}; //event is guaranteed to be an Action
|
Action* action = static_cast<Action*>(event); //event is guaranteed to be an Action
|
||||||
|
|
||||||
pugi::xml_attribute attr;
|
pugi::xml_attribute attr;
|
||||||
if ((attr = node.attribute("itemid"))) {
|
if ((attr = node.attribute("itemid"))) {
|
||||||
uint16_t id = pugi::cast<uint16_t>(attr.value());
|
uint16_t id = pugi::cast<uint16_t>(attr.value());
|
||||||
|
|
||||||
auto result = useItemMap.emplace(id, std::move(*action));
|
auto result = useItemMap.emplace(id, action);
|
||||||
if (!result.second) {
|
if (!result.second) {
|
||||||
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with id: " << id << std::endl;
|
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with id: " << id << std::endl;
|
||||||
}
|
}
|
||||||
@@ -105,14 +107,14 @@ bool Actions::registerEvent(Event_ptr event, const pugi::xml_node& node)
|
|||||||
uint16_t iterId = fromId;
|
uint16_t iterId = fromId;
|
||||||
uint16_t toId = pugi::cast<uint16_t>(toIdAttribute.value());
|
uint16_t toId = pugi::cast<uint16_t>(toIdAttribute.value());
|
||||||
|
|
||||||
auto result = useItemMap.emplace(iterId, *action);
|
auto result = useItemMap.emplace(iterId, action);
|
||||||
if (!result.second) {
|
if (!result.second) {
|
||||||
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with id: " << iterId << " in fromid: " << fromId << ", toid: " << toId << std::endl;
|
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with id: " << iterId << " in fromid: " << fromId << ", toid: " << toId << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = result.second;
|
bool success = result.second;
|
||||||
while (++iterId <= toId) {
|
while (++iterId <= toId) {
|
||||||
result = useItemMap.emplace(iterId, *action);
|
result = useItemMap.emplace(iterId, action);
|
||||||
if (!result.second) {
|
if (!result.second) {
|
||||||
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with id: " << iterId << " in fromid: " << fromId << ", toid: " << toId << std::endl;
|
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with id: " << iterId << " in fromid: " << fromId << ", toid: " << toId << std::endl;
|
||||||
continue;
|
continue;
|
||||||
@@ -120,44 +122,10 @@ bool Actions::registerEvent(Event_ptr event, const pugi::xml_node& node)
|
|||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
} else if ((attr = node.attribute("uniqueid"))) {
|
|
||||||
uint16_t uid = pugi::cast<uint16_t>(attr.value());
|
|
||||||
|
|
||||||
auto result = uniqueItemMap.emplace(uid, std::move(*action));
|
|
||||||
if (!result.second) {
|
|
||||||
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with uniqueid: " << uid << std::endl;
|
|
||||||
}
|
|
||||||
return result.second;
|
|
||||||
} else if ((attr = node.attribute("fromuid"))) {
|
|
||||||
pugi::xml_attribute toUidAttribute = node.attribute("touid");
|
|
||||||
if (!toUidAttribute) {
|
|
||||||
std::cout << "[Warning - Actions::registerEvent] Missing touid in fromuid: " << attr.as_string() << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t fromUid = pugi::cast<uint16_t>(attr.value());
|
|
||||||
uint16_t iterUid = fromUid;
|
|
||||||
uint16_t toUid = pugi::cast<uint16_t>(toUidAttribute.value());
|
|
||||||
|
|
||||||
auto result = uniqueItemMap.emplace(iterUid, *action);
|
|
||||||
if (!result.second) {
|
|
||||||
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with unique id: " << iterUid << " in fromuid: " << fromUid << ", touid: " << toUid << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool success = result.second;
|
|
||||||
while (++iterUid <= toUid) {
|
|
||||||
result = uniqueItemMap.emplace(iterUid, *action);
|
|
||||||
if (!result.second) {
|
|
||||||
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with unique id: " << iterUid << " in fromuid: " << fromUid << ", touid: " << toUid << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
success = true;
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
} else if ((attr = node.attribute("actionid"))) {
|
} else if ((attr = node.attribute("actionid"))) {
|
||||||
uint16_t aid = pugi::cast<uint16_t>(attr.value());
|
uint16_t aid = pugi::cast<uint16_t>(attr.value());
|
||||||
|
|
||||||
auto result = actionItemMap.emplace(aid, std::move(*action));
|
auto result = actionItemMap.emplace(aid, action);
|
||||||
if (!result.second) {
|
if (!result.second) {
|
||||||
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with actionid: " << aid << std::endl;
|
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with actionid: " << aid << std::endl;
|
||||||
}
|
}
|
||||||
@@ -173,14 +141,14 @@ bool Actions::registerEvent(Event_ptr event, const pugi::xml_node& node)
|
|||||||
uint16_t iterAid = fromAid;
|
uint16_t iterAid = fromAid;
|
||||||
uint16_t toAid = pugi::cast<uint16_t>(toAidAttribute.value());
|
uint16_t toAid = pugi::cast<uint16_t>(toAidAttribute.value());
|
||||||
|
|
||||||
auto result = actionItemMap.emplace(iterAid, *action);
|
auto result = actionItemMap.emplace(iterAid, action);
|
||||||
if (!result.second) {
|
if (!result.second) {
|
||||||
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with action id: " << iterAid << " in fromaid: " << fromAid << ", toaid: " << toAid << std::endl;
|
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with action id: " << iterAid << " in fromaid: " << fromAid << ", toaid: " << toAid << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = result.second;
|
bool success = result.second;
|
||||||
while (++iterAid <= toAid) {
|
while (++iterAid <= toAid) {
|
||||||
result = actionItemMap.emplace(iterAid, *action);
|
result = actionItemMap.emplace(iterAid, action);
|
||||||
if (!result.second) {
|
if (!result.second) {
|
||||||
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with action id: " << iterAid << " in fromaid: " << fromAid << ", toaid: " << toAid << std::endl;
|
std::cout << "[Warning - Actions::registerEvent] Duplicate registered item with action id: " << iterAid << " in fromaid: " << fromAid << ", toaid: " << toAid << std::endl;
|
||||||
continue;
|
continue;
|
||||||
@@ -192,69 +160,6 @@ bool Actions::registerEvent(Event_ptr event, const pugi::xml_node& node)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Actions::registerLuaEvent(Action* event)
|
|
||||||
{
|
|
||||||
Action_ptr action{ event };
|
|
||||||
if (action->getItemIdRange().size() > 0) {
|
|
||||||
if (action->getItemIdRange().size() == 1) {
|
|
||||||
auto result = useItemMap.emplace(action->getItemIdRange().at(0), std::move(*action));
|
|
||||||
if (!result.second) {
|
|
||||||
std::cout << "[Warning - Actions::registerLuaEvent] Duplicate registered item with id: " << action->getItemIdRange().at(0) << std::endl;
|
|
||||||
}
|
|
||||||
return result.second;
|
|
||||||
} else {
|
|
||||||
auto v = action->getItemIdRange();
|
|
||||||
for (auto i = v.begin(); i != v.end(); i++) {
|
|
||||||
auto result = useItemMap.emplace(*i, std::move(*action));
|
|
||||||
if (!result.second) {
|
|
||||||
std::cout << "[Warning - Actions::registerLuaEvent] Duplicate registered item with id: " << *i << " in range from id: " << v.at(0) << ", to id: " << v.at(v.size() - 1) << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (action->getUniqueIdRange().size() > 0) {
|
|
||||||
if (action->getUniqueIdRange().size() == 1) {
|
|
||||||
auto result = uniqueItemMap.emplace(action->getUniqueIdRange().at(0), std::move(*action));
|
|
||||||
if (!result.second) {
|
|
||||||
std::cout << "[Warning - Actions::registerLuaEvent] Duplicate registered item with uid: " << action->getUniqueIdRange().at(0) << std::endl;
|
|
||||||
}
|
|
||||||
return result.second;
|
|
||||||
} else {
|
|
||||||
auto v = action->getUniqueIdRange();
|
|
||||||
for (auto i = v.begin(); i != v.end(); i++) {
|
|
||||||
auto result = uniqueItemMap.emplace(*i, std::move(*action));
|
|
||||||
if (!result.second) {
|
|
||||||
std::cout << "[Warning - Actions::registerLuaEvent] Duplicate registered item with uid: " << *i << " in range from uid: " << v.at(0) << ", to uid: " << v.at(v.size() - 1) << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (action->getActionIdRange().size() > 0) {
|
|
||||||
if (action->getActionIdRange().size() == 1) {
|
|
||||||
auto result = actionItemMap.emplace(action->getActionIdRange().at(0), std::move(*action));
|
|
||||||
if (!result.second) {
|
|
||||||
std::cout << "[Warning - Actions::registerLuaEvent] Duplicate registered item with aid: " << action->getActionIdRange().at(0) << std::endl;
|
|
||||||
}
|
|
||||||
return result.second;
|
|
||||||
} else {
|
|
||||||
auto v = action->getActionIdRange();
|
|
||||||
for (auto i = v.begin(); i != v.end(); i++) {
|
|
||||||
auto result = actionItemMap.emplace(*i, std::move(*action));
|
|
||||||
if (!result.second) {
|
|
||||||
std::cout << "[Warning - Actions::registerLuaEvent] Duplicate registered item with aid: " << *i << " in range from aid: " << v.at(0) << ", to aid: " << v.at(v.size() - 1) << std::endl;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::cout << "[Warning - Actions::registerLuaEvent] There is no id / aid / uid set for this event" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue Actions::canUse(const Player* player, const Position& pos)
|
ReturnValue Actions::canUse(const Player* player, const Position& pos)
|
||||||
{
|
{
|
||||||
if (pos.x != 0xFFFF) {
|
if (pos.x != 0xFFFF) {
|
||||||
@@ -303,23 +208,16 @@ ReturnValue Actions::canUseFar(const Creature* creature, const Position& toPos,
|
|||||||
|
|
||||||
Action* Actions::getAction(const Item* item)
|
Action* Actions::getAction(const Item* item)
|
||||||
{
|
{
|
||||||
if (item->hasAttribute(ITEM_ATTRIBUTE_UNIQUEID)) {
|
|
||||||
auto it = uniqueItemMap.find(item->getUniqueId());
|
|
||||||
if (it != uniqueItemMap.end()) {
|
|
||||||
return &it->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->hasAttribute(ITEM_ATTRIBUTE_ACTIONID)) {
|
if (item->hasAttribute(ITEM_ATTRIBUTE_ACTIONID)) {
|
||||||
auto it = actionItemMap.find(item->getActionId());
|
auto it = actionItemMap.find(item->getActionId());
|
||||||
if (it != actionItemMap.end()) {
|
if (it != actionItemMap.end()) {
|
||||||
return &it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto it = useItemMap.find(item->getID());
|
auto it = useItemMap.find(item->getID());
|
||||||
if (it != useItemMap.end()) {
|
if (it != useItemMap.end()) {
|
||||||
return &it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
//rune items
|
//rune items
|
||||||
@@ -358,41 +256,44 @@ ReturnValue Actions::internalUseItem(Player* player, const Position& pos, uint8_
|
|||||||
|
|
||||||
if (bed->trySleep(player)) {
|
if (bed->trySleep(player)) {
|
||||||
player->setBedItem(bed);
|
player->setBedItem(bed);
|
||||||
g_game.sendOfflineTrainingDialog(player);
|
if (!bed->sleep(player)) {
|
||||||
|
return RETURNVALUE_CANNOTUSETHISOBJECT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return RETURNVALUE_NOERROR;
|
return RETURNVALUE_NOERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Container* container = item->getContainer()) {
|
if (Container* container = item->getContainer()) {
|
||||||
Container* openContainer;
|
if (!item->isChestQuest()) {
|
||||||
|
Container* openContainer;
|
||||||
|
|
||||||
//depot container
|
//depot container
|
||||||
if (DepotLocker* depot = container->getDepotLocker()) {
|
if (DepotLocker* depot = container->getDepotLocker()) {
|
||||||
DepotLocker* myDepotLocker = player->getDepotLocker(depot->getDepotId());
|
DepotLocker* myDepotLocker = player->getDepotLocker(depot->getDepotId(), true);
|
||||||
myDepotLocker->setParent(depot->getParent()->getTile());
|
myDepotLocker->setParent(depot->getParent()->getTile());
|
||||||
openContainer = myDepotLocker;
|
openContainer = myDepotLocker;
|
||||||
player->setLastDepotId(depot->getDepotId());
|
} else {
|
||||||
} else {
|
openContainer = container;
|
||||||
openContainer = container;
|
}
|
||||||
|
|
||||||
|
uint32_t corpseOwner = container->getCorpseOwner();
|
||||||
|
if (corpseOwner != 0 && !player->canOpenCorpse(corpseOwner)) {
|
||||||
|
return RETURNVALUE_YOUARENOTTHEOWNER;
|
||||||
|
}
|
||||||
|
|
||||||
|
//open/close container
|
||||||
|
int32_t oldContainerId = player->getContainerID(openContainer);
|
||||||
|
if (oldContainerId != -1) {
|
||||||
|
player->onCloseContainer(openContainer);
|
||||||
|
player->closeContainer(oldContainerId);
|
||||||
|
} else {
|
||||||
|
player->addContainer(index, openContainer);
|
||||||
|
player->onSendContainer(openContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RETURNVALUE_NOERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t corpseOwner = container->getCorpseOwner();
|
|
||||||
if (corpseOwner != 0 && !player->canOpenCorpse(corpseOwner)) {
|
|
||||||
return RETURNVALUE_YOUARENOTTHEOWNER;
|
|
||||||
}
|
|
||||||
|
|
||||||
//open/close container
|
|
||||||
int32_t oldContainerId = player->getContainerID(openContainer);
|
|
||||||
if (oldContainerId != -1) {
|
|
||||||
player->onCloseContainer(openContainer);
|
|
||||||
player->closeContainer(oldContainerId);
|
|
||||||
} else {
|
|
||||||
player->addContainer(index, openContainer);
|
|
||||||
player->onSendContainer(openContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return RETURNVALUE_NOERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ItemType& it = Item::items[item->getID()];
|
const ItemType& it = Item::items[item->getID()];
|
||||||
@@ -406,6 +307,12 @@ ReturnValue Actions::internalUseItem(Player* player, const Position& pos, uint8_
|
|||||||
}
|
}
|
||||||
|
|
||||||
return RETURNVALUE_NOERROR;
|
return RETURNVALUE_NOERROR;
|
||||||
|
} else if (it.changeUse) {
|
||||||
|
if (it.transformToOnUse) {
|
||||||
|
g_game.transformItem(item, it.transformToOnUse);
|
||||||
|
g_game.startDecay(item);
|
||||||
|
return RETURNVALUE_NOERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return RETURNVALUE_CANNOTUSETHISOBJECT;
|
return RETURNVALUE_CANNOTUSETHISOBJECT;
|
||||||
@@ -417,7 +324,7 @@ bool Actions::useItem(Player* player, const Position& pos, uint8_t index, Item*
|
|||||||
player->stopWalk();
|
player->stopWalk();
|
||||||
|
|
||||||
if (isHotkey) {
|
if (isHotkey) {
|
||||||
showUseHotkeyMessage(player, item, player->getItemTypeCount(item->getID(), item->getSubType()));
|
showUseHotkeyMessage(player, item, player->getItemTypeCount(item->getID(), -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue ret = internalUseItem(player, pos, index, item, isHotkey);
|
ReturnValue ret = internalUseItem(player, pos, index, item, isHotkey);
|
||||||
@@ -447,7 +354,7 @@ bool Actions::useItemEx(Player* player, const Position& fromPos, const Position&
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isHotkey) {
|
if (isHotkey) {
|
||||||
showUseHotkeyMessage(player, item, player->getItemTypeCount(item->getID(), item->getSubType()));
|
showUseHotkeyMessage(player, item, player->getItemTypeCount(item->getID(), -1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!action->executeUse(player, item, fromPos, action->getTarget(player, creature, toPos, toStackPos), toPos, isHotkey)) {
|
if (!action->executeUse(player, item, fromPos, action->getTarget(player, creature, toPos, toStackPos), toPos, isHotkey)) {
|
||||||
@@ -466,9 +373,11 @@ void Actions::showUseHotkeyMessage(Player* player, const Item* item, uint32_t co
|
|||||||
const ItemType& it = Item::items[item->getID()];
|
const ItemType& it = Item::items[item->getID()];
|
||||||
if (!it.showCount) {
|
if (!it.showCount) {
|
||||||
ss << "Using one of " << item->getName() << "...";
|
ss << "Using one of " << item->getName() << "...";
|
||||||
} else if (count == 1) {
|
}
|
||||||
|
else if (count == 1) {
|
||||||
ss << "Using the last " << item->getName() << "...";
|
ss << "Using the last " << item->getName() << "...";
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
ss << "Using one of " << count << ' ' << item->getPluralName() << "...";
|
ss << "Using one of " << count << ' ' << item->getPluralName() << "...";
|
||||||
}
|
}
|
||||||
player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
|
player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
|
||||||
@@ -477,6 +386,9 @@ void Actions::showUseHotkeyMessage(Player* player, const Item* item, uint32_t co
|
|||||||
Action::Action(LuaScriptInterface* interface) :
|
Action::Action(LuaScriptInterface* interface) :
|
||||||
Event(interface), function(nullptr), allowFarUse(false), checkFloor(true), checkLineOfSight(true) {}
|
Event(interface), function(nullptr), allowFarUse(false), checkFloor(true), checkLineOfSight(true) {}
|
||||||
|
|
||||||
|
Action::Action(const Action* copy) :
|
||||||
|
Event(copy), allowFarUse(copy->allowFarUse), checkFloor(copy->checkFloor), checkLineOfSight(copy->checkLineOfSight) {}
|
||||||
|
|
||||||
bool Action::configureEvent(const pugi::xml_node& node)
|
bool Action::configureEvent(const pugi::xml_node& node)
|
||||||
{
|
{
|
||||||
pugi::xml_attribute allowFarUseAttr = node.attribute("allowfaruse");
|
pugi::xml_attribute allowFarUseAttr = node.attribute("allowfaruse");
|
||||||
@@ -497,38 +409,6 @@ bool Action::configureEvent(const pugi::xml_node& node)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
bool enterMarket(Player* player, Item*, const Position&, Thing*, const Position&, bool)
|
|
||||||
{
|
|
||||||
if (player->getLastDepotId() == -1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
player->sendMarketEnter(player->getLastDepotId());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Action::loadFunction(const pugi::xml_attribute& attr, bool isScripted)
|
|
||||||
{
|
|
||||||
const char* functionName = attr.as_string();
|
|
||||||
if (strcasecmp(functionName, "market") == 0) {
|
|
||||||
function = enterMarket;
|
|
||||||
} else {
|
|
||||||
if (!isScripted) {
|
|
||||||
std::cout << "[Warning - Action::loadFunction] Function \"" << functionName << "\" does not exist." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isScripted) {
|
|
||||||
scripted = false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Action::getScriptEventName() const
|
std::string Action::getScriptEventName() const
|
||||||
{
|
{
|
||||||
return "onUse";
|
return "onUse";
|
||||||
@@ -538,7 +418,8 @@ ReturnValue Action::canExecuteAction(const Player* player, const Position& toPos
|
|||||||
{
|
{
|
||||||
if (!allowFarUse) {
|
if (!allowFarUse) {
|
||||||
return g_actions->canUse(player, toPos);
|
return g_actions->canUse(player, toPos);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
return g_actions->canUseFar(player, toPos, checkLineOfSight, checkFloor);
|
return g_actions->canUseFar(player, toPos, checkLineOfSight, checkFloor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -31,14 +31,15 @@ using ActionFunction = std::function<bool(Player* player, Item* item, const Posi
|
|||||||
class Action : public Event
|
class Action : public Event
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
explicit Action(const Action* copy);
|
||||||
explicit Action(LuaScriptInterface* interface);
|
explicit Action(LuaScriptInterface* interface);
|
||||||
|
|
||||||
bool configureEvent(const pugi::xml_node& node) override;
|
bool configureEvent(const pugi::xml_node& node) override;
|
||||||
bool loadFunction(const pugi::xml_attribute& attr, bool isScripted) override;
|
|
||||||
|
|
||||||
//scripting
|
//scripting
|
||||||
virtual bool executeUse(Player* player, Item* item, const Position& fromPosition,
|
virtual bool executeUse(Player* player, Item* item, const Position& fromPosition,
|
||||||
Thing* target, const Position& toPosition, bool isHotkey);
|
Thing* target, const Position& toPosition, bool isHotkey);
|
||||||
|
//
|
||||||
|
|
||||||
bool getAllowFarUse() const {
|
bool getAllowFarUse() const {
|
||||||
return allowFarUse;
|
return allowFarUse;
|
||||||
@@ -118,25 +119,22 @@ class Actions final : public BaseEvents
|
|||||||
ReturnValue canUse(const Player* player, const Position& pos, const Item* item);
|
ReturnValue canUse(const Player* player, const Position& pos, const Item* item);
|
||||||
ReturnValue canUseFar(const Creature* creature, const Position& toPos, bool checkLineOfSight, bool checkFloor);
|
ReturnValue canUseFar(const Creature* creature, const Position& toPos, bool checkLineOfSight, bool checkFloor);
|
||||||
|
|
||||||
bool registerLuaEvent(Action* event);
|
|
||||||
void clear(bool fromLua) override final;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ReturnValue internalUseItem(Player* player, const Position& pos, uint8_t index, Item* item, bool isHotkey);
|
ReturnValue internalUseItem(Player* player, const Position& pos, uint8_t index, Item* item, bool isHotkey);
|
||||||
static void showUseHotkeyMessage(Player* player, const Item* item, uint32_t count);
|
static void showUseHotkeyMessage(Player* player, const Item* item, uint32_t count);
|
||||||
|
|
||||||
LuaScriptInterface& getScriptInterface() override;
|
void clear() final;
|
||||||
std::string getScriptBaseName() const override;
|
LuaScriptInterface& getScriptInterface() final;
|
||||||
Event_ptr getEvent(const std::string& nodeName) override;
|
std::string getScriptBaseName() const final;
|
||||||
bool registerEvent(Event_ptr event, const pugi::xml_node& node) override;
|
Event* getEvent(const std::string& nodeName) final;
|
||||||
|
bool registerEvent(Event* event, const pugi::xml_node& node) final;
|
||||||
|
|
||||||
using ActionUseMap = std::map<uint16_t, Action>;
|
typedef std::map<uint16_t, Action*> ActionUseMap;
|
||||||
ActionUseMap useItemMap;
|
ActionUseMap useItemMap;
|
||||||
ActionUseMap uniqueItemMap;
|
|
||||||
ActionUseMap actionItemMap;
|
ActionUseMap actionItemMap;
|
||||||
|
|
||||||
Action* getAction(const Item* item);
|
Action* getAction(const Item* item);
|
||||||
void clearMap(ActionUseMap& map, bool fromLua);
|
void clearMap(ActionUseMap& map);
|
||||||
|
|
||||||
LuaScriptInterface scriptInterface;
|
LuaScriptInterface scriptInterface;
|
||||||
};
|
};
|
||||||
|
|||||||
30
src/ban.cpp
30
src/ban.cpp
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,15 +24,15 @@
|
|||||||
#include "databasetasks.h"
|
#include "databasetasks.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
bool Ban::acceptConnection(uint32_t clientIP)
|
bool Ban::acceptConnection(uint32_t clientip)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lockClass(lock);
|
std::lock_guard<std::recursive_mutex> lockClass(lock);
|
||||||
|
|
||||||
uint64_t currentTime = OTSYS_TIME();
|
uint64_t currentTime = OTSYS_TIME();
|
||||||
|
|
||||||
auto it = ipConnectMap.find(clientIP);
|
auto it = ipConnectMap.find(clientip);
|
||||||
if (it == ipConnectMap.end()) {
|
if (it == ipConnectMap.end()) {
|
||||||
ipConnectMap.emplace(clientIP, ConnectBlock(currentTime, 0, 1));
|
ipConnectMap.emplace(clientip, ConnectBlock(currentTime, 0, 1));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,12 +60,12 @@ bool Ban::acceptConnection(uint32_t clientIP)
|
|||||||
|
|
||||||
bool IOBan::isAccountBanned(uint32_t accountId, BanInfo& banInfo)
|
bool IOBan::isAccountBanned(uint32_t accountId, BanInfo& banInfo)
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `reason`, `expires_at`, `banned_at`, `banned_by`, (SELECT `name` FROM `players` WHERE `id` = `banned_by`) AS `name` FROM `account_bans` WHERE `account_id` = " << accountId;
|
query << "SELECT `reason`, `expires_at`, `banned_at`, `banned_by`, (SELECT `name` FROM `players` WHERE `id` = `banned_by`) AS `name` FROM `account_bans` WHERE `account_id` = " << accountId;
|
||||||
|
|
||||||
DBResult_ptr result = db.storeQuery(query.str());
|
DBResult_ptr result = db->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ bool IOBan::isAccountBanned(uint32_t accountId, BanInfo& banInfo)
|
|||||||
if (expiresAt != 0 && time(nullptr) > expiresAt) {
|
if (expiresAt != 0 && time(nullptr) > expiresAt) {
|
||||||
// Move the ban to history if it has expired
|
// Move the ban to history if it has expired
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "INSERT INTO `account_ban_history` (`account_id`, `reason`, `banned_at`, `expired_at`, `banned_by`) VALUES (" << accountId << ',' << db.escapeString(result->getString("reason")) << ',' << result->getNumber<time_t>("banned_at") << ',' << expiresAt << ',' << result->getNumber<uint32_t>("banned_by") << ')';
|
query << "INSERT INTO `account_ban_history` (`account_id`, `reason`, `banned_at`, `expired_at`, `banned_by`) VALUES (" << accountId << ',' << db->escapeString(result->getString("reason")) << ',' << result->getNumber<time_t>("banned_at") << ',' << expiresAt << ',' << result->getNumber<uint32_t>("banned_by") << ')';
|
||||||
g_databaseTasks.addTask(query.str());
|
g_databaseTasks.addTask(query.str());
|
||||||
|
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
@@ -89,18 +89,18 @@ bool IOBan::isAccountBanned(uint32_t accountId, BanInfo& banInfo)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IOBan::isIpBanned(uint32_t clientIP, BanInfo& banInfo)
|
bool IOBan::isIpBanned(uint32_t clientip, BanInfo& banInfo)
|
||||||
{
|
{
|
||||||
if (clientIP == 0) {
|
if (clientip == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `reason`, `expires_at`, (SELECT `name` FROM `players` WHERE `id` = `banned_by`) AS `name` FROM `ip_bans` WHERE `ip` = " << clientIP;
|
query << "SELECT `reason`, `expires_at`, (SELECT `name` FROM `players` WHERE `id` = `banned_by`) AS `name` FROM `ip_bans` WHERE `ip` = " << clientip;
|
||||||
|
|
||||||
DBResult_ptr result = db.storeQuery(query.str());
|
DBResult_ptr result = db->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ bool IOBan::isIpBanned(uint32_t clientIP, BanInfo& banInfo)
|
|||||||
int64_t expiresAt = result->getNumber<int64_t>("expires_at");
|
int64_t expiresAt = result->getNumber<int64_t>("expires_at");
|
||||||
if (expiresAt != 0 && time(nullptr) > expiresAt) {
|
if (expiresAt != 0 && time(nullptr) > expiresAt) {
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "DELETE FROM `ip_bans` WHERE `ip` = " << clientIP;
|
query << "DELETE FROM `ip_bans` WHERE `ip` = " << clientip;
|
||||||
g_databaseTasks.addTask(query.str());
|
g_databaseTasks.addTask(query.str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -123,5 +123,5 @@ bool IOBan::isPlayerNamelocked(uint32_t playerId)
|
|||||||
{
|
{
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT 1 FROM `player_namelocks` WHERE `player_id` = " << playerId;
|
query << "SELECT 1 FROM `player_namelocks` WHERE `player_id` = " << playerId;
|
||||||
return Database::getInstance().storeQuery(query.str()).get() != nullptr;
|
return Database::getInstance()->storeQuery(query.str()).get() != nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/ban.h
12
src/ban.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -35,14 +35,14 @@ struct ConnectBlock {
|
|||||||
uint32_t count;
|
uint32_t count;
|
||||||
};
|
};
|
||||||
|
|
||||||
using IpConnectMap = std::map<uint32_t, ConnectBlock>;
|
typedef std::map<uint32_t, ConnectBlock> IpConnectMap;
|
||||||
|
|
||||||
class Ban
|
class Ban
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool acceptConnection(uint32_t clientIP);
|
bool acceptConnection(uint32_t clientip);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
IpConnectMap ipConnectMap;
|
IpConnectMap ipConnectMap;
|
||||||
std::recursive_mutex lock;
|
std::recursive_mutex lock;
|
||||||
};
|
};
|
||||||
@@ -51,7 +51,7 @@ class IOBan
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool isAccountBanned(uint32_t accountId, BanInfo& banInfo);
|
static bool isAccountBanned(uint32_t accountId, BanInfo& banInfo);
|
||||||
static bool isIpBanned(uint32_t clientIP, BanInfo& banInfo);
|
static bool isIpBanned(uint32_t ip, BanInfo& banInfo);
|
||||||
static bool isPlayerNamelocked(uint32_t playerId);
|
static bool isPlayerNamelocked(uint32_t playerId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -51,13 +51,14 @@ bool BaseEvents::loadFromXml()
|
|||||||
loaded = true;
|
loaded = true;
|
||||||
|
|
||||||
for (auto node : doc.child(scriptsName.c_str()).children()) {
|
for (auto node : doc.child(scriptsName.c_str()).children()) {
|
||||||
Event_ptr event = getEvent(node.name());
|
Event* event = getEvent(node.name());
|
||||||
if (!event) {
|
if (!event) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!event->configureEvent(node)) {
|
if (!event->configureEvent(node)) {
|
||||||
std::cout << "[Warning - BaseEvents::loadFromXml] Failed to configure event" << std::endl;
|
std::cout << "[Warning - BaseEvents::loadFromXml] Failed to configure event" << std::endl;
|
||||||
|
delete event;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,15 +68,12 @@ bool BaseEvents::loadFromXml()
|
|||||||
if (scriptAttribute) {
|
if (scriptAttribute) {
|
||||||
std::string scriptFile = "scripts/" + std::string(scriptAttribute.as_string());
|
std::string scriptFile = "scripts/" + std::string(scriptAttribute.as_string());
|
||||||
success = event->checkScript(basePath, scriptsName, scriptFile) && event->loadScript(basePath + scriptFile);
|
success = event->checkScript(basePath, scriptsName, scriptFile) && event->loadScript(basePath + scriptFile);
|
||||||
if (node.attribute("function")) {
|
|
||||||
event->loadFunction(node.attribute("function"), true);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
success = event->loadFunction(node.attribute("function"), false);
|
success = event->loadFunction(node.attribute("function"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success) {
|
if (!success || !registerEvent(event, node)) {
|
||||||
registerEvent(std::move(event), node);
|
delete event;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -84,19 +82,15 @@ bool BaseEvents::loadFromXml()
|
|||||||
bool BaseEvents::reload()
|
bool BaseEvents::reload()
|
||||||
{
|
{
|
||||||
loaded = false;
|
loaded = false;
|
||||||
clear(false);
|
clear();
|
||||||
return loadFromXml();
|
return loadFromXml();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseEvents::reInitState(bool fromLua)
|
|
||||||
{
|
|
||||||
if (!fromLua) {
|
|
||||||
getScriptInterface().reInitState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Event::Event(LuaScriptInterface* interface) : scriptInterface(interface) {}
|
Event::Event(LuaScriptInterface* interface) : scriptInterface(interface) {}
|
||||||
|
|
||||||
|
Event::Event(const Event* copy) :
|
||||||
|
scripted(copy->scripted), scriptId(copy->scriptId), scriptInterface(copy->scriptInterface) {}
|
||||||
|
|
||||||
bool Event::checkScript(const std::string& basePath, const std::string& scriptsName, const std::string& scriptFile) const
|
bool Event::checkScript(const std::string& basePath, const std::string& scriptsName, const std::string& scriptFile) const
|
||||||
{
|
{
|
||||||
LuaScriptInterface* testInterface = g_luaEnvironment.getTestInterface();
|
LuaScriptInterface* testInterface = g_luaEnvironment.getTestInterface();
|
||||||
@@ -149,24 +143,6 @@ bool Event::loadScript(const std::string& scriptFile)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Event::loadCallback()
|
|
||||||
{
|
|
||||||
if (!scriptInterface || scriptId != 0) {
|
|
||||||
std::cout << "Failure: [Event::loadCallback] scriptInterface == nullptr. scriptid = " << scriptId << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t id = scriptInterface->getEvent();
|
|
||||||
if (id == -1) {
|
|
||||||
std::cout << "[Warning - Event::loadCallback] Event " << getScriptEventName() << " not found. " << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
scripted = true;
|
|
||||||
scriptId = id;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CallBack::loadCallBack(LuaScriptInterface* interface, const std::string& name)
|
bool CallBack::loadCallBack(LuaScriptInterface* interface, const std::string& name)
|
||||||
{
|
{
|
||||||
if (!interface) {
|
if (!interface) {
|
||||||
@@ -182,6 +158,7 @@ bool CallBack::loadCallBack(LuaScriptInterface* interface, const std::string& na
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callbackName = name;
|
||||||
scriptId = id;
|
scriptId = id;
|
||||||
loaded = true;
|
loaded = true;
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,21 +22,18 @@
|
|||||||
|
|
||||||
#include "luascript.h"
|
#include "luascript.h"
|
||||||
|
|
||||||
class Event;
|
|
||||||
using Event_ptr = std::unique_ptr<Event>;
|
|
||||||
|
|
||||||
class Event
|
class Event
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Event(LuaScriptInterface* interface);
|
explicit Event(LuaScriptInterface* interface);
|
||||||
|
explicit Event(const Event* copy);
|
||||||
virtual ~Event() = default;
|
virtual ~Event() = default;
|
||||||
|
|
||||||
virtual bool configureEvent(const pugi::xml_node& node) = 0;
|
virtual bool configureEvent(const pugi::xml_node& node) = 0;
|
||||||
|
|
||||||
bool checkScript(const std::string& basePath, const std::string& scriptsName, const std::string& scriptFile) const;
|
bool checkScript(const std::string& basePath, const std::string& scriptsName, const std::string& scriptFile) const;
|
||||||
bool loadScript(const std::string& scriptFile);
|
bool loadScript(const std::string& scriptFile);
|
||||||
bool loadCallback();
|
virtual bool loadFunction(const pugi::xml_attribute&) {
|
||||||
virtual bool loadFunction(const pugi::xml_attribute&, bool) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,12 +41,10 @@ class Event
|
|||||||
return scripted;
|
return scripted;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool scripted = false;
|
|
||||||
bool fromLua = false;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual std::string getScriptEventName() const = 0;
|
virtual std::string getScriptEventName() const = 0;
|
||||||
|
|
||||||
|
bool scripted = false;
|
||||||
int32_t scriptId = 0;
|
int32_t scriptId = 0;
|
||||||
LuaScriptInterface* scriptInterface = nullptr;
|
LuaScriptInterface* scriptInterface = nullptr;
|
||||||
};
|
};
|
||||||
@@ -65,14 +60,13 @@ class BaseEvents
|
|||||||
bool isLoaded() const {
|
bool isLoaded() const {
|
||||||
return loaded;
|
return loaded;
|
||||||
}
|
}
|
||||||
void reInitState(bool fromLua);
|
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
virtual LuaScriptInterface& getScriptInterface() = 0;
|
virtual LuaScriptInterface& getScriptInterface() = 0;
|
||||||
virtual std::string getScriptBaseName() const = 0;
|
virtual std::string getScriptBaseName() const = 0;
|
||||||
virtual Event_ptr getEvent(const std::string& nodeName) = 0;
|
virtual Event* getEvent(const std::string& nodeName) = 0;
|
||||||
virtual bool registerEvent(Event_ptr event, const pugi::xml_node& node) = 0;
|
virtual bool registerEvent(Event* event, const pugi::xml_node& node) = 0;
|
||||||
virtual void clear(bool) = 0;
|
virtual void clear() = 0;
|
||||||
|
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
};
|
};
|
||||||
@@ -88,8 +82,9 @@ class CallBack
|
|||||||
int32_t scriptId = 0;
|
int32_t scriptId = 0;
|
||||||
LuaScriptInterface* scriptInterface = nullptr;
|
LuaScriptInterface* scriptInterface = nullptr;
|
||||||
|
|
||||||
private:
|
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
|
|
||||||
|
std::string callbackName;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
14
src/bed.cpp
14
src/bed.cpp
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -159,8 +159,8 @@ bool BedItem::sleep(Player* player)
|
|||||||
// make the player walk onto the bed
|
// make the player walk onto the bed
|
||||||
g_game.map.moveCreature(*player, *getTile());
|
g_game.map.moveCreature(*player, *getTile());
|
||||||
|
|
||||||
// display 'Zzzz'/sleep effect
|
// display poff effect
|
||||||
g_game.addMagicEffect(player->getPosition(), CONST_ME_SLEEP);
|
g_game.addMagicEffect(player->getPosition(), CONST_ME_POFF);
|
||||||
|
|
||||||
// kick player after he sees himself walk onto the bed and it change id
|
// kick player after he sees himself walk onto the bed and it change id
|
||||||
uint32_t playerId = player->getID();
|
uint32_t playerId = player->getID();
|
||||||
@@ -246,10 +246,10 @@ void BedItem::updateAppearance(const Player* player)
|
|||||||
{
|
{
|
||||||
const ItemType& it = Item::items[id];
|
const ItemType& it = Item::items[id];
|
||||||
if (it.type == ITEM_TYPE_BED) {
|
if (it.type == ITEM_TYPE_BED) {
|
||||||
if (player && it.transformToOnUse[player->getSex()] != 0) {
|
if (player && it.transformToOnUse != 0) {
|
||||||
const ItemType& newType = Item::items[it.transformToOnUse[player->getSex()]];
|
const ItemType& newType = Item::items[it.transformToOnUse];
|
||||||
if (newType.type == ITEM_TYPE_BED) {
|
if (newType.type == ITEM_TYPE_BED) {
|
||||||
g_game.transformItem(this, it.transformToOnUse[player->getSex()]);
|
g_game.transformItem(this, it.transformToOnUse);
|
||||||
}
|
}
|
||||||
} else if (it.transformToFree != 0) {
|
} else if (it.transformToFree != 0) {
|
||||||
const ItemType& newType = Item::items[it.transformToFree];
|
const ItemType& newType = Item::items[it.transformToFree];
|
||||||
|
|||||||
19
src/bed.h
19
src/bed.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -30,17 +30,17 @@ class BedItem final : public Item
|
|||||||
public:
|
public:
|
||||||
explicit BedItem(uint16_t id);
|
explicit BedItem(uint16_t id);
|
||||||
|
|
||||||
BedItem* getBed() override {
|
BedItem* getBed() final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
const BedItem* getBed() const override {
|
const BedItem* getBed() const final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream) override;
|
Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream) final;
|
||||||
void serializeAttr(PropWriteStream& propWriteStream) const override;
|
void serializeAttr(PropWriteStream& propWriteStream) const final;
|
||||||
|
|
||||||
bool canRemove() const override {
|
bool canRemove() const final {
|
||||||
return house == nullptr;
|
return house == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,6 +48,9 @@ class BedItem final : public Item
|
|||||||
return sleeperGUID;
|
return sleeperGUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
House* getHouse() const {
|
||||||
|
return house;
|
||||||
|
}
|
||||||
void setHouse(House* h) {
|
void setHouse(House* h) {
|
||||||
house = h;
|
house = h;
|
||||||
}
|
}
|
||||||
@@ -60,7 +63,7 @@ class BedItem final : public Item
|
|||||||
|
|
||||||
BedItem* getNextBedItem() const;
|
BedItem* getNextBedItem() const;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
void updateAppearance(const Player* player);
|
void updateAppearance(const Player* player);
|
||||||
void regeneratePlayer(Player* player) const;
|
void regeneratePlayer(Player* player) const;
|
||||||
void internalSetSleeper(const Player* player);
|
void internalSetSleeper(const Player* player);
|
||||||
|
|||||||
92
src/chat.cpp
92
src/chat.cpp
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -54,10 +54,6 @@ void PrivateChatChannel::invitePlayer(const Player& player, Player& invitePlayer
|
|||||||
ss.str(std::string());
|
ss.str(std::string());
|
||||||
ss << invitePlayer.getName() << " has been invited.";
|
ss << invitePlayer.getName() << " has been invited.";
|
||||||
player.sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
|
player.sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
|
||||||
|
|
||||||
for (const auto& it : users) {
|
|
||||||
it.second->sendChannelEvent(id, invitePlayer.getName(), CHANNELEVENT_INVITE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrivateChatChannel::excludePlayer(const Player& player, Player& excludePlayer)
|
void PrivateChatChannel::excludePlayer(const Player& player, Player& excludePlayer)
|
||||||
@@ -73,10 +69,6 @@ void PrivateChatChannel::excludePlayer(const Player& player, Player& excludePlay
|
|||||||
player.sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
|
player.sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
|
||||||
|
|
||||||
excludePlayer.sendClosePrivate(id);
|
excludePlayer.sendClosePrivate(id);
|
||||||
|
|
||||||
for (const auto& it : users) {
|
|
||||||
it.second->sendChannelEvent(id, excludePlayer.getName(), CHANNELEVENT_EXCLUDE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrivateChatChannel::closeChannel() const
|
void PrivateChatChannel::closeChannel() const
|
||||||
@@ -96,20 +88,6 @@ bool ChatChannel::addUser(Player& player)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Move to script when guild channels can be scripted
|
|
||||||
if (id == CHANNEL_GUILD) {
|
|
||||||
Guild* guild = player.getGuild();
|
|
||||||
if (guild && !guild->getMotd().empty()) {
|
|
||||||
g_scheduler.addEvent(createSchedulerTask(150, std::bind(&Game::sendGuildMotd, &g_game, player.getID())));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!publicChannel) {
|
|
||||||
for (const auto& it : users) {
|
|
||||||
it.second->sendChannelEvent(id, player.getName(), CHANNELEVENT_JOIN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
users[player.getID()] = &player;
|
users[player.getID()] = &player;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -123,27 +101,10 @@ bool ChatChannel::removeUser(const Player& player)
|
|||||||
|
|
||||||
users.erase(iter);
|
users.erase(iter);
|
||||||
|
|
||||||
if (!publicChannel) {
|
|
||||||
for (const auto& it : users) {
|
|
||||||
it.second->sendChannelEvent(id, player.getName(), CHANNELEVENT_LEAVE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
executeOnLeaveEvent(player);
|
executeOnLeaveEvent(player);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChatChannel::hasUser(const Player& player) {
|
|
||||||
return users.find(player.getID()) != users.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChatChannel::sendToAll(const std::string& message, SpeakClasses type) const
|
|
||||||
{
|
|
||||||
for (const auto& it : users) {
|
|
||||||
it.second->sendChannelMessage("", message, type, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ChatChannel::talk(const Player& fromPlayer, SpeakClasses type, const std::string& text)
|
bool ChatChannel::talk(const Player& fromPlayer, SpeakClasses type, const std::string& text)
|
||||||
{
|
{
|
||||||
if (users.find(fromPlayer.getID()) == users.end()) {
|
if (users.find(fromPlayer.getID()) == users.end()) {
|
||||||
@@ -294,39 +255,21 @@ bool Chat::load()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::forward_list<uint16_t> removedChannels;
|
||||||
|
for (auto& channelEntry : normalChannels) {
|
||||||
|
ChatChannel& channel = channelEntry.second;
|
||||||
|
channel.onSpeakEvent = -1;
|
||||||
|
channel.canJoinEvent = -1;
|
||||||
|
channel.onJoinEvent = -1;
|
||||||
|
channel.onLeaveEvent = -1;
|
||||||
|
removedChannels.push_front(channelEntry.first);
|
||||||
|
}
|
||||||
|
|
||||||
for (auto channelNode : doc.child("channels").children()) {
|
for (auto channelNode : doc.child("channels").children()) {
|
||||||
uint16_t channelId = pugi::cast<uint16_t>(channelNode.attribute("id").value());
|
ChatChannel channel(pugi::cast<uint16_t>(channelNode.attribute("id").value()), channelNode.attribute("name").as_string());
|
||||||
std::string channelName = channelNode.attribute("name").as_string();
|
channel.publicChannel = channelNode.attribute("public").as_bool();
|
||||||
bool isPublic = channelNode.attribute("public").as_bool();
|
|
||||||
pugi::xml_attribute scriptAttribute = channelNode.attribute("script");
|
pugi::xml_attribute scriptAttribute = channelNode.attribute("script");
|
||||||
|
|
||||||
auto it = normalChannels.find(channelId);
|
|
||||||
if (it != normalChannels.end()) {
|
|
||||||
ChatChannel& channel = it->second;
|
|
||||||
channel.publicChannel = isPublic;
|
|
||||||
channel.name = channelName;
|
|
||||||
|
|
||||||
if (scriptAttribute) {
|
|
||||||
if (scriptInterface.loadFile("data/chatchannels/scripts/" + std::string(scriptAttribute.as_string())) == 0) {
|
|
||||||
channel.onSpeakEvent = scriptInterface.getEvent("onSpeak");
|
|
||||||
channel.canJoinEvent = scriptInterface.getEvent("canJoin");
|
|
||||||
channel.onJoinEvent = scriptInterface.getEvent("onJoin");
|
|
||||||
channel.onLeaveEvent = scriptInterface.getEvent("onLeave");
|
|
||||||
} else {
|
|
||||||
std::cout << "[Warning - Chat::load] Can not load script: " << scriptAttribute.as_string() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UsersMap tempUserMap = std::move(channel.users);
|
|
||||||
for (const auto& pair : tempUserMap) {
|
|
||||||
channel.addUser(*pair.second);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChatChannel channel(channelId, channelName);
|
|
||||||
channel.publicChannel = isPublic;
|
|
||||||
|
|
||||||
if (scriptAttribute) {
|
if (scriptAttribute) {
|
||||||
if (scriptInterface.loadFile("data/chatchannels/scripts/" + std::string(scriptAttribute.as_string())) == 0) {
|
if (scriptInterface.loadFile("data/chatchannels/scripts/" + std::string(scriptAttribute.as_string())) == 0) {
|
||||||
channel.onSpeakEvent = scriptInterface.getEvent("onSpeak");
|
channel.onSpeakEvent = scriptInterface.getEvent("onSpeak");
|
||||||
@@ -338,8 +281,13 @@ bool Chat::load()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removedChannels.remove(channel.id);
|
||||||
normalChannels[channel.id] = channel;
|
normalChannels[channel.id] = channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uint16_t channelId : removedChannels) {
|
||||||
|
normalChannels.erase(channelId);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
src/chat.h
25
src/chat.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,24 +26,23 @@
|
|||||||
class Party;
|
class Party;
|
||||||
class Player;
|
class Player;
|
||||||
|
|
||||||
using UsersMap = std::map<uint32_t, Player*>;
|
typedef std::map<uint32_t, Player*> UsersMap;
|
||||||
using InvitedMap = std::map<uint32_t, const Player*>;
|
typedef std::map<uint32_t, const Player*> InvitedMap;
|
||||||
|
|
||||||
class ChatChannel
|
class ChatChannel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ChatChannel() = default;
|
ChatChannel() = default;
|
||||||
ChatChannel(uint16_t channelId, std::string channelName):
|
ChatChannel(uint16_t channelId, std::string channelName):
|
||||||
id{channelId}, name{std::move(channelName)} {}
|
name(std::move(channelName)),
|
||||||
|
id(channelId) {}
|
||||||
|
|
||||||
virtual ~ChatChannel() = default;
|
virtual ~ChatChannel() = default;
|
||||||
|
|
||||||
bool addUser(Player& player);
|
bool addUser(Player& player);
|
||||||
bool removeUser(const Player& player);
|
bool removeUser(const Player& player);
|
||||||
bool hasUser(const Player& player);
|
|
||||||
|
|
||||||
bool talk(const Player& fromPlayer, SpeakClasses type, const std::string& text);
|
bool talk(const Player& fromPlayer, SpeakClasses type, const std::string& text);
|
||||||
void sendToAll(const std::string& message, SpeakClasses type) const;
|
|
||||||
|
|
||||||
const std::string& getName() const {
|
const std::string& getName() const {
|
||||||
return name;
|
return name;
|
||||||
@@ -72,9 +71,6 @@ class ChatChannel
|
|||||||
protected:
|
protected:
|
||||||
UsersMap users;
|
UsersMap users;
|
||||||
|
|
||||||
uint16_t id;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
int32_t canJoinEvent = -1;
|
int32_t canJoinEvent = -1;
|
||||||
@@ -82,6 +78,7 @@ class ChatChannel
|
|||||||
int32_t onLeaveEvent = -1;
|
int32_t onLeaveEvent = -1;
|
||||||
int32_t onSpeakEvent = -1;
|
int32_t onSpeakEvent = -1;
|
||||||
|
|
||||||
|
uint16_t id;
|
||||||
bool publicChannel = false;
|
bool publicChannel = false;
|
||||||
|
|
||||||
friend class Chat;
|
friend class Chat;
|
||||||
@@ -92,7 +89,7 @@ class PrivateChatChannel final : public ChatChannel
|
|||||||
public:
|
public:
|
||||||
PrivateChatChannel(uint16_t channelId, std::string channelName) : ChatChannel(channelId, channelName) {}
|
PrivateChatChannel(uint16_t channelId, std::string channelName) : ChatChannel(channelId, channelName) {}
|
||||||
|
|
||||||
uint32_t getOwner() const override {
|
uint32_t getOwner() const final {
|
||||||
return owner;
|
return owner;
|
||||||
}
|
}
|
||||||
void setOwner(uint32_t owner) {
|
void setOwner(uint32_t owner) {
|
||||||
@@ -108,16 +105,16 @@ class PrivateChatChannel final : public ChatChannel
|
|||||||
|
|
||||||
void closeChannel() const;
|
void closeChannel() const;
|
||||||
|
|
||||||
const InvitedMap* getInvitedUsers() const override {
|
const InvitedMap* getInvitedUsers() const final {
|
||||||
return &invites;
|
return &invites;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
InvitedMap invites;
|
InvitedMap invites;
|
||||||
uint32_t owner = 0;
|
uint32_t owner = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
using ChannelList = std::list<ChatChannel*>;
|
typedef std::list<ChatChannel*> ChannelList;
|
||||||
|
|
||||||
class Chat
|
class Chat
|
||||||
{
|
{
|
||||||
|
|||||||
903
src/combat.cpp
903
src/combat.cpp
File diff suppressed because it is too large
Load Diff
102
src/combat.h
102
src/combat.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -38,7 +38,7 @@ class ValueCallback final : public CallBack
|
|||||||
explicit ValueCallback(formulaType_t type): type(type) {}
|
explicit ValueCallback(formulaType_t type): type(type) {}
|
||||||
void getMinMaxValues(Player* player, CombatDamage& damage, bool useCharges) const;
|
void getMinMaxValues(Player* player, CombatDamage& damage, bool useCharges) const;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
formulaType_t type;
|
formulaType_t type;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -46,12 +46,18 @@ class TileCallback final : public CallBack
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void onTileCombat(Creature* creature, Tile* tile) const;
|
void onTileCombat(Creature* creature, Tile* tile) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
formulaType_t type;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TargetCallback final : public CallBack
|
class TargetCallback final : public CallBack
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void onTargetCombat(Creature* creature, Creature* target) const;
|
void onTargetCombat(Creature* creature, Creature* target) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
formulaType_t type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CombatParams {
|
struct CombatParams {
|
||||||
@@ -62,6 +68,8 @@ struct CombatParams {
|
|||||||
std::unique_ptr<TargetCallback> targetCallback;
|
std::unique_ptr<TargetCallback> targetCallback;
|
||||||
|
|
||||||
uint16_t itemId = 0;
|
uint16_t itemId = 0;
|
||||||
|
uint16_t decreaseDamage = 0;
|
||||||
|
uint16_t maximumDecreasedDamage = 0;
|
||||||
|
|
||||||
ConditionType_t dispelType = CONDITION_NONE;
|
ConditionType_t dispelType = CONDITION_NONE;
|
||||||
CombatType_t combatType = COMBAT_NONE;
|
CombatType_t combatType = COMBAT_NONE;
|
||||||
@@ -77,7 +85,39 @@ struct CombatParams {
|
|||||||
bool useCharges = false;
|
bool useCharges = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
using CombatFunction = std::function<void(Creature*, Creature*, const CombatParams&, CombatDamage*)>;
|
struct Impact
|
||||||
|
{
|
||||||
|
Creature* actor = nullptr;
|
||||||
|
|
||||||
|
virtual void handleCreature(Creature*) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DamageImpact : Impact
|
||||||
|
{
|
||||||
|
CombatParams params;
|
||||||
|
CombatDamage damage;
|
||||||
|
|
||||||
|
void handleCreature(Creature* target) final;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SpeedImpact : Impact
|
||||||
|
{
|
||||||
|
int32_t percent = 0;
|
||||||
|
int32_t duration = 0;
|
||||||
|
|
||||||
|
void handleCreature(Creature* target) final;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DunkenImpact : Impact
|
||||||
|
{
|
||||||
|
int32_t duration = 0;
|
||||||
|
|
||||||
|
void handleCreature(Creature* target) final;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void(*COMBATFUNC)(Creature*, Creature*, const CombatParams&, CombatDamage*);
|
||||||
|
|
||||||
class MatrixArea
|
class MatrixArea
|
||||||
{
|
{
|
||||||
@@ -145,14 +185,14 @@ class MatrixArea
|
|||||||
return cols;
|
return cols;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool* operator[](uint32_t i) const {
|
inline const bool* operator[](uint32_t i) const {
|
||||||
return data_[i];
|
return data_[i];
|
||||||
}
|
}
|
||||||
bool* operator[](uint32_t i) {
|
inline bool* operator[](uint32_t i) {
|
||||||
return data_[i];
|
return data_[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
uint32_t centerX;
|
uint32_t centerX;
|
||||||
uint32_t centerY;
|
uint32_t centerY;
|
||||||
|
|
||||||
@@ -182,7 +222,7 @@ class AreaCombat
|
|||||||
void setupExtArea(const std::list<uint32_t>& list, uint32_t rows);
|
void setupExtArea(const std::list<uint32_t>& list, uint32_t rows);
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
enum MatrixOperation_t {
|
enum MatrixOperation_t {
|
||||||
MATRIXOPERATION_COPY,
|
MATRIXOPERATION_COPY,
|
||||||
MATRIXOPERATION_MIRROR,
|
MATRIXOPERATION_MIRROR,
|
||||||
@@ -193,7 +233,7 @@ class AreaCombat
|
|||||||
};
|
};
|
||||||
|
|
||||||
MatrixArea* createArea(const std::list<uint32_t>& list, uint32_t rows);
|
MatrixArea* createArea(const std::list<uint32_t>& list, uint32_t rows);
|
||||||
static void copyArea(const MatrixArea* input, MatrixArea* output, MatrixOperation_t op);
|
void copyArea(const MatrixArea* input, MatrixArea* output, MatrixOperation_t op) const;
|
||||||
|
|
||||||
MatrixArea* getArea(const Position& centerPos, const Position& targetPos) const {
|
MatrixArea* getArea(const Position& centerPos, const Position& targetPos) const {
|
||||||
int32_t dx = Position::getOffsetX(targetPos, centerPos);
|
int32_t dx = Position::getOffsetX(targetPos, centerPos);
|
||||||
@@ -242,7 +282,18 @@ class Combat
|
|||||||
Combat(const Combat&) = delete;
|
Combat(const Combat&) = delete;
|
||||||
Combat& operator=(const Combat&) = delete;
|
Combat& operator=(const Combat&) = delete;
|
||||||
|
|
||||||
static void doCombatHealth(Creature* caster, Creature* target, CombatDamage& damage, const CombatParams& params);
|
static int32_t computeDamage(Creature* creature, int32_t strength, int32_t variation);
|
||||||
|
static int32_t getTotalDamage(int32_t attackSkill, int32_t attackValue, fightMode_t fightMode);
|
||||||
|
|
||||||
|
static bool attack(Creature* attacker, Creature* target);
|
||||||
|
static bool closeAttack(Creature* attacker, Creature* target, fightMode_t fightMode);
|
||||||
|
static bool rangeAttack(Creature* attacker, Creature* target, fightMode_t fightMode);
|
||||||
|
|
||||||
|
static void circleShapeSpell(Creature* attacker, const Position& toPos, int32_t range, int32_t animation, int32_t radius, DamageImpact* impact, int32_t effect);
|
||||||
|
|
||||||
|
static void getAttackValue(Creature* creature, uint32_t& attackValue, uint32_t& skillValue, uint8_t& skill);
|
||||||
|
|
||||||
|
static bool doCombatHealth(Creature* caster, Creature* target, CombatDamage& damage, const CombatParams& params);
|
||||||
static void doCombatHealth(Creature* caster, const Position& position, const AreaCombat* area, CombatDamage& damage, const CombatParams& params);
|
static void doCombatHealth(Creature* caster, const Position& position, const AreaCombat* area, CombatDamage& damage, const CombatParams& params);
|
||||||
|
|
||||||
static void doCombatMana(Creature* caster, Creature* target, CombatDamage& damage, const CombatParams& params);
|
static void doCombatMana(Creature* caster, Creature* target, CombatDamage& damage, const CombatParams& params);
|
||||||
@@ -266,10 +317,10 @@ class Combat
|
|||||||
static ReturnValue canDoCombat(Creature* attacker, Creature* target);
|
static ReturnValue canDoCombat(Creature* attacker, Creature* target);
|
||||||
static void postCombatEffects(Creature* caster, const Position& pos, const CombatParams& params);
|
static void postCombatEffects(Creature* caster, const Position& pos, const CombatParams& params);
|
||||||
|
|
||||||
static void addDistanceEffect(Creature* caster, const Position& fromPos, const Position& toPos, uint8_t effect);
|
static void addDistanceEffect(const Position& fromPos, const Position& toPos, uint8_t effect);
|
||||||
|
|
||||||
void doCombat(Creature* caster, Creature* target) const;
|
void doCombat(Creature* caster, Creature* target) const;
|
||||||
void doCombat(Creature* caster, const Position& position) const;
|
void doCombat(Creature* caster, const Position& pos) const;
|
||||||
|
|
||||||
bool setCallback(CallBackParam_t key);
|
bool setCallback(CallBackParam_t key);
|
||||||
CallBack* getCallback(CallBackParam_t key);
|
CallBack* getCallback(CallBackParam_t key);
|
||||||
@@ -281,12 +332,9 @@ class Combat
|
|||||||
bool hasArea() const {
|
bool hasArea() const {
|
||||||
return area != nullptr;
|
return area != nullptr;
|
||||||
}
|
}
|
||||||
void addCondition(const Condition* condition) {
|
void setCondition(const Condition* condition) {
|
||||||
params.conditionList.emplace_front(condition);
|
params.conditionList.emplace_front(condition);
|
||||||
}
|
}
|
||||||
void clearConditions() {
|
|
||||||
params.conditionList.clear();
|
|
||||||
}
|
|
||||||
void setPlayerCombatValues(formulaType_t formulaType, double mina, double minb, double maxa, double maxb);
|
void setPlayerCombatValues(formulaType_t formulaType, double mina, double minb, double maxa, double maxb);
|
||||||
void postCombatEffects(Creature* caster, const Position& pos) const {
|
void postCombatEffects(Creature* caster, const Position& pos) const {
|
||||||
postCombatEffects(caster, pos, params);
|
postCombatEffects(caster, pos, params);
|
||||||
@@ -296,10 +344,13 @@ class Combat
|
|||||||
params.origin = origin;
|
params.origin = origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
|
static bool canUseWeapon(Player* player, Item* weapon);
|
||||||
|
static void postWeaponEffects(Player* player, Item* weapon);
|
||||||
|
|
||||||
static void doCombatDefault(Creature* caster, Creature* target, const CombatParams& params);
|
static void doCombatDefault(Creature* caster, Creature* target, const CombatParams& params);
|
||||||
|
|
||||||
static void CombatFunc(Creature* caster, const Position& pos, const AreaCombat* area, const CombatParams& params, CombatFunction func, CombatDamage* data);
|
static void CombatFunc(Creature* caster, const Position& pos, const AreaCombat* area, const CombatParams& params, COMBATFUNC func, CombatDamage* data);
|
||||||
|
|
||||||
static void CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
|
static void CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
|
||||||
static void CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* damage);
|
static void CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* damage);
|
||||||
@@ -307,8 +358,8 @@ class Combat
|
|||||||
static void CombatDispelFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
|
static void CombatDispelFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
|
||||||
static void CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
|
static void CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
|
||||||
|
|
||||||
static void combatTileEffects(const SpectatorVec& spectators, Creature* caster, Tile* tile, const CombatParams& params);
|
static void combatTileEffects(const SpectatorVec& list, Creature* caster, Tile* tile, const CombatParams& params);
|
||||||
CombatDamage getCombatDamage(Creature* creature, Creature* target) const;
|
CombatDamage getCombatDamage(Creature* creature) const;
|
||||||
|
|
||||||
//configureable
|
//configureable
|
||||||
CombatParams params;
|
CombatParams params;
|
||||||
@@ -328,10 +379,10 @@ class MagicField final : public Item
|
|||||||
public:
|
public:
|
||||||
explicit MagicField(uint16_t type) : Item(type), createTime(OTSYS_TIME()) {}
|
explicit MagicField(uint16_t type) : Item(type), createTime(OTSYS_TIME()) {}
|
||||||
|
|
||||||
MagicField* getMagicField() override {
|
MagicField* getMagicField() final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
const MagicField* getMagicField() const override {
|
const MagicField* getMagicField() const final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,13 +393,6 @@ class MagicField final : public Item
|
|||||||
const ItemType& it = items[getID()];
|
const ItemType& it = items[getID()];
|
||||||
return it.combatType;
|
return it.combatType;
|
||||||
}
|
}
|
||||||
int32_t getDamage() const {
|
|
||||||
const ItemType& it = items[getID()];
|
|
||||||
if (it.conditionDamage) {
|
|
||||||
return it.conditionDamage->getTotalDamage();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
void onStepInField(Creature* creature);
|
void onStepInField(Creature* creature);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
278
src/condition.h
278
src/condition.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -35,10 +35,13 @@ enum ConditionAttr_t {
|
|||||||
CONDITIONATTR_HEALTHGAIN,
|
CONDITIONATTR_HEALTHGAIN,
|
||||||
CONDITIONATTR_MANATICKS,
|
CONDITIONATTR_MANATICKS,
|
||||||
CONDITIONATTR_MANAGAIN,
|
CONDITIONATTR_MANAGAIN,
|
||||||
CONDITIONATTR_DELAYED,
|
|
||||||
CONDITIONATTR_OWNER,
|
CONDITIONATTR_OWNER,
|
||||||
CONDITIONATTR_INTERVALDATA,
|
CONDITIONATTR_CYCLE,
|
||||||
|
CONDITIONATTR_COUNT,
|
||||||
|
CONDITIONATTR_MAX_COUNT,
|
||||||
|
CONDITIONATTR_FACTOR_PERCENT,
|
||||||
CONDITIONATTR_SPEEDDELTA,
|
CONDITIONATTR_SPEEDDELTA,
|
||||||
|
CONDITIONATTR_APPLIEDSPEEDDELTA,
|
||||||
CONDITIONATTR_FORMULA_MINA,
|
CONDITIONATTR_FORMULA_MINA,
|
||||||
CONDITIONATTR_FORMULA_MINB,
|
CONDITIONATTR_FORMULA_MINB,
|
||||||
CONDITIONATTR_FORMULA_MAXA,
|
CONDITIONATTR_FORMULA_MAXA,
|
||||||
@@ -52,8 +55,6 @@ enum ConditionAttr_t {
|
|||||||
CONDITIONATTR_SKILLS,
|
CONDITIONATTR_SKILLS,
|
||||||
CONDITIONATTR_STATS,
|
CONDITIONATTR_STATS,
|
||||||
CONDITIONATTR_OUTFIT,
|
CONDITIONATTR_OUTFIT,
|
||||||
CONDITIONATTR_PERIODDAMAGE,
|
|
||||||
CONDITIONATTR_ISBUFF,
|
|
||||||
CONDITIONATTR_SUBID,
|
CONDITIONATTR_SUBID,
|
||||||
|
|
||||||
//reserved for serialization
|
//reserved for serialization
|
||||||
@@ -70,9 +71,9 @@ class Condition
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Condition() = default;
|
Condition() = default;
|
||||||
Condition(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0) :
|
Condition(ConditionId_t id, ConditionType_t type, int32_t ticks, uint32_t subId = 0) :
|
||||||
endTime(ticks == -1 ? std::numeric_limits<int64_t>::max() : 0),
|
endTime(ticks == -1 ? std::numeric_limits<int64_t>::max() : 0),
|
||||||
subId(subId), ticks(ticks), conditionType(type), isBuff(buff), id(id) {}
|
subId(subId), ticks(ticks), conditionType(type), id(id) {}
|
||||||
virtual ~Condition() = default;
|
virtual ~Condition() = default;
|
||||||
|
|
||||||
virtual bool startCondition(Creature* creature);
|
virtual bool startCondition(Creature* creature);
|
||||||
@@ -100,7 +101,7 @@ class Condition
|
|||||||
}
|
}
|
||||||
void setTicks(int32_t newTicks);
|
void setTicks(int32_t newTicks);
|
||||||
|
|
||||||
static Condition* createCondition(ConditionId_t id, ConditionType_t type, int32_t ticks, int32_t param = 0, bool buff = false, uint32_t subId = 0);
|
static Condition* createCondition(ConditionId_t id, ConditionType_t type, int32_t ticks, int32_t param = 0, uint32_t subId = 0);
|
||||||
static Condition* createCondition(PropStream& propStream);
|
static Condition* createCondition(PropStream& propStream);
|
||||||
|
|
||||||
virtual bool setParam(ConditionParam_t param, int32_t value);
|
virtual bool setParam(ConditionParam_t param, int32_t value);
|
||||||
@@ -113,23 +114,20 @@ class Condition
|
|||||||
bool isPersistent() const;
|
bool isPersistent() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool updateCondition(const Condition* addCondition);
|
|
||||||
|
|
||||||
int64_t endTime;
|
int64_t endTime;
|
||||||
uint32_t subId;
|
uint32_t subId;
|
||||||
int32_t ticks;
|
int32_t ticks;
|
||||||
ConditionType_t conditionType;
|
ConditionType_t conditionType;
|
||||||
bool isBuff;
|
|
||||||
|
|
||||||
private:
|
|
||||||
ConditionId_t id;
|
ConditionId_t id;
|
||||||
|
|
||||||
|
virtual bool updateCondition(const Condition* addCondition);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConditionGeneric : public Condition
|
class ConditionGeneric : public Condition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConditionGeneric(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0):
|
ConditionGeneric(ConditionId_t id, ConditionType_t type, int32_t ticks, uint32_t subId = 0):
|
||||||
Condition(id, type, ticks, buff, subId) {}
|
Condition(id, type, ticks, subId) {}
|
||||||
|
|
||||||
bool startCondition(Creature* creature) override;
|
bool startCondition(Creature* creature) override;
|
||||||
bool executeCondition(Creature* creature, int32_t interval) override;
|
bool executeCondition(Creature* creature, int32_t interval) override;
|
||||||
@@ -145,35 +143,32 @@ class ConditionGeneric : public Condition
|
|||||||
class ConditionAttributes final : public ConditionGeneric
|
class ConditionAttributes final : public ConditionGeneric
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConditionAttributes(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0) :
|
ConditionAttributes(ConditionId_t id, ConditionType_t type, int32_t ticks, uint32_t subId = 0) :
|
||||||
ConditionGeneric(id, type, ticks, buff, subId) {}
|
ConditionGeneric(id, type, ticks, subId) {}
|
||||||
|
|
||||||
bool startCondition(Creature* creature) override;
|
bool startCondition(Creature* creature) final;
|
||||||
bool executeCondition(Creature* creature, int32_t interval) override;
|
bool executeCondition(Creature* creature, int32_t interval) final;
|
||||||
void endCondition(Creature* creature) override;
|
void endCondition(Creature* creature) final;
|
||||||
void addCondition(Creature* creature, const Condition* condition) override;
|
void addCondition(Creature* creature, const Condition* condition) final;
|
||||||
|
|
||||||
bool setParam(ConditionParam_t param, int32_t value) override;
|
bool setParam(ConditionParam_t param, int32_t value) final;
|
||||||
|
|
||||||
ConditionAttributes* clone() const override {
|
ConditionAttributes* clone() const final {
|
||||||
return new ConditionAttributes(*this);
|
return new ConditionAttributes(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//serialization
|
//serialization
|
||||||
void serialize(PropWriteStream& propWriteStream) override;
|
void serialize(PropWriteStream& propWriteStream) final;
|
||||||
bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) override;
|
bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) final;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
int32_t skills[SKILL_LAST + 1] = {};
|
int32_t skills[SKILL_LAST + 1] = {};
|
||||||
int32_t skillsPercent[SKILL_LAST + 1] = {};
|
int32_t skillsPercent[SKILL_LAST + 1] = {};
|
||||||
int32_t specialSkills[SPECIALSKILL_LAST + 1] = {};
|
|
||||||
int32_t stats[STAT_LAST + 1] = {};
|
int32_t stats[STAT_LAST + 1] = {};
|
||||||
int32_t statsPercent[STAT_LAST + 1] = {};
|
int32_t statsPercent[STAT_LAST + 1] = {};
|
||||||
int32_t currentSkill = 0;
|
int32_t currentSkill = 0;
|
||||||
int32_t currentStat = 0;
|
int32_t currentStat = 0;
|
||||||
|
|
||||||
bool disableDefense = false;
|
|
||||||
|
|
||||||
void updatePercentStats(Player* player);
|
void updatePercentStats(Player* player);
|
||||||
void updateStats(Player* player);
|
void updateStats(Player* player);
|
||||||
void updatePercentSkills(Player* player);
|
void updatePercentSkills(Player* player);
|
||||||
@@ -183,23 +178,23 @@ class ConditionAttributes final : public ConditionGeneric
|
|||||||
class ConditionRegeneration final : public ConditionGeneric
|
class ConditionRegeneration final : public ConditionGeneric
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConditionRegeneration(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0):
|
ConditionRegeneration(ConditionId_t id, ConditionType_t type, int32_t ticks, uint32_t subId = 0):
|
||||||
ConditionGeneric(id, type, ticks, buff, subId) {}
|
ConditionGeneric(id, type, ticks, subId) {}
|
||||||
|
|
||||||
void addCondition(Creature* creature, const Condition* condition) override;
|
void addCondition(Creature* creature, const Condition* addCondition) final;
|
||||||
bool executeCondition(Creature* creature, int32_t interval) override;
|
bool executeCondition(Creature* creature, int32_t interval) final;
|
||||||
|
|
||||||
bool setParam(ConditionParam_t param, int32_t value) override;
|
bool setParam(ConditionParam_t param, int32_t value) final;
|
||||||
|
|
||||||
ConditionRegeneration* clone() const override {
|
ConditionRegeneration* clone() const final {
|
||||||
return new ConditionRegeneration(*this);
|
return new ConditionRegeneration(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//serialization
|
//serialization
|
||||||
void serialize(PropWriteStream& propWriteStream) override;
|
void serialize(PropWriteStream& propWriteStream) final;
|
||||||
bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) override;
|
bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) final;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
uint32_t internalHealthTicks = 0;
|
uint32_t internalHealthTicks = 0;
|
||||||
uint32_t internalManaTicks = 0;
|
uint32_t internalManaTicks = 0;
|
||||||
|
|
||||||
@@ -212,23 +207,23 @@ class ConditionRegeneration final : public ConditionGeneric
|
|||||||
class ConditionSoul final : public ConditionGeneric
|
class ConditionSoul final : public ConditionGeneric
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConditionSoul(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0) :
|
ConditionSoul(ConditionId_t id, ConditionType_t type, int32_t ticks, uint32_t subId = 0) :
|
||||||
ConditionGeneric(id, type, ticks, buff, subId) {}
|
ConditionGeneric(id, type, ticks, subId) {}
|
||||||
|
|
||||||
void addCondition(Creature* creature, const Condition* condition) override;
|
void addCondition(Creature* creature, const Condition* addCondition) final;
|
||||||
bool executeCondition(Creature* creature, int32_t interval) override;
|
bool executeCondition(Creature* creature, int32_t interval) final;
|
||||||
|
|
||||||
bool setParam(ConditionParam_t param, int32_t value) override;
|
bool setParam(ConditionParam_t param, int32_t value) final;
|
||||||
|
|
||||||
ConditionSoul* clone() const override {
|
ConditionSoul* clone() const final {
|
||||||
return new ConditionSoul(*this);
|
return new ConditionSoul(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//serialization
|
//serialization
|
||||||
void serialize(PropWriteStream& propWriteStream) override;
|
void serialize(PropWriteStream& propWriteStream) final;
|
||||||
bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) override;
|
bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) final;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
uint32_t internalSoulTicks = 0;
|
uint32_t internalSoulTicks = 0;
|
||||||
uint32_t soulTicks = 0;
|
uint32_t soulTicks = 0;
|
||||||
uint32_t soulGain = 0;
|
uint32_t soulGain = 0;
|
||||||
@@ -237,13 +232,13 @@ class ConditionSoul final : public ConditionGeneric
|
|||||||
class ConditionInvisible final : public ConditionGeneric
|
class ConditionInvisible final : public ConditionGeneric
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConditionInvisible(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0) :
|
ConditionInvisible(ConditionId_t id, ConditionType_t type, int32_t ticks, uint32_t subId = 0) :
|
||||||
ConditionGeneric(id, type, ticks, buff, subId) {}
|
ConditionGeneric(id, type, ticks, subId) {}
|
||||||
|
|
||||||
bool startCondition(Creature* creature) override;
|
bool startCondition(Creature* creature) final;
|
||||||
void endCondition(Creature* creature) override;
|
void endCondition(Creature* creature) final;
|
||||||
|
|
||||||
ConditionInvisible* clone() const override {
|
ConditionInvisible* clone() const final {
|
||||||
return new ConditionInvisible(*this);
|
return new ConditionInvisible(*this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -252,170 +247,133 @@ class ConditionDamage final : public Condition
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConditionDamage() = default;
|
ConditionDamage() = default;
|
||||||
ConditionDamage(ConditionId_t id, ConditionType_t type, bool buff = false, uint32_t subId = 0) :
|
ConditionDamage(ConditionId_t id, ConditionType_t type, uint32_t subId = 0) :
|
||||||
Condition(id, type, 0, buff, subId) {}
|
Condition(id, type, 0, subId) {
|
||||||
|
if (type == CONDITION_POISON) {
|
||||||
|
count = max_count = 3;
|
||||||
|
} else if (type == CONDITION_FIRE) {
|
||||||
|
count = max_count = 8;
|
||||||
|
} else if (type == CONDITION_ENERGY) {
|
||||||
|
count = max_count = 10;
|
||||||
|
} else if (type == CONDITION_DROWN) {
|
||||||
|
count = max_count = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void generateDamageList(int32_t amount, int32_t start, std::list<int32_t>& list);
|
bool startCondition(Creature* creature) final;
|
||||||
|
bool executeCondition(Creature* creature, int32_t interval) final;
|
||||||
|
void endCondition(Creature* creature) final;
|
||||||
|
void addCondition(Creature* creature, const Condition* condition) final;
|
||||||
|
uint32_t getIcons() const final;
|
||||||
|
|
||||||
bool startCondition(Creature* creature) override;
|
ConditionDamage* clone() const final {
|
||||||
bool executeCondition(Creature* creature, int32_t interval) override;
|
|
||||||
void endCondition(Creature* creature) override;
|
|
||||||
void addCondition(Creature* creature, const Condition* condition) override;
|
|
||||||
uint32_t getIcons() const override;
|
|
||||||
|
|
||||||
ConditionDamage* clone() const override {
|
|
||||||
return new ConditionDamage(*this);
|
return new ConditionDamage(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setParam(ConditionParam_t param, int32_t value) override;
|
bool setParam(ConditionParam_t param, int32_t value) final;
|
||||||
|
|
||||||
bool addDamage(int32_t rounds, int32_t time, int32_t value);
|
|
||||||
bool doForceUpdate() const {
|
|
||||||
return forceUpdate;
|
|
||||||
}
|
|
||||||
int32_t getTotalDamage() const;
|
int32_t getTotalDamage() const;
|
||||||
|
|
||||||
//serialization
|
//serialization
|
||||||
void serialize(PropWriteStream& propWriteStream) override;
|
void serialize(PropWriteStream& propWriteStream) final;
|
||||||
bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) override;
|
bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) final;
|
||||||
|
protected:
|
||||||
private:
|
int32_t cycle = 0;
|
||||||
int32_t maxDamage = 0;
|
int32_t count = 0;
|
||||||
int32_t minDamage = 0;
|
int32_t max_count = 0;
|
||||||
int32_t startDamage = 0;
|
int32_t factor_percent = -1;
|
||||||
int32_t periodDamage = 0;
|
int32_t hit_damage = 0;
|
||||||
int32_t periodDamageTick = 0;
|
bool isFirstCycle = true;
|
||||||
int32_t tickInterval = 2000;
|
|
||||||
|
|
||||||
bool forceUpdate = false;
|
|
||||||
bool delayed = false;
|
|
||||||
bool field = false;
|
|
||||||
uint32_t owner = 0;
|
uint32_t owner = 0;
|
||||||
|
|
||||||
bool init();
|
|
||||||
|
|
||||||
std::list<IntervalInfo> damageList;
|
|
||||||
|
|
||||||
bool getNextDamage(int32_t& damage);
|
|
||||||
bool doDamage(Creature* creature, int32_t healthChange);
|
bool doDamage(Creature* creature, int32_t healthChange);
|
||||||
|
|
||||||
bool updateCondition(const Condition* addCondition) override;
|
bool updateCondition(const Condition* addCondition) final;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConditionSpeed final : public Condition
|
class ConditionSpeed final : public Condition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConditionSpeed(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff, uint32_t subId, int32_t changeSpeed) :
|
ConditionSpeed(ConditionId_t id, ConditionType_t type, int32_t ticks, uint32_t subId, int32_t changeSpeed) :
|
||||||
Condition(id, type, ticks, buff, subId), speedDelta(changeSpeed) {}
|
Condition(id, type, ticks, subId), speedDelta(changeSpeed) {}
|
||||||
|
|
||||||
bool startCondition(Creature* creature) override;
|
bool startCondition(Creature* creature) final;
|
||||||
bool executeCondition(Creature* creature, int32_t interval) override;
|
bool executeCondition(Creature* creature, int32_t interval) final;
|
||||||
void endCondition(Creature* creature) override;
|
void endCondition(Creature* creature) final;
|
||||||
void addCondition(Creature* creature, const Condition* condition) override;
|
void addCondition(Creature* creature, const Condition* condition) final;
|
||||||
uint32_t getIcons() const override;
|
uint32_t getIcons() const final;
|
||||||
|
|
||||||
ConditionSpeed* clone() const override {
|
ConditionSpeed* clone() const final {
|
||||||
return new ConditionSpeed(*this);
|
return new ConditionSpeed(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setParam(ConditionParam_t param, int32_t value) override;
|
void setVariation(int32_t newVariation) {
|
||||||
|
variation = newVariation;
|
||||||
void setFormulaVars(float mina, float minb, float maxa, float maxb);
|
}
|
||||||
|
void setSpeedDelta(int32_t newSpeedDelta) {
|
||||||
|
speedDelta = newSpeedDelta;
|
||||||
|
}
|
||||||
|
|
||||||
//serialization
|
//serialization
|
||||||
void serialize(PropWriteStream& propWriteStream) override;
|
void serialize(PropWriteStream& propWriteStream) final;
|
||||||
bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) override;
|
bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) final;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
void getFormulaValues(int32_t var, int32_t& min, int32_t& max) const;
|
int32_t appliedSpeedDelta = 0;
|
||||||
|
int32_t speedDelta = 0;
|
||||||
int32_t speedDelta;
|
int32_t variation = 0;
|
||||||
|
|
||||||
//formula variables
|
|
||||||
float mina = 0.0f;
|
|
||||||
float minb = 0.0f;
|
|
||||||
float maxa = 0.0f;
|
|
||||||
float maxb = 0.0f;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConditionOutfit final : public Condition
|
class ConditionOutfit final : public Condition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConditionOutfit(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0) :
|
ConditionOutfit(ConditionId_t id, ConditionType_t type, int32_t ticks, uint32_t subId = 0) :
|
||||||
Condition(id, type, ticks, buff, subId) {}
|
Condition(id, type, ticks, subId) {}
|
||||||
|
|
||||||
bool startCondition(Creature* creature) override;
|
bool startCondition(Creature* creature) final;
|
||||||
bool executeCondition(Creature* creature, int32_t interval) override;
|
bool executeCondition(Creature* creature, int32_t interval) final;
|
||||||
void endCondition(Creature* creature) override;
|
void endCondition(Creature* creature) final;
|
||||||
void addCondition(Creature* creature, const Condition* condition) override;
|
void addCondition(Creature* creature, const Condition* condition) final;
|
||||||
|
|
||||||
ConditionOutfit* clone() const override {
|
ConditionOutfit* clone() const final {
|
||||||
return new ConditionOutfit(*this);
|
return new ConditionOutfit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setOutfit(const Outfit_t& outfit);
|
void setOutfit(const Outfit_t& outfit);
|
||||||
|
|
||||||
//serialization
|
//serialization
|
||||||
void serialize(PropWriteStream& propWriteStream) override;
|
void serialize(PropWriteStream& propWriteStream) final;
|
||||||
bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) override;
|
bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) final;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
Outfit_t outfit;
|
Outfit_t outfit;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConditionLight final : public Condition
|
class ConditionLight final : public Condition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConditionLight(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff, uint32_t subId, uint8_t lightlevel, uint8_t lightcolor) :
|
ConditionLight(ConditionId_t id, ConditionType_t type, int32_t ticks, uint32_t subId, uint8_t lightlevel, uint8_t lightcolor) :
|
||||||
Condition(id, type, ticks, buff, subId), lightInfo(lightlevel, lightcolor) {}
|
Condition(id, type, ticks, subId), lightInfo(lightlevel, lightcolor) {}
|
||||||
|
|
||||||
bool startCondition(Creature* creature) override;
|
bool startCondition(Creature* creature) final;
|
||||||
bool executeCondition(Creature* creature, int32_t interval) override;
|
bool executeCondition(Creature* creature, int32_t interval) final;
|
||||||
void endCondition(Creature* creature) override;
|
void endCondition(Creature* creature) final;
|
||||||
void addCondition(Creature* creature, const Condition* condition) override;
|
void addCondition(Creature* creature, const Condition* addCondition) final;
|
||||||
|
|
||||||
ConditionLight* clone() const override {
|
ConditionLight* clone() const final {
|
||||||
return new ConditionLight(*this);
|
return new ConditionLight(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setParam(ConditionParam_t param, int32_t value) override;
|
bool setParam(ConditionParam_t param, int32_t value) final;
|
||||||
|
|
||||||
//serialization
|
//serialization
|
||||||
void serialize(PropWriteStream& propWriteStream) override;
|
void serialize(PropWriteStream& propWriteStream) final;
|
||||||
bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) override;
|
bool unserializeProp(ConditionAttr_t attr, PropStream& propStream) final;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
LightInfo lightInfo;
|
LightInfo lightInfo;
|
||||||
uint32_t internalLightTicks = 0;
|
uint32_t internalLightTicks = 0;
|
||||||
uint32_t lightChangeInterval = 0;
|
uint32_t lightChangeInterval = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConditionSpellCooldown final : public ConditionGeneric
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ConditionSpellCooldown(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0) :
|
|
||||||
ConditionGeneric(id, type, ticks, buff, subId) {}
|
|
||||||
|
|
||||||
bool startCondition(Creature* creature) override;
|
|
||||||
void addCondition(Creature* creature, const Condition* condition) override;
|
|
||||||
|
|
||||||
ConditionSpellCooldown* clone() const override {
|
|
||||||
return new ConditionSpellCooldown(*this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ConditionSpellGroupCooldown final : public ConditionGeneric
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ConditionSpellGroupCooldown(ConditionId_t id, ConditionType_t type, int32_t ticks, bool buff = false, uint32_t subId = 0) :
|
|
||||||
ConditionGeneric(id, type, ticks, buff, subId) {}
|
|
||||||
|
|
||||||
bool startCondition(Creature* creature) override;
|
|
||||||
void addCondition(Creature* creature, const Condition* condition) override;
|
|
||||||
|
|
||||||
ConditionSpellGroupCooldown* clone() const override {
|
|
||||||
return new ConditionSpellGroupCooldown(*this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,12 +19,6 @@
|
|||||||
|
|
||||||
#include "otpch.h"
|
#include "otpch.h"
|
||||||
|
|
||||||
#if __has_include("luajit/lua.hpp")
|
|
||||||
#include <luajit/lua.hpp>
|
|
||||||
#else
|
|
||||||
#include <lua.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "configmanager.h"
|
#include "configmanager.h"
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
|
||||||
@@ -35,57 +29,6 @@
|
|||||||
|
|
||||||
extern Game g_game;
|
extern Game g_game;
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
std::string getGlobalString(lua_State* L, const char* identifier, const char* defaultValue)
|
|
||||||
{
|
|
||||||
lua_getglobal(L, identifier);
|
|
||||||
if (!lua_isstring(L, -1)) {
|
|
||||||
lua_pop(L, 1);
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t len = lua_strlen(L, -1);
|
|
||||||
std::string ret(lua_tostring(L, -1), len);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t getGlobalNumber(lua_State* L, const char* identifier, const int32_t defaultValue = 0)
|
|
||||||
{
|
|
||||||
lua_getglobal(L, identifier);
|
|
||||||
if (!lua_isnumber(L, -1)) {
|
|
||||||
lua_pop(L, 1);
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t val = lua_tonumber(L, -1);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getGlobalBoolean(lua_State* L, const char* identifier, const bool defaultValue)
|
|
||||||
{
|
|
||||||
lua_getglobal(L, identifier);
|
|
||||||
if (!lua_isboolean(L, -1)) {
|
|
||||||
if (!lua_isstring(L, -1)) {
|
|
||||||
lua_pop(L, 1);
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t len = lua_strlen(L, -1);
|
|
||||||
std::string ret(lua_tostring(L, -1), len);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
return booleanString(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
int val = lua_toboolean(L, -1);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
return val != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ConfigManager::load()
|
bool ConfigManager::load()
|
||||||
{
|
{
|
||||||
lua_State* L = luaL_newstate();
|
lua_State* L = luaL_newstate();
|
||||||
@@ -120,10 +63,9 @@ bool ConfigManager::load()
|
|||||||
integer[GAME_PORT] = getGlobalNumber(L, "gameProtocolPort", 7172);
|
integer[GAME_PORT] = getGlobalNumber(L, "gameProtocolPort", 7172);
|
||||||
integer[LOGIN_PORT] = getGlobalNumber(L, "loginProtocolPort", 7171);
|
integer[LOGIN_PORT] = getGlobalNumber(L, "loginProtocolPort", 7171);
|
||||||
integer[STATUS_PORT] = getGlobalNumber(L, "statusProtocolPort", 7171);
|
integer[STATUS_PORT] = getGlobalNumber(L, "statusProtocolPort", 7171);
|
||||||
|
|
||||||
integer[MARKET_OFFER_DURATION] = getGlobalNumber(L, "marketOfferDuration", 30 * 24 * 60 * 60);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean[SHOW_MONSTER_LOOT] = getGlobalBoolean(L, "showMonsterLoot", true);
|
||||||
boolean[ALLOW_CHANGEOUTFIT] = getGlobalBoolean(L, "allowChangeOutfit", true);
|
boolean[ALLOW_CHANGEOUTFIT] = getGlobalBoolean(L, "allowChangeOutfit", true);
|
||||||
boolean[ONE_PLAYER_ON_ACCOUNT] = getGlobalBoolean(L, "onePlayerOnlinePerAccount", true);
|
boolean[ONE_PLAYER_ON_ACCOUNT] = getGlobalBoolean(L, "onePlayerOnlinePerAccount", true);
|
||||||
boolean[AIMBOT_HOTKEY_ENABLED] = getGlobalBoolean(L, "hotkeyAimbotEnabled", true);
|
boolean[AIMBOT_HOTKEY_ENABLED] = getGlobalBoolean(L, "hotkeyAimbotEnabled", true);
|
||||||
@@ -132,19 +74,14 @@ bool ConfigManager::load()
|
|||||||
boolean[FREE_PREMIUM] = getGlobalBoolean(L, "freePremium", false);
|
boolean[FREE_PREMIUM] = getGlobalBoolean(L, "freePremium", false);
|
||||||
boolean[REPLACE_KICK_ON_LOGIN] = getGlobalBoolean(L, "replaceKickOnLogin", true);
|
boolean[REPLACE_KICK_ON_LOGIN] = getGlobalBoolean(L, "replaceKickOnLogin", true);
|
||||||
boolean[ALLOW_CLONES] = getGlobalBoolean(L, "allowClones", false);
|
boolean[ALLOW_CLONES] = getGlobalBoolean(L, "allowClones", false);
|
||||||
boolean[MARKET_PREMIUM] = getGlobalBoolean(L, "premiumToCreateMarketOffer", true);
|
|
||||||
boolean[EMOTE_SPELLS] = getGlobalBoolean(L, "emoteSpells", false);
|
|
||||||
boolean[STAMINA_SYSTEM] = getGlobalBoolean(L, "staminaSystem", true);
|
boolean[STAMINA_SYSTEM] = getGlobalBoolean(L, "staminaSystem", true);
|
||||||
boolean[WARN_UNSAFE_SCRIPTS] = getGlobalBoolean(L, "warnUnsafeScripts", true);
|
boolean[WARN_UNSAFE_SCRIPTS] = getGlobalBoolean(L, "warnUnsafeScripts", true);
|
||||||
boolean[CONVERT_UNSAFE_SCRIPTS] = getGlobalBoolean(L, "convertUnsafeScripts", true);
|
boolean[CONVERT_UNSAFE_SCRIPTS] = getGlobalBoolean(L, "convertUnsafeScripts", true);
|
||||||
boolean[CLASSIC_EQUIPMENT_SLOTS] = getGlobalBoolean(L, "classicEquipmentSlots", false);
|
boolean[TELEPORT_NEWBIES] = getGlobalBoolean(L, "teleportNewbies", true);
|
||||||
boolean[CLASSIC_ATTACK_SPEED] = getGlobalBoolean(L, "classicAttackSpeed", false);
|
boolean[STACK_CUMULATIVES] = getGlobalBoolean(L, "autoStackCumulatives", false);
|
||||||
boolean[SCRIPTS_CONSOLE_LOGS] = getGlobalBoolean(L, "showScriptsLogInConsole", true);
|
boolean[BLOCK_HEIGHT] = getGlobalBoolean(L, "blockHeight", false);
|
||||||
boolean[SERVER_SAVE_NOTIFY_MESSAGE] = getGlobalBoolean(L, "serverSaveNotifyMessage", true);
|
boolean[DROP_ITEMS] = getGlobalBoolean(L, "dropItems", false);
|
||||||
boolean[SERVER_SAVE_CLEAN_MAP] = getGlobalBoolean(L, "serverSaveCleanMap", false);
|
|
||||||
boolean[SERVER_SAVE_CLOSE] = getGlobalBoolean(L, "serverSaveClose", false);
|
|
||||||
boolean[SERVER_SAVE_SHUTDOWN] = getGlobalBoolean(L, "serverSaveShutdown", true);
|
|
||||||
boolean[ONLINE_OFFLINE_CHARLIST] = getGlobalBoolean(L, "showOnlineStatusInCharlist", false);
|
|
||||||
|
|
||||||
string[DEFAULT_PRIORITY] = getGlobalString(L, "defaultPriority", "high");
|
string[DEFAULT_PRIORITY] = getGlobalString(L, "defaultPriority", "high");
|
||||||
string[SERVER_NAME] = getGlobalString(L, "serverName", "");
|
string[SERVER_NAME] = getGlobalString(L, "serverName", "");
|
||||||
@@ -164,9 +101,7 @@ bool ConfigManager::load()
|
|||||||
integer[RATE_LOOT] = getGlobalNumber(L, "rateLoot", 2);
|
integer[RATE_LOOT] = getGlobalNumber(L, "rateLoot", 2);
|
||||||
integer[RATE_MAGIC] = getGlobalNumber(L, "rateMagic", 3);
|
integer[RATE_MAGIC] = getGlobalNumber(L, "rateMagic", 3);
|
||||||
integer[RATE_SPAWN] = getGlobalNumber(L, "rateSpawn", 1);
|
integer[RATE_SPAWN] = getGlobalNumber(L, "rateSpawn", 1);
|
||||||
integer[HOUSE_PRICE] = getGlobalNumber(L, "housePriceEachSQM", 1000);
|
integer[BAN_LENGTH] = getGlobalNumber(L, "banLength", 30 * 24 * 60 * 60);
|
||||||
integer[KILLS_TO_RED] = getGlobalNumber(L, "killsToRedSkull", 3);
|
|
||||||
integer[KILLS_TO_BLACK] = getGlobalNumber(L, "killsToBlackSkull", 6);
|
|
||||||
integer[ACTIONS_DELAY_INTERVAL] = getGlobalNumber(L, "timeBetweenActions", 200);
|
integer[ACTIONS_DELAY_INTERVAL] = getGlobalNumber(L, "timeBetweenActions", 200);
|
||||||
integer[EX_ACTIONS_DELAY_INTERVAL] = getGlobalNumber(L, "timeBetweenExActions", 1000);
|
integer[EX_ACTIONS_DELAY_INTERVAL] = getGlobalNumber(L, "timeBetweenExActions", 1000);
|
||||||
integer[MAX_MESSAGEBUFFER] = getGlobalNumber(L, "maxMessageBuffer", 4);
|
integer[MAX_MESSAGEBUFFER] = getGlobalNumber(L, "maxMessageBuffer", 4);
|
||||||
@@ -174,14 +109,20 @@ bool ConfigManager::load()
|
|||||||
integer[PROTECTION_LEVEL] = getGlobalNumber(L, "protectionLevel", 1);
|
integer[PROTECTION_LEVEL] = getGlobalNumber(L, "protectionLevel", 1);
|
||||||
integer[DEATH_LOSE_PERCENT] = getGlobalNumber(L, "deathLosePercent", -1);
|
integer[DEATH_LOSE_PERCENT] = getGlobalNumber(L, "deathLosePercent", -1);
|
||||||
integer[STATUSQUERY_TIMEOUT] = getGlobalNumber(L, "statusTimeout", 5000);
|
integer[STATUSQUERY_TIMEOUT] = getGlobalNumber(L, "statusTimeout", 5000);
|
||||||
integer[FRAG_TIME] = getGlobalNumber(L, "timeToDecreaseFrags", 24 * 60 * 60 * 1000);
|
integer[WHITE_SKULL_TIME] = getGlobalNumber(L, "whiteSkullTime", 15 * 60);
|
||||||
integer[WHITE_SKULL_TIME] = getGlobalNumber(L, "whiteSkullTime", 15 * 60 * 1000);
|
integer[RED_SKULL_TIME] = getGlobalNumber(L, "redSkullTime", 30 * 24 * 60 * 60);
|
||||||
|
integer[KILLS_DAY_RED_SKULL] = getGlobalNumber(L, "killsDayRedSkull", 3);
|
||||||
|
integer[KILLS_WEEK_RED_SKULL] = getGlobalNumber(L, "killsWeekRedSkull", 5);
|
||||||
|
integer[KILLS_MONTH_RED_SKULL] = getGlobalNumber(L, "killsMonthRedSkull", 10);
|
||||||
|
integer[KILLS_DAY_BANISHMENT] = getGlobalNumber(L, "killsDayBanishment", 5);
|
||||||
|
integer[KILLS_WEEK_BANISHMENT] = getGlobalNumber(L, "killsWeekBanishment", 8);
|
||||||
|
integer[KILLS_MONTH_BANISHMENT] = getGlobalNumber(L, "killsMonthBanishment", 10);
|
||||||
integer[STAIRHOP_DELAY] = getGlobalNumber(L, "stairJumpExhaustion", 2000);
|
integer[STAIRHOP_DELAY] = getGlobalNumber(L, "stairJumpExhaustion", 2000);
|
||||||
integer[EXP_FROM_PLAYERS_LEVEL_RANGE] = getGlobalNumber(L, "expFromPlayersLevelRange", 75);
|
integer[EXP_FROM_PLAYERS_LEVEL_RANGE] = getGlobalNumber(L, "expFromPlayersLevelRange", 75);
|
||||||
integer[CHECK_EXPIRED_MARKET_OFFERS_EACH_MINUTES] = getGlobalNumber(L, "checkExpiredMarketOffersEachMinutes", 60);
|
|
||||||
integer[MAX_MARKET_OFFERS_AT_A_TIME_PER_PLAYER] = getGlobalNumber(L, "maxMarketOffersAtATimePerPlayer", 100);
|
|
||||||
integer[MAX_PACKETS_PER_SECOND] = getGlobalNumber(L, "maxPacketsPerSecond", 25);
|
integer[MAX_PACKETS_PER_SECOND] = getGlobalNumber(L, "maxPacketsPerSecond", 25);
|
||||||
integer[SERVER_SAVE_NOTIFY_DURATION] = getGlobalNumber(L, "serverSaveNotifyDuration", 5);
|
integer[NEWBIE_TOWN] = getGlobalNumber(L, "newbieTownId", 1);
|
||||||
|
integer[NEWBIE_LEVEL_THRESHOLD] = getGlobalNumber(L, "newbieLevelThreshold", 5);
|
||||||
|
integer[MONEY_RATE] = getGlobalNumber(L, "moneyRate", 1);
|
||||||
|
|
||||||
loaded = true;
|
loaded = true;
|
||||||
lua_close(L);
|
lua_close(L);
|
||||||
@@ -197,13 +138,11 @@ bool ConfigManager::reload()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string dummyStr;
|
|
||||||
|
|
||||||
const std::string& ConfigManager::getString(string_config_t what) const
|
const std::string& ConfigManager::getString(string_config_t what) const
|
||||||
{
|
{
|
||||||
if (what >= LAST_STRING_CONFIG) {
|
if (what >= LAST_STRING_CONFIG) {
|
||||||
std::cout << "[Warning - ConfigManager::getString] Accessing invalid index: " << what << std::endl;
|
std::cout << "[Warning - ConfigManager::getString] Accessing invalid index: " << what << std::endl;
|
||||||
return dummyStr;
|
return string[DUMMY_STR];
|
||||||
}
|
}
|
||||||
return string[what];
|
return string[what];
|
||||||
}
|
}
|
||||||
@@ -225,3 +164,47 @@ bool ConfigManager::getBoolean(boolean_config_t what) const
|
|||||||
}
|
}
|
||||||
return boolean[what];
|
return boolean[what];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ConfigManager::getGlobalString(lua_State* L, const char* identifier, const char* defaultValue)
|
||||||
|
{
|
||||||
|
lua_getglobal(L, identifier);
|
||||||
|
if (!lua_isstring(L, -1)) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = lua_strlen(L, -1);
|
||||||
|
std::string ret(lua_tostring(L, -1), len);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t ConfigManager::getGlobalNumber(lua_State* L, const char* identifier, const int32_t defaultValue)
|
||||||
|
{
|
||||||
|
lua_getglobal(L, identifier);
|
||||||
|
if (!lua_isnumber(L, -1)) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t val = lua_tonumber(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfigManager::getGlobalBoolean(lua_State* L, const char* identifier, const bool defaultValue)
|
||||||
|
{
|
||||||
|
lua_getglobal(L, identifier);
|
||||||
|
if (!lua_isboolean(L, -1)) {
|
||||||
|
if (!lua_isstring(L, -1)) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = lua_strlen(L, -1);
|
||||||
|
std::string ret(lua_tostring(L, -1), len);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return booleanString(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
int val = lua_toboolean(L, -1);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return val != 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -20,10 +20,13 @@
|
|||||||
#ifndef FS_CONFIGMANAGER_H_6BDD23BD0B8344F4B7C40E8BE6AF6F39
|
#ifndef FS_CONFIGMANAGER_H_6BDD23BD0B8344F4B7C40E8BE6AF6F39
|
||||||
#define FS_CONFIGMANAGER_H_6BDD23BD0B8344F4B7C40E8BE6AF6F39
|
#define FS_CONFIGMANAGER_H_6BDD23BD0B8344F4B7C40E8BE6AF6F39
|
||||||
|
|
||||||
|
#include <luajit/lua.hpp>
|
||||||
|
|
||||||
class ConfigManager
|
class ConfigManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum boolean_config_t {
|
enum boolean_config_t {
|
||||||
|
SHOW_MONSTER_LOOT,
|
||||||
ALLOW_CHANGEOUTFIT,
|
ALLOW_CHANGEOUTFIT,
|
||||||
ONE_PLAYER_ON_ACCOUNT,
|
ONE_PLAYER_ON_ACCOUNT,
|
||||||
AIMBOT_HOTKEY_ENABLED,
|
AIMBOT_HOTKEY_ENABLED,
|
||||||
@@ -34,24 +37,19 @@ class ConfigManager
|
|||||||
ALLOW_CLONES,
|
ALLOW_CLONES,
|
||||||
BIND_ONLY_GLOBAL_ADDRESS,
|
BIND_ONLY_GLOBAL_ADDRESS,
|
||||||
OPTIMIZE_DATABASE,
|
OPTIMIZE_DATABASE,
|
||||||
MARKET_PREMIUM,
|
|
||||||
EMOTE_SPELLS,
|
|
||||||
STAMINA_SYSTEM,
|
STAMINA_SYSTEM,
|
||||||
WARN_UNSAFE_SCRIPTS,
|
WARN_UNSAFE_SCRIPTS,
|
||||||
CONVERT_UNSAFE_SCRIPTS,
|
CONVERT_UNSAFE_SCRIPTS,
|
||||||
CLASSIC_EQUIPMENT_SLOTS,
|
TELEPORT_NEWBIES,
|
||||||
CLASSIC_ATTACK_SPEED,
|
STACK_CUMULATIVES,
|
||||||
SCRIPTS_CONSOLE_LOGS,
|
BLOCK_HEIGHT,
|
||||||
SERVER_SAVE_NOTIFY_MESSAGE,
|
DROP_ITEMS,
|
||||||
SERVER_SAVE_CLEAN_MAP,
|
|
||||||
SERVER_SAVE_CLOSE,
|
|
||||||
SERVER_SAVE_SHUTDOWN,
|
|
||||||
ONLINE_OFFLINE_CHARLIST,
|
|
||||||
|
|
||||||
LAST_BOOLEAN_CONFIG /* this must be the last one */
|
LAST_BOOLEAN_CONFIG /* this must be the last one */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum string_config_t {
|
enum string_config_t {
|
||||||
|
DUMMY_STR,
|
||||||
MAP_NAME,
|
MAP_NAME,
|
||||||
HOUSE_RENT_PERIOD,
|
HOUSE_RENT_PERIOD,
|
||||||
SERVER_NAME,
|
SERVER_NAME,
|
||||||
@@ -84,9 +82,7 @@ class ConfigManager
|
|||||||
RATE_LOOT,
|
RATE_LOOT,
|
||||||
RATE_MAGIC,
|
RATE_MAGIC,
|
||||||
RATE_SPAWN,
|
RATE_SPAWN,
|
||||||
HOUSE_PRICE,
|
BAN_LENGTH,
|
||||||
KILLS_TO_RED,
|
|
||||||
KILLS_TO_BLACK,
|
|
||||||
MAX_MESSAGEBUFFER,
|
MAX_MESSAGEBUFFER,
|
||||||
ACTIONS_DELAY_INTERVAL,
|
ACTIONS_DELAY_INTERVAL,
|
||||||
EX_ACTIONS_DELAY_INTERVAL,
|
EX_ACTIONS_DELAY_INTERVAL,
|
||||||
@@ -94,18 +90,23 @@ class ConfigManager
|
|||||||
PROTECTION_LEVEL,
|
PROTECTION_LEVEL,
|
||||||
DEATH_LOSE_PERCENT,
|
DEATH_LOSE_PERCENT,
|
||||||
STATUSQUERY_TIMEOUT,
|
STATUSQUERY_TIMEOUT,
|
||||||
FRAG_TIME,
|
|
||||||
WHITE_SKULL_TIME,
|
WHITE_SKULL_TIME,
|
||||||
|
RED_SKULL_TIME,
|
||||||
|
KILLS_DAY_RED_SKULL,
|
||||||
|
KILLS_WEEK_RED_SKULL,
|
||||||
|
KILLS_MONTH_RED_SKULL,
|
||||||
|
KILLS_DAY_BANISHMENT,
|
||||||
|
KILLS_WEEK_BANISHMENT,
|
||||||
|
KILLS_MONTH_BANISHMENT,
|
||||||
GAME_PORT,
|
GAME_PORT,
|
||||||
LOGIN_PORT,
|
LOGIN_PORT,
|
||||||
STATUS_PORT,
|
STATUS_PORT,
|
||||||
STAIRHOP_DELAY,
|
STAIRHOP_DELAY,
|
||||||
MARKET_OFFER_DURATION,
|
|
||||||
CHECK_EXPIRED_MARKET_OFFERS_EACH_MINUTES,
|
|
||||||
MAX_MARKET_OFFERS_AT_A_TIME_PER_PLAYER,
|
|
||||||
EXP_FROM_PLAYERS_LEVEL_RANGE,
|
EXP_FROM_PLAYERS_LEVEL_RANGE,
|
||||||
MAX_PACKETS_PER_SECOND,
|
MAX_PACKETS_PER_SECOND,
|
||||||
SERVER_SAVE_NOTIFY_DURATION,
|
NEWBIE_TOWN,
|
||||||
|
NEWBIE_LEVEL_THRESHOLD,
|
||||||
|
MONEY_RATE,
|
||||||
|
|
||||||
LAST_INTEGER_CONFIG /* this must be the last one */
|
LAST_INTEGER_CONFIG /* this must be the last one */
|
||||||
};
|
};
|
||||||
@@ -118,6 +119,10 @@ class ConfigManager
|
|||||||
bool getBoolean(boolean_config_t what) const;
|
bool getBoolean(boolean_config_t what) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static std::string getGlobalString(lua_State* L, const char* identifier, const char* defaultValue);
|
||||||
|
static int32_t getGlobalNumber(lua_State* L, const char* identifier, const int32_t defaultValue = 0);
|
||||||
|
static bool getGlobalBoolean(lua_State* L, const char* identifier, const bool defaultValue);
|
||||||
|
|
||||||
std::string string[LAST_STRING_CONFIG] = {};
|
std::string string[LAST_STRING_CONFIG] = {};
|
||||||
int32_t integer[LAST_INTEGER_CONFIG] = {};
|
int32_t integer[LAST_INTEGER_CONFIG] = {};
|
||||||
bool boolean[LAST_BOOLEAN_CONFIG] = {};
|
bool boolean[LAST_BOOLEAN_CONFIG] = {};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -182,60 +182,51 @@ void Connection::parsePacket(const boost::system::error_code& error)
|
|||||||
if (error) {
|
if (error) {
|
||||||
close(FORCE_CLOSE);
|
close(FORCE_CLOSE);
|
||||||
return;
|
return;
|
||||||
} else if (connectionState != CONNECTION_STATE_OPEN) {
|
}
|
||||||
|
else if (connectionState != CONNECTION_STATE_OPEN) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check packet checksum
|
|
||||||
uint32_t checksum;
|
|
||||||
int32_t len = msg.getLength() - msg.getBufferPosition() - NetworkMessage::CHECKSUM_LENGTH;
|
|
||||||
if (len > 0) {
|
|
||||||
checksum = adlerChecksum(msg.getBuffer() + msg.getBufferPosition() + NetworkMessage::CHECKSUM_LENGTH, len);
|
|
||||||
} else {
|
|
||||||
checksum = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t recvChecksum = msg.get<uint32_t>();
|
|
||||||
if (recvChecksum != checksum) {
|
|
||||||
// it might not have been the checksum, step back
|
|
||||||
msg.skipBytes(-NetworkMessage::CHECKSUM_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!receivedFirst) {
|
if (!receivedFirst) {
|
||||||
// First message received
|
// First message received
|
||||||
receivedFirst = true;
|
receivedFirst = true;
|
||||||
|
|
||||||
if (!protocol) {
|
if (!protocol) {
|
||||||
// Game protocol has already been created at this point
|
// Game protocol has already been created at this point
|
||||||
protocol = service_port->make_protocol(recvChecksum == checksum, msg, shared_from_this());
|
protocol = service_port->make_protocol(msg, shared_from_this());
|
||||||
if (!protocol) {
|
if (!protocol) {
|
||||||
close(FORCE_CLOSE);
|
close(FORCE_CLOSE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
msg.skipBytes(1); // Skip protocol ID
|
msg.skipBytes(1); // Skip protocol ID
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol->onRecvFirstMessage(msg);
|
protocol->onRecvFirstMessage(msg);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
protocol->onRecvMessage(msg); // Send the packet to the current protocol
|
protocol->onRecvMessage(msg); // Send the packet to the current protocol
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
readTimer.expires_from_now(boost::posix_time::seconds(CONNECTION_READ_TIMEOUT));
|
readTimer.expires_from_now(boost::posix_time::seconds(CONNECTION_READ_TIMEOUT));
|
||||||
readTimer.async_wait(std::bind(&Connection::handleTimeout, std::weak_ptr<Connection>(shared_from_this()),
|
readTimer.async_wait(std::bind(&Connection::handleTimeout, std::weak_ptr<Connection>(shared_from_this()),
|
||||||
std::placeholders::_1));
|
std::placeholders::_1));
|
||||||
|
|
||||||
// Wait to the next packet
|
// Wait to the next packet
|
||||||
boost::asio::async_read(socket,
|
boost::asio::async_read(socket,
|
||||||
boost::asio::buffer(msg.getBuffer(), NetworkMessage::HEADER_LENGTH),
|
boost::asio::buffer(msg.getBuffer(), NetworkMessage::HEADER_LENGTH),
|
||||||
std::bind(&Connection::parseHeader, shared_from_this(), std::placeholders::_1));
|
std::bind(&Connection::parseHeader, shared_from_this(), std::placeholders::_1));
|
||||||
} catch (boost::system::system_error& e) {
|
}
|
||||||
|
catch (boost::system::system_error& e) {
|
||||||
std::cout << "[Network error - Connection::parsePacket] " << e.what() << std::endl;
|
std::cout << "[Network error - Connection::parsePacket] " << e.what() << std::endl;
|
||||||
close(FORCE_CLOSE);
|
close(FORCE_CLOSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Connection::send(const OutputMessage_ptr& msg)
|
void Connection::send(const OutputMessage_ptr& msg)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lockClass(connectionLock);
|
std::lock_guard<std::recursive_mutex> lockClass(connectionLock);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,17 +28,17 @@ static constexpr int32_t CONNECTION_WRITE_TIMEOUT = 30;
|
|||||||
static constexpr int32_t CONNECTION_READ_TIMEOUT = 30;
|
static constexpr int32_t CONNECTION_READ_TIMEOUT = 30;
|
||||||
|
|
||||||
class Protocol;
|
class Protocol;
|
||||||
using Protocol_ptr = std::shared_ptr<Protocol>;
|
typedef std::shared_ptr<Protocol> Protocol_ptr;
|
||||||
class OutputMessage;
|
class OutputMessage;
|
||||||
using OutputMessage_ptr = std::shared_ptr<OutputMessage>;
|
typedef std::shared_ptr<OutputMessage> OutputMessage_ptr;
|
||||||
class Connection;
|
class Connection;
|
||||||
using Connection_ptr = std::shared_ptr<Connection> ;
|
typedef std::shared_ptr<Connection> Connection_ptr;
|
||||||
using ConnectionWeak_ptr = std::weak_ptr<Connection>;
|
typedef std::weak_ptr<Connection> ConnectionWeak_ptr;
|
||||||
class ServiceBase;
|
class ServiceBase;
|
||||||
using Service_ptr = std::shared_ptr<ServiceBase>;
|
typedef std::shared_ptr<ServiceBase> Service_ptr;
|
||||||
class ServicePort;
|
class ServicePort;
|
||||||
using ServicePort_ptr = std::shared_ptr<ServicePort>;
|
typedef std::shared_ptr<ServicePort> ServicePort_ptr;
|
||||||
using ConstServicePort_ptr = std::shared_ptr<const ServicePort>;
|
typedef std::shared_ptr<const ServicePort> ConstServicePort_ptr;
|
||||||
|
|
||||||
class ConnectionManager
|
class ConnectionManager
|
||||||
{
|
{
|
||||||
@@ -52,7 +52,7 @@ class ConnectionManager
|
|||||||
void releaseConnection(const Connection_ptr& connection);
|
void releaseConnection(const Connection_ptr& connection);
|
||||||
void closeAll();
|
void closeAll();
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
ConnectionManager() = default;
|
ConnectionManager() = default;
|
||||||
|
|
||||||
std::unordered_set<Connection_ptr> connections;
|
std::unordered_set<Connection_ptr> connections;
|
||||||
@@ -78,8 +78,12 @@ class Connection : public std::enable_shared_from_this<Connection>
|
|||||||
readTimer(io_service),
|
readTimer(io_service),
|
||||||
writeTimer(io_service),
|
writeTimer(io_service),
|
||||||
service_port(std::move(service_port)),
|
service_port(std::move(service_port)),
|
||||||
socket(io_service),
|
socket(io_service) {
|
||||||
timeConnected(time(nullptr)) {}
|
connectionState = CONNECTION_STATE_OPEN;
|
||||||
|
receivedFirst = false;
|
||||||
|
packetsSent = 0;
|
||||||
|
timeConnected = time(nullptr);
|
||||||
|
}
|
||||||
~Connection();
|
~Connection();
|
||||||
|
|
||||||
friend class ConnectionManager;
|
friend class ConnectionManager;
|
||||||
@@ -124,10 +128,10 @@ class Connection : public std::enable_shared_from_this<Connection>
|
|||||||
boost::asio::ip::tcp::socket socket;
|
boost::asio::ip::tcp::socket socket;
|
||||||
|
|
||||||
time_t timeConnected;
|
time_t timeConnected;
|
||||||
uint32_t packetsSent = 0;
|
uint32_t packetsSent;
|
||||||
|
|
||||||
bool connectionState = CONNECTION_STATE_OPEN;
|
bool connectionState;
|
||||||
bool receivedFirst = false;
|
bool receivedFirst;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
414
src/const.h
414
src/const.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -52,67 +52,6 @@ enum MagicEffectClasses : uint8_t {
|
|||||||
CONST_ME_SOUND_WHITE = 25,
|
CONST_ME_SOUND_WHITE = 25,
|
||||||
CONST_ME_BUBBLES = 26,
|
CONST_ME_BUBBLES = 26,
|
||||||
CONST_ME_CRAPS = 27,
|
CONST_ME_CRAPS = 27,
|
||||||
CONST_ME_GIFT_WRAPS = 28,
|
|
||||||
CONST_ME_FIREWORK_YELLOW = 29,
|
|
||||||
CONST_ME_FIREWORK_RED = 30,
|
|
||||||
CONST_ME_FIREWORK_BLUE = 31,
|
|
||||||
CONST_ME_STUN = 32,
|
|
||||||
CONST_ME_SLEEP = 33,
|
|
||||||
CONST_ME_WATERCREATURE = 34,
|
|
||||||
CONST_ME_GROUNDSHAKER = 35,
|
|
||||||
CONST_ME_HEARTS = 36,
|
|
||||||
CONST_ME_FIREATTACK = 37,
|
|
||||||
CONST_ME_ENERGYAREA = 38,
|
|
||||||
CONST_ME_SMALLCLOUDS = 39,
|
|
||||||
CONST_ME_HOLYDAMAGE = 40,
|
|
||||||
CONST_ME_BIGCLOUDS = 41,
|
|
||||||
CONST_ME_ICEAREA = 42,
|
|
||||||
CONST_ME_ICETORNADO = 43,
|
|
||||||
CONST_ME_ICEATTACK = 44,
|
|
||||||
CONST_ME_STONES = 45,
|
|
||||||
CONST_ME_SMALLPLANTS = 46,
|
|
||||||
CONST_ME_CARNIPHILA = 47,
|
|
||||||
CONST_ME_PURPLEENERGY = 48,
|
|
||||||
CONST_ME_YELLOWENERGY = 49,
|
|
||||||
CONST_ME_HOLYAREA = 50,
|
|
||||||
CONST_ME_BIGPLANTS = 51,
|
|
||||||
CONST_ME_CAKE = 52,
|
|
||||||
CONST_ME_GIANTICE = 53,
|
|
||||||
CONST_ME_WATERSPLASH = 54,
|
|
||||||
CONST_ME_PLANTATTACK = 55,
|
|
||||||
CONST_ME_TUTORIALARROW = 56,
|
|
||||||
CONST_ME_TUTORIALSQUARE = 57,
|
|
||||||
CONST_ME_MIRRORHORIZONTAL = 58,
|
|
||||||
CONST_ME_MIRRORVERTICAL = 59,
|
|
||||||
CONST_ME_SKULLHORIZONTAL = 60,
|
|
||||||
CONST_ME_SKULLVERTICAL = 61,
|
|
||||||
CONST_ME_ASSASSIN = 62,
|
|
||||||
CONST_ME_STEPSHORIZONTAL = 63,
|
|
||||||
CONST_ME_BLOODYSTEPS = 64,
|
|
||||||
CONST_ME_STEPSVERTICAL = 65,
|
|
||||||
CONST_ME_YALAHARIGHOST = 66,
|
|
||||||
CONST_ME_BATS = 67,
|
|
||||||
CONST_ME_SMOKE = 68,
|
|
||||||
CONST_ME_INSECTS = 69,
|
|
||||||
CONST_ME_DRAGONHEAD = 70,
|
|
||||||
CONST_ME_ORCSHAMAN = 71,
|
|
||||||
CONST_ME_ORCSHAMAN_FIRE = 72,
|
|
||||||
CONST_ME_THUNDER = 73,
|
|
||||||
CONST_ME_FERUMBRAS = 74,
|
|
||||||
CONST_ME_CONFETTI_HORIZONTAL = 75,
|
|
||||||
CONST_ME_CONFETTI_VERTICAL = 76,
|
|
||||||
// 77-157 are empty
|
|
||||||
CONST_ME_BLACKSMOKE = 158,
|
|
||||||
// 159-166 are empty
|
|
||||||
CONST_ME_REDSMOKE = 167,
|
|
||||||
CONST_ME_YELLOWSMOKE = 168,
|
|
||||||
CONST_ME_GREENSMOKE = 169,
|
|
||||||
CONST_ME_PURPLESMOKE = 170,
|
|
||||||
CONST_ME_EARLY_THUNDER = 171,
|
|
||||||
CONST_ME_RAGIAZ_BONECAPSULE = 172,
|
|
||||||
CONST_ME_CRITICAL_DAMAGE = 173,
|
|
||||||
// 174 is empty
|
|
||||||
CONST_ME_PLUNGING_FISH = 175,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ShootType_t : uint8_t {
|
enum ShootType_t : uint8_t {
|
||||||
@@ -133,192 +72,75 @@ enum ShootType_t : uint8_t {
|
|||||||
CONST_ANI_SNOWBALL = 13,
|
CONST_ANI_SNOWBALL = 13,
|
||||||
CONST_ANI_POWERBOLT = 14,
|
CONST_ANI_POWERBOLT = 14,
|
||||||
CONST_ANI_POISON = 15,
|
CONST_ANI_POISON = 15,
|
||||||
CONST_ANI_INFERNALBOLT = 16,
|
|
||||||
CONST_ANI_HUNTINGSPEAR = 17,
|
|
||||||
CONST_ANI_ENCHANTEDSPEAR = 18,
|
|
||||||
CONST_ANI_REDSTAR = 19,
|
|
||||||
CONST_ANI_GREENSTAR = 20,
|
|
||||||
CONST_ANI_ROYALSPEAR = 21,
|
|
||||||
CONST_ANI_SNIPERARROW = 22,
|
|
||||||
CONST_ANI_ONYXARROW = 23,
|
|
||||||
CONST_ANI_PIERCINGBOLT = 24,
|
|
||||||
CONST_ANI_WHIRLWINDSWORD = 25,
|
|
||||||
CONST_ANI_WHIRLWINDAXE = 26,
|
|
||||||
CONST_ANI_WHIRLWINDCLUB = 27,
|
|
||||||
CONST_ANI_ETHEREALSPEAR = 28,
|
|
||||||
CONST_ANI_ICE = 29,
|
|
||||||
CONST_ANI_EARTH = 30,
|
|
||||||
CONST_ANI_HOLY = 31,
|
|
||||||
CONST_ANI_SUDDENDEATH = 32,
|
|
||||||
CONST_ANI_FLASHARROW = 33,
|
|
||||||
CONST_ANI_FLAMMINGARROW = 34,
|
|
||||||
CONST_ANI_SHIVERARROW = 35,
|
|
||||||
CONST_ANI_ENERGYBALL = 36,
|
|
||||||
CONST_ANI_SMALLICE = 37,
|
|
||||||
CONST_ANI_SMALLHOLY = 38,
|
|
||||||
CONST_ANI_SMALLEARTH = 39,
|
|
||||||
CONST_ANI_EARTHARROW = 40,
|
|
||||||
CONST_ANI_EXPLOSION = 41,
|
|
||||||
CONST_ANI_CAKE = 42,
|
|
||||||
|
|
||||||
CONST_ANI_TARSALARROW = 44,
|
|
||||||
CONST_ANI_VORTEXBOLT = 45,
|
|
||||||
|
|
||||||
CONST_ANI_PRISMATICBOLT = 48,
|
|
||||||
CONST_ANI_CRYSTALLINEARROW = 49,
|
|
||||||
CONST_ANI_DRILLBOLT = 50,
|
|
||||||
CONST_ANI_ENVENOMEDARROW = 51,
|
|
||||||
|
|
||||||
CONST_ANI_GLOOTHSPEAR = 53,
|
|
||||||
CONST_ANI_SIMPLEARROW = 54,
|
|
||||||
|
|
||||||
// for internal use, don't send to client
|
|
||||||
CONST_ANI_WEAPONTYPE = 0xFE, // 254
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SpeakClasses : uint8_t {
|
enum SpeakClasses : uint8_t {
|
||||||
TALKTYPE_SAY = 1,
|
TALKTYPE_SAY = 1,
|
||||||
TALKTYPE_WHISPER = 2,
|
TALKTYPE_WHISPER = 2,
|
||||||
TALKTYPE_YELL = 3,
|
TALKTYPE_YELL = 3,
|
||||||
TALKTYPE_PRIVATE_FROM = 4,
|
TALKTYPE_PRIVATE = 4,
|
||||||
TALKTYPE_PRIVATE_TO = 5,
|
TALKTYPE_CHANNEL_Y = 5, // Yellow
|
||||||
TALKTYPE_CHANNEL_Y = 7,
|
TALKTYPE_RVR_CHANNEL = 6,
|
||||||
TALKTYPE_CHANNEL_O = 8,
|
TALKTYPE_RVR_ANSWER = 7,
|
||||||
TALKTYPE_PRIVATE_NP = 10,
|
TALKTYPE_RVR_CONTINUE = 8,
|
||||||
TALKTYPE_PRIVATE_PN = 12,
|
TALKTYPE_BROADCAST = 9,
|
||||||
TALKTYPE_BROADCAST = 13,
|
TALKTYPE_CHANNEL_R1 = 10, // Red - #c text
|
||||||
TALKTYPE_CHANNEL_R1 = 14, //red - #c text
|
TALKTYPE_PRIVATE_RED = 11, // @name@text
|
||||||
TALKTYPE_PRIVATE_RED_FROM = 15, //@name@text
|
TALKTYPE_CHANNEL_O = 12, // orange
|
||||||
TALKTYPE_PRIVATE_RED_TO = 16, //@name@text
|
TALKTYPE_CHANNEL_R2 = 13, // red anonymous - #d text
|
||||||
TALKTYPE_MONSTER_SAY = 36,
|
TALKTYPE_MONSTER_YELL = 0x10,
|
||||||
TALKTYPE_MONSTER_YELL = 37,
|
TALKTYPE_MONSTER_SAY = 0x11,
|
||||||
|
|
||||||
TALKTYPE_CHANNEL_R2 = 0xFF, //#d
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MessageClasses : uint8_t {
|
enum MessageClasses : uint8_t {
|
||||||
MESSAGE_STATUS_CONSOLE_BLUE = 4, /*FIXME Blue message in the console*/
|
MESSAGE_STATUS_CONSOLE_YELLOW = 0x01, //Yellow message in the console
|
||||||
|
MESSAGE_STATUS_CONSOLE_LBLUE = 0x04, //Light blue message in the console
|
||||||
|
MESSAGE_STATUS_CONSOLE_ORANGE = 0x11, //Orange message in the console
|
||||||
|
MESSAGE_STATUS_WARNING = 0x12, //Red message in game window and in the console
|
||||||
|
MESSAGE_EVENT_ADVANCE = 0x13, //White message in game window and in the console
|
||||||
|
MESSAGE_EVENT_DEFAULT = 0x14, //White message at the bottom of the game window and in the console
|
||||||
|
MESSAGE_STATUS_DEFAULT = 0x15, //White message at the bottom of the game window and in the console
|
||||||
|
MESSAGE_INFO_DESCR = 0x16, //Green message in game window and in the console
|
||||||
|
MESSAGE_STATUS_SMALL = 0x17, //White message at the bottom of the game window"
|
||||||
|
MESSAGE_STATUS_CONSOLE_BLUE = 0x18, //Blue message in the console
|
||||||
|
MESSAGE_STATUS_CONSOLE_RED = 0x19, //Red message in the console
|
||||||
|
|
||||||
MESSAGE_STATUS_CONSOLE_RED = 13, /*Red message in the console*/
|
MESSAGE_CLASS_FIRST = MESSAGE_STATUS_CONSOLE_YELLOW,
|
||||||
|
MESSAGE_CLASS_LAST = MESSAGE_STATUS_CONSOLE_RED,
|
||||||
MESSAGE_STATUS_DEFAULT = 17, /*White message at the bottom of the game window and in the console*/
|
|
||||||
MESSAGE_STATUS_WARNING = 18, /*Red message in game window and in the console*/
|
|
||||||
MESSAGE_EVENT_ADVANCE = 19, /*White message in game window and in the console*/
|
|
||||||
|
|
||||||
MESSAGE_STATUS_SMALL = 21, /*White message at the bottom of the game window"*/
|
|
||||||
MESSAGE_INFO_DESCR = 22, /*Green message in game window and in the console*/
|
|
||||||
MESSAGE_DAMAGE_DEALT = 23,
|
|
||||||
MESSAGE_DAMAGE_RECEIVED = 24,
|
|
||||||
MESSAGE_HEALED = 25,
|
|
||||||
MESSAGE_EXPERIENCE = 26,
|
|
||||||
MESSAGE_DAMAGE_OTHERS = 27,
|
|
||||||
MESSAGE_HEALED_OTHERS = 28,
|
|
||||||
MESSAGE_EXPERIENCE_OTHERS = 29,
|
|
||||||
MESSAGE_EVENT_DEFAULT = 30, /*White message at the bottom of the game window and in the console*/
|
|
||||||
MESSAGE_LOOT = 31,
|
|
||||||
|
|
||||||
MESSAGE_GUILD = 33, /*White message in channel (+ channelId)*/
|
|
||||||
MESSAGE_PARTY_MANAGEMENT = 34, /*White message in channel (+ channelId)*/
|
|
||||||
MESSAGE_PARTY = 35, /*White message in channel (+ channelId)*/
|
|
||||||
MESSAGE_EVENT_ORANGE = 36, /*Orange message in the console*/
|
|
||||||
MESSAGE_STATUS_CONSOLE_ORANGE = 37, /*Orange message in the console*/
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum FluidColors_t : uint8_t {
|
enum FluidTypes_t : uint8_t
|
||||||
FLUID_EMPTY,
|
{
|
||||||
FLUID_BLUE,
|
FLUID_NONE = 0,
|
||||||
FLUID_RED,
|
|
||||||
FLUID_BROWN,
|
|
||||||
FLUID_GREEN,
|
|
||||||
FLUID_YELLOW,
|
|
||||||
FLUID_WHITE,
|
|
||||||
FLUID_PURPLE,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum FluidTypes_t : uint8_t {
|
|
||||||
FLUID_NONE = FLUID_EMPTY,
|
|
||||||
FLUID_WATER = FLUID_BLUE,
|
|
||||||
FLUID_BLOOD = FLUID_RED,
|
|
||||||
FLUID_BEER = FLUID_BROWN,
|
|
||||||
FLUID_SLIME = FLUID_GREEN,
|
|
||||||
FLUID_LEMONADE = FLUID_YELLOW,
|
|
||||||
FLUID_MILK = FLUID_WHITE,
|
|
||||||
FLUID_MANA = FLUID_PURPLE,
|
|
||||||
|
|
||||||
FLUID_LIFE = FLUID_RED + 8,
|
|
||||||
FLUID_OIL = FLUID_BROWN + 8,
|
|
||||||
FLUID_URINE = FLUID_YELLOW + 8,
|
|
||||||
FLUID_COCONUTMILK = FLUID_WHITE + 8,
|
|
||||||
FLUID_WINE = FLUID_PURPLE + 8,
|
|
||||||
|
|
||||||
FLUID_MUD = FLUID_BROWN + 16,
|
|
||||||
FLUID_FRUITJUICE = FLUID_YELLOW + 16,
|
|
||||||
|
|
||||||
FLUID_LAVA = FLUID_RED + 24,
|
|
||||||
FLUID_RUM = FLUID_BROWN + 24,
|
|
||||||
FLUID_SWAMP = FLUID_GREEN + 24,
|
|
||||||
|
|
||||||
FLUID_TEA = FLUID_BROWN + 32,
|
|
||||||
|
|
||||||
FLUID_MEAD = FLUID_BROWN + 40,
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint8_t reverseFluidMap[] = {
|
|
||||||
FLUID_EMPTY,
|
|
||||||
FLUID_WATER,
|
FLUID_WATER,
|
||||||
FLUID_MANA,
|
FLUID_WINE,
|
||||||
FLUID_BEER,
|
|
||||||
FLUID_EMPTY,
|
|
||||||
FLUID_BLOOD,
|
|
||||||
FLUID_SLIME,
|
|
||||||
FLUID_EMPTY,
|
|
||||||
FLUID_LEMONADE,
|
|
||||||
FLUID_MILK,
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint8_t clientToServerFluidMap[] = {
|
|
||||||
FLUID_EMPTY,
|
|
||||||
FLUID_WATER,
|
|
||||||
FLUID_MANA,
|
|
||||||
FLUID_BEER,
|
FLUID_BEER,
|
||||||
FLUID_MUD,
|
FLUID_MUD,
|
||||||
FLUID_BLOOD,
|
FLUID_BLOOD,
|
||||||
FLUID_SLIME,
|
FLUID_SLIME,
|
||||||
FLUID_RUM,
|
|
||||||
FLUID_LEMONADE,
|
|
||||||
FLUID_MILK,
|
|
||||||
FLUID_WINE,
|
|
||||||
FLUID_LIFE,
|
|
||||||
FLUID_URINE,
|
|
||||||
FLUID_OIL,
|
FLUID_OIL,
|
||||||
FLUID_FRUITJUICE,
|
FLUID_URINE,
|
||||||
|
FLUID_MILK,
|
||||||
|
FLUID_MANAFLUID,
|
||||||
|
FLUID_LIFEFLUID,
|
||||||
|
FLUID_LEMONADE,
|
||||||
|
FLUID_RUM,
|
||||||
FLUID_COCONUTMILK,
|
FLUID_COCONUTMILK,
|
||||||
FLUID_TEA,
|
FLUID_FRUITJUICE,
|
||||||
FLUID_MEAD,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ClientFluidTypes_t : uint8_t {
|
enum FluidColor_t : uint8_t
|
||||||
CLIENTFLUID_EMPTY = 0,
|
{
|
||||||
CLIENTFLUID_BLUE = 1,
|
FLUID_COLOR_NONE = 0,
|
||||||
CLIENTFLUID_PURPLE = 2,
|
FLUID_COLOR_BLUE = 1,
|
||||||
CLIENTFLUID_BROWN_1 = 3,
|
FLUID_COLOR_PURPLE = 2,
|
||||||
CLIENTFLUID_BROWN_2 = 4,
|
FLUID_COLOR_BROWN = 3,
|
||||||
CLIENTFLUID_RED = 5,
|
FLUID_COLOR_BROWN1 = 4,
|
||||||
CLIENTFLUID_GREEN = 6,
|
FLUID_COLOR_RED = 5,
|
||||||
CLIENTFLUID_BROWN = 7,
|
FLUID_COLOR_GREEN = 6,
|
||||||
CLIENTFLUID_YELLOW = 8,
|
FLUID_COLOR_BROWN2 = 7,
|
||||||
CLIENTFLUID_WHITE = 9,
|
FLUID_COLOR_YELLOW = 8,
|
||||||
};
|
FLUID_COLOR_WHITE = 9,
|
||||||
|
|
||||||
const uint8_t fluidMap[] = {
|
|
||||||
CLIENTFLUID_EMPTY,
|
|
||||||
CLIENTFLUID_BLUE,
|
|
||||||
CLIENTFLUID_RED,
|
|
||||||
CLIENTFLUID_BROWN_1,
|
|
||||||
CLIENTFLUID_GREEN,
|
|
||||||
CLIENTFLUID_YELLOW,
|
|
||||||
CLIENTFLUID_WHITE,
|
|
||||||
CLIENTFLUID_PURPLE,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SquareColor_t : uint8_t {
|
enum SquareColor_t : uint8_t {
|
||||||
@@ -333,10 +155,8 @@ enum TextColor_t : uint8_t {
|
|||||||
TEXTCOLOR_DARKRED = 108,
|
TEXTCOLOR_DARKRED = 108,
|
||||||
TEXTCOLOR_LIGHTGREY = 129,
|
TEXTCOLOR_LIGHTGREY = 129,
|
||||||
TEXTCOLOR_SKYBLUE = 143,
|
TEXTCOLOR_SKYBLUE = 143,
|
||||||
TEXTCOLOR_PURPLE = 154,
|
TEXTCOLOR_PURPLE = 155,
|
||||||
TEXTCOLOR_ELECTRICPURPLE = 155,
|
|
||||||
TEXTCOLOR_RED = 180,
|
TEXTCOLOR_RED = 180,
|
||||||
TEXTCOLOR_PASTELRED = 194,
|
|
||||||
TEXTCOLOR_ORANGE = 198,
|
TEXTCOLOR_ORANGE = 198,
|
||||||
TEXTCOLOR_YELLOW = 210,
|
TEXTCOLOR_YELLOW = 210,
|
||||||
TEXTCOLOR_WHITE_EXP = 215,
|
TEXTCOLOR_WHITE_EXP = 215,
|
||||||
@@ -353,13 +173,6 @@ enum Icons_t {
|
|||||||
ICON_HASTE = 1 << 6,
|
ICON_HASTE = 1 << 6,
|
||||||
ICON_SWORDS = 1 << 7,
|
ICON_SWORDS = 1 << 7,
|
||||||
ICON_DROWNING = 1 << 8,
|
ICON_DROWNING = 1 << 8,
|
||||||
ICON_FREEZING = 1 << 9,
|
|
||||||
ICON_DAZZLED = 1 << 10,
|
|
||||||
ICON_CURSED = 1 << 11,
|
|
||||||
ICON_PARTY_BUFF = 1 << 12,
|
|
||||||
ICON_REDSWORDS = 1 << 13,
|
|
||||||
ICON_PIGEON = 1 << 14,
|
|
||||||
ICON_BLEEDING = 1 << 15,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum WeaponType_t : uint8_t {
|
enum WeaponType_t : uint8_t {
|
||||||
@@ -392,7 +205,6 @@ enum WeaponAction_t : uint8_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum WieldInfo_t {
|
enum WieldInfo_t {
|
||||||
WIELDINFO_NONE = 0 << 0,
|
|
||||||
WIELDINFO_LEVEL = 1 << 0,
|
WIELDINFO_LEVEL = 1 << 0,
|
||||||
WIELDINFO_MAGLV = 1 << 1,
|
WIELDINFO_MAGLV = 1 << 1,
|
||||||
WIELDINFO_VOCREQ = 1 << 2,
|
WIELDINFO_VOCREQ = 1 << 2,
|
||||||
@@ -405,8 +217,6 @@ enum Skulls_t : uint8_t {
|
|||||||
SKULL_GREEN = 2,
|
SKULL_GREEN = 2,
|
||||||
SKULL_WHITE = 3,
|
SKULL_WHITE = 3,
|
||||||
SKULL_RED = 4,
|
SKULL_RED = 4,
|
||||||
SKULL_BLACK = 5,
|
|
||||||
SKULL_ORANGE = 6,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PartyShields_t : uint8_t {
|
enum PartyShields_t : uint8_t {
|
||||||
@@ -414,97 +224,54 @@ enum PartyShields_t : uint8_t {
|
|||||||
SHIELD_WHITEYELLOW = 1,
|
SHIELD_WHITEYELLOW = 1,
|
||||||
SHIELD_WHITEBLUE = 2,
|
SHIELD_WHITEBLUE = 2,
|
||||||
SHIELD_BLUE = 3,
|
SHIELD_BLUE = 3,
|
||||||
SHIELD_YELLOW = 4,
|
SHIELD_YELLOW = 4
|
||||||
SHIELD_BLUE_SHAREDEXP = 5,
|
|
||||||
SHIELD_YELLOW_SHAREDEXP = 6,
|
|
||||||
SHIELD_BLUE_NOSHAREDEXP_BLINK = 7,
|
|
||||||
SHIELD_YELLOW_NOSHAREDEXP_BLINK = 8,
|
|
||||||
SHIELD_BLUE_NOSHAREDEXP = 9,
|
|
||||||
SHIELD_YELLOW_NOSHAREDEXP = 10,
|
|
||||||
SHIELD_GRAY = 11,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum GuildEmblems_t : uint8_t {
|
|
||||||
GUILDEMBLEM_NONE = 0,
|
|
||||||
GUILDEMBLEM_ALLY = 1,
|
|
||||||
GUILDEMBLEM_ENEMY = 2,
|
|
||||||
GUILDEMBLEM_NEUTRAL = 3,
|
|
||||||
GUILDEMBLEM_MEMBER = 4,
|
|
||||||
GUILDEMBLEM_OTHER = 5,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum item_t : uint16_t {
|
enum item_t : uint16_t {
|
||||||
ITEM_BROWSEFIELD = 460, // for internal use
|
ITEM_FIREFIELD_PVP_FULL = 2118,
|
||||||
|
ITEM_FIREFIELD_PVP_MEDIUM = 2119,
|
||||||
|
ITEM_FIREFIELD_PVP_SMALL = 2120,
|
||||||
|
ITEM_FIREFIELD_PERSISTENT_FULL = 2123,
|
||||||
|
ITEM_FIREFIELD_PERSISTENT_MEDIUM = 2124,
|
||||||
|
ITEM_FIREFIELD_PERSISTENT_SMALL = 2125,
|
||||||
|
ITEM_FIREFIELD_NOPVP = 2131,
|
||||||
|
|
||||||
ITEM_FIREFIELD_PVP_FULL = 1487,
|
ITEM_POISONFIELD_PVP = 2121,
|
||||||
ITEM_FIREFIELD_PVP_MEDIUM = 1488,
|
ITEM_POISONFIELD_PERSISTENT = 2127,
|
||||||
ITEM_FIREFIELD_PVP_SMALL = 1489,
|
ITEM_POISONFIELD_NOPVP = 2134,
|
||||||
ITEM_FIREFIELD_PERSISTENT_FULL = 1492,
|
|
||||||
ITEM_FIREFIELD_PERSISTENT_MEDIUM = 1493,
|
|
||||||
ITEM_FIREFIELD_PERSISTENT_SMALL = 1494,
|
|
||||||
ITEM_FIREFIELD_NOPVP = 1500,
|
|
||||||
|
|
||||||
ITEM_POISONFIELD_PVP = 1490,
|
ITEM_ENERGYFIELD_PVP = 2122,
|
||||||
ITEM_POISONFIELD_PERSISTENT = 1496,
|
ITEM_ENERGYFIELD_PERSISTENT = 2126,
|
||||||
ITEM_POISONFIELD_NOPVP = 1503,
|
ITEM_ENERGYFIELD_NOPVP = 2135,
|
||||||
|
|
||||||
ITEM_ENERGYFIELD_PVP = 1491,
|
ITEM_MAGICWALL = 2128,
|
||||||
ITEM_ENERGYFIELD_PERSISTENT = 1495,
|
ITEM_MAGICWALL_PERSISTENT = 2128,
|
||||||
ITEM_ENERGYFIELD_NOPVP = 1504,
|
|
||||||
|
|
||||||
ITEM_MAGICWALL = 1497,
|
ITEM_WILDGROWTH = 2130,
|
||||||
ITEM_MAGICWALL_PERSISTENT = 1498,
|
ITEM_WILDGROWTH_PERSISTENT = 2130,
|
||||||
ITEM_MAGICWALL_SAFE = 11098,
|
|
||||||
|
|
||||||
ITEM_WILDGROWTH = 1499,
|
ITEM_GOLD_COIN = 3031,
|
||||||
ITEM_WILDGROWTH_PERSISTENT = 2721,
|
ITEM_PLATINUM_COIN = 3035,
|
||||||
ITEM_WILDGROWTH_SAFE = 11099,
|
ITEM_CRYSTAL_COIN = 3043,
|
||||||
|
|
||||||
ITEM_BAG = 1987,
|
ITEM_DEPOT = 3502,
|
||||||
ITEM_SHOPPING_BAG = 23782,
|
ITEM_LOCKER1 = 3497,
|
||||||
|
|
||||||
ITEM_GOLD_COIN = 2148,
|
ITEM_MALE_CORPSE = 4240,
|
||||||
ITEM_PLATINUM_COIN = 2152,
|
ITEM_FEMALE_CORPSE = 4247,
|
||||||
ITEM_CRYSTAL_COIN = 2160,
|
|
||||||
ITEM_STORE_COIN = 24774, // in-game store currency
|
|
||||||
|
|
||||||
ITEM_DEPOT = 2594,
|
ITEM_FULLSPLASH = 2886,
|
||||||
ITEM_LOCKER1 = 2589,
|
ITEM_SMALLSPLASH = 2889,
|
||||||
ITEM_INBOX = 14404,
|
|
||||||
ITEM_MARKET = 14405,
|
|
||||||
ITEM_STORE_INBOX = 26052,
|
|
||||||
ITEM_DEPOT_BOX_I = 25453,
|
|
||||||
ITEM_DEPOT_BOX_II = 25454,
|
|
||||||
ITEM_DEPOT_BOX_III = 25455,
|
|
||||||
ITEM_DEPOT_BOX_IV = 25456,
|
|
||||||
ITEM_DEPOT_BOX_V = 25457,
|
|
||||||
ITEM_DEPOT_BOX_VI = 25458,
|
|
||||||
ITEM_DEPOT_BOX_VII = 25459,
|
|
||||||
ITEM_DEPOT_BOX_VIII = 25460,
|
|
||||||
ITEM_DEPOT_BOX_IX = 25461,
|
|
||||||
ITEM_DEPOT_BOX_X = 25462,
|
|
||||||
ITEM_DEPOT_BOX_XI = 25463,
|
|
||||||
ITEM_DEPOT_BOX_XII = 25464,
|
|
||||||
ITEM_DEPOT_BOX_XIII = 25465,
|
|
||||||
ITEM_DEPOT_BOX_XIV = 25466,
|
|
||||||
ITEM_DEPOT_BOX_XV = 25467,
|
|
||||||
ITEM_DEPOT_BOX_XVI = 25468,
|
|
||||||
ITEM_DEPOT_BOX_XVII = 25469,
|
|
||||||
|
|
||||||
ITEM_MALE_CORPSE = 3058,
|
ITEM_PARCEL = 3503,
|
||||||
ITEM_FEMALE_CORPSE = 3065,
|
ITEM_PARCEL_STAMPED = 3504,
|
||||||
|
ITEM_LETTER = 3505,
|
||||||
|
ITEM_LETTER_STAMPED = 3506,
|
||||||
|
ITEM_LABEL = 3507,
|
||||||
|
|
||||||
ITEM_FULLSPLASH = 2016,
|
ITEM_AMULETOFLOSS = 3057,
|
||||||
ITEM_SMALLSPLASH = 2019,
|
|
||||||
|
|
||||||
ITEM_PARCEL = 2595,
|
ITEM_DOCUMENT_RO = 2819, //read-only
|
||||||
ITEM_LETTER = 2597,
|
|
||||||
ITEM_LETTER_STAMPED = 2598,
|
|
||||||
ITEM_LABEL = 2599,
|
|
||||||
|
|
||||||
ITEM_AMULETOFLOSS = 2173,
|
|
||||||
|
|
||||||
ITEM_DOCUMENT_RO = 1968, //read-only
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PlayerFlags : uint64_t {
|
enum PlayerFlags : uint64_t {
|
||||||
@@ -546,12 +313,14 @@ enum PlayerFlags : uint64_t {
|
|||||||
PlayerFlag_IgnoreWeaponCheck = static_cast<uint64_t>(1) << 35,
|
PlayerFlag_IgnoreWeaponCheck = static_cast<uint64_t>(1) << 35,
|
||||||
PlayerFlag_CannotBeMuted = static_cast<uint64_t>(1) << 36,
|
PlayerFlag_CannotBeMuted = static_cast<uint64_t>(1) << 36,
|
||||||
PlayerFlag_IsAlwaysPremium = static_cast<uint64_t>(1) << 37,
|
PlayerFlag_IsAlwaysPremium = static_cast<uint64_t>(1) << 37,
|
||||||
|
PlayerFlag_SpecialMoveUse = static_cast<uint64_t>(1) << 38,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ReloadTypes_t : uint8_t {
|
enum ReloadTypes_t : uint8_t {
|
||||||
RELOAD_TYPE_ALL,
|
RELOAD_TYPE_ALL,
|
||||||
RELOAD_TYPE_ACTIONS,
|
RELOAD_TYPE_ACTIONS,
|
||||||
RELOAD_TYPE_CHAT,
|
RELOAD_TYPE_CHAT,
|
||||||
|
RELOAD_TYPE_COMMANDS,
|
||||||
RELOAD_TYPE_CONFIG,
|
RELOAD_TYPE_CONFIG,
|
||||||
RELOAD_TYPE_CREATURESCRIPTS,
|
RELOAD_TYPE_CREATURESCRIPTS,
|
||||||
RELOAD_TYPE_EVENTS,
|
RELOAD_TYPE_EVENTS,
|
||||||
@@ -564,7 +333,6 @@ enum ReloadTypes_t : uint8_t {
|
|||||||
RELOAD_TYPE_NPCS,
|
RELOAD_TYPE_NPCS,
|
||||||
RELOAD_TYPE_QUESTS,
|
RELOAD_TYPE_QUESTS,
|
||||||
RELOAD_TYPE_RAIDS,
|
RELOAD_TYPE_RAIDS,
|
||||||
RELOAD_TYPE_SCRIPTS,
|
|
||||||
RELOAD_TYPE_SPELLS,
|
RELOAD_TYPE_SPELLS,
|
||||||
RELOAD_TYPE_TALKACTIONS,
|
RELOAD_TYPE_TALKACTIONS,
|
||||||
RELOAD_TYPE_WEAPONS,
|
RELOAD_TYPE_WEAPONS,
|
||||||
@@ -572,6 +340,7 @@ enum ReloadTypes_t : uint8_t {
|
|||||||
|
|
||||||
static constexpr int32_t CHANNEL_GUILD = 0x00;
|
static constexpr int32_t CHANNEL_GUILD = 0x00;
|
||||||
static constexpr int32_t CHANNEL_PARTY = 0x01;
|
static constexpr int32_t CHANNEL_PARTY = 0x01;
|
||||||
|
static constexpr int32_t CHANNEL_RULE_REP = 0x02;
|
||||||
static constexpr int32_t CHANNEL_PRIVATE = 0xFFFF;
|
static constexpr int32_t CHANNEL_PRIVATE = 0xFFFF;
|
||||||
|
|
||||||
//Reserved player storage key ranges;
|
//Reserved player storage key ranges;
|
||||||
@@ -581,11 +350,6 @@ static constexpr int32_t PSTRG_RESERVED_RANGE_SIZE = 10000000;
|
|||||||
//[1000 - 1500];
|
//[1000 - 1500];
|
||||||
static constexpr int32_t PSTRG_OUTFITS_RANGE_START = (PSTRG_RESERVED_RANGE_START + 1000);
|
static constexpr int32_t PSTRG_OUTFITS_RANGE_START = (PSTRG_RESERVED_RANGE_START + 1000);
|
||||||
static constexpr int32_t PSTRG_OUTFITS_RANGE_SIZE = 500;
|
static constexpr int32_t PSTRG_OUTFITS_RANGE_SIZE = 500;
|
||||||
//[2001 - 2011];
|
|
||||||
static constexpr int32_t PSTRG_MOUNTS_RANGE_START = (PSTRG_RESERVED_RANGE_START + 2001);
|
|
||||||
static constexpr int32_t PSTRG_MOUNTS_RANGE_SIZE = 10;
|
|
||||||
static constexpr int32_t PSTRG_MOUNTS_CURRENTMOUNT = (PSTRG_MOUNTS_RANGE_START + 10);
|
|
||||||
|
|
||||||
|
|
||||||
#define IS_IN_KEYRANGE(key, range) (key >= PSTRG_##range##_START && ((key - PSTRG_##range##_START) <= PSTRG_##range##_SIZE))
|
#define IS_IN_KEYRANGE(key, range) (key >= PSTRG_##range##_START && ((key - PSTRG_##range##_START) <= PSTRG_##range##_SIZE))
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,41 +28,16 @@ extern Game g_game;
|
|||||||
Container::Container(uint16_t type) :
|
Container::Container(uint16_t type) :
|
||||||
Container(type, items[type].maxItems) {}
|
Container(type, items[type].maxItems) {}
|
||||||
|
|
||||||
Container::Container(uint16_t type, uint16_t size, bool unlocked /*= true*/, bool pagination /*= false*/) :
|
Container::Container(uint16_t type, uint16_t size) :
|
||||||
Item(type),
|
Item(type),
|
||||||
maxSize(size),
|
maxSize(size)
|
||||||
unlocked(unlocked),
|
|
||||||
pagination(pagination)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Container::Container(Tile* tile) : Container(ITEM_BROWSEFIELD, 30, false, true)
|
|
||||||
{
|
|
||||||
TileItemVector* itemVector = tile->getItemList();
|
|
||||||
if (itemVector) {
|
|
||||||
for (Item* item : *itemVector) {
|
|
||||||
if ((item->getContainer() || item->hasProperty(CONST_PROP_MOVEABLE)) && !item->hasAttribute(ITEM_ATTRIBUTE_UNIQUEID)) {
|
|
||||||
itemlist.push_front(item);
|
|
||||||
item->setParent(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setParent(tile);
|
|
||||||
}
|
|
||||||
|
|
||||||
Container::~Container()
|
Container::~Container()
|
||||||
{
|
{
|
||||||
if (getID() == ITEM_BROWSEFIELD) {
|
for (Item* item : itemlist) {
|
||||||
g_game.browseFields.erase(getTile());
|
item->setParent(nullptr);
|
||||||
|
item->decrementReferenceCounter();
|
||||||
for (Item* item : itemlist) {
|
|
||||||
item->setParent(parent);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (Item* item : itemlist) {
|
|
||||||
item->setParent(nullptr);
|
|
||||||
item->decrementReferenceCounter();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +62,7 @@ Container* Container::getParentContainer()
|
|||||||
|
|
||||||
bool Container::hasParent() const
|
bool Container::hasParent() const
|
||||||
{
|
{
|
||||||
return getID() != ITEM_BROWSEFIELD && dynamic_cast<const Player*>(getParent()) == nullptr;
|
return dynamic_cast<const Container*>(getParent()) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::addItem(Item* item)
|
void Container::addItem(Item* item)
|
||||||
@@ -107,22 +82,24 @@ Attr_ReadValue Container::readAttr(AttrTypes_t attr, PropStream& propStream)
|
|||||||
return Item::readAttr(attr, propStream);
|
return Item::readAttr(attr, propStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Container::unserializeItemNode(OTB::Loader& loader, const OTB::Node& node, PropStream& propStream)
|
bool Container::unserializeItemNode(FileLoader& f, NODE node, PropStream& propStream)
|
||||||
{
|
{
|
||||||
bool ret = Item::unserializeItemNode(loader, node, propStream);
|
bool ret = Item::unserializeItemNode(f, node, propStream);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& itemNode : node.children) {
|
uint32_t type;
|
||||||
|
NODE nodeItem = f.getChildNode(node, type);
|
||||||
|
while (nodeItem) {
|
||||||
//load container items
|
//load container items
|
||||||
if (itemNode.type != OTBM_ITEM) {
|
if (type != OTBM_ITEM) {
|
||||||
// unknown type
|
// unknown type
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PropStream itemPropStream;
|
PropStream itemPropStream;
|
||||||
if (!loader.getProps(itemNode, itemPropStream)) {
|
if (!f.getProps(nodeItem, itemPropStream)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,12 +108,14 @@ bool Container::unserializeItemNode(OTB::Loader& loader, const OTB::Node& node,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!item->unserializeItemNode(loader, itemNode, itemPropStream)) {
|
if (!item->unserializeItemNode(f, nodeItem, itemPropStream)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
addItem(item);
|
addItem(item);
|
||||||
updateItemWeight(item->getWeight());
|
updateItemWeight(item->getWeight());
|
||||||
|
|
||||||
|
nodeItem = f.getNextNode(nodeItem, type);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -215,48 +194,48 @@ bool Container::isHoldingItem(const Item* item) const
|
|||||||
|
|
||||||
void Container::onAddContainerItem(Item* item)
|
void Container::onAddContainerItem(Item* item)
|
||||||
{
|
{
|
||||||
SpectatorVec spectators;
|
SpectatorVec list;
|
||||||
g_game.map.getSpectators(spectators, getPosition(), false, true, 2, 2, 2, 2);
|
g_game.map.getSpectators(list, getPosition(), false, true, 2, 2, 2, 2);
|
||||||
|
|
||||||
//send to client
|
//send to client
|
||||||
for (Creature* spectator : spectators) {
|
for (Creature* spectator : list) {
|
||||||
spectator->getPlayer()->sendAddContainerItem(this, item);
|
spectator->getPlayer()->sendAddContainerItem(this, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
//event methods
|
//event methods
|
||||||
for (Creature* spectator : spectators) {
|
for (Creature* spectator : list) {
|
||||||
spectator->getPlayer()->onAddContainerItem(item);
|
spectator->getPlayer()->onAddContainerItem(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::onUpdateContainerItem(uint32_t index, Item* oldItem, Item* newItem)
|
void Container::onUpdateContainerItem(uint32_t index, Item* oldItem, Item* newItem)
|
||||||
{
|
{
|
||||||
SpectatorVec spectators;
|
SpectatorVec list;
|
||||||
g_game.map.getSpectators(spectators, getPosition(), false, true, 2, 2, 2, 2);
|
g_game.map.getSpectators(list, getPosition(), false, true, 2, 2, 2, 2);
|
||||||
|
|
||||||
//send to client
|
//send to client
|
||||||
for (Creature* spectator : spectators) {
|
for (Creature* spectator : list) {
|
||||||
spectator->getPlayer()->sendUpdateContainerItem(this, index, newItem);
|
spectator->getPlayer()->sendUpdateContainerItem(this, index, newItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
//event methods
|
//event methods
|
||||||
for (Creature* spectator : spectators) {
|
for (Creature* spectator : list) {
|
||||||
spectator->getPlayer()->onUpdateContainerItem(this, oldItem, newItem);
|
spectator->getPlayer()->onUpdateContainerItem(this, oldItem, newItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Container::onRemoveContainerItem(uint32_t index, Item* item)
|
void Container::onRemoveContainerItem(uint32_t index, Item* item)
|
||||||
{
|
{
|
||||||
SpectatorVec spectators;
|
SpectatorVec list;
|
||||||
g_game.map.getSpectators(spectators, getPosition(), false, true, 2, 2, 2, 2);
|
g_game.map.getSpectators(list, getPosition(), false, true, 2, 2, 2, 2);
|
||||||
|
|
||||||
//send change to client
|
//send change to client
|
||||||
for (Creature* spectator : spectators) {
|
for (Creature* spectator : list) {
|
||||||
spectator->getPlayer()->sendRemoveContainerItem(this, index);
|
spectator->getPlayer()->sendRemoveContainerItem(this, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
//event methods
|
//event methods
|
||||||
for (Creature* spectator : spectators) {
|
for (Creature* spectator : list) {
|
||||||
spectator->getPlayer()->onRemoveContainerItem(this, item);
|
spectator->getPlayer()->onRemoveContainerItem(this, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,10 +250,6 @@ ReturnValue Container::queryAdd(int32_t index, const Thing& thing, uint32_t coun
|
|||||||
return RETURNVALUE_NOERROR;
|
return RETURNVALUE_NOERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!unlocked) {
|
|
||||||
return RETURNVALUE_NOTPOSSIBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Item* item = thing.getItem();
|
const Item* item = thing.getItem();
|
||||||
if (item == nullptr) {
|
if (item == nullptr) {
|
||||||
return RETURNVALUE_NOTPOSSIBLE;
|
return RETURNVALUE_NOTPOSSIBLE;
|
||||||
@@ -295,10 +270,6 @@ ReturnValue Container::queryAdd(int32_t index, const Thing& thing, uint32_t coun
|
|||||||
return RETURNVALUE_THISISIMPOSSIBLE;
|
return RETURNVALUE_THISISIMPOSSIBLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dynamic_cast<const Inbox*>(cylinder)) {
|
|
||||||
return RETURNVALUE_CONTAINERNOTENOUGHROOM;
|
|
||||||
}
|
|
||||||
|
|
||||||
cylinder = cylinder->getParent();
|
cylinder = cylinder->getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +326,7 @@ ReturnValue Container::queryMaxCount(int32_t index, const Thing& thing, uint32_t
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const Item* destItem = getItemByIndex(index);
|
const Item* destItem = getItemByIndex(index);
|
||||||
if (item->equals(destItem) && destItem->getItemCount() < 100) {
|
if (item->equals(destItem) && !destItem->isRune() && destItem->getItemCount() < 100) {
|
||||||
uint32_t remainder = 100 - destItem->getItemCount();
|
uint32_t remainder = 100 - destItem->getItemCount();
|
||||||
if (queryAdd(index, *item, remainder, flags) == RETURNVALUE_NOERROR) {
|
if (queryAdd(index, *item, remainder, flags) == RETURNVALUE_NOERROR) {
|
||||||
n = remainder;
|
n = remainder;
|
||||||
@@ -398,14 +369,9 @@ ReturnValue Container::queryRemove(const Thing& thing, uint32_t count, uint32_t
|
|||||||
return RETURNVALUE_NOERROR;
|
return RETURNVALUE_NOERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
Cylinder* Container::queryDestination(int32_t& index, const Thing& thing, Item** destItem,
|
Cylinder* Container::queryDestination(int32_t& index, const Thing &thing, Item** destItem,
|
||||||
uint32_t& flags)
|
uint32_t& flags)
|
||||||
{
|
{
|
||||||
if (!unlocked) {
|
|
||||||
*destItem = nullptr;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index == 254 /*move up*/) {
|
if (index == 254 /*move up*/) {
|
||||||
index = INDEX_WHEREEVER;
|
index = INDEX_WHEREEVER;
|
||||||
*destItem = nullptr;
|
*destItem = nullptr;
|
||||||
@@ -420,7 +386,8 @@ Cylinder* Container::queryDestination(int32_t& index, const Thing& thing, Item**
|
|||||||
if (index == 255 /*add wherever*/) {
|
if (index == 255 /*add wherever*/) {
|
||||||
index = INDEX_WHEREEVER;
|
index = INDEX_WHEREEVER;
|
||||||
*destItem = nullptr;
|
*destItem = nullptr;
|
||||||
} else if (index >= static_cast<int32_t>(capacity())) {
|
}
|
||||||
|
else if (index >= static_cast<int32_t>(capacity())) {
|
||||||
/*
|
/*
|
||||||
if you have a container, maximize it to show all 20 slots
|
if you have a container, maximize it to show all 20 slots
|
||||||
then you open a bag that is inside the container you will have a bag with 8 slots
|
then you open a bag that is inside the container you will have a bag with 8 slots
|
||||||
@@ -451,19 +418,22 @@ Cylinder* Container::queryDestination(int32_t& index, const Thing& thing, Item**
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool autoStack = !hasBitSet(FLAG_IGNOREAUTOSTACK, flags);
|
if (g_config.getBoolean(ConfigManager::STACK_CUMULATIVES)) {
|
||||||
if (autoStack && item->isStackable() && item->getParent() != this) {
|
bool autoStack = !hasBitSet(FLAG_IGNOREAUTOSTACK, flags);
|
||||||
//try find a suitable item to stack with
|
if (autoStack && item->isStackable() && item->getParent() != this) {
|
||||||
uint32_t n = 0;
|
//try find a suitable item to stack with
|
||||||
for (Item* listItem : itemlist) {
|
uint32_t n = 0;
|
||||||
if (listItem != item && listItem->equals(item) && listItem->getItemCount() < 100) {
|
for (Item* listItem : itemlist) {
|
||||||
*destItem = listItem;
|
if (listItem != item && listItem->equals(item) && listItem->getItemCount() < 100) {
|
||||||
index = n;
|
*destItem = listItem;
|
||||||
return this;
|
index = n;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
++n;
|
||||||
}
|
}
|
||||||
++n;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,7 +26,6 @@
|
|||||||
#include "item.h"
|
#include "item.h"
|
||||||
|
|
||||||
class Container;
|
class Container;
|
||||||
class DepotChest;
|
|
||||||
class DepotLocker;
|
class DepotLocker;
|
||||||
|
|
||||||
class ContainerIterator
|
class ContainerIterator
|
||||||
@@ -39,7 +38,7 @@ class ContainerIterator
|
|||||||
void advance();
|
void advance();
|
||||||
Item* operator*();
|
Item* operator*();
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
std::list<const Container*> over;
|
std::list<const Container*> over;
|
||||||
ItemDeque::const_iterator cur;
|
ItemDeque::const_iterator cur;
|
||||||
|
|
||||||
@@ -50,32 +49,31 @@ class Container : public Item, public Cylinder
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Container(uint16_t type);
|
explicit Container(uint16_t type);
|
||||||
Container(uint16_t type, uint16_t size, bool unlocked = true, bool pagination = false);
|
Container(uint16_t type, uint16_t size);
|
||||||
explicit Container(Tile* tile);
|
|
||||||
~Container();
|
~Container();
|
||||||
|
|
||||||
// non-copyable
|
// non-copyable
|
||||||
Container(const Container&) = delete;
|
Container(const Container&) = delete;
|
||||||
Container& operator=(const Container&) = delete;
|
Container& operator=(const Container&) = delete;
|
||||||
|
|
||||||
Item* clone() const override final;
|
Item* clone() const final;
|
||||||
|
|
||||||
Container* getContainer() override final {
|
Container* getContainer() final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
const Container* getContainer() const override final {
|
const Container* getContainer() const final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual DepotLocker* getDepotLocker() {
|
virtual DepotLocker* getDepotLocker() override {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
virtual const DepotLocker* getDepotLocker() const {
|
virtual const DepotLocker* getDepotLocker() const override {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream) override;
|
Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream) override;
|
||||||
bool unserializeItemNode(OTB::Loader& loader, const OTB::Node& node, PropStream& propStream) override;
|
bool unserializeItemNode(FileLoader& f, NODE node, PropStream& propStream) override;
|
||||||
std::string getContentDescription() const;
|
std::string getContentDescription() const;
|
||||||
|
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
@@ -107,60 +105,41 @@ class Container : public Item, public Cylinder
|
|||||||
bool isHoldingItem(const Item* item) const;
|
bool isHoldingItem(const Item* item) const;
|
||||||
|
|
||||||
uint32_t getItemHoldingCount() const;
|
uint32_t getItemHoldingCount() const;
|
||||||
uint32_t getWeight() const override final;
|
uint32_t getWeight() const final;
|
||||||
|
|
||||||
bool isUnlocked() const {
|
|
||||||
return unlocked;
|
|
||||||
}
|
|
||||||
bool hasPagination() const {
|
|
||||||
return pagination;
|
|
||||||
}
|
|
||||||
|
|
||||||
//cylinder implementations
|
//cylinder implementations
|
||||||
virtual ReturnValue queryAdd(int32_t index, const Thing& thing, uint32_t count,
|
virtual ReturnValue queryAdd(int32_t index, const Thing& thing, uint32_t count,
|
||||||
uint32_t flags, Creature* actor = nullptr) const override;
|
uint32_t flags, Creature* actor = nullptr) const override;
|
||||||
ReturnValue queryMaxCount(int32_t index, const Thing& thing, uint32_t count, uint32_t& maxQueryCount,
|
ReturnValue queryMaxCount(int32_t index, const Thing& thing, uint32_t count, uint32_t& maxQueryCount,
|
||||||
uint32_t flags) const override final;
|
uint32_t flags) const final;
|
||||||
ReturnValue queryRemove(const Thing& thing, uint32_t count, uint32_t flags) const override final;
|
ReturnValue queryRemove(const Thing& thing, uint32_t count, uint32_t flags) const final;
|
||||||
Cylinder* queryDestination(int32_t& index, const Thing& thing, Item** destItem,
|
Cylinder* queryDestination(int32_t& index, const Thing& thing, Item** destItem,
|
||||||
uint32_t& flags) override final;
|
uint32_t& flags) final;
|
||||||
|
|
||||||
void addThing(Thing* thing) override final;
|
void addThing(Thing* thing) final;
|
||||||
void addThing(int32_t index, Thing* thing) override final;
|
void addThing(int32_t index, Thing* thing) final;
|
||||||
void addItemBack(Item* item);
|
void addItemBack(Item* item);
|
||||||
|
|
||||||
void updateThing(Thing* thing, uint16_t itemId, uint32_t count) override final;
|
void updateThing(Thing* thing, uint16_t itemId, uint32_t count) final;
|
||||||
void replaceThing(uint32_t index, Thing* thing) override final;
|
void replaceThing(uint32_t index, Thing* thing) final;
|
||||||
|
|
||||||
void removeThing(Thing* thing, uint32_t count) override final;
|
void removeThing(Thing* thing, uint32_t count) final;
|
||||||
|
|
||||||
int32_t getThingIndex(const Thing* thing) const override final;
|
int32_t getThingIndex(const Thing* thing) const final;
|
||||||
size_t getFirstIndex() const override final;
|
size_t getFirstIndex() const final;
|
||||||
size_t getLastIndex() const override final;
|
size_t getLastIndex() const final;
|
||||||
uint32_t getItemTypeCount(uint16_t itemId, int32_t subType = -1) const override final;
|
uint32_t getItemTypeCount(uint16_t itemId, int32_t subType = -1) const final;
|
||||||
std::map<uint32_t, uint32_t>& getAllItemTypeCount(std::map<uint32_t, uint32_t>& countMap) const override final;
|
std::map<uint32_t, uint32_t>& getAllItemTypeCount(std::map<uint32_t, uint32_t>& countMap) const final;
|
||||||
Thing* getThing(size_t index) const override final;
|
Thing* getThing(size_t index) const final;
|
||||||
|
|
||||||
void postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
|
void postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
|
||||||
void postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
|
void postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
|
||||||
|
|
||||||
void internalAddThing(Thing* thing) override final;
|
void internalAddThing(Thing* thing) final;
|
||||||
void internalAddThing(uint32_t index, Thing* thing) override final;
|
void internalAddThing(uint32_t index, Thing* thing) final;
|
||||||
void startDecaying() override final;
|
void startDecaying() final;
|
||||||
|
|
||||||
protected:
|
|
||||||
ItemDeque itemlist;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::ostringstream& getContentDescription(std::ostringstream& os) const;
|
|
||||||
|
|
||||||
uint32_t maxSize;
|
|
||||||
uint32_t totalWeight = 0;
|
|
||||||
uint32_t serializationCount = 0;
|
|
||||||
|
|
||||||
bool unlocked;
|
|
||||||
bool pagination;
|
|
||||||
|
|
||||||
void onAddContainerItem(Item* item);
|
void onAddContainerItem(Item* item);
|
||||||
void onUpdateContainerItem(uint32_t index, Item* oldItem, Item* newItem);
|
void onUpdateContainerItem(uint32_t index, Item* oldItem, Item* newItem);
|
||||||
void onRemoveContainerItem(uint32_t index, Item* item);
|
void onRemoveContainerItem(uint32_t index, Item* item);
|
||||||
@@ -168,6 +147,14 @@ class Container : public Item, public Cylinder
|
|||||||
Container* getParentContainer();
|
Container* getParentContainer();
|
||||||
void updateItemWeight(int32_t diff);
|
void updateItemWeight(int32_t diff);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::ostringstream& getContentDescription(std::ostringstream& os) const;
|
||||||
|
|
||||||
|
uint32_t maxSize;
|
||||||
|
uint32_t totalWeight = 0;
|
||||||
|
ItemDeque itemlist;
|
||||||
|
uint32_t serializationCount = 0;
|
||||||
|
|
||||||
friend class ContainerIterator;
|
friend class ContainerIterator;
|
||||||
friend class IOMapSerialize;
|
friend class IOMapSerialize;
|
||||||
};
|
};
|
||||||
|
|||||||
283
src/creature.cpp
283
src/creature.cpp
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -25,10 +25,6 @@
|
|||||||
#include "configmanager.h"
|
#include "configmanager.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
|
|
||||||
double Creature::speedA = 857.36;
|
|
||||||
double Creature::speedB = 261.29;
|
|
||||||
double Creature::speedC = -4795.01;
|
|
||||||
|
|
||||||
extern Game g_game;
|
extern Game g_game;
|
||||||
extern ConfigManager g_config;
|
extern ConfigManager g_config;
|
||||||
extern CreatureEvents* g_creatureEvents;
|
extern CreatureEvents* g_creatureEvents;
|
||||||
@@ -42,7 +38,8 @@ Creature::~Creature()
|
|||||||
{
|
{
|
||||||
for (Creature* summon : summons) {
|
for (Creature* summon : summons) {
|
||||||
summon->setAttackedCreature(nullptr);
|
summon->setAttackedCreature(nullptr);
|
||||||
summon->removeMaster();
|
summon->setMaster(nullptr);
|
||||||
|
summon->decrementReferenceCounter();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Condition* condition : conditions) {
|
for (Condition* condition : conditions) {
|
||||||
@@ -230,7 +227,7 @@ void Creature::onWalk(Direction& dir)
|
|||||||
if (r < DIRECTION_DIAGONAL_MASK) {
|
if (r < DIRECTION_DIAGONAL_MASK) {
|
||||||
dir = static_cast<Direction>(r);
|
dir = static_cast<Direction>(r);
|
||||||
}
|
}
|
||||||
g_game.internalCreatureSay(this, TALKTYPE_MONSTER_SAY, "Hicks!", false);
|
g_game.internalCreatureSay(this, TALKTYPE_SAY, "Hicks!", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,7 +307,7 @@ void Creature::updateMapCache()
|
|||||||
void Creature::updateTileCache(const Tile* tile, int32_t dx, int32_t dy)
|
void Creature::updateTileCache(const Tile* tile, int32_t dx, int32_t dy)
|
||||||
{
|
{
|
||||||
if (std::abs(dx) <= maxWalkCacheWidth && std::abs(dy) <= maxWalkCacheHeight) {
|
if (std::abs(dx) <= maxWalkCacheWidth && std::abs(dy) <= maxWalkCacheHeight) {
|
||||||
localMapCache[maxWalkCacheHeight + dy][maxWalkCacheWidth + dx] = tile && tile->queryAdd(0, *this, 1, FLAG_PATHFINDING | FLAG_IGNOREFIELDDAMAGE) == RETURNVALUE_NOERROR;
|
localMapCache[maxWalkCacheHeight + dy][maxWalkCacheWidth + dx] = tile && tile->queryAdd(0, *this, 1, FLAG_PATHFINDING) == RETURNVALUE_NOERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +409,7 @@ void Creature::onRemoveCreature(Creature* creature, bool)
|
|||||||
onCreatureDisappear(creature, true);
|
onCreatureDisappear(creature, true);
|
||||||
if (creature == this) {
|
if (creature == this) {
|
||||||
if (master && !master->isRemoved()) {
|
if (master && !master->isRemoved()) {
|
||||||
setMaster(nullptr);
|
master->removeSummon(this);
|
||||||
}
|
}
|
||||||
} else if (isMapLoaded) {
|
} else if (isMapLoaded) {
|
||||||
if (creature->getPosition().z == getPosition().z) {
|
if (creature->getPosition().z == getPosition().z) {
|
||||||
@@ -585,6 +582,11 @@ void Creature::onCreatureMove(Creature* creature, const Tile* newTile, const Pos
|
|||||||
if (creature == followCreature || (creature == this && followCreature)) {
|
if (creature == followCreature || (creature == this && followCreature)) {
|
||||||
if (hasFollowPath) {
|
if (hasFollowPath) {
|
||||||
isUpdatingPath = true;
|
isUpdatingPath = true;
|
||||||
|
// this updates following walking
|
||||||
|
if (lastWalkUpdate == 0 || OTSYS_TIME() - lastWalkUpdate >= 250) {
|
||||||
|
g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
|
||||||
|
lastWalkUpdate = OTSYS_TIME();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newPos.z != oldPos.z || !canSee(followCreature->getPosition())) {
|
if (newPos.z != oldPos.z || !canSee(followCreature->getPosition())) {
|
||||||
@@ -617,7 +619,8 @@ void Creature::onDeath()
|
|||||||
if (lastHitCreature) {
|
if (lastHitCreature) {
|
||||||
lastHitUnjustified = lastHitCreature->onKilledCreature(this);
|
lastHitUnjustified = lastHitCreature->onKilledCreature(this);
|
||||||
lastHitCreatureMaster = lastHitCreature->getMaster();
|
lastHitCreatureMaster = lastHitCreature->getMaster();
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
lastHitCreatureMaster = nullptr;
|
lastHitCreatureMaster = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,7 +642,6 @@ void Creature::onDeath()
|
|||||||
uint64_t gainExp = getGainedExperience(attacker);
|
uint64_t gainExp = getGainedExperience(attacker);
|
||||||
if (Player* attackerPlayer = attacker->getPlayer()) {
|
if (Player* attackerPlayer = attacker->getPlayer()) {
|
||||||
attackerPlayer->removeAttacked(getPlayer());
|
attackerPlayer->removeAttacked(getPlayer());
|
||||||
|
|
||||||
Party* party = attackerPlayer->getParty();
|
Party* party = attackerPlayer->getParty();
|
||||||
if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) {
|
if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) {
|
||||||
attacker = party->getLeader();
|
attacker = party->getLeader();
|
||||||
@@ -649,7 +651,8 @@ void Creature::onDeath()
|
|||||||
auto tmpIt = experienceMap.find(attacker);
|
auto tmpIt = experienceMap.find(attacker);
|
||||||
if (tmpIt == experienceMap.end()) {
|
if (tmpIt == experienceMap.end()) {
|
||||||
experienceMap[attacker] = gainExp;
|
experienceMap[attacker] = gainExp;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
tmpIt->second += gainExp;
|
tmpIt->second += gainExp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -673,7 +676,7 @@ void Creature::onDeath()
|
|||||||
death(lastHitCreature);
|
death(lastHitCreature);
|
||||||
|
|
||||||
if (master) {
|
if (master) {
|
||||||
setMaster(nullptr);
|
master->removeSummon(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (droppedCorpse) {
|
if (droppedCorpse) {
|
||||||
@@ -683,53 +686,41 @@ void Creature::onDeath()
|
|||||||
|
|
||||||
bool Creature::dropCorpse(Creature* lastHitCreature, Creature* mostDamageCreature, bool lastHitUnjustified, bool mostDamageUnjustified)
|
bool Creature::dropCorpse(Creature* lastHitCreature, Creature* mostDamageCreature, bool lastHitUnjustified, bool mostDamageUnjustified)
|
||||||
{
|
{
|
||||||
if (!lootDrop && getMonster()) {
|
Item* splash;
|
||||||
if (master) {
|
switch (getRace()) {
|
||||||
//scripting event - onDeath
|
case RACE_VENOM:
|
||||||
const CreatureEventList& deathEvents = getCreatureEvents(CREATURE_EVENT_DEATH);
|
splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_SLIME);
|
||||||
for (CreatureEvent* deathEvent : deathEvents) {
|
break;
|
||||||
deathEvent->executeOnDeath(this, nullptr, lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
g_game.addMagicEffect(getPosition(), CONST_ME_POFF);
|
case RACE_BLOOD:
|
||||||
} else {
|
splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_BLOOD);
|
||||||
Item* splash;
|
break;
|
||||||
switch (getRace()) {
|
|
||||||
case RACE_VENOM:
|
|
||||||
splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_SLIME);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RACE_BLOOD:
|
default:
|
||||||
splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_BLOOD);
|
splash = nullptr;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
Tile* tile = getTile();
|
||||||
splash = nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Tile* tile = getTile();
|
if (splash) {
|
||||||
|
g_game.internalAddItem(tile, splash, INDEX_WHEREEVER, FLAG_NOLIMIT);
|
||||||
|
g_game.startDecay(splash);
|
||||||
|
}
|
||||||
|
|
||||||
if (splash) {
|
Item* corpse = getCorpse(lastHitCreature, mostDamageCreature);
|
||||||
g_game.internalAddItem(tile, splash, INDEX_WHEREEVER, FLAG_NOLIMIT);
|
if (corpse) {
|
||||||
g_game.startDecay(splash);
|
g_game.internalAddItem(tile, corpse, INDEX_WHEREEVER, FLAG_NOLIMIT);
|
||||||
}
|
g_game.startDecay(corpse);
|
||||||
|
}
|
||||||
|
|
||||||
Item* corpse = getCorpse(lastHitCreature, mostDamageCreature);
|
//scripting event - onDeath
|
||||||
if (corpse) {
|
for (CreatureEvent* deathEvent : getCreatureEvents(CREATURE_EVENT_DEATH)) {
|
||||||
g_game.internalAddItem(tile, corpse, INDEX_WHEREEVER, FLAG_NOLIMIT);
|
deathEvent->executeOnDeath(this, corpse, lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified);
|
||||||
g_game.startDecay(corpse);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//scripting event - onDeath
|
if (corpse) {
|
||||||
for (CreatureEvent* deathEvent : getCreatureEvents(CREATURE_EVENT_DEATH)) {
|
dropLoot(corpse->getContainer(), lastHitCreature);
|
||||||
deathEvent->executeOnDeath(this, corpse, lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (corpse) {
|
|
||||||
dropLoot(corpse->getContainer(), lastHitCreature);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -790,6 +781,28 @@ BlockType_t Creature::blockHit(Creature* attacker, CombatType_t combatType, int3
|
|||||||
damage = 0;
|
damage = 0;
|
||||||
blockType = BLOCK_IMMUNITY;
|
blockType = BLOCK_IMMUNITY;
|
||||||
} else if (checkDefense || checkArmor) {
|
} else if (checkDefense || checkArmor) {
|
||||||
|
if (checkDefense && OTSYS_TIME() >= earliestDefendTime) {
|
||||||
|
damage -= getDefense();
|
||||||
|
|
||||||
|
earliestDefendTime = lastDefendTime + 2000;
|
||||||
|
lastDefendTime = OTSYS_TIME();
|
||||||
|
|
||||||
|
if (damage <= 0) {
|
||||||
|
damage = 0;
|
||||||
|
blockType = BLOCK_DEFENSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkArmor) {
|
||||||
|
if (damage > 0 && combatType == COMBAT_PHYSICALDAMAGE) {
|
||||||
|
damage -= getArmor();
|
||||||
|
if (damage <= 0) {
|
||||||
|
damage = 0;
|
||||||
|
blockType = BLOCK_ARMOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool hasDefense = false;
|
bool hasDefense = false;
|
||||||
|
|
||||||
if (blockCount > 0) {
|
if (blockCount > 0) {
|
||||||
@@ -797,30 +810,6 @@ BlockType_t Creature::blockHit(Creature* attacker, CombatType_t combatType, int3
|
|||||||
hasDefense = true;
|
hasDefense = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkDefense && hasDefense && canUseDefense) {
|
|
||||||
int32_t defense = getDefense();
|
|
||||||
damage -= uniform_random(defense / 2, defense);
|
|
||||||
if (damage <= 0) {
|
|
||||||
damage = 0;
|
|
||||||
blockType = BLOCK_DEFENSE;
|
|
||||||
checkArmor = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkArmor) {
|
|
||||||
int32_t armor = getArmor();
|
|
||||||
if (armor > 3) {
|
|
||||||
damage -= uniform_random(armor / 2, armor - (armor % 2 + 1));
|
|
||||||
} else if (armor > 0) {
|
|
||||||
--damage;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (damage <= 0) {
|
|
||||||
damage = 0;
|
|
||||||
blockType = BLOCK_ARMOR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasDefense && blockType != BLOCK_NONE) {
|
if (hasDefense && blockType != BLOCK_NONE) {
|
||||||
onBlockHit();
|
onBlockHit();
|
||||||
}
|
}
|
||||||
@@ -844,6 +833,16 @@ bool Creature::setAttackedCreature(Creature* creature)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isSummon() && master) {
|
||||||
|
if (Monster* monster = master->getMonster()) {
|
||||||
|
if (monster->mType->info.targetDistance <= 1) {
|
||||||
|
if (!monster->hasFollowPath && !monster->followCreature) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
attackedCreature = creature;
|
attackedCreature = creature;
|
||||||
onAttackedCreature(attackedCreature);
|
onAttackedCreature(attackedCreature);
|
||||||
attackedCreature->onAttacked();
|
attackedCreature->onAttacked();
|
||||||
@@ -1027,21 +1026,9 @@ void Creature::onTickCondition(ConditionType_t type, bool& bRemove)
|
|||||||
case CONDITION_POISON:
|
case CONDITION_POISON:
|
||||||
bRemove = (field->getCombatType() != COMBAT_EARTHDAMAGE);
|
bRemove = (field->getCombatType() != COMBAT_EARTHDAMAGE);
|
||||||
break;
|
break;
|
||||||
case CONDITION_FREEZING:
|
|
||||||
bRemove = (field->getCombatType() != COMBAT_ICEDAMAGE);
|
|
||||||
break;
|
|
||||||
case CONDITION_DAZZLED:
|
|
||||||
bRemove = (field->getCombatType() != COMBAT_HOLYDAMAGE);
|
|
||||||
break;
|
|
||||||
case CONDITION_CURSED:
|
|
||||||
bRemove = (field->getCombatType() != COMBAT_DEATHDAMAGE);
|
|
||||||
break;
|
|
||||||
case CONDITION_DROWN:
|
case CONDITION_DROWN:
|
||||||
bRemove = (field->getCombatType() != COMBAT_DROWNDAMAGE);
|
bRemove = (field->getCombatType() != COMBAT_DROWNDAMAGE);
|
||||||
break;
|
break;
|
||||||
case CONDITION_BLEEDING:
|
|
||||||
bRemove = (field->getCombatType() != COMBAT_PHYSICALDAMAGE);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1064,8 +1051,15 @@ void Creature::onAttackedCreatureDrainHealth(Creature* target, int32_t points)
|
|||||||
|
|
||||||
bool Creature::onKilledCreature(Creature* target, bool)
|
bool Creature::onKilledCreature(Creature* target, bool)
|
||||||
{
|
{
|
||||||
|
if (latestKillEvent == target->getID()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
latestKillEvent = target->getID();
|
||||||
|
|
||||||
if (master) {
|
if (master) {
|
||||||
master->onKilledCreature(target);
|
master->onKilledCreature(target);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//scripting event - onKill
|
//scripting event - onKill
|
||||||
@@ -1085,43 +1079,28 @@ void Creature::onGainExperience(uint64_t gainExp, Creature* target)
|
|||||||
gainExp /= 2;
|
gainExp /= 2;
|
||||||
master->onGainExperience(gainExp, target);
|
master->onGainExperience(gainExp, target);
|
||||||
|
|
||||||
SpectatorVec spectators;
|
g_game.addAnimatedText(position, TEXTCOLOR_WHITE_EXP, std::to_string(gainExp));
|
||||||
g_game.map.getSpectators(spectators, position, false, true);
|
|
||||||
if (spectators.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextMessage message(MESSAGE_EXPERIENCE_OTHERS, ucfirst(getNameDescription()) + " gained " + std::to_string(gainExp) + (gainExp != 1 ? " experience points." : " experience point."));
|
|
||||||
message.position = position;
|
|
||||||
message.primary.color = TEXTCOLOR_WHITE_EXP;
|
|
||||||
message.primary.value = gainExp;
|
|
||||||
|
|
||||||
for (Creature* spectator : spectators) {
|
|
||||||
spectator->getPlayer()->sendTextMessage(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Creature::setMaster(Creature* newMaster) {
|
void Creature::addSummon(Creature* creature)
|
||||||
if (!newMaster && !master) {
|
{
|
||||||
return false;
|
creature->setDropLoot(false);
|
||||||
}
|
creature->setLossSkill(false);
|
||||||
|
creature->setMaster(this);
|
||||||
|
creature->incrementReferenceCounter();
|
||||||
|
summons.push_back(creature);
|
||||||
|
}
|
||||||
|
|
||||||
if (newMaster) {
|
void Creature::removeSummon(Creature* creature)
|
||||||
incrementReferenceCounter();
|
{
|
||||||
newMaster->summons.push_back(this);
|
auto cit = std::find(summons.begin(), summons.end(), creature);
|
||||||
|
if (cit != summons.end()) {
|
||||||
|
creature->setDropLoot(true);
|
||||||
|
creature->setLossSkill(true);
|
||||||
|
creature->setMaster(nullptr);
|
||||||
|
creature->decrementReferenceCounter();
|
||||||
|
summons.erase(cit);
|
||||||
}
|
}
|
||||||
|
|
||||||
Creature* oldMaster = master;
|
|
||||||
master = newMaster;
|
|
||||||
|
|
||||||
if (oldMaster) {
|
|
||||||
auto summon = std::find(oldMaster->summons.begin(), oldMaster->summons.end(), this);
|
|
||||||
if (summon != oldMaster->summons.end()) {
|
|
||||||
oldMaster->summons.erase(summon);
|
|
||||||
decrementReferenceCounter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Creature::addCondition(Condition* condition, bool force/* = false*/)
|
bool Creature::addCondition(Condition* condition, bool force/* = false*/)
|
||||||
@@ -1280,21 +1259,20 @@ Condition* Creature::getCondition(ConditionType_t type, ConditionId_t conditionI
|
|||||||
|
|
||||||
void Creature::executeConditions(uint32_t interval)
|
void Creature::executeConditions(uint32_t interval)
|
||||||
{
|
{
|
||||||
ConditionList tempConditions{ conditions };
|
auto it = conditions.begin(), end = conditions.end();
|
||||||
for (Condition* condition : tempConditions) {
|
while (it != end) {
|
||||||
auto it = std::find(conditions.begin(), conditions.end(), condition);
|
Condition* condition = *it;
|
||||||
if (it == conditions.end()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!condition->executeCondition(this, interval)) {
|
if (!condition->executeCondition(this, interval)) {
|
||||||
it = std::find(conditions.begin(), conditions.end(), condition);
|
ConditionType_t type = condition->getType();
|
||||||
if (it != conditions.end()) {
|
|
||||||
conditions.erase(it);
|
it = conditions.erase(it);
|
||||||
condition->endCondition(this);
|
|
||||||
onEndCondition(condition->getType());
|
condition->endCondition(this);
|
||||||
delete condition;
|
delete condition;
|
||||||
}
|
|
||||||
|
onEndCondition(type);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1311,7 +1289,7 @@ bool Creature::hasCondition(ConditionType_t type, uint32_t subId/* = 0*/) const
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (condition->getEndTime() >= timeNow || condition->getTicks() == -1) {
|
if (condition->getEndTime() >= timeNow) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1348,18 +1326,8 @@ int64_t Creature::getStepDuration() const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t calculatedStepSpeed;
|
|
||||||
uint32_t groundSpeed;
|
uint32_t groundSpeed;
|
||||||
|
|
||||||
int32_t stepSpeed = getStepSpeed();
|
int32_t stepSpeed = getStepSpeed();
|
||||||
if (stepSpeed > -Creature::speedB) {
|
|
||||||
calculatedStepSpeed = floor((Creature::speedA * log((stepSpeed / 2) + Creature::speedB) + Creature::speedC) + 0.5);
|
|
||||||
if (calculatedStepSpeed == 0) {
|
|
||||||
calculatedStepSpeed = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
calculatedStepSpeed = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Item* ground = tile->getGround();
|
Item* ground = tile->getGround();
|
||||||
if (ground) {
|
if (ground) {
|
||||||
@@ -1371,12 +1339,12 @@ int64_t Creature::getStepDuration() const
|
|||||||
groundSpeed = 150;
|
groundSpeed = 150;
|
||||||
}
|
}
|
||||||
|
|
||||||
double duration = std::floor(1000 * groundSpeed / calculatedStepSpeed);
|
double duration = std::floor(1000 * groundSpeed) / stepSpeed;
|
||||||
int64_t stepDuration = std::ceil(duration / 50) * 50;
|
int64_t stepDuration = std::ceil(duration / 50) * 50;
|
||||||
|
|
||||||
const Monster* monster = getMonster();
|
const Monster* monster = getMonster();
|
||||||
if (monster && monster->isTargetNearby() && !monster->isFleeing() && !monster->getMaster()) {
|
if (monster && monster->isTargetNearby() && !monster->isFleeing() && !monster->getMaster()) {
|
||||||
stepDuration *= 2;
|
stepDuration *= 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
return stepDuration;
|
return stepDuration;
|
||||||
@@ -1396,18 +1364,15 @@ int64_t Creature::getEventStepTicks(bool onlyDelay) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
LightInfo Creature::getCreatureLight() const
|
void Creature::getCreatureLight(LightInfo& light) const
|
||||||
{
|
{
|
||||||
return internalLight;
|
light = internalLight;
|
||||||
}
|
|
||||||
|
|
||||||
void Creature::setCreatureLight(LightInfo lightInfo) {
|
|
||||||
internalLight = std::move(lightInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Creature::setNormalCreatureLight()
|
void Creature::setNormalCreatureLight()
|
||||||
{
|
{
|
||||||
internalLight = {};
|
internalLight.level = 0;
|
||||||
|
internalLight.color = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Creature::registerCreatureEvent(const std::string& name)
|
bool Creature::registerCreatureEvent(const std::string& name)
|
||||||
@@ -1475,10 +1440,6 @@ CreatureEventList Creature::getCreatureEvents(CreatureEventType_t type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (CreatureEvent* creatureEvent : eventsList) {
|
for (CreatureEvent* creatureEvent : eventsList) {
|
||||||
if (!creatureEvent->isLoaded()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (creatureEvent->getEventType() == type) {
|
if (creatureEvent->getEventType() == type) {
|
||||||
tmpEventList.push_back(creatureEvent);
|
tmpEventList.push_back(creatureEvent);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,8 +28,8 @@
|
|||||||
#include "enums.h"
|
#include "enums.h"
|
||||||
#include "creatureevent.h"
|
#include "creatureevent.h"
|
||||||
|
|
||||||
using ConditionList = std::list<Condition*>;
|
typedef std::list<Condition*> ConditionList;
|
||||||
using CreatureEventList = std::list<CreatureEvent*>;
|
typedef std::list<CreatureEvent*> CreatureEventList;
|
||||||
|
|
||||||
enum slots_t : uint8_t {
|
enum slots_t : uint8_t {
|
||||||
CONST_SLOT_WHEREEVER = 0,
|
CONST_SLOT_WHEREEVER = 0,
|
||||||
@@ -66,6 +66,7 @@ class Monster;
|
|||||||
class Npc;
|
class Npc;
|
||||||
class Item;
|
class Item;
|
||||||
class Tile;
|
class Tile;
|
||||||
|
class Combat;
|
||||||
|
|
||||||
static constexpr int32_t EVENT_CREATURECOUNT = 10;
|
static constexpr int32_t EVENT_CREATURECOUNT = 10;
|
||||||
static constexpr int32_t EVENT_CREATURE_THINK_INTERVAL = 1000;
|
static constexpr int32_t EVENT_CREATURE_THINK_INTERVAL = 1000;
|
||||||
@@ -82,7 +83,7 @@ class FrozenPathingConditionCall
|
|||||||
bool isInRange(const Position& startPos, const Position& testPos,
|
bool isInRange(const Position& startPos, const Position& testPos,
|
||||||
const FindPathParams& fpp) const;
|
const FindPathParams& fpp) const;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
Position targetPos;
|
Position targetPos;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -96,18 +97,16 @@ class Creature : virtual public Thing
|
|||||||
Creature();
|
Creature();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static double speedA, speedB, speedC;
|
|
||||||
|
|
||||||
virtual ~Creature();
|
virtual ~Creature();
|
||||||
|
|
||||||
// non-copyable
|
// non-copyable
|
||||||
Creature(const Creature&) = delete;
|
Creature(const Creature&) = delete;
|
||||||
Creature& operator=(const Creature&) = delete;
|
Creature& operator=(const Creature&) = delete;
|
||||||
|
|
||||||
Creature* getCreature() override final {
|
Creature* getCreature() final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
const Creature* getCreature() const override final {
|
const Creature* getCreature() const final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
virtual Player* getPlayer() {
|
virtual Player* getPlayer() {
|
||||||
@@ -132,8 +131,6 @@ class Creature : virtual public Thing
|
|||||||
virtual const std::string& getName() const = 0;
|
virtual const std::string& getName() const = 0;
|
||||||
virtual const std::string& getNameDescription() const = 0;
|
virtual const std::string& getNameDescription() const = 0;
|
||||||
|
|
||||||
virtual CreatureType_t getType() const = 0;
|
|
||||||
|
|
||||||
virtual void setID() = 0;
|
virtual void setID() = 0;
|
||||||
void setRemoved() {
|
void setRemoved() {
|
||||||
isInternalRemoved = true;
|
isInternalRemoved = true;
|
||||||
@@ -172,13 +169,13 @@ class Creature : virtual public Thing
|
|||||||
hiddenHealth = b;
|
hiddenHealth = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t getThrowRange() const override final {
|
int32_t getThrowRange() const final {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
bool isPushable() const override {
|
bool isPushable() const override {
|
||||||
return getWalkDelay() <= 0;
|
return getWalkDelay() <= 0;
|
||||||
}
|
}
|
||||||
bool isRemoved() const override final {
|
bool isRemoved() const final {
|
||||||
return isInternalRemoved;
|
return isInternalRemoved;
|
||||||
}
|
}
|
||||||
virtual bool canSeeInvisibility() const {
|
virtual bool canSeeInvisibility() const {
|
||||||
@@ -199,11 +196,15 @@ class Creature : virtual public Thing
|
|||||||
return getSpeed();
|
return getSpeed();
|
||||||
}
|
}
|
||||||
int32_t getSpeed() const {
|
int32_t getSpeed() const {
|
||||||
return baseSpeed + varSpeed;
|
if (baseSpeed == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (2 * (varSpeed + baseSpeed)) + 80;
|
||||||
}
|
}
|
||||||
void setSpeed(int32_t varSpeedDelta) {
|
void setSpeed(int32_t varSpeedDelta) {
|
||||||
int32_t oldSpeed = getSpeed();
|
int32_t oldSpeed = getSpeed();
|
||||||
varSpeed = varSpeedDelta;
|
varSpeed += varSpeedDelta;
|
||||||
|
|
||||||
if (getSpeed() <= 0) {
|
if (getSpeed() <= 0) {
|
||||||
stopEventWalk();
|
stopEventWalk();
|
||||||
@@ -270,15 +271,9 @@ class Creature : virtual public Thing
|
|||||||
virtual BlockType_t blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage,
|
virtual BlockType_t blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage,
|
||||||
bool checkDefense = false, bool checkArmor = false, bool field = false);
|
bool checkDefense = false, bool checkArmor = false, bool field = false);
|
||||||
|
|
||||||
bool setMaster(Creature* newMaster);
|
void setMaster(Creature* creature) {
|
||||||
|
master = creature;
|
||||||
void removeMaster() {
|
|
||||||
if (master) {
|
|
||||||
master = nullptr;
|
|
||||||
decrementReferenceCounter();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSummon() const {
|
bool isSummon() const {
|
||||||
return master != nullptr;
|
return master != nullptr;
|
||||||
}
|
}
|
||||||
@@ -286,6 +281,8 @@ class Creature : virtual public Thing
|
|||||||
return master;
|
return master;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void addSummon(Creature* creature);
|
||||||
|
void removeSummon(Creature* creature);
|
||||||
const std::list<Creature*>& getSummons() const {
|
const std::list<Creature*>& getSummons() const {
|
||||||
return summons;
|
return summons;
|
||||||
}
|
}
|
||||||
@@ -293,19 +290,9 @@ class Creature : virtual public Thing
|
|||||||
virtual int32_t getArmor() const {
|
virtual int32_t getArmor() const {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
virtual int32_t getDefense() const {
|
virtual int32_t getDefense() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
virtual float getAttackFactor() const {
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
virtual float getDefenseFactor() const {
|
|
||||||
return 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual uint8_t getSpeechBubble() const {
|
|
||||||
return SPEECHBUBBLE_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool addCondition(Condition* condition, bool force = false);
|
bool addCondition(Condition* condition, bool force = false);
|
||||||
bool addCombatCondition(Condition* condition);
|
bool addCombatCondition(Condition* condition);
|
||||||
@@ -335,12 +322,15 @@ class Creature : virtual public Thing
|
|||||||
|
|
||||||
virtual void changeHealth(int32_t healthChange, bool sendHealthChange = true);
|
virtual void changeHealth(int32_t healthChange, bool sendHealthChange = true);
|
||||||
|
|
||||||
void gainHealth(Creature* healer, int32_t healthGain);
|
void gainHealth(Creature* attacker, int32_t healthGain);
|
||||||
virtual void drainHealth(Creature* attacker, int32_t damage);
|
virtual void drainHealth(Creature* attacker, int32_t damage);
|
||||||
|
|
||||||
virtual bool challengeCreature(Creature*) {
|
virtual bool challengeCreature(Creature*) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
virtual bool convinceCreature(Creature*) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void onDeath();
|
void onDeath();
|
||||||
virtual uint64_t getGainedExperience(Creature* attacker) const;
|
virtual uint64_t getGainedExperience(Creature* attacker) const;
|
||||||
@@ -365,9 +355,11 @@ class Creature : virtual public Thing
|
|||||||
virtual void onAttackedCreatureChangeZone(ZoneType_t zone);
|
virtual void onAttackedCreatureChangeZone(ZoneType_t zone);
|
||||||
virtual void onIdleStatus();
|
virtual void onIdleStatus();
|
||||||
|
|
||||||
virtual LightInfo getCreatureLight() const;
|
virtual void getCreatureLight(LightInfo& light) const;
|
||||||
virtual void setNormalCreatureLight();
|
virtual void setNormalCreatureLight();
|
||||||
void setCreatureLight(LightInfo lightInfo);
|
void setCreatureLight(LightInfo light) {
|
||||||
|
internalLight = light;
|
||||||
|
}
|
||||||
|
|
||||||
virtual void onThink(uint32_t interval);
|
virtual void onThink(uint32_t interval);
|
||||||
void onAttacking(uint32_t interval);
|
void onAttacking(uint32_t interval);
|
||||||
@@ -390,6 +382,7 @@ class Creature : virtual public Thing
|
|||||||
|
|
||||||
virtual void onCreatureSay(Creature*, SpeakClasses, const std::string&) {}
|
virtual void onCreatureSay(Creature*, SpeakClasses, const std::string&) {}
|
||||||
|
|
||||||
|
virtual void onCreatureConvinced(const Creature*, const Creature*) {}
|
||||||
virtual void onPlacedCreature() {}
|
virtual void onPlacedCreature() {}
|
||||||
|
|
||||||
virtual bool getCombatValues(int32_t&, int32_t&) {
|
virtual bool getCombatValues(int32_t&, int32_t&) {
|
||||||
@@ -402,33 +395,30 @@ class Creature : virtual public Thing
|
|||||||
void setDropLoot(bool lootDrop) {
|
void setDropLoot(bool lootDrop) {
|
||||||
this->lootDrop = lootDrop;
|
this->lootDrop = lootDrop;
|
||||||
}
|
}
|
||||||
void setSkillLoss(bool skillLoss) {
|
void setLossSkill(bool skillLoss) {
|
||||||
this->skillLoss = skillLoss;
|
this->skillLoss = skillLoss;
|
||||||
}
|
}
|
||||||
void setUseDefense(bool useDefense) {
|
|
||||||
canUseDefense = useDefense;
|
|
||||||
}
|
|
||||||
|
|
||||||
//creature script events
|
//creature script events
|
||||||
bool registerCreatureEvent(const std::string& name);
|
bool registerCreatureEvent(const std::string& name);
|
||||||
bool unregisterCreatureEvent(const std::string& name);
|
bool unregisterCreatureEvent(const std::string& name);
|
||||||
|
|
||||||
Cylinder* getParent() const override final {
|
Cylinder* getParent() const final {
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
void setParent(Cylinder* cylinder) override final {
|
void setParent(Cylinder* cylinder) final {
|
||||||
tile = static_cast<Tile*>(cylinder);
|
tile = static_cast<Tile*>(cylinder);
|
||||||
position = tile->getPosition();
|
position = tile->getPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Position& getPosition() const override final {
|
inline const Position& getPosition() const final {
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tile* getTile() override final {
|
Tile* getTile() final {
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
const Tile* getTile() const override final {
|
const Tile* getTile() const final {
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,7 +464,7 @@ class Creature : virtual public Thing
|
|||||||
|
|
||||||
Position position;
|
Position position;
|
||||||
|
|
||||||
using CountMap = std::map<uint32_t, CountBlock_t>;
|
typedef std::map<uint32_t, CountBlock_t> CountMap;
|
||||||
CountMap damageMap;
|
CountMap damageMap;
|
||||||
|
|
||||||
std::list<Creature*> summons;
|
std::list<Creature*> summons;
|
||||||
@@ -488,6 +478,10 @@ class Creature : virtual public Thing
|
|||||||
Creature* master = nullptr;
|
Creature* master = nullptr;
|
||||||
Creature* followCreature = nullptr;
|
Creature* followCreature = nullptr;
|
||||||
|
|
||||||
|
int64_t earliestDefendTime = 0;
|
||||||
|
int64_t lastDefendTime = 0;
|
||||||
|
|
||||||
|
uint64_t lastWalkUpdate = 0;
|
||||||
uint64_t lastStep = 0;
|
uint64_t lastStep = 0;
|
||||||
uint32_t referenceCounter = 0;
|
uint32_t referenceCounter = 0;
|
||||||
uint32_t id = 0;
|
uint32_t id = 0;
|
||||||
@@ -498,7 +492,8 @@ class Creature : virtual public Thing
|
|||||||
uint32_t blockCount = 0;
|
uint32_t blockCount = 0;
|
||||||
uint32_t blockTicks = 0;
|
uint32_t blockTicks = 0;
|
||||||
uint32_t lastStepCost = 1;
|
uint32_t lastStepCost = 1;
|
||||||
uint32_t baseSpeed = 220;
|
uint32_t baseSpeed = 70;
|
||||||
|
uint32_t latestKillEvent = 0;
|
||||||
int32_t varSpeed = 0;
|
int32_t varSpeed = 0;
|
||||||
int32_t health = 1000;
|
int32_t health = 1000;
|
||||||
int32_t healthMax = 1000;
|
int32_t healthMax = 1000;
|
||||||
@@ -524,7 +519,6 @@ class Creature : virtual public Thing
|
|||||||
bool hasFollowPath = false;
|
bool hasFollowPath = false;
|
||||||
bool forceUpdateFollowPath = false;
|
bool forceUpdateFollowPath = false;
|
||||||
bool hiddenHealth = false;
|
bool hiddenHealth = false;
|
||||||
bool canUseDefense = true;
|
|
||||||
|
|
||||||
//creature script events
|
//creature script events
|
||||||
bool hasEventRegistered(CreatureEventType_t event) const {
|
bool hasEventRegistered(CreatureEventType_t event) const {
|
||||||
@@ -556,6 +550,7 @@ class Creature : virtual public Thing
|
|||||||
friend class Game;
|
friend class Game;
|
||||||
friend class Map;
|
friend class Map;
|
||||||
friend class LuaScriptInterface;
|
friend class LuaScriptInterface;
|
||||||
|
friend class Combat;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -29,15 +29,22 @@ CreatureEvents::CreatureEvents() :
|
|||||||
scriptInterface.initState();
|
scriptInterface.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureEvents::clear(bool fromLua)
|
CreatureEvents::~CreatureEvents()
|
||||||
{
|
{
|
||||||
for (auto it = creatureEvents.begin(); it != creatureEvents.end(); ++it) {
|
for (const auto& it : creatureEvents) {
|
||||||
if (fromLua == it->second.fromLua) {
|
delete it.second;
|
||||||
it->second.clearEvent();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CreatureEvents::clear()
|
||||||
|
{
|
||||||
|
//clear creature events
|
||||||
|
for (const auto& it : creatureEvents) {
|
||||||
|
it.second->clearEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
reInitState(fromLua);
|
//clear lua state
|
||||||
|
scriptInterface.reInitState();
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaScriptInterface& CreatureEvents::getScriptInterface()
|
LuaScriptInterface& CreatureEvents::getScriptInterface()
|
||||||
@@ -50,17 +57,17 @@ std::string CreatureEvents::getScriptBaseName() const
|
|||||||
return "creaturescripts";
|
return "creaturescripts";
|
||||||
}
|
}
|
||||||
|
|
||||||
Event_ptr CreatureEvents::getEvent(const std::string& nodeName)
|
Event* CreatureEvents::getEvent(const std::string& nodeName)
|
||||||
{
|
{
|
||||||
if (strcasecmp(nodeName.c_str(), "event") != 0) {
|
if (strcasecmp(nodeName.c_str(), "event") != 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return Event_ptr(new CreatureEvent(&scriptInterface));
|
return new CreatureEvent(&scriptInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CreatureEvents::registerEvent(Event_ptr event, const pugi::xml_node&)
|
bool CreatureEvents::registerEvent(Event* event, const pugi::xml_node&)
|
||||||
{
|
{
|
||||||
CreatureEvent_ptr creatureEvent{static_cast<CreatureEvent*>(event.release())}; //event is guaranteed to be a CreatureEvent
|
CreatureEvent* creatureEvent = static_cast<CreatureEvent*>(event); //event is guaranteed to be a CreatureEvent
|
||||||
if (creatureEvent->getEventType() == CREATURE_EVENT_NONE) {
|
if (creatureEvent->getEventType() == CREATURE_EVENT_NONE) {
|
||||||
std::cout << "Error: [CreatureEvents::registerEvent] Trying to register event without type!" << std::endl;
|
std::cout << "Error: [CreatureEvents::registerEvent] Trying to register event without type!" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
@@ -71,37 +78,13 @@ bool CreatureEvents::registerEvent(Event_ptr event, const pugi::xml_node&)
|
|||||||
//if there was an event with the same that is not loaded
|
//if there was an event with the same that is not loaded
|
||||||
//(happens when realoading), it is reused
|
//(happens when realoading), it is reused
|
||||||
if (!oldEvent->isLoaded() && oldEvent->getEventType() == creatureEvent->getEventType()) {
|
if (!oldEvent->isLoaded() && oldEvent->getEventType() == creatureEvent->getEventType()) {
|
||||||
oldEvent->copyEvent(creatureEvent.get());
|
oldEvent->copyEvent(creatureEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
//if not, register it normally
|
//if not, register it normally
|
||||||
creatureEvents.emplace(creatureEvent->getName(), std::move(*creatureEvent));
|
creatureEvents[creatureEvent->getName()] = creatureEvent;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CreatureEvents::registerLuaEvent(CreatureEvent* event)
|
|
||||||
{
|
|
||||||
CreatureEvent_ptr creatureEvent{ event };
|
|
||||||
if (creatureEvent->getEventType() == CREATURE_EVENT_NONE) {
|
|
||||||
std::cout << "Error: [CreatureEvents::registerLuaEvent] Trying to register event without type!" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
CreatureEvent* oldEvent = getEventByName(creatureEvent->getName(), false);
|
|
||||||
if (oldEvent) {
|
|
||||||
//if there was an event with the same that is not loaded
|
|
||||||
//(happens when realoading), it is reused
|
|
||||||
if (!oldEvent->isLoaded() && oldEvent->getEventType() == creatureEvent->getEventType()) {
|
|
||||||
oldEvent->copyEvent(creatureEvent.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
//if not, register it normally
|
|
||||||
creatureEvents.emplace(creatureEvent->getName(), std::move(*creatureEvent));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,8 +93,8 @@ CreatureEvent* CreatureEvents::getEventByName(const std::string& name, bool forc
|
|||||||
{
|
{
|
||||||
auto it = creatureEvents.find(name);
|
auto it = creatureEvents.find(name);
|
||||||
if (it != creatureEvents.end()) {
|
if (it != creatureEvents.end()) {
|
||||||
if (!forceLoaded || it->second.isLoaded()) {
|
if (!forceLoaded || it->second->isLoaded()) {
|
||||||
return &it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -121,8 +104,8 @@ bool CreatureEvents::playerLogin(Player* player) const
|
|||||||
{
|
{
|
||||||
//fire global event if is registered
|
//fire global event if is registered
|
||||||
for (const auto& it : creatureEvents) {
|
for (const auto& it : creatureEvents) {
|
||||||
if (it.second.getEventType() == CREATURE_EVENT_LOGIN) {
|
if (it.second->getEventType() == CREATURE_EVENT_LOGIN) {
|
||||||
if (!it.second.executeOnLogin(player)) {
|
if (!it.second->executeOnLogin(player)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,8 +117,8 @@ bool CreatureEvents::playerLogout(Player* player) const
|
|||||||
{
|
{
|
||||||
//fire global event if is registered
|
//fire global event if is registered
|
||||||
for (const auto& it : creatureEvents) {
|
for (const auto& it : creatureEvents) {
|
||||||
if (it.second.getEventType() == CREATURE_EVENT_LOGOUT) {
|
if (it.second->getEventType() == CREATURE_EVENT_LOGOUT) {
|
||||||
if (!it.second.executeOnLogout(player)) {
|
if (!it.second->executeOnLogout(player)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,9 +129,9 @@ bool CreatureEvents::playerLogout(Player* player) const
|
|||||||
bool CreatureEvents::playerAdvance(Player* player, skills_t skill, uint32_t oldLevel,
|
bool CreatureEvents::playerAdvance(Player* player, skills_t skill, uint32_t oldLevel,
|
||||||
uint32_t newLevel)
|
uint32_t newLevel)
|
||||||
{
|
{
|
||||||
for (auto& it : creatureEvents) {
|
for (const auto& it : creatureEvents) {
|
||||||
if (it.second.getEventType() == CREATURE_EVENT_ADVANCE) {
|
if (it.second->getEventType() == CREATURE_EVENT_ADVANCE) {
|
||||||
if (!it.second.executeAdvance(player, skill, oldLevel, newLevel)) {
|
if (!it.second->executeAdvance(player, skill, oldLevel, newLevel)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -194,10 +177,6 @@ bool CreatureEvent::configureEvent(const pugi::xml_node& node)
|
|||||||
type = CREATURE_EVENT_KILL;
|
type = CREATURE_EVENT_KILL;
|
||||||
} else if (tmpStr == "advance") {
|
} else if (tmpStr == "advance") {
|
||||||
type = CREATURE_EVENT_ADVANCE;
|
type = CREATURE_EVENT_ADVANCE;
|
||||||
} else if (tmpStr == "modalwindow") {
|
|
||||||
type = CREATURE_EVENT_MODALWINDOW;
|
|
||||||
} else if (tmpStr == "textedit") {
|
|
||||||
type = CREATURE_EVENT_TEXTEDIT;
|
|
||||||
} else if (tmpStr == "healthchange") {
|
} else if (tmpStr == "healthchange") {
|
||||||
type = CREATURE_EVENT_HEALTHCHANGE;
|
type = CREATURE_EVENT_HEALTHCHANGE;
|
||||||
} else if (tmpStr == "manachange") {
|
} else if (tmpStr == "manachange") {
|
||||||
@@ -238,12 +217,6 @@ std::string CreatureEvent::getScriptEventName() const
|
|||||||
case CREATURE_EVENT_ADVANCE:
|
case CREATURE_EVENT_ADVANCE:
|
||||||
return "onAdvance";
|
return "onAdvance";
|
||||||
|
|
||||||
case CREATURE_EVENT_MODALWINDOW:
|
|
||||||
return "onModalWindow";
|
|
||||||
|
|
||||||
case CREATURE_EVENT_TEXTEDIT:
|
|
||||||
return "onTextEdit";
|
|
||||||
|
|
||||||
case CREATURE_EVENT_HEALTHCHANGE:
|
case CREATURE_EVENT_HEALTHCHANGE:
|
||||||
return "onHealthChange";
|
return "onHealthChange";
|
||||||
|
|
||||||
@@ -275,7 +248,7 @@ void CreatureEvent::clearEvent()
|
|||||||
loaded = false;
|
loaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CreatureEvent::executeOnLogin(Player* player) const
|
bool CreatureEvent::executeOnLogin(Player* player)
|
||||||
{
|
{
|
||||||
//onLogin(player)
|
//onLogin(player)
|
||||||
if (!scriptInterface->reserveScriptEnv()) {
|
if (!scriptInterface->reserveScriptEnv()) {
|
||||||
@@ -294,7 +267,7 @@ bool CreatureEvent::executeOnLogin(Player* player) const
|
|||||||
return scriptInterface->callFunction(1);
|
return scriptInterface->callFunction(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CreatureEvent::executeOnLogout(Player* player) const
|
bool CreatureEvent::executeOnLogout(Player* player)
|
||||||
{
|
{
|
||||||
//onLogout(player)
|
//onLogout(player)
|
||||||
if (!scriptInterface->reserveScriptEnv()) {
|
if (!scriptInterface->reserveScriptEnv()) {
|
||||||
@@ -446,56 +419,9 @@ void CreatureEvent::executeOnKill(Creature* creature, Creature* target)
|
|||||||
scriptInterface->callVoidFunction(2);
|
scriptInterface->callVoidFunction(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureEvent::executeModalWindow(Player* player, uint32_t modalWindowId, uint8_t buttonId, uint8_t choiceId)
|
|
||||||
{
|
|
||||||
//onModalWindow(player, modalWindowId, buttonId, choiceId)
|
|
||||||
if (!scriptInterface->reserveScriptEnv()) {
|
|
||||||
std::cout << "[Error - CreatureEvent::executeModalWindow] Call stack overflow" << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface->getScriptEnv();
|
|
||||||
env->setScriptId(scriptId, scriptInterface);
|
|
||||||
|
|
||||||
lua_State* L = scriptInterface->getLuaState();
|
|
||||||
scriptInterface->pushFunction(scriptId);
|
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata(L, player);
|
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
|
||||||
|
|
||||||
lua_pushnumber(L, modalWindowId);
|
|
||||||
lua_pushnumber(L, buttonId);
|
|
||||||
lua_pushnumber(L, choiceId);
|
|
||||||
|
|
||||||
scriptInterface->callVoidFunction(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CreatureEvent::executeTextEdit(Player* player, Item* item, const std::string& text)
|
|
||||||
{
|
|
||||||
//onTextEdit(player, item, text)
|
|
||||||
if (!scriptInterface->reserveScriptEnv()) {
|
|
||||||
std::cout << "[Error - CreatureEvent::executeTextEdit] Call stack overflow" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface->getScriptEnv();
|
|
||||||
env->setScriptId(scriptId, scriptInterface);
|
|
||||||
|
|
||||||
lua_State* L = scriptInterface->getLuaState();
|
|
||||||
scriptInterface->pushFunction(scriptId);
|
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata(L, player);
|
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
|
||||||
|
|
||||||
LuaScriptInterface::pushThing(L, item);
|
|
||||||
LuaScriptInterface::pushString(L, text);
|
|
||||||
|
|
||||||
return scriptInterface->callFunction(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CreatureEvent::executeHealthChange(Creature* creature, Creature* attacker, CombatDamage& damage)
|
void CreatureEvent::executeHealthChange(Creature* creature, Creature* attacker, CombatDamage& damage)
|
||||||
{
|
{
|
||||||
//onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
|
//onHealthChange(creature, attacker, value, type, min, max, origin)
|
||||||
if (!scriptInterface->reserveScriptEnv()) {
|
if (!scriptInterface->reserveScriptEnv()) {
|
||||||
std::cout << "[Error - CreatureEvent::executeHealthChange] Call stack overflow" << std::endl;
|
std::cout << "[Error - CreatureEvent::executeHealthChange] Call stack overflow" << std::endl;
|
||||||
return;
|
return;
|
||||||
@@ -512,7 +438,8 @@ void CreatureEvent::executeHealthChange(Creature* creature, Creature* attacker,
|
|||||||
if (attacker) {
|
if (attacker) {
|
||||||
LuaScriptInterface::pushUserdata(L, attacker);
|
LuaScriptInterface::pushUserdata(L, attacker);
|
||||||
LuaScriptInterface::setCreatureMetatable(L, -1, attacker);
|
LuaScriptInterface::setCreatureMetatable(L, -1, attacker);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,16 +447,16 @@ void CreatureEvent::executeHealthChange(Creature* creature, Creature* attacker,
|
|||||||
|
|
||||||
if (scriptInterface->protectedCall(L, 7, 4) != 0) {
|
if (scriptInterface->protectedCall(L, 7, 4) != 0) {
|
||||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||||
} else {
|
}
|
||||||
damage.primary.value = std::abs(LuaScriptInterface::getNumber<int32_t>(L, -4));
|
else {
|
||||||
damage.primary.type = LuaScriptInterface::getNumber<CombatType_t>(L, -3);
|
damage.value = std::abs(LuaScriptInterface::getNumber<int32_t>(L, -4));
|
||||||
damage.secondary.value = std::abs(LuaScriptInterface::getNumber<int32_t>(L, -2));
|
damage.type = LuaScriptInterface::getNumber<CombatType_t>(L, -3);
|
||||||
damage.secondary.type = LuaScriptInterface::getNumber<CombatType_t>(L, -1);
|
damage.min = std::abs(LuaScriptInterface::getNumber<int32_t>(L, -2));
|
||||||
|
damage.max = LuaScriptInterface::getNumber<CombatType_t>(L, -1);
|
||||||
|
|
||||||
lua_pop(L, 4);
|
lua_pop(L, 4);
|
||||||
if (damage.primary.type != COMBAT_HEALING) {
|
if (damage.type != COMBAT_HEALING) {
|
||||||
damage.primary.value = -damage.primary.value;
|
damage.value = -damage.value;
|
||||||
damage.secondary.value = -damage.secondary.value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -537,7 +464,7 @@ void CreatureEvent::executeHealthChange(Creature* creature, Creature* attacker,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CreatureEvent::executeManaChange(Creature* creature, Creature* attacker, CombatDamage& damage) {
|
void CreatureEvent::executeManaChange(Creature* creature, Creature* attacker, CombatDamage& damage) {
|
||||||
//onManaChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin)
|
//onManaChange(creature, attacker, value, type, min, max, origin)
|
||||||
if (!scriptInterface->reserveScriptEnv()) {
|
if (!scriptInterface->reserveScriptEnv()) {
|
||||||
std::cout << "[Error - CreatureEvent::executeManaChange] Call stack overflow" << std::endl;
|
std::cout << "[Error - CreatureEvent::executeManaChange] Call stack overflow" << std::endl;
|
||||||
return;
|
return;
|
||||||
@@ -554,7 +481,8 @@ void CreatureEvent::executeManaChange(Creature* creature, Creature* attacker, Co
|
|||||||
if (attacker) {
|
if (attacker) {
|
||||||
LuaScriptInterface::pushUserdata(L, attacker);
|
LuaScriptInterface::pushUserdata(L, attacker);
|
||||||
LuaScriptInterface::setCreatureMetatable(L, -1, attacker);
|
LuaScriptInterface::setCreatureMetatable(L, -1, attacker);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,12 +490,9 @@ void CreatureEvent::executeManaChange(Creature* creature, Creature* attacker, Co
|
|||||||
|
|
||||||
if (scriptInterface->protectedCall(L, 7, 4) != 0) {
|
if (scriptInterface->protectedCall(L, 7, 4) != 0) {
|
||||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||||
} else {
|
}
|
||||||
damage.primary.value = LuaScriptInterface::getNumber<int32_t>(L, -4);
|
else {
|
||||||
damage.primary.type = LuaScriptInterface::getNumber<CombatType_t>(L, -3);
|
damage = LuaScriptInterface::getCombatDamage(L);
|
||||||
damage.secondary.value = LuaScriptInterface::getNumber<int32_t>(L, -2);
|
|
||||||
damage.secondary.type = LuaScriptInterface::getNumber<CombatType_t>(L, -1);
|
|
||||||
lua_pop(L, 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptInterface->resetScriptEnv();
|
scriptInterface->resetScriptEnv();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,9 +24,6 @@
|
|||||||
#include "baseevents.h"
|
#include "baseevents.h"
|
||||||
#include "enums.h"
|
#include "enums.h"
|
||||||
|
|
||||||
class CreatureEvent;
|
|
||||||
using CreatureEvent_ptr = std::unique_ptr<CreatureEvent>;
|
|
||||||
|
|
||||||
enum CreatureEventType_t {
|
enum CreatureEventType_t {
|
||||||
CREATURE_EVENT_NONE,
|
CREATURE_EVENT_NONE,
|
||||||
CREATURE_EVENT_LOGIN,
|
CREATURE_EVENT_LOGIN,
|
||||||
@@ -36,69 +33,18 @@ enum CreatureEventType_t {
|
|||||||
CREATURE_EVENT_DEATH,
|
CREATURE_EVENT_DEATH,
|
||||||
CREATURE_EVENT_KILL,
|
CREATURE_EVENT_KILL,
|
||||||
CREATURE_EVENT_ADVANCE,
|
CREATURE_EVENT_ADVANCE,
|
||||||
CREATURE_EVENT_MODALWINDOW,
|
|
||||||
CREATURE_EVENT_TEXTEDIT,
|
|
||||||
CREATURE_EVENT_HEALTHCHANGE,
|
CREATURE_EVENT_HEALTHCHANGE,
|
||||||
CREATURE_EVENT_MANACHANGE,
|
CREATURE_EVENT_MANACHANGE,
|
||||||
CREATURE_EVENT_EXTENDED_OPCODE, // otclient additional network opcodes
|
CREATURE_EVENT_EXTENDED_OPCODE, // otclient additional network opcodes
|
||||||
};
|
};
|
||||||
|
|
||||||
class CreatureEvent final : public Event
|
class CreatureEvent;
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit CreatureEvent(LuaScriptInterface* interface);
|
|
||||||
|
|
||||||
bool configureEvent(const pugi::xml_node& node) override;
|
|
||||||
|
|
||||||
CreatureEventType_t getEventType() const {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
void setEventType(CreatureEventType_t eventType) {
|
|
||||||
type = eventType;
|
|
||||||
}
|
|
||||||
const std::string& getName() const {
|
|
||||||
return eventName;
|
|
||||||
}
|
|
||||||
void setName(const std::string& name) {
|
|
||||||
eventName = name;
|
|
||||||
}
|
|
||||||
bool isLoaded() const {
|
|
||||||
return loaded;
|
|
||||||
}
|
|
||||||
void setLoaded(bool b) {
|
|
||||||
loaded = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearEvent();
|
|
||||||
void copyEvent(CreatureEvent* creatureEvent);
|
|
||||||
|
|
||||||
//scripting
|
|
||||||
bool executeOnLogin(Player* player) const;
|
|
||||||
bool executeOnLogout(Player* player) const;
|
|
||||||
bool executeOnThink(Creature* creature, uint32_t interval);
|
|
||||||
bool executeOnPrepareDeath(Creature* creature, Creature* killer);
|
|
||||||
bool executeOnDeath(Creature* creature, Item* corpse, Creature* killer, Creature* mostDamageKiller, bool lastHitUnjustified, bool mostDamageUnjustified);
|
|
||||||
void executeOnKill(Creature* creature, Creature* target);
|
|
||||||
bool executeAdvance(Player* player, skills_t, uint32_t, uint32_t);
|
|
||||||
void executeModalWindow(Player* player, uint32_t modalWindowId, uint8_t buttonId, uint8_t choiceId);
|
|
||||||
bool executeTextEdit(Player* player, Item* item, const std::string& text);
|
|
||||||
void executeHealthChange(Creature* creature, Creature* attacker, CombatDamage& damage);
|
|
||||||
void executeManaChange(Creature* creature, Creature* attacker, CombatDamage& damage);
|
|
||||||
void executeExtendedOpcode(Player* player, uint8_t opcode, const std::string& buffer);
|
|
||||||
//
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string getScriptEventName() const override;
|
|
||||||
|
|
||||||
std::string eventName;
|
|
||||||
CreatureEventType_t type;
|
|
||||||
bool loaded;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CreatureEvents final : public BaseEvents
|
class CreatureEvents final : public BaseEvents
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CreatureEvents();
|
CreatureEvents();
|
||||||
|
~CreatureEvents();
|
||||||
|
|
||||||
// non-copyable
|
// non-copyable
|
||||||
CreatureEvents(const CreatureEvents&) = delete;
|
CreatureEvents(const CreatureEvents&) = delete;
|
||||||
@@ -111,20 +57,59 @@ class CreatureEvents final : public BaseEvents
|
|||||||
|
|
||||||
CreatureEvent* getEventByName(const std::string& name, bool forceLoaded = true);
|
CreatureEvent* getEventByName(const std::string& name, bool forceLoaded = true);
|
||||||
|
|
||||||
bool registerLuaEvent(CreatureEvent* event);
|
protected:
|
||||||
void clear(bool fromLua) override final;
|
LuaScriptInterface& getScriptInterface() final;
|
||||||
|
std::string getScriptBaseName() const final;
|
||||||
private:
|
Event* getEvent(const std::string& nodeName) final;
|
||||||
LuaScriptInterface& getScriptInterface() override;
|
bool registerEvent(Event* event, const pugi::xml_node& node) final;
|
||||||
std::string getScriptBaseName() const override;
|
void clear() final;
|
||||||
Event_ptr getEvent(const std::string& nodeName) override;
|
|
||||||
bool registerEvent(Event_ptr event, const pugi::xml_node& node) override;
|
|
||||||
|
|
||||||
//creature events
|
//creature events
|
||||||
using CreatureEventMap = std::map<std::string, CreatureEvent>;
|
typedef std::map<std::string, CreatureEvent*> CreatureEventList;
|
||||||
CreatureEventMap creatureEvents;
|
CreatureEventList creatureEvents;
|
||||||
|
|
||||||
LuaScriptInterface scriptInterface;
|
LuaScriptInterface scriptInterface;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class CreatureEvent final : public Event
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit CreatureEvent(LuaScriptInterface* interface);
|
||||||
|
|
||||||
|
bool configureEvent(const pugi::xml_node& node) final;
|
||||||
|
|
||||||
|
CreatureEventType_t getEventType() const {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
const std::string& getName() const {
|
||||||
|
return eventName;
|
||||||
|
}
|
||||||
|
bool isLoaded() const {
|
||||||
|
return loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearEvent();
|
||||||
|
void copyEvent(CreatureEvent* creatureEvent);
|
||||||
|
|
||||||
|
//scripting
|
||||||
|
bool executeOnLogin(Player* player);
|
||||||
|
bool executeOnLogout(Player* player);
|
||||||
|
bool executeOnThink(Creature* creature, uint32_t interval);
|
||||||
|
bool executeOnPrepareDeath(Creature* creature, Creature* killer);
|
||||||
|
bool executeOnDeath(Creature* creature, Item* corpse, Creature* killer, Creature* mostDamageKiller, bool lastHitUnjustified, bool mostDamageUnjustified);
|
||||||
|
void executeOnKill(Creature* creature, Creature* target);
|
||||||
|
bool executeAdvance(Player* player, skills_t, uint32_t, uint32_t);
|
||||||
|
void executeHealthChange(Creature* creature, Creature* attacker, CombatDamage& damage);
|
||||||
|
void executeManaChange(Creature* creature, Creature* attacker, CombatDamage& damage);
|
||||||
|
void executeExtendedOpcode(Player* player, uint8_t opcode, const std::string& buffer);
|
||||||
|
//
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string getScriptEventName() const final;
|
||||||
|
|
||||||
|
std::string eventName;
|
||||||
|
CreatureEventType_t type;
|
||||||
|
bool loaded;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -37,6 +37,7 @@ enum cylinderflags_t {
|
|||||||
FLAG_IGNOREFIELDDAMAGE = 1 << 5, //Bypass field damage checks
|
FLAG_IGNOREFIELDDAMAGE = 1 << 5, //Bypass field damage checks
|
||||||
FLAG_IGNORENOTMOVEABLE = 1 << 6, //Bypass check for mobility
|
FLAG_IGNORENOTMOVEABLE = 1 << 6, //Bypass check for mobility
|
||||||
FLAG_IGNOREAUTOSTACK = 1 << 7, //queryDestination will not try to stack items together
|
FLAG_IGNOREAUTOSTACK = 1 << 7, //queryDestination will not try to stack items together
|
||||||
|
FLAG_PLACECHECK = 1 << 8, //Special check for placing the monster
|
||||||
};
|
};
|
||||||
|
|
||||||
enum cylinderlink_t {
|
enum cylinderlink_t {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -255,7 +255,7 @@ bool DBInsert::addRow(const std::string& row)
|
|||||||
// adds new row to buffer
|
// adds new row to buffer
|
||||||
const size_t rowLength = row.length();
|
const size_t rowLength = row.length();
|
||||||
length += rowLength;
|
length += rowLength;
|
||||||
if (length > Database::getInstance().getMaxPacketSize() && !execute()) {
|
if (length > Database::getInstance()->getMaxPacketSize() && !execute()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +288,7 @@ bool DBInsert::execute()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// executes buffer
|
// executes buffer
|
||||||
bool res = Database::getInstance().executeQuery(query + values);
|
bool res = Database::getInstance()->executeQuery(query + values);
|
||||||
values.clear();
|
values.clear();
|
||||||
length = query.length();
|
length = query.length();
|
||||||
return res;
|
return res;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
#include <mysql/mysql.h>
|
#include <mysql/mysql.h>
|
||||||
|
|
||||||
class DBResult;
|
class DBResult;
|
||||||
using DBResult_ptr = std::shared_ptr<DBResult>;
|
typedef std::shared_ptr<DBResult> DBResult_ptr;
|
||||||
|
|
||||||
class Database
|
class Database
|
||||||
{
|
{
|
||||||
@@ -42,10 +42,10 @@ class Database
|
|||||||
*
|
*
|
||||||
* @return database connection handler singleton
|
* @return database connection handler singleton
|
||||||
*/
|
*/
|
||||||
static Database& getInstance()
|
static Database* getInstance()
|
||||||
{
|
{
|
||||||
static Database instance;
|
static Database instance;
|
||||||
return instance;
|
return &instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,7 +117,7 @@ class Database
|
|||||||
return maxPacketSize;
|
return maxPacketSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
/**
|
/**
|
||||||
* Transaction related methods.
|
* Transaction related methods.
|
||||||
*
|
*
|
||||||
@@ -129,6 +129,7 @@ class Database
|
|||||||
bool rollback();
|
bool rollback();
|
||||||
bool commit();
|
bool commit();
|
||||||
|
|
||||||
|
private:
|
||||||
MYSQL* handle = nullptr;
|
MYSQL* handle = nullptr;
|
||||||
std::recursive_mutex databaseLock;
|
std::recursive_mutex databaseLock;
|
||||||
uint64_t maxPacketSize = 1048576;
|
uint64_t maxPacketSize = 1048576;
|
||||||
@@ -194,7 +195,7 @@ class DBInsert
|
|||||||
bool addRow(std::ostringstream& row);
|
bool addRow(std::ostringstream& row);
|
||||||
bool execute();
|
bool execute();
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
std::string query;
|
std::string query;
|
||||||
std::string values;
|
std::string values;
|
||||||
size_t length;
|
size_t length;
|
||||||
@@ -207,7 +208,7 @@ class DBTransaction
|
|||||||
|
|
||||||
~DBTransaction() {
|
~DBTransaction() {
|
||||||
if (state == STATE_START) {
|
if (state == STATE_START) {
|
||||||
Database::getInstance().rollback();
|
Database::getInstance()->rollback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +218,7 @@ class DBTransaction
|
|||||||
|
|
||||||
bool begin() {
|
bool begin() {
|
||||||
state = STATE_START;
|
state = STATE_START;
|
||||||
return Database::getInstance().beginTransaction();
|
return Database::getInstance()->beginTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool commit() {
|
bool commit() {
|
||||||
@@ -225,15 +226,15 @@ class DBTransaction
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
state = STATE_COMMIT;
|
state = STEATE_COMMIT;
|
||||||
return Database::getInstance().commit();
|
return Database::getInstance()->commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum TransactionStates_t {
|
enum TransactionStates_t {
|
||||||
STATE_NO_START,
|
STATE_NO_START,
|
||||||
STATE_START,
|
STATE_START,
|
||||||
STATE_COMMIT,
|
STEATE_COMMIT,
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionStates_t state = STATE_NO_START;
|
TransactionStates_t state = STATE_NO_START;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -27,11 +27,11 @@ extern ConfigManager g_config;
|
|||||||
|
|
||||||
bool DatabaseManager::optimizeTables()
|
bool DatabaseManager::optimizeTables()
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
|
|
||||||
query << "SELECT `TABLE_NAME` FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` = " << db.escapeString(g_config.getString(ConfigManager::MYSQL_DB)) << " AND `DATA_FREE` > 0";
|
query << "SELECT `TABLE_NAME` FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA` = " << db->escapeString(g_config.getString(ConfigManager::MYSQL_DB)) << " AND `DATA_FREE` > 0";
|
||||||
DBResult_ptr result = db.storeQuery(query.str());
|
DBResult_ptr result = db->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ bool DatabaseManager::optimizeTables()
|
|||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "OPTIMIZE TABLE `" << tableName << '`';
|
query << "OPTIMIZE TABLE `" << tableName << '`';
|
||||||
|
|
||||||
if (db.executeQuery(query.str())) {
|
if (db->executeQuery(query.str())) {
|
||||||
std::cout << " [success]" << std::endl;
|
std::cout << " [success]" << std::endl;
|
||||||
} else {
|
} else {
|
||||||
std::cout << " [failed]" << std::endl;
|
std::cout << " [failed]" << std::endl;
|
||||||
@@ -54,27 +54,27 @@ bool DatabaseManager::optimizeTables()
|
|||||||
|
|
||||||
bool DatabaseManager::tableExists(const std::string& tableName)
|
bool DatabaseManager::tableExists(const std::string& tableName)
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = " << db.escapeString(g_config.getString(ConfigManager::MYSQL_DB)) << " AND `TABLE_NAME` = " << db.escapeString(tableName) << " LIMIT 1";
|
query << "SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = " << db->escapeString(g_config.getString(ConfigManager::MYSQL_DB)) << " AND `TABLE_NAME` = " << db->escapeString(tableName) << " LIMIT 1";
|
||||||
return db.storeQuery(query.str()).get() != nullptr;
|
return db->storeQuery(query.str()).get() != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DatabaseManager::isDatabaseSetup()
|
bool DatabaseManager::isDatabaseSetup()
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = " << db.escapeString(g_config.getString(ConfigManager::MYSQL_DB));
|
query << "SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = " << db->escapeString(g_config.getString(ConfigManager::MYSQL_DB));
|
||||||
return db.storeQuery(query.str()).get() != nullptr;
|
return db->storeQuery(query.str()).get() != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t DatabaseManager::getDatabaseVersion()
|
int32_t DatabaseManager::getDatabaseVersion()
|
||||||
{
|
{
|
||||||
if (!tableExists("server_config")) {
|
if (!tableExists("server_config")) {
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
db.executeQuery("CREATE TABLE `server_config` (`config` VARCHAR(50) NOT NULL, `value` VARCHAR(256) NOT NULL DEFAULT '', UNIQUE(`config`)) ENGINE = InnoDB");
|
db->executeQuery("CREATE TABLE `server_config` (`config` VARCHAR(50) NOT NULL, `value` VARCHAR(256) NOT NULL DEFAULT '', UNIQUE(`config`)) ENGINE = InnoDB");
|
||||||
db.executeQuery("INSERT INTO `server_config` VALUES ('db_version', 0)");
|
db->executeQuery("INSERT INTO `server_config` VALUES ('db_version', 0)");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,68 +85,13 @@ int32_t DatabaseManager::getDatabaseVersion()
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseManager::updateDatabase()
|
|
||||||
{
|
|
||||||
lua_State* L = luaL_newstate();
|
|
||||||
if (!L) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
luaL_openlibs(L);
|
|
||||||
|
|
||||||
#ifndef LUAJIT_VERSION
|
|
||||||
//bit operations for Lua, based on bitlib project release 24
|
|
||||||
//bit.bnot, bit.band, bit.bor, bit.bxor, bit.lshift, bit.rshift
|
|
||||||
luaL_register(L, "bit", LuaScriptInterface::luaBitReg);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//db table
|
|
||||||
luaL_register(L, "db", LuaScriptInterface::luaDatabaseTable);
|
|
||||||
|
|
||||||
//result table
|
|
||||||
luaL_register(L, "result", LuaScriptInterface::luaResultTable);
|
|
||||||
|
|
||||||
int32_t version = getDatabaseVersion();
|
|
||||||
do {
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << "data/migrations/" << version << ".lua";
|
|
||||||
if (luaL_dofile(L, ss.str().c_str()) != 0) {
|
|
||||||
std::cout << "[Error - DatabaseManager::updateDatabase - Version: " << version << "] " << lua_tostring(L, -1) << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!LuaScriptInterface::reserveScriptEnv()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_getglobal(L, "onUpdateDatabase");
|
|
||||||
if (lua_pcall(L, 0, 1, 0) != 0) {
|
|
||||||
LuaScriptInterface::resetScriptEnv();
|
|
||||||
std::cout << "[Error - DatabaseManager::updateDatabase - Version: " << version << "] " << lua_tostring(L, -1) << std::endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!LuaScriptInterface::getBoolean(L, -1, false)) {
|
|
||||||
LuaScriptInterface::resetScriptEnv();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
version++;
|
|
||||||
std::cout << "> Database has been updated to version " << version << '.' << std::endl;
|
|
||||||
registerDatabaseConfig("db_version", version);
|
|
||||||
|
|
||||||
LuaScriptInterface::resetScriptEnv();
|
|
||||||
} while (true);
|
|
||||||
lua_close(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DatabaseManager::getDatabaseConfig(const std::string& config, int32_t& value)
|
bool DatabaseManager::getDatabaseConfig(const std::string& config, int32_t& value)
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `value` FROM `server_config` WHERE `config` = " << db.escapeString(config);
|
query << "SELECT `value` FROM `server_config` WHERE `config` = " << db->escapeString(config);
|
||||||
|
|
||||||
DBResult_ptr result = db.storeQuery(query.str());
|
DBResult_ptr result = db->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -157,16 +102,16 @@ bool DatabaseManager::getDatabaseConfig(const std::string& config, int32_t& valu
|
|||||||
|
|
||||||
void DatabaseManager::registerDatabaseConfig(const std::string& config, int32_t value)
|
void DatabaseManager::registerDatabaseConfig(const std::string& config, int32_t value)
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
|
|
||||||
int32_t tmp;
|
int32_t tmp;
|
||||||
|
|
||||||
if (!getDatabaseConfig(config, tmp)) {
|
if (!getDatabaseConfig(config, tmp)) {
|
||||||
query << "INSERT INTO `server_config` VALUES (" << db.escapeString(config) << ", '" << value << "')";
|
query << "INSERT INTO `server_config` VALUES (" << db->escapeString(config) << ", '" << value << "')";
|
||||||
} else {
|
} else {
|
||||||
query << "UPDATE `server_config` SET `value` = '" << value << "' WHERE `config` = " << db.escapeString(config);
|
query << "UPDATE `server_config` SET `value` = '" << value << "' WHERE `config` = " << db->escapeString(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
db.executeQuery(query.str());
|
db->executeQuery(query.str());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,13 +24,12 @@
|
|||||||
class DatabaseManager
|
class DatabaseManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static bool tableExists(const std::string& tableName);
|
static bool tableExists(const std::string& table);
|
||||||
|
|
||||||
static int32_t getDatabaseVersion();
|
static int32_t getDatabaseVersion();
|
||||||
static bool isDatabaseSetup();
|
static bool isDatabaseSetup();
|
||||||
|
|
||||||
static bool optimizeTables();
|
static bool optimizeTables();
|
||||||
static void updateDatabase();
|
|
||||||
|
|
||||||
static bool getDatabaseConfig(const std::string& config, int32_t& value);
|
static bool getDatabaseConfig(const std::string& config, int32_t& value);
|
||||||
static void registerDatabaseConfig(const std::string& config, int32_t value);
|
static void registerDatabaseConfig(const std::string& config, int32_t value);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -51,13 +51,13 @@ void DatabaseTasks::threadMain()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseTasks::addTask(std::string query, std::function<void(DBResult_ptr, bool)> callback/* = nullptr*/, bool store/* = false*/)
|
void DatabaseTasks::addTask(const std::string& query, const std::function<void(DBResult_ptr, bool)>& callback/* = nullptr*/, bool store/* = false*/)
|
||||||
{
|
{
|
||||||
bool signal = false;
|
bool signal = false;
|
||||||
taskLock.lock();
|
taskLock.lock();
|
||||||
if (getState() == THREAD_STATE_RUNNING) {
|
if (getState() == THREAD_STATE_RUNNING) {
|
||||||
signal = tasks.empty();
|
signal = tasks.empty();
|
||||||
tasks.emplace_back(std::move(query), std::move(callback), store);
|
tasks.emplace_back(query, callback, store);
|
||||||
}
|
}
|
||||||
taskLock.unlock();
|
taskLock.unlock();
|
||||||
|
|
||||||
@@ -85,13 +85,9 @@ void DatabaseTasks::runTask(const DatabaseTask& task)
|
|||||||
|
|
||||||
void DatabaseTasks::flush()
|
void DatabaseTasks::flush()
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> guard{ taskLock };
|
|
||||||
while (!tasks.empty()) {
|
while (!tasks.empty()) {
|
||||||
auto task = std::move(tasks.front());
|
runTask(tasks.front());
|
||||||
tasks.pop_front();
|
tasks.pop_front();
|
||||||
guard.unlock();
|
|
||||||
runTask(task);
|
|
||||||
guard.lock();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +95,7 @@ void DatabaseTasks::shutdown()
|
|||||||
{
|
{
|
||||||
taskLock.lock();
|
taskLock.lock();
|
||||||
setState(THREAD_STATE_TERMINATED);
|
setState(THREAD_STATE_TERMINATED);
|
||||||
taskLock.unlock();
|
|
||||||
flush();
|
flush();
|
||||||
|
taskLock.unlock();
|
||||||
taskSignal.notify_one();
|
taskSignal.notify_one();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
#include "enums.h"
|
#include "enums.h"
|
||||||
|
|
||||||
struct DatabaseTask {
|
struct DatabaseTask {
|
||||||
DatabaseTask(std::string&& query, std::function<void(DBResult_ptr, bool)>&& callback, bool store) :
|
DatabaseTask(std::string query, std::function<void(DBResult_ptr, bool)> callback, bool store) :
|
||||||
query(std::move(query)), callback(std::move(callback)), store(store) {}
|
query(std::move(query)), callback(std::move(callback)), store(store) {}
|
||||||
|
|
||||||
std::string query;
|
std::string query;
|
||||||
@@ -42,7 +42,7 @@ class DatabaseTasks : public ThreadHolder<DatabaseTasks>
|
|||||||
void flush();
|
void flush();
|
||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
void addTask(std::string query, std::function<void(DBResult_ptr, bool)> callback = nullptr, bool store = false);
|
void addTask(const std::string& query, const std::function<void(DBResult_ptr, bool)>& callback = nullptr, bool store = false);
|
||||||
|
|
||||||
void threadMain();
|
void threadMain();
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -20,13 +20,13 @@
|
|||||||
#ifndef FS_DEFINITIONS_H_877452FEC245450C9F96B8FD268D8963
|
#ifndef FS_DEFINITIONS_H_877452FEC245450C9F96B8FD268D8963
|
||||||
#define FS_DEFINITIONS_H_877452FEC245450C9F96B8FD268D8963
|
#define FS_DEFINITIONS_H_877452FEC245450C9F96B8FD268D8963
|
||||||
|
|
||||||
static constexpr auto STATUS_SERVER_NAME = "The Forgotten Server";
|
static constexpr auto STATUS_SERVER_NAME = "Sabrehaven";
|
||||||
static constexpr auto STATUS_SERVER_VERSION = "1.3";
|
static constexpr auto STATUS_SERVER_VERSION = "1.0";
|
||||||
static constexpr auto STATUS_SERVER_DEVELOPERS = "Mark Samman";
|
static constexpr auto STATUS_SERVER_DEVELOPERS = "OTLand community & Sabrehaven Developers Team";
|
||||||
|
|
||||||
static constexpr auto CLIENT_VERSION_MIN = 1097;
|
static constexpr auto CLIENT_VERSION_MIN = 781;
|
||||||
static constexpr auto CLIENT_VERSION_MAX = 1098;
|
static constexpr auto CLIENT_VERSION_MAX = 781;
|
||||||
static constexpr auto CLIENT_VERSION_STR = "10.98";
|
static constexpr auto CLIENT_VERSION_STR = "7.81";
|
||||||
|
|
||||||
static constexpr auto AUTHENTICATOR_DIGITS = 6U;
|
static constexpr auto AUTHENTICATOR_DIGITS = 6U;
|
||||||
static constexpr auto AUTHENTICATOR_PERIOD = 30U;
|
static constexpr auto AUTHENTICATOR_PERIOD = 30U;
|
||||||
@@ -60,6 +60,7 @@ static constexpr auto AUTHENTICATOR_PERIOD = 30U;
|
|||||||
#pragma warning(disable:4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
|
#pragma warning(disable:4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
|
||||||
#pragma warning(disable:4351) // new behavior: elements of array will be default initialized
|
#pragma warning(disable:4351) // new behavior: elements of array will be default initialized
|
||||||
#pragma warning(disable:4458) // declaration hides class member
|
#pragma warning(disable:4458) // declaration hides class member
|
||||||
|
#pragma warning(disable:4996) // inetpton warning
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define strcasecmp _stricmp
|
#define strcasecmp _stricmp
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
/**
|
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "otpch.h"
|
|
||||||
|
|
||||||
#include "depotchest.h"
|
|
||||||
#include "tools.h"
|
|
||||||
|
|
||||||
DepotChest::DepotChest(uint16_t type) :
|
|
||||||
Container(type), maxDepotItems(1500) {}
|
|
||||||
|
|
||||||
ReturnValue DepotChest::queryAdd(int32_t index, const Thing& thing, uint32_t count,
|
|
||||||
uint32_t flags, Creature* actor/* = nullptr*/) const
|
|
||||||
{
|
|
||||||
const Item* item = thing.getItem();
|
|
||||||
if (item == nullptr) {
|
|
||||||
return RETURNVALUE_NOTPOSSIBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool skipLimit = hasBitSet(FLAG_NOLIMIT, flags);
|
|
||||||
if (!skipLimit) {
|
|
||||||
int32_t addCount = 0;
|
|
||||||
|
|
||||||
if ((item->isStackable() && item->getItemCount() != count)) {
|
|
||||||
addCount = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->getTopParent() != this) {
|
|
||||||
if (const Container* container = item->getContainer()) {
|
|
||||||
addCount = container->getItemHoldingCount() + 1;
|
|
||||||
} else {
|
|
||||||
addCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getItemHoldingCount() + addCount > maxDepotItems) {
|
|
||||||
return RETURNVALUE_DEPOTISFULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Container::queryAdd(index, thing, count, flags, actor);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DepotChest::postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t)
|
|
||||||
{
|
|
||||||
Cylinder* parent = getParent();
|
|
||||||
if (parent != nullptr) {
|
|
||||||
parent->postAddNotification(thing, oldParent, index, LINK_PARENT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DepotChest::postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t)
|
|
||||||
{
|
|
||||||
Cylinder* parent = getParent();
|
|
||||||
if (parent != nullptr) {
|
|
||||||
parent->postRemoveNotification(thing, newParent, index, LINK_PARENT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Cylinder* DepotChest::getParent() const
|
|
||||||
{
|
|
||||||
if (parent) {
|
|
||||||
return parent->getParent();
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
/**
|
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FS_DEPOTCHEST_H_6538526014684E3DBC92CC12815B6766
|
|
||||||
#define FS_DEPOTCHEST_H_6538526014684E3DBC92CC12815B6766
|
|
||||||
|
|
||||||
#include "container.h"
|
|
||||||
|
|
||||||
class DepotChest final : public Container
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit DepotChest(uint16_t type);
|
|
||||||
|
|
||||||
//serialization
|
|
||||||
void setMaxDepotItems(uint32_t maxitems) {
|
|
||||||
maxDepotItems = maxitems;
|
|
||||||
}
|
|
||||||
|
|
||||||
//cylinder implementations
|
|
||||||
ReturnValue queryAdd(int32_t index, const Thing& thing, uint32_t count,
|
|
||||||
uint32_t flags, Creature* actor = nullptr) const override;
|
|
||||||
|
|
||||||
void postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
|
|
||||||
void postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
|
|
||||||
|
|
||||||
//overrides
|
|
||||||
bool canRemove() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Cylinder* getParent() const override;
|
|
||||||
Cylinder* getRealParent() const override {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint32_t maxDepotItems;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -20,9 +20,12 @@
|
|||||||
#include "otpch.h"
|
#include "otpch.h"
|
||||||
|
|
||||||
#include "depotlocker.h"
|
#include "depotlocker.h"
|
||||||
|
#include "creature.h"
|
||||||
|
#include "player.h"
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
DepotLocker::DepotLocker(uint16_t type) :
|
DepotLocker::DepotLocker(uint16_t type) :
|
||||||
Container(type, 3), depotId(0) {}
|
Container(type, 30), depotId(0) {}
|
||||||
|
|
||||||
Attr_ReadValue DepotLocker::readAttr(AttrTypes_t attr, PropStream& propStream)
|
Attr_ReadValue DepotLocker::readAttr(AttrTypes_t attr, PropStream& propStream)
|
||||||
{
|
{
|
||||||
@@ -35,9 +38,40 @@ Attr_ReadValue DepotLocker::readAttr(AttrTypes_t attr, PropStream& propStream)
|
|||||||
return Item::readAttr(attr, propStream);
|
return Item::readAttr(attr, propStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue DepotLocker::queryAdd(int32_t, const Thing&, uint32_t, uint32_t, Creature*) const
|
ReturnValue DepotLocker::queryAdd(int32_t index, const Thing& thing, uint32_t count, uint32_t flags, Creature* actor) const
|
||||||
{
|
{
|
||||||
return RETURNVALUE_NOTENOUGHROOM;
|
const Item* item = thing.getItem();
|
||||||
|
if (item == nullptr) {
|
||||||
|
return RETURNVALUE_NOTPOSSIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool skipLimit = hasBitSet(FLAG_NOLIMIT, flags);
|
||||||
|
if (!skipLimit) {
|
||||||
|
int32_t addCount = 0;
|
||||||
|
|
||||||
|
if ((item->isStackable() && item->getItemCount() != count)) {
|
||||||
|
addCount = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item->getTopParent() != this) {
|
||||||
|
if (const Container* container = item->getContainer()) {
|
||||||
|
addCount = container->getItemHoldingCount() + 1;
|
||||||
|
} else {
|
||||||
|
addCount = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actor) {
|
||||||
|
Player* player = actor->getPlayer();
|
||||||
|
if (player) {
|
||||||
|
if (getItemHoldingCount() + addCount > player->getMaxDepotItems()) {
|
||||||
|
return RETURNVALUE_DEPOTISFULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container::queryAdd(index, thing, count, flags, actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DepotLocker::postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t)
|
void DepotLocker::postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t)
|
||||||
@@ -53,12 +87,3 @@ void DepotLocker::postRemoveNotification(Thing* thing, const Cylinder* newParent
|
|||||||
parent->postRemoveNotification(thing, newParent, index, LINK_PARENT);
|
parent->postRemoveNotification(thing, newParent, index, LINK_PARENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DepotLocker::removeInbox(Inbox* inbox)
|
|
||||||
{
|
|
||||||
auto cit = std::find(itemlist.begin(), itemlist.end(), inbox);
|
|
||||||
if (cit == itemlist.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
itemlist.erase(cit);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,24 +21,21 @@
|
|||||||
#define FS_DEPOTLOCKER_H_53AD8E0606A34070B87F792611F4F3F8
|
#define FS_DEPOTLOCKER_H_53AD8E0606A34070B87F792611F4F3F8
|
||||||
|
|
||||||
#include "container.h"
|
#include "container.h"
|
||||||
#include "inbox.h"
|
|
||||||
|
|
||||||
class DepotLocker final : public Container
|
class DepotLocker final : public Container
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit DepotLocker(uint16_t type);
|
explicit DepotLocker(uint16_t type);
|
||||||
|
|
||||||
DepotLocker* getDepotLocker() override {
|
DepotLocker* getDepotLocker() final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
const DepotLocker* getDepotLocker() const override {
|
const DepotLocker* getDepotLocker() const final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeInbox(Inbox* inbox);
|
|
||||||
|
|
||||||
//serialization
|
//serialization
|
||||||
Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream) override;
|
Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream) final;
|
||||||
|
|
||||||
uint16_t getDepotId() const {
|
uint16_t getDepotId() const {
|
||||||
return depotId;
|
return depotId;
|
||||||
@@ -49,12 +46,12 @@ class DepotLocker final : public Container
|
|||||||
|
|
||||||
//cylinder implementations
|
//cylinder implementations
|
||||||
ReturnValue queryAdd(int32_t index, const Thing& thing, uint32_t count,
|
ReturnValue queryAdd(int32_t index, const Thing& thing, uint32_t count,
|
||||||
uint32_t flags, Creature* actor = nullptr) const override;
|
uint32_t flags, Creature* actor = nullptr) const final;
|
||||||
|
|
||||||
void postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
|
void postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link = LINK_OWNER) final;
|
||||||
void postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
|
void postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t link = LINK_OWNER) final;
|
||||||
|
|
||||||
bool canRemove() const override {
|
bool canRemove() const final {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
356
src/enums.h
356
src/enums.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -20,43 +20,6 @@
|
|||||||
#ifndef FS_ENUMS_H_003445999FEE4A67BCECBE918B0124CE
|
#ifndef FS_ENUMS_H_003445999FEE4A67BCECBE918B0124CE
|
||||||
#define FS_ENUMS_H_003445999FEE4A67BCECBE918B0124CE
|
#define FS_ENUMS_H_003445999FEE4A67BCECBE918B0124CE
|
||||||
|
|
||||||
enum RuleViolationType_t : uint8_t {
|
|
||||||
REPORT_TYPE_NAME = 0,
|
|
||||||
REPORT_TYPE_STATEMENT = 1,
|
|
||||||
REPORT_TYPE_BOT = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
enum RuleViolationReasons_t : uint8_t {
|
|
||||||
REPORT_REASON_NAMEINAPPROPRIATE = 0,
|
|
||||||
REPORT_REASON_NAMEPOORFORMATTED = 1,
|
|
||||||
REPORT_REASON_NAMEADVERTISING = 2,
|
|
||||||
REPORT_REASON_NAMEUNFITTING = 3,
|
|
||||||
REPORT_REASON_NAMERULEVIOLATION = 4,
|
|
||||||
REPORT_REASON_INSULTINGSTATEMENT = 5,
|
|
||||||
REPORT_REASON_SPAMMING = 6,
|
|
||||||
REPORT_REASON_ADVERTISINGSTATEMENT = 7,
|
|
||||||
REPORT_REASON_UNFITTINGSTATEMENT = 8,
|
|
||||||
REPORT_REASON_LANGUAGESTATEMENT = 9,
|
|
||||||
REPORT_REASON_DISCLOSURE = 10,
|
|
||||||
REPORT_REASON_RULEVIOLATION = 11,
|
|
||||||
REPORT_REASON_STATEMENT_BUGABUSE = 12,
|
|
||||||
REPORT_REASON_UNOFFICIALSOFTWARE = 13,
|
|
||||||
REPORT_REASON_PRETENDING = 14,
|
|
||||||
REPORT_REASON_HARASSINGOWNERS = 15,
|
|
||||||
REPORT_REASON_FALSEINFO = 16,
|
|
||||||
REPORT_REASON_ACCOUNTSHARING = 17,
|
|
||||||
REPORT_REASON_STEALINGDATA = 18,
|
|
||||||
REPORT_REASON_SERVICEATTACKING = 19,
|
|
||||||
REPORT_REASON_SERVICEAGREEMENT = 20
|
|
||||||
};
|
|
||||||
|
|
||||||
enum BugReportType_t : uint8_t {
|
|
||||||
BUG_CATEGORY_MAP = 0,
|
|
||||||
BUG_CATEGORY_TYPO = 1,
|
|
||||||
BUG_CATEGORY_TECHNICAL = 2,
|
|
||||||
BUG_CATEGORY_OTHER = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ThreadState {
|
enum ThreadState {
|
||||||
THREAD_STATE_RUNNING,
|
THREAD_STATE_RUNNING,
|
||||||
THREAD_STATE_CLOSING,
|
THREAD_STATE_CLOSING,
|
||||||
@@ -67,7 +30,7 @@ enum itemAttrTypes : uint32_t {
|
|||||||
ITEM_ATTRIBUTE_NONE,
|
ITEM_ATTRIBUTE_NONE,
|
||||||
|
|
||||||
ITEM_ATTRIBUTE_ACTIONID = 1 << 0,
|
ITEM_ATTRIBUTE_ACTIONID = 1 << 0,
|
||||||
ITEM_ATTRIBUTE_UNIQUEID = 1 << 1,
|
ITEM_ATTRIBUTE_MOVEMENTID = 1 << 1,
|
||||||
ITEM_ATTRIBUTE_DESCRIPTION = 1 << 2,
|
ITEM_ATTRIBUTE_DESCRIPTION = 1 << 2,
|
||||||
ITEM_ATTRIBUTE_TEXT = 1 << 3,
|
ITEM_ATTRIBUTE_TEXT = 1 << 3,
|
||||||
ITEM_ATTRIBUTE_DATE = 1 << 4,
|
ITEM_ATTRIBUTE_DATE = 1 << 4,
|
||||||
@@ -78,60 +41,26 @@ enum itemAttrTypes : uint32_t {
|
|||||||
ITEM_ATTRIBUTE_WEIGHT = 1 << 9,
|
ITEM_ATTRIBUTE_WEIGHT = 1 << 9,
|
||||||
ITEM_ATTRIBUTE_ATTACK = 1 << 10,
|
ITEM_ATTRIBUTE_ATTACK = 1 << 10,
|
||||||
ITEM_ATTRIBUTE_DEFENSE = 1 << 11,
|
ITEM_ATTRIBUTE_DEFENSE = 1 << 11,
|
||||||
ITEM_ATTRIBUTE_EXTRADEFENSE = 1 << 12,
|
ITEM_ATTRIBUTE_ARMOR = 1 << 12,
|
||||||
ITEM_ATTRIBUTE_ARMOR = 1 << 13,
|
ITEM_ATTRIBUTE_SHOOTRANGE = 1 << 13,
|
||||||
ITEM_ATTRIBUTE_HITCHANCE = 1 << 14,
|
ITEM_ATTRIBUTE_OWNER = 1 << 14,
|
||||||
ITEM_ATTRIBUTE_SHOOTRANGE = 1 << 15,
|
ITEM_ATTRIBUTE_DURATION = 1 << 15,
|
||||||
ITEM_ATTRIBUTE_OWNER = 1 << 16,
|
ITEM_ATTRIBUTE_DECAYSTATE = 1 << 16,
|
||||||
ITEM_ATTRIBUTE_DURATION = 1 << 17,
|
ITEM_ATTRIBUTE_CORPSEOWNER = 1 << 17,
|
||||||
ITEM_ATTRIBUTE_DECAYSTATE = 1 << 18,
|
ITEM_ATTRIBUTE_CHARGES = 1 << 18,
|
||||||
ITEM_ATTRIBUTE_CORPSEOWNER = 1 << 19,
|
ITEM_ATTRIBUTE_FLUIDTYPE = 1 << 19,
|
||||||
ITEM_ATTRIBUTE_CHARGES = 1 << 20,
|
ITEM_ATTRIBUTE_DOORID = 1 << 20,
|
||||||
ITEM_ATTRIBUTE_FLUIDTYPE = 1 << 21,
|
ITEM_ATTRIBUTE_KEYNUMBER = 1 << 21,
|
||||||
ITEM_ATTRIBUTE_DOORID = 1 << 22,
|
ITEM_ATTRIBUTE_KEYHOLENUMBER = 1 << 22,
|
||||||
ITEM_ATTRIBUTE_DECAYTO = 1 << 23,
|
ITEM_ATTRIBUTE_DOORQUESTNUMBER = 1 << 23,
|
||||||
|
ITEM_ATTRIBUTE_DOORQUESTVALUE = 1 << 24,
|
||||||
ITEM_ATTRIBUTE_CUSTOM = 1U << 31
|
ITEM_ATTRIBUTE_DOORLEVEL = 1 << 25,
|
||||||
|
ITEM_ATTRIBUTE_CHESTQUESTNUMBER = 1 << 26,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum VipStatus_t : uint8_t {
|
enum VipStatus_t : uint8_t {
|
||||||
VIPSTATUS_OFFLINE = 0,
|
VIPSTATUS_OFFLINE = 0,
|
||||||
VIPSTATUS_ONLINE = 1,
|
VIPSTATUS_ONLINE = 1,
|
||||||
VIPSTATUS_PENDING = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
enum MarketAction_t {
|
|
||||||
MARKETACTION_BUY = 0,
|
|
||||||
MARKETACTION_SELL = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum MarketRequest_t {
|
|
||||||
MARKETREQUEST_OWN_OFFERS = 0xFFFE,
|
|
||||||
MARKETREQUEST_OWN_HISTORY = 0xFFFF,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum MarketOfferState_t {
|
|
||||||
OFFERSTATE_ACTIVE = 0,
|
|
||||||
OFFERSTATE_CANCELLED = 1,
|
|
||||||
OFFERSTATE_EXPIRED = 2,
|
|
||||||
OFFERSTATE_ACCEPTED = 3,
|
|
||||||
|
|
||||||
OFFERSTATE_ACCEPTEDEX = 255,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ChannelEvent_t : uint8_t {
|
|
||||||
CHANNELEVENT_JOIN = 0,
|
|
||||||
CHANNELEVENT_LEAVE = 1,
|
|
||||||
CHANNELEVENT_INVITE = 2,
|
|
||||||
CHANNELEVENT_EXCLUDE = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum CreatureType_t : uint8_t {
|
|
||||||
CREATURETYPE_PLAYER = 0,
|
|
||||||
CREATURETYPE_MONSTER = 1,
|
|
||||||
CREATURETYPE_NPC = 2,
|
|
||||||
CREATURETYPE_SUMMON_OWN = 3,
|
|
||||||
CREATURETYPE_SUMMON_OTHERS = 4,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum OperatingSystem_t : uint8_t {
|
enum OperatingSystem_t : uint8_t {
|
||||||
@@ -146,20 +75,6 @@ enum OperatingSystem_t : uint8_t {
|
|||||||
CLIENTOS_OTCLIENT_MAC = 12,
|
CLIENTOS_OTCLIENT_MAC = 12,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SpellGroup_t : uint8_t {
|
|
||||||
SPELLGROUP_NONE = 0,
|
|
||||||
SPELLGROUP_ATTACK = 1,
|
|
||||||
SPELLGROUP_HEALING = 2,
|
|
||||||
SPELLGROUP_SUPPORT = 3,
|
|
||||||
SPELLGROUP_SPECIAL = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SpellType_t : uint8_t {
|
|
||||||
SPELL_UNDEFINED = 0,
|
|
||||||
SPELL_INSTANT = 1,
|
|
||||||
SPELL_RUNE = 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum AccountType_t : uint8_t {
|
enum AccountType_t : uint8_t {
|
||||||
ACCOUNT_TYPE_NORMAL = 1,
|
ACCOUNT_TYPE_NORMAL = 1,
|
||||||
ACCOUNT_TYPE_TUTOR = 2,
|
ACCOUNT_TYPE_TUTOR = 2,
|
||||||
@@ -174,7 +89,6 @@ enum RaceType_t : uint8_t {
|
|||||||
RACE_BLOOD,
|
RACE_BLOOD,
|
||||||
RACE_UNDEAD,
|
RACE_UNDEAD,
|
||||||
RACE_FIRE,
|
RACE_FIRE,
|
||||||
RACE_ENERGY,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CombatType_t : uint16_t {
|
enum CombatType_t : uint16_t {
|
||||||
@@ -189,11 +103,8 @@ enum CombatType_t : uint16_t {
|
|||||||
COMBAT_MANADRAIN = 1 << 6,
|
COMBAT_MANADRAIN = 1 << 6,
|
||||||
COMBAT_HEALING = 1 << 7,
|
COMBAT_HEALING = 1 << 7,
|
||||||
COMBAT_DROWNDAMAGE = 1 << 8,
|
COMBAT_DROWNDAMAGE = 1 << 8,
|
||||||
COMBAT_ICEDAMAGE = 1 << 9,
|
|
||||||
COMBAT_HOLYDAMAGE = 1 << 10,
|
|
||||||
COMBAT_DEATHDAMAGE = 1 << 11,
|
|
||||||
|
|
||||||
COMBAT_COUNT = 12
|
COMBAT_COUNT = 10
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CombatParam_t {
|
enum CombatParam_t {
|
||||||
@@ -207,6 +118,14 @@ enum CombatParam_t {
|
|||||||
COMBAT_PARAM_AGGRESSIVE,
|
COMBAT_PARAM_AGGRESSIVE,
|
||||||
COMBAT_PARAM_DISPEL,
|
COMBAT_PARAM_DISPEL,
|
||||||
COMBAT_PARAM_USECHARGES,
|
COMBAT_PARAM_USECHARGES,
|
||||||
|
COMBAT_PARAM_DECREASEDAMAGE,
|
||||||
|
COMBAT_PARAM_MAXIMUMDECREASEDDAMAGE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum fightMode_t : uint8_t {
|
||||||
|
FIGHTMODE_ATTACK = 1,
|
||||||
|
FIGHTMODE_BALANCED = 2,
|
||||||
|
FIGHTMODE_DEFENSE = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CallBackParam_t {
|
enum CallBackParam_t {
|
||||||
@@ -234,7 +153,6 @@ enum ConditionParam_t {
|
|||||||
CONDITION_PARAM_MAXVALUE = 15,
|
CONDITION_PARAM_MAXVALUE = 15,
|
||||||
CONDITION_PARAM_STARTVALUE = 16,
|
CONDITION_PARAM_STARTVALUE = 16,
|
||||||
CONDITION_PARAM_TICKINTERVAL = 17,
|
CONDITION_PARAM_TICKINTERVAL = 17,
|
||||||
CONDITION_PARAM_FORCEUPDATE = 18,
|
|
||||||
CONDITION_PARAM_SKILL_MELEE = 19,
|
CONDITION_PARAM_SKILL_MELEE = 19,
|
||||||
CONDITION_PARAM_SKILL_FIST = 20,
|
CONDITION_PARAM_SKILL_FIST = 20,
|
||||||
CONDITION_PARAM_SKILL_CLUB = 21,
|
CONDITION_PARAM_SKILL_CLUB = 21,
|
||||||
@@ -260,16 +178,13 @@ enum ConditionParam_t {
|
|||||||
CONDITION_PARAM_SKILL_DISTANCEPERCENT = 41,
|
CONDITION_PARAM_SKILL_DISTANCEPERCENT = 41,
|
||||||
CONDITION_PARAM_SKILL_SHIELDPERCENT = 42,
|
CONDITION_PARAM_SKILL_SHIELDPERCENT = 42,
|
||||||
CONDITION_PARAM_SKILL_FISHINGPERCENT = 43,
|
CONDITION_PARAM_SKILL_FISHINGPERCENT = 43,
|
||||||
CONDITION_PARAM_BUFF_SPELL = 44,
|
// CONDITION_PARAM_BUFF_SPELL = 44,
|
||||||
CONDITION_PARAM_SUBID = 45,
|
CONDITION_PARAM_SUBID = 45,
|
||||||
CONDITION_PARAM_FIELD = 46,
|
CONDITION_PARAM_FIELD = 46,
|
||||||
CONDITION_PARAM_DISABLE_DEFENSE = 47,
|
CONDITION_PARAM_CYCLE = 47,
|
||||||
CONDITION_PARAM_SPECIALSKILL_CRITICALHITCHANCE = 48,
|
CONDITION_PARAM_HIT_DAMAGE = 48,
|
||||||
CONDITION_PARAM_SPECIALSKILL_CRITICALHITAMOUNT = 49,
|
CONDITION_PARAM_COUNT = 49,
|
||||||
CONDITION_PARAM_SPECIALSKILL_LIFELEECHCHANCE = 50,
|
CONDITION_PARAM_MAX_COUNT = 50,
|
||||||
CONDITION_PARAM_SPECIALSKILL_LIFELEECHAMOUNT = 51,
|
|
||||||
CONDITION_PARAM_SPECIALSKILL_MANALEECHCHANCE = 52,
|
|
||||||
CONDITION_PARAM_SPECIALSKILL_MANALEECHAMOUNT = 53,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BlockType_t : uint8_t {
|
enum BlockType_t : uint8_t {
|
||||||
@@ -305,18 +220,6 @@ enum stats_t {
|
|||||||
STAT_LAST = STAT_MAGICPOINTS
|
STAT_LAST = STAT_MAGICPOINTS
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SpecialSkills_t {
|
|
||||||
SPECIALSKILL_CRITICALHITCHANCE,
|
|
||||||
SPECIALSKILL_CRITICALHITAMOUNT,
|
|
||||||
SPECIALSKILL_LIFELEECHCHANCE,
|
|
||||||
SPECIALSKILL_LIFELEECHAMOUNT,
|
|
||||||
SPECIALSKILL_MANALEECHCHANCE,
|
|
||||||
SPECIALSKILL_MANALEECHAMOUNT,
|
|
||||||
|
|
||||||
SPECIALSKILL_FIRST = SPECIALSKILL_CRITICALHITCHANCE,
|
|
||||||
SPECIALSKILL_LAST = SPECIALSKILL_MANALEECHAMOUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
enum formulaType_t {
|
enum formulaType_t {
|
||||||
COMBAT_FORMULA_UNDEFINED,
|
COMBAT_FORMULA_UNDEFINED,
|
||||||
COMBAT_FORMULA_LEVELMAGIC,
|
COMBAT_FORMULA_LEVELMAGIC,
|
||||||
@@ -330,31 +233,24 @@ enum ConditionType_t {
|
|||||||
CONDITION_POISON = 1 << 0,
|
CONDITION_POISON = 1 << 0,
|
||||||
CONDITION_FIRE = 1 << 1,
|
CONDITION_FIRE = 1 << 1,
|
||||||
CONDITION_ENERGY = 1 << 2,
|
CONDITION_ENERGY = 1 << 2,
|
||||||
CONDITION_BLEEDING = 1 << 3,
|
CONDITION_HASTE = 1 << 3,
|
||||||
CONDITION_HASTE = 1 << 4,
|
CONDITION_PARALYZE = 1 << 4,
|
||||||
CONDITION_PARALYZE = 1 << 5,
|
CONDITION_OUTFIT = 1 << 5,
|
||||||
CONDITION_OUTFIT = 1 << 6,
|
CONDITION_INVISIBLE = 1 << 6,
|
||||||
CONDITION_INVISIBLE = 1 << 7,
|
CONDITION_LIGHT = 1 << 7,
|
||||||
CONDITION_LIGHT = 1 << 8,
|
CONDITION_MANASHIELD = 1 << 8,
|
||||||
CONDITION_MANASHIELD = 1 << 9,
|
CONDITION_INFIGHT = 1 << 9,
|
||||||
CONDITION_INFIGHT = 1 << 10,
|
CONDITION_DRUNK = 1 << 10,
|
||||||
CONDITION_DRUNK = 1 << 11,
|
CONDITION_REGENERATION = 1 << 11,
|
||||||
CONDITION_EXHAUST_WEAPON = 1 << 12, // unused
|
CONDITION_SOUL = 1 << 12,
|
||||||
CONDITION_REGENERATION = 1 << 13,
|
CONDITION_MUTED = 1 << 13,
|
||||||
CONDITION_SOUL = 1 << 14,
|
CONDITION_CHANNELMUTEDTICKS = 1 << 14,
|
||||||
CONDITION_DROWN = 1 << 15,
|
CONDITION_YELLTICKS = 1 << 15,
|
||||||
CONDITION_MUTED = 1 << 16,
|
CONDITION_ATTRIBUTES = 1 << 16,
|
||||||
CONDITION_CHANNELMUTEDTICKS = 1 << 17,
|
CONDITION_EXHAUST = 1 << 17,
|
||||||
CONDITION_YELLTICKS = 1 << 18,
|
CONDITION_PACIFIED = 1 << 18,
|
||||||
CONDITION_ATTRIBUTES = 1 << 19,
|
CONDITION_AGGRESSIVE = 1 << 19,
|
||||||
CONDITION_FREEZING = 1 << 20,
|
CONDITION_DROWN = 1 << 20,
|
||||||
CONDITION_DAZZLED = 1 << 21,
|
|
||||||
CONDITION_CURSED = 1 << 22,
|
|
||||||
CONDITION_EXHAUST_COMBAT = 1 << 23, // unused
|
|
||||||
CONDITION_EXHAUST_HEAL = 1 << 24, // unused
|
|
||||||
CONDITION_PACIFIED = 1 << 25,
|
|
||||||
CONDITION_SPELLCOOLDOWN = 1 << 26,
|
|
||||||
CONDITION_SPELLGROUPCOOLDOWN = 1 << 27,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ConditionId_t : int8_t {
|
enum ConditionId_t : int8_t {
|
||||||
@@ -380,7 +276,11 @@ enum PlayerSex_t : uint8_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum Vocation_t : uint16_t {
|
enum Vocation_t : uint16_t {
|
||||||
VOCATION_NONE = 0
|
VOCATION_NONE,
|
||||||
|
VOCATION_SORCERER = 1 << 0,
|
||||||
|
VOCATION_DRUID = 1 << 1,
|
||||||
|
VOCATION_PALADIN = 1 << 2,
|
||||||
|
VOCATION_KNIGHT = 1 << 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ReturnValue {
|
enum ReturnValue {
|
||||||
@@ -443,12 +343,10 @@ enum ReturnValue {
|
|||||||
RETURNVALUE_YOUNEEDAMAGICITEMTOCASTSPELL,
|
RETURNVALUE_YOUNEEDAMAGICITEMTOCASTSPELL,
|
||||||
RETURNVALUE_CANNOTCONJUREITEMHERE,
|
RETURNVALUE_CANNOTCONJUREITEMHERE,
|
||||||
RETURNVALUE_YOUNEEDTOSPLITYOURSPEARS,
|
RETURNVALUE_YOUNEEDTOSPLITYOURSPEARS,
|
||||||
RETURNVALUE_NAMEISTOOAMBIGUOUS,
|
RETURNVALUE_NAMEISTOOAMBIGIOUS,
|
||||||
RETURNVALUE_CANONLYUSEONESHIELD,
|
RETURNVALUE_CANONLYUSEONESHIELD,
|
||||||
RETURNVALUE_NOPARTYMEMBERSINRANGE,
|
RETURNVALUE_NOPARTYMEMBERSINRANGE,
|
||||||
RETURNVALUE_YOUARENOTTHEOWNER,
|
RETURNVALUE_YOUARENOTTHEOWNER,
|
||||||
RETURNVALUE_NOSUCHRAIDEXISTS,
|
|
||||||
RETURNVALUE_ANOTHERRAIDISALREADYEXECUTING,
|
|
||||||
RETURNVALUE_TRADEPLAYERFARAWAY,
|
RETURNVALUE_TRADEPLAYERFARAWAY,
|
||||||
RETURNVALUE_YOUDONTOWNTHISHOUSE,
|
RETURNVALUE_YOUDONTOWNTHISHOUSE,
|
||||||
RETURNVALUE_TRADEPLAYERALREADYOWNSAHOUSE,
|
RETURNVALUE_TRADEPLAYERALREADYOWNSAHOUSE,
|
||||||
@@ -456,43 +354,9 @@ enum ReturnValue {
|
|||||||
RETURNVALUE_YOUCANNOTTRADETHISHOUSE,
|
RETURNVALUE_YOUCANNOTTRADETHISHOUSE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SpeechBubble_t
|
|
||||||
{
|
|
||||||
SPEECHBUBBLE_NONE = 0,
|
|
||||||
SPEECHBUBBLE_NORMAL = 1,
|
|
||||||
SPEECHBUBBLE_TRADE = 2,
|
|
||||||
SPEECHBUBBLE_QUEST = 3,
|
|
||||||
SPEECHBUBBLE_QUESTTRADER = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum MapMark_t
|
|
||||||
{
|
|
||||||
MAPMARK_TICK = 0,
|
|
||||||
MAPMARK_QUESTION = 1,
|
|
||||||
MAPMARK_EXCLAMATION = 2,
|
|
||||||
MAPMARK_STAR = 3,
|
|
||||||
MAPMARK_CROSS = 4,
|
|
||||||
MAPMARK_TEMPLE = 5,
|
|
||||||
MAPMARK_KISS = 6,
|
|
||||||
MAPMARK_SHOVEL = 7,
|
|
||||||
MAPMARK_SWORD = 8,
|
|
||||||
MAPMARK_FLAG = 9,
|
|
||||||
MAPMARK_LOCK = 10,
|
|
||||||
MAPMARK_BAG = 11,
|
|
||||||
MAPMARK_SKULL = 12,
|
|
||||||
MAPMARK_DOLLAR = 13,
|
|
||||||
MAPMARK_REDNORTH = 14,
|
|
||||||
MAPMARK_REDSOUTH = 15,
|
|
||||||
MAPMARK_REDEAST = 16,
|
|
||||||
MAPMARK_REDWEST = 17,
|
|
||||||
MAPMARK_GREENNORTH = 18,
|
|
||||||
MAPMARK_GREENSOUTH = 19,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Outfit_t {
|
struct Outfit_t {
|
||||||
uint16_t lookType = 0;
|
uint16_t lookType = 0;
|
||||||
uint16_t lookTypeEx = 0;
|
uint16_t lookTypeEx = 0;
|
||||||
uint16_t lookMount = 0;
|
|
||||||
uint8_t lookHead = 0;
|
uint8_t lookHead = 0;
|
||||||
uint8_t lookBody = 0;
|
uint8_t lookBody = 0;
|
||||||
uint8_t lookLegs = 0;
|
uint8_t lookLegs = 0;
|
||||||
@@ -507,85 +371,6 @@ struct LightInfo {
|
|||||||
constexpr LightInfo(uint8_t level, uint8_t color) : level(level), color(color) {}
|
constexpr LightInfo(uint8_t level, uint8_t color) : level(level), color(color) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ShopInfo {
|
|
||||||
uint16_t itemId;
|
|
||||||
int32_t subType;
|
|
||||||
uint32_t buyPrice;
|
|
||||||
uint32_t sellPrice;
|
|
||||||
std::string realName;
|
|
||||||
|
|
||||||
ShopInfo() {
|
|
||||||
itemId = 0;
|
|
||||||
subType = 1;
|
|
||||||
buyPrice = 0;
|
|
||||||
sellPrice = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShopInfo(uint16_t itemId, int32_t subType = 0, uint32_t buyPrice = 0, uint32_t sellPrice = 0, std::string realName = "")
|
|
||||||
: itemId(itemId), subType(subType), buyPrice(buyPrice), sellPrice(sellPrice), realName(std::move(realName)) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MarketOffer {
|
|
||||||
uint32_t price;
|
|
||||||
uint32_t timestamp;
|
|
||||||
uint16_t amount;
|
|
||||||
uint16_t counter;
|
|
||||||
uint16_t itemId;
|
|
||||||
std::string playerName;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MarketOfferEx {
|
|
||||||
MarketOfferEx() = default;
|
|
||||||
MarketOfferEx(MarketOfferEx&& other) :
|
|
||||||
id(other.id), playerId(other.playerId), timestamp(other.timestamp), price(other.price),
|
|
||||||
amount(other.amount), counter(other.counter), itemId(other.itemId), type(other.type),
|
|
||||||
playerName(std::move(other.playerName)) {}
|
|
||||||
|
|
||||||
uint32_t id;
|
|
||||||
uint32_t playerId;
|
|
||||||
uint32_t timestamp;
|
|
||||||
uint32_t price;
|
|
||||||
uint16_t amount;
|
|
||||||
uint16_t counter;
|
|
||||||
uint16_t itemId;
|
|
||||||
MarketAction_t type;
|
|
||||||
std::string playerName;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HistoryMarketOffer {
|
|
||||||
uint32_t timestamp;
|
|
||||||
uint32_t price;
|
|
||||||
uint16_t itemId;
|
|
||||||
uint16_t amount;
|
|
||||||
MarketOfferState_t state;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MarketStatistics {
|
|
||||||
MarketStatistics() {
|
|
||||||
numTransactions = 0;
|
|
||||||
highestPrice = 0;
|
|
||||||
totalPrice = 0;
|
|
||||||
lowestPrice = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t numTransactions;
|
|
||||||
uint32_t highestPrice;
|
|
||||||
uint64_t totalPrice;
|
|
||||||
uint32_t lowestPrice;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ModalWindow
|
|
||||||
{
|
|
||||||
std::list<std::pair<std::string, uint8_t>> buttons, choices;
|
|
||||||
std::string title, message;
|
|
||||||
uint32_t id;
|
|
||||||
uint8_t defaultEnterButton, defaultEscapeButton;
|
|
||||||
bool priority;
|
|
||||||
|
|
||||||
ModalWindow(uint32_t id, std::string title, std::string message)
|
|
||||||
: title(std::move(title)), message(std::move(message)), id(id), defaultEnterButton(0xFF), defaultEscapeButton(0xFF), priority(false) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum CombatOrigin
|
enum CombatOrigin
|
||||||
{
|
{
|
||||||
ORIGIN_NONE,
|
ORIGIN_NONE,
|
||||||
@@ -597,31 +382,20 @@ enum CombatOrigin
|
|||||||
|
|
||||||
struct CombatDamage
|
struct CombatDamage
|
||||||
{
|
{
|
||||||
struct {
|
CombatType_t type;
|
||||||
CombatType_t type;
|
int32_t value;
|
||||||
int32_t value;
|
int32_t min;
|
||||||
} primary, secondary;
|
int32_t max;
|
||||||
|
|
||||||
CombatOrigin origin;
|
CombatOrigin origin;
|
||||||
|
|
||||||
CombatDamage()
|
CombatDamage()
|
||||||
{
|
{
|
||||||
origin = ORIGIN_NONE;
|
origin = ORIGIN_NONE;
|
||||||
primary.type = secondary.type = COMBAT_NONE;
|
type = COMBAT_NONE;
|
||||||
primary.value = secondary.value = 0;
|
value = 0;
|
||||||
|
min = 0;
|
||||||
|
max = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using MarketOfferList = std::list<MarketOffer>;
|
|
||||||
using HistoryMarketOfferList = std::list<HistoryMarketOffer>;
|
|
||||||
using ShopInfoList = std::list<ShopInfo>;
|
|
||||||
|
|
||||||
enum MonstersEvent_t : uint8_t {
|
|
||||||
MONSTERS_EVENT_NONE = 0,
|
|
||||||
MONSTERS_EVENT_THINK = 1,
|
|
||||||
MONSTERS_EVENT_APPEAR = 2,
|
|
||||||
MONSTERS_EVENT_DISAPPEAR = 3,
|
|
||||||
MONSTERS_EVENT_MOVE = 4,
|
|
||||||
MONSTERS_EVENT_SAY = 5,
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
430
src/events.cpp
430
src/events.cpp
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* The Forgotten Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2016 Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -29,9 +29,39 @@
|
|||||||
Events::Events() :
|
Events::Events() :
|
||||||
scriptInterface("Event Interface")
|
scriptInterface("Event Interface")
|
||||||
{
|
{
|
||||||
|
clear();
|
||||||
scriptInterface.initState();
|
scriptInterface.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Events::clear()
|
||||||
|
{
|
||||||
|
// Creature
|
||||||
|
creatureOnChangeOutfit = -1;
|
||||||
|
creatureOnAreaCombat = -1;
|
||||||
|
creatureOnTargetCombat = -1;
|
||||||
|
|
||||||
|
// Party
|
||||||
|
partyOnJoin = -1;
|
||||||
|
partyOnLeave = -1;
|
||||||
|
partyOnDisband = -1;
|
||||||
|
|
||||||
|
// Player
|
||||||
|
playerOnLook = -1;
|
||||||
|
playerOnLookInBattleList = -1;
|
||||||
|
playerOnLookInTrade = -1;
|
||||||
|
playerOnMoveItem = -1;
|
||||||
|
playerOnItemMoved = -1;
|
||||||
|
playerOnMoveCreature = -1;
|
||||||
|
playerOnTurn = -1;
|
||||||
|
playerOnTradeRequest = -1;
|
||||||
|
playerOnTradeAccept = -1;
|
||||||
|
playerOnGainExperience = -1;
|
||||||
|
playerOnLoseExperience = -1;
|
||||||
|
playerOnGainSkillTries = -1;
|
||||||
|
playerOnReportBug = -1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool Events::load()
|
bool Events::load()
|
||||||
{
|
{
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
@@ -41,8 +71,6 @@ bool Events::load()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
info = {};
|
|
||||||
|
|
||||||
std::set<std::string> classes;
|
std::set<std::string> classes;
|
||||||
for (auto eventNode : doc.child("events").children()) {
|
for (auto eventNode : doc.child("events").children()) {
|
||||||
if (!eventNode.attribute("enabled").as_bool()) {
|
if (!eventNode.attribute("enabled").as_bool()) {
|
||||||
@@ -63,69 +91,80 @@ bool Events::load()
|
|||||||
const int32_t event = scriptInterface.getMetaEvent(className, methodName);
|
const int32_t event = scriptInterface.getMetaEvent(className, methodName);
|
||||||
if (className == "Creature") {
|
if (className == "Creature") {
|
||||||
if (methodName == "onChangeOutfit") {
|
if (methodName == "onChangeOutfit") {
|
||||||
info.creatureOnChangeOutfit = event;
|
creatureOnChangeOutfit = event;
|
||||||
} else if (methodName == "onAreaCombat") {
|
}
|
||||||
info.creatureOnAreaCombat = event;
|
else if (methodName == "onAreaCombat") {
|
||||||
} else if (methodName == "onTargetCombat") {
|
creatureOnAreaCombat = event;
|
||||||
info.creatureOnTargetCombat = event;
|
}
|
||||||
} else {
|
else if (methodName == "onTargetCombat") {
|
||||||
|
creatureOnTargetCombat = event;
|
||||||
|
}
|
||||||
|
else {
|
||||||
std::cout << "[Warning - Events::load] Unknown creature method: " << methodName << std::endl;
|
std::cout << "[Warning - Events::load] Unknown creature method: " << methodName << std::endl;
|
||||||
}
|
}
|
||||||
} else if (className == "Party") {
|
}
|
||||||
|
else if (className == "Party") {
|
||||||
if (methodName == "onJoin") {
|
if (methodName == "onJoin") {
|
||||||
info.partyOnJoin = event;
|
partyOnJoin = event;
|
||||||
} else if (methodName == "onLeave") {
|
}
|
||||||
info.partyOnLeave = event;
|
else if (methodName == "onLeave") {
|
||||||
} else if (methodName == "onDisband") {
|
partyOnLeave = event;
|
||||||
info.partyOnDisband = event;
|
}
|
||||||
} else if (methodName == "onShareExperience") {
|
else if (methodName == "onDisband") {
|
||||||
info.partyOnShareExperience = event;
|
partyOnDisband = event;
|
||||||
} else {
|
}
|
||||||
|
else if (methodName == "onShareExperience") {
|
||||||
|
partyOnShareExperience = event;
|
||||||
|
}
|
||||||
|
else {
|
||||||
std::cout << "[Warning - Events::load] Unknown party method: " << methodName << std::endl;
|
std::cout << "[Warning - Events::load] Unknown party method: " << methodName << std::endl;
|
||||||
}
|
}
|
||||||
} else if (className == "Player") {
|
}
|
||||||
if (methodName == "onBrowseField") {
|
else if (className == "Player") {
|
||||||
info.playerOnBrowseField = event;
|
if (methodName == "onLook") {
|
||||||
} else if (methodName == "onLook") {
|
playerOnLook = event;
|
||||||
info.playerOnLook = event;
|
}
|
||||||
} else if (methodName == "onLookInBattleList") {
|
else if (methodName == "onLookInBattleList") {
|
||||||
info.playerOnLookInBattleList = event;
|
playerOnLookInBattleList = event;
|
||||||
} else if (methodName == "onLookInTrade") {
|
}
|
||||||
info.playerOnLookInTrade = event;
|
else if (methodName == "onLookInTrade") {
|
||||||
} else if (methodName == "onLookInShop") {
|
playerOnLookInTrade = event;
|
||||||
info.playerOnLookInShop = event;
|
}
|
||||||
} else if (methodName == "onTradeRequest") {
|
else if (methodName == "onTradeRequest") {
|
||||||
info.playerOnTradeRequest = event;
|
playerOnTradeRequest = event;
|
||||||
} else if (methodName == "onTradeAccept") {
|
}
|
||||||
info.playerOnTradeAccept = event;
|
else if (methodName == "onTradeAccept") {
|
||||||
} else if (methodName == "onMoveItem") {
|
playerOnTradeAccept = event;
|
||||||
info.playerOnMoveItem = event;
|
}
|
||||||
} else if (methodName == "onItemMoved") {
|
else if (methodName == "onMoveItem") {
|
||||||
info.playerOnItemMoved = event;
|
playerOnMoveItem = event;
|
||||||
} else if (methodName == "onMoveCreature") {
|
}
|
||||||
info.playerOnMoveCreature = event;
|
else if (methodName == "onItemMoved") {
|
||||||
} else if (methodName == "onReportRuleViolation") {
|
playerOnItemMoved = event;
|
||||||
info.playerOnReportRuleViolation = event;
|
}
|
||||||
} else if (methodName == "onReportBug") {
|
else if (methodName == "onMoveCreature") {
|
||||||
info.playerOnReportBug = event;
|
playerOnMoveCreature = event;
|
||||||
} else if (methodName == "onTurn") {
|
}
|
||||||
info.playerOnTurn = event;
|
else if (methodName == "onReportBug") {
|
||||||
} else if (methodName == "onGainExperience") {
|
playerOnReportBug = event;
|
||||||
info.playerOnGainExperience = event;
|
}
|
||||||
} else if (methodName == "onLoseExperience") {
|
else if (methodName == "onTurn") {
|
||||||
info.playerOnLoseExperience = event;
|
playerOnTurn = event;
|
||||||
} else if (methodName == "onGainSkillTries") {
|
}
|
||||||
info.playerOnGainSkillTries = event;
|
else if (methodName == "onGainExperience") {
|
||||||
} else {
|
playerOnGainExperience = event;
|
||||||
|
}
|
||||||
|
else if (methodName == "onLoseExperience") {
|
||||||
|
playerOnLoseExperience = event;
|
||||||
|
}
|
||||||
|
else if (methodName == "onGainSkillTries") {
|
||||||
|
playerOnGainSkillTries = event;
|
||||||
|
}
|
||||||
|
else {
|
||||||
std::cout << "[Warning - Events::load] Unknown player method: " << methodName << std::endl;
|
std::cout << "[Warning - Events::load] Unknown player method: " << methodName << std::endl;
|
||||||
}
|
}
|
||||||
} else if (className == "Monster") {
|
}
|
||||||
if (methodName == "onDropLoot") {
|
else {
|
||||||
info.monsterOnDropLoot = event;
|
|
||||||
} else {
|
|
||||||
std::cout << "[Warning - Events::load] Unknown monster method: " << methodName << std::endl;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::cout << "[Warning - Events::load] Unknown class: " << className << std::endl;
|
std::cout << "[Warning - Events::load] Unknown class: " << className << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +175,7 @@ bool Events::load()
|
|||||||
bool Events::eventCreatureOnChangeOutfit(Creature* creature, const Outfit_t& outfit)
|
bool Events::eventCreatureOnChangeOutfit(Creature* creature, const Outfit_t& outfit)
|
||||||
{
|
{
|
||||||
// Creature:onChangeOutfit(outfit) or Creature.onChangeOutfit(self, outfit)
|
// Creature:onChangeOutfit(outfit) or Creature.onChangeOutfit(self, outfit)
|
||||||
if (info.creatureOnChangeOutfit == -1) {
|
if (creatureOnChangeOutfit == -1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,10 +185,10 @@ bool Events::eventCreatureOnChangeOutfit(Creature* creature, const Outfit_t& out
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.creatureOnChangeOutfit, &scriptInterface);
|
env->setScriptId(creatureOnChangeOutfit, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.creatureOnChangeOutfit);
|
scriptInterface.pushFunction(creatureOnChangeOutfit);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
||||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||||
@@ -162,7 +201,7 @@ bool Events::eventCreatureOnChangeOutfit(Creature* creature, const Outfit_t& out
|
|||||||
ReturnValue Events::eventCreatureOnAreaCombat(Creature* creature, Tile* tile, bool aggressive)
|
ReturnValue Events::eventCreatureOnAreaCombat(Creature* creature, Tile* tile, bool aggressive)
|
||||||
{
|
{
|
||||||
// Creature:onAreaCombat(tile, aggressive) or Creature.onAreaCombat(self, tile, aggressive)
|
// Creature:onAreaCombat(tile, aggressive) or Creature.onAreaCombat(self, tile, aggressive)
|
||||||
if (info.creatureOnAreaCombat == -1) {
|
if (creatureOnAreaCombat == -1) {
|
||||||
return RETURNVALUE_NOERROR;
|
return RETURNVALUE_NOERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,15 +211,16 @@ ReturnValue Events::eventCreatureOnAreaCombat(Creature* creature, Tile* tile, bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.creatureOnAreaCombat, &scriptInterface);
|
env->setScriptId(creatureOnAreaCombat, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.creatureOnAreaCombat);
|
scriptInterface.pushFunction(creatureOnAreaCombat);
|
||||||
|
|
||||||
if (creature) {
|
if (creature) {
|
||||||
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
||||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +233,8 @@ ReturnValue Events::eventCreatureOnAreaCombat(Creature* creature, Tile* tile, bo
|
|||||||
if (scriptInterface.protectedCall(L, 3, 1) != 0) {
|
if (scriptInterface.protectedCall(L, 3, 1) != 0) {
|
||||||
returnValue = RETURNVALUE_NOTPOSSIBLE;
|
returnValue = RETURNVALUE_NOTPOSSIBLE;
|
||||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
returnValue = LuaScriptInterface::getNumber<ReturnValue>(L, -1);
|
returnValue = LuaScriptInterface::getNumber<ReturnValue>(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
@@ -205,7 +246,7 @@ ReturnValue Events::eventCreatureOnAreaCombat(Creature* creature, Tile* tile, bo
|
|||||||
ReturnValue Events::eventCreatureOnTargetCombat(Creature* creature, Creature* target)
|
ReturnValue Events::eventCreatureOnTargetCombat(Creature* creature, Creature* target)
|
||||||
{
|
{
|
||||||
// Creature:onTargetCombat(target) or Creature.onTargetCombat(self, target)
|
// Creature:onTargetCombat(target) or Creature.onTargetCombat(self, target)
|
||||||
if (info.creatureOnTargetCombat == -1) {
|
if (creatureOnTargetCombat == -1) {
|
||||||
return RETURNVALUE_NOERROR;
|
return RETURNVALUE_NOERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,15 +256,16 @@ ReturnValue Events::eventCreatureOnTargetCombat(Creature* creature, Creature* ta
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.creatureOnTargetCombat, &scriptInterface);
|
env->setScriptId(creatureOnTargetCombat, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.creatureOnTargetCombat);
|
scriptInterface.pushFunction(creatureOnTargetCombat);
|
||||||
|
|
||||||
if (creature) {
|
if (creature) {
|
||||||
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
||||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,7 +276,8 @@ ReturnValue Events::eventCreatureOnTargetCombat(Creature* creature, Creature* ta
|
|||||||
if (scriptInterface.protectedCall(L, 2, 1) != 0) {
|
if (scriptInterface.protectedCall(L, 2, 1) != 0) {
|
||||||
returnValue = RETURNVALUE_NOTPOSSIBLE;
|
returnValue = RETURNVALUE_NOTPOSSIBLE;
|
||||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
returnValue = LuaScriptInterface::getNumber<ReturnValue>(L, -1);
|
returnValue = LuaScriptInterface::getNumber<ReturnValue>(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
@@ -247,7 +290,7 @@ ReturnValue Events::eventCreatureOnTargetCombat(Creature* creature, Creature* ta
|
|||||||
bool Events::eventPartyOnJoin(Party* party, Player* player)
|
bool Events::eventPartyOnJoin(Party* party, Player* player)
|
||||||
{
|
{
|
||||||
// Party:onJoin(player) or Party.onJoin(self, player)
|
// Party:onJoin(player) or Party.onJoin(self, player)
|
||||||
if (info.partyOnJoin == -1) {
|
if (partyOnJoin == -1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,10 +300,10 @@ bool Events::eventPartyOnJoin(Party* party, Player* player)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.partyOnJoin, &scriptInterface);
|
env->setScriptId(partyOnJoin, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.partyOnJoin);
|
scriptInterface.pushFunction(partyOnJoin);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Party>(L, party);
|
LuaScriptInterface::pushUserdata<Party>(L, party);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Party");
|
LuaScriptInterface::setMetatable(L, -1, "Party");
|
||||||
@@ -274,7 +317,7 @@ bool Events::eventPartyOnJoin(Party* party, Player* player)
|
|||||||
bool Events::eventPartyOnLeave(Party* party, Player* player)
|
bool Events::eventPartyOnLeave(Party* party, Player* player)
|
||||||
{
|
{
|
||||||
// Party:onLeave(player) or Party.onLeave(self, player)
|
// Party:onLeave(player) or Party.onLeave(self, player)
|
||||||
if (info.partyOnLeave == -1) {
|
if (partyOnLeave == -1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,10 +327,10 @@ bool Events::eventPartyOnLeave(Party* party, Player* player)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.partyOnLeave, &scriptInterface);
|
env->setScriptId(partyOnLeave, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.partyOnLeave);
|
scriptInterface.pushFunction(partyOnLeave);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Party>(L, party);
|
LuaScriptInterface::pushUserdata<Party>(L, party);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Party");
|
LuaScriptInterface::setMetatable(L, -1, "Party");
|
||||||
@@ -301,7 +344,7 @@ bool Events::eventPartyOnLeave(Party* party, Player* player)
|
|||||||
bool Events::eventPartyOnDisband(Party* party)
|
bool Events::eventPartyOnDisband(Party* party)
|
||||||
{
|
{
|
||||||
// Party:onDisband() or Party.onDisband(self)
|
// Party:onDisband() or Party.onDisband(self)
|
||||||
if (info.partyOnDisband == -1) {
|
if (partyOnDisband == -1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,10 +354,10 @@ bool Events::eventPartyOnDisband(Party* party)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.partyOnDisband, &scriptInterface);
|
env->setScriptId(partyOnDisband, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.partyOnDisband);
|
scriptInterface.pushFunction(partyOnDisband);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Party>(L, party);
|
LuaScriptInterface::pushUserdata<Party>(L, party);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Party");
|
LuaScriptInterface::setMetatable(L, -1, "Party");
|
||||||
@@ -325,7 +368,7 @@ bool Events::eventPartyOnDisband(Party* party)
|
|||||||
void Events::eventPartyOnShareExperience(Party* party, uint64_t& exp)
|
void Events::eventPartyOnShareExperience(Party* party, uint64_t& exp)
|
||||||
{
|
{
|
||||||
// Party:onShareExperience(exp) or Party.onShareExperience(self, exp)
|
// Party:onShareExperience(exp) or Party.onShareExperience(self, exp)
|
||||||
if (info.partyOnShareExperience == -1) {
|
if (partyOnShareExperience == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,10 +378,10 @@ void Events::eventPartyOnShareExperience(Party* party, uint64_t& exp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.partyOnShareExperience, &scriptInterface);
|
env->setScriptId(partyOnShareExperience, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.partyOnShareExperience);
|
scriptInterface.pushFunction(partyOnShareExperience);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Party>(L, party);
|
LuaScriptInterface::pushUserdata<Party>(L, party);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Party");
|
LuaScriptInterface::setMetatable(L, -1, "Party");
|
||||||
@@ -347,7 +390,8 @@ void Events::eventPartyOnShareExperience(Party* party, uint64_t& exp)
|
|||||||
|
|
||||||
if (scriptInterface.protectedCall(L, 2, 1) != 0) {
|
if (scriptInterface.protectedCall(L, 2, 1) != 0) {
|
||||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
|
exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
@@ -355,37 +399,10 @@ void Events::eventPartyOnShareExperience(Party* party, uint64_t& exp)
|
|||||||
scriptInterface.resetScriptEnv();
|
scriptInterface.resetScriptEnv();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Player
|
|
||||||
bool Events::eventPlayerOnBrowseField(Player* player, const Position& position)
|
|
||||||
{
|
|
||||||
// Player:onBrowseField(position) or Player.onBrowseField(self, position)
|
|
||||||
if (info.playerOnBrowseField == -1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!scriptInterface.reserveScriptEnv()) {
|
|
||||||
std::cout << "[Error - Events::eventPlayerOnBrowseField] Call stack overflow" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
|
||||||
env->setScriptId(info.playerOnBrowseField, &scriptInterface);
|
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
|
||||||
scriptInterface.pushFunction(info.playerOnBrowseField);
|
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
|
||||||
|
|
||||||
LuaScriptInterface::pushPosition(L, position);
|
|
||||||
|
|
||||||
return scriptInterface.callFunction(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Events::eventPlayerOnLook(Player* player, const Position& position, Thing* thing, uint8_t stackpos, int32_t lookDistance)
|
void Events::eventPlayerOnLook(Player* player, const Position& position, Thing* thing, uint8_t stackpos, int32_t lookDistance)
|
||||||
{
|
{
|
||||||
// Player:onLook(thing, position, distance) or Player.onLook(self, thing, position, distance)
|
// Player:onLook(thing, position, distance) or Player.onLook(self, thing, position, distance)
|
||||||
if (info.playerOnLook == -1) {
|
if (playerOnLook == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,10 +412,10 @@ void Events::eventPlayerOnLook(Player* player, const Position& position, Thing*
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.playerOnLook, &scriptInterface);
|
env->setScriptId(playerOnLook, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.playerOnLook);
|
scriptInterface.pushFunction(playerOnLook);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||||
@@ -406,10 +423,12 @@ void Events::eventPlayerOnLook(Player* player, const Position& position, Thing*
|
|||||||
if (Creature* creature = thing->getCreature()) {
|
if (Creature* creature = thing->getCreature()) {
|
||||||
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
LuaScriptInterface::pushUserdata<Creature>(L, creature);
|
||||||
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
LuaScriptInterface::setCreatureMetatable(L, -1, creature);
|
||||||
} else if (Item* item = thing->getItem()) {
|
}
|
||||||
|
else if (Item* item = thing->getItem()) {
|
||||||
LuaScriptInterface::pushUserdata<Item>(L, item);
|
LuaScriptInterface::pushUserdata<Item>(L, item);
|
||||||
LuaScriptInterface::setItemMetatable(L, -1, item);
|
LuaScriptInterface::setItemMetatable(L, -1, item);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,7 +441,7 @@ void Events::eventPlayerOnLook(Player* player, const Position& position, Thing*
|
|||||||
void Events::eventPlayerOnLookInBattleList(Player* player, Creature* creature, int32_t lookDistance)
|
void Events::eventPlayerOnLookInBattleList(Player* player, Creature* creature, int32_t lookDistance)
|
||||||
{
|
{
|
||||||
// Player:onLookInBattleList(creature, position, distance) or Player.onLookInBattleList(self, creature, position, distance)
|
// Player:onLookInBattleList(creature, position, distance) or Player.onLookInBattleList(self, creature, position, distance)
|
||||||
if (info.playerOnLookInBattleList == -1) {
|
if (playerOnLookInBattleList == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,10 +451,10 @@ void Events::eventPlayerOnLookInBattleList(Player* player, Creature* creature, i
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.playerOnLookInBattleList, &scriptInterface);
|
env->setScriptId(playerOnLookInBattleList, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.playerOnLookInBattleList);
|
scriptInterface.pushFunction(playerOnLookInBattleList);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||||
@@ -451,7 +470,7 @@ void Events::eventPlayerOnLookInBattleList(Player* player, Creature* creature, i
|
|||||||
void Events::eventPlayerOnLookInTrade(Player* player, Player* partner, Item* item, int32_t lookDistance)
|
void Events::eventPlayerOnLookInTrade(Player* player, Player* partner, Item* item, int32_t lookDistance)
|
||||||
{
|
{
|
||||||
// Player:onLookInTrade(partner, item, distance) or Player.onLookInTrade(self, partner, item, distance)
|
// Player:onLookInTrade(partner, item, distance) or Player.onLookInTrade(self, partner, item, distance)
|
||||||
if (info.playerOnLookInTrade == -1) {
|
if (playerOnLookInTrade == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,10 +480,10 @@ void Events::eventPlayerOnLookInTrade(Player* player, Player* partner, Item* ite
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.playerOnLookInTrade, &scriptInterface);
|
env->setScriptId(playerOnLookInTrade, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.playerOnLookInTrade);
|
scriptInterface.pushFunction(playerOnLookInTrade);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||||
@@ -480,39 +499,10 @@ void Events::eventPlayerOnLookInTrade(Player* player, Player* partner, Item* ite
|
|||||||
scriptInterface.callVoidFunction(4);
|
scriptInterface.callVoidFunction(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Events::eventPlayerOnLookInShop(Player* player, const ItemType* itemType, uint8_t count)
|
|
||||||
{
|
|
||||||
// Player:onLookInShop(itemType, count) or Player.onLookInShop(self, itemType, count)
|
|
||||||
if (info.playerOnLookInShop == -1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!scriptInterface.reserveScriptEnv()) {
|
|
||||||
std::cout << "[Error - Events::eventPlayerOnLookInShop] Call stack overflow" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
|
||||||
env->setScriptId(info.playerOnLookInShop, &scriptInterface);
|
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
|
||||||
scriptInterface.pushFunction(info.playerOnLookInShop);
|
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<const ItemType>(L, itemType);
|
|
||||||
LuaScriptInterface::setMetatable(L, -1, "ItemType");
|
|
||||||
|
|
||||||
lua_pushnumber(L, count);
|
|
||||||
|
|
||||||
return scriptInterface.callFunction(3);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Events::eventPlayerOnMoveItem(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder)
|
bool Events::eventPlayerOnMoveItem(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder)
|
||||||
{
|
{
|
||||||
// Player:onMoveItem(item, count, fromPosition, toPosition) or Player.onMoveItem(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
|
// Player:onMoveItem(item, count, fromPosition, toPosition) or Player.onMoveItem(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
|
||||||
if (info.playerOnMoveItem == -1) {
|
if (playerOnMoveItem == -1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -522,10 +512,10 @@ bool Events::eventPlayerOnMoveItem(Player* player, Item* item, uint16_t count, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.playerOnMoveItem, &scriptInterface);
|
env->setScriptId(playerOnMoveItem, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.playerOnMoveItem);
|
scriptInterface.pushFunction(playerOnMoveItem);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||||
@@ -546,7 +536,7 @@ bool Events::eventPlayerOnMoveItem(Player* player, Item* item, uint16_t count, c
|
|||||||
void Events::eventPlayerOnItemMoved(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder)
|
void Events::eventPlayerOnItemMoved(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder)
|
||||||
{
|
{
|
||||||
// Player:onItemMoved(item, count, fromPosition, toPosition) or Player.onItemMoved(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
|
// Player:onItemMoved(item, count, fromPosition, toPosition) or Player.onItemMoved(self, item, count, fromPosition, toPosition, fromCylinder, toCylinder)
|
||||||
if (info.playerOnItemMoved == -1) {
|
if (playerOnItemMoved == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,10 +546,10 @@ void Events::eventPlayerOnItemMoved(Player* player, Item* item, uint16_t count,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.playerOnItemMoved, &scriptInterface);
|
env->setScriptId(playerOnItemMoved, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.playerOnItemMoved);
|
scriptInterface.pushFunction(playerOnItemMoved);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||||
@@ -580,7 +570,7 @@ void Events::eventPlayerOnItemMoved(Player* player, Item* item, uint16_t count,
|
|||||||
bool Events::eventPlayerOnMoveCreature(Player* player, Creature* creature, const Position& fromPosition, const Position& toPosition)
|
bool Events::eventPlayerOnMoveCreature(Player* player, Creature* creature, const Position& fromPosition, const Position& toPosition)
|
||||||
{
|
{
|
||||||
// Player:onMoveCreature(creature, fromPosition, toPosition) or Player.onMoveCreature(self, creature, fromPosition, toPosition)
|
// Player:onMoveCreature(creature, fromPosition, toPosition) or Player.onMoveCreature(self, creature, fromPosition, toPosition)
|
||||||
if (info.playerOnMoveCreature == -1) {
|
if (playerOnMoveCreature == -1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,10 +580,10 @@ bool Events::eventPlayerOnMoveCreature(Player* player, Creature* creature, const
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.playerOnMoveCreature, &scriptInterface);
|
env->setScriptId(playerOnMoveCreature, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.playerOnMoveCreature);
|
scriptInterface.pushFunction(playerOnMoveCreature);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||||
@@ -607,42 +597,10 @@ bool Events::eventPlayerOnMoveCreature(Player* player, Creature* creature, const
|
|||||||
return scriptInterface.callFunction(4);
|
return scriptInterface.callFunction(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::eventPlayerOnReportRuleViolation(Player* player, const std::string& targetName, uint8_t reportType, uint8_t reportReason, const std::string& comment, const std::string& translation)
|
bool Events::eventPlayerOnReportBug(Player* player, const std::string& message, const Position& position)
|
||||||
{
|
|
||||||
// Player:onReportRuleViolation(targetName, reportType, reportReason, comment, translation)
|
|
||||||
if (info.playerOnReportRuleViolation == -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!scriptInterface.reserveScriptEnv()) {
|
|
||||||
std::cout << "[Error - Events::eventPlayerOnReportRuleViolation] Call stack overflow" << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
|
||||||
env->setScriptId(info.playerOnReportRuleViolation, &scriptInterface);
|
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
|
||||||
scriptInterface.pushFunction(info.playerOnReportRuleViolation);
|
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
|
||||||
|
|
||||||
LuaScriptInterface::pushString(L, targetName);
|
|
||||||
|
|
||||||
lua_pushnumber(L, reportType);
|
|
||||||
lua_pushnumber(L, reportReason);
|
|
||||||
|
|
||||||
LuaScriptInterface::pushString(L, comment);
|
|
||||||
LuaScriptInterface::pushString(L, translation);
|
|
||||||
|
|
||||||
scriptInterface.callVoidFunction(6);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Events::eventPlayerOnReportBug(Player* player, const std::string& message, const Position& position, uint8_t category)
|
|
||||||
{
|
{
|
||||||
// Player:onReportBug(message, position, category)
|
// Player:onReportBug(message, position, category)
|
||||||
if (info.playerOnReportBug == -1) {
|
if (playerOnReportBug == -1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -652,25 +610,24 @@ bool Events::eventPlayerOnReportBug(Player* player, const std::string& message,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.playerOnReportBug, &scriptInterface);
|
env->setScriptId(playerOnReportBug, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.playerOnReportBug);
|
scriptInterface.pushFunction(playerOnReportBug);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||||
|
|
||||||
LuaScriptInterface::pushString(L, message);
|
LuaScriptInterface::pushString(L, message);
|
||||||
LuaScriptInterface::pushPosition(L, position);
|
LuaScriptInterface::pushPosition(L, position);
|
||||||
lua_pushnumber(L, category);
|
|
||||||
|
|
||||||
return scriptInterface.callFunction(4);
|
return scriptInterface.callFunction(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Events::eventPlayerOnTurn(Player* player, Direction direction)
|
bool Events::eventPlayerOnTurn(Player* player, Direction direction)
|
||||||
{
|
{
|
||||||
// Player:onTurn(direction) or Player.onTurn(self, direction)
|
// Player:onTurn(direction) or Player.onTurn(self, direction)
|
||||||
if (info.playerOnTurn == -1) {
|
if (playerOnTurn == -1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -680,10 +637,10 @@ bool Events::eventPlayerOnTurn(Player* player, Direction direction)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.playerOnTurn, &scriptInterface);
|
env->setScriptId(playerOnTurn, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.playerOnTurn);
|
scriptInterface.pushFunction(playerOnTurn);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||||
@@ -696,7 +653,7 @@ bool Events::eventPlayerOnTurn(Player* player, Direction direction)
|
|||||||
bool Events::eventPlayerOnTradeRequest(Player* player, Player* target, Item* item)
|
bool Events::eventPlayerOnTradeRequest(Player* player, Player* target, Item* item)
|
||||||
{
|
{
|
||||||
// Player:onTradeRequest(target, item)
|
// Player:onTradeRequest(target, item)
|
||||||
if (info.playerOnTradeRequest == -1) {
|
if (playerOnTradeRequest == -1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -706,10 +663,10 @@ bool Events::eventPlayerOnTradeRequest(Player* player, Player* target, Item* ite
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.playerOnTradeRequest, &scriptInterface);
|
env->setScriptId(playerOnTradeRequest, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.playerOnTradeRequest);
|
scriptInterface.pushFunction(playerOnTradeRequest);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||||
@@ -726,7 +683,7 @@ bool Events::eventPlayerOnTradeRequest(Player* player, Player* target, Item* ite
|
|||||||
bool Events::eventPlayerOnTradeAccept(Player* player, Player* target, Item* item, Item* targetItem)
|
bool Events::eventPlayerOnTradeAccept(Player* player, Player* target, Item* item, Item* targetItem)
|
||||||
{
|
{
|
||||||
// Player:onTradeAccept(target, item, targetItem)
|
// Player:onTradeAccept(target, item, targetItem)
|
||||||
if (info.playerOnTradeAccept == -1) {
|
if (playerOnTradeAccept == -1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -736,10 +693,10 @@ bool Events::eventPlayerOnTradeAccept(Player* player, Player* target, Item* item
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.playerOnTradeAccept, &scriptInterface);
|
env->setScriptId(playerOnTradeAccept, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.playerOnTradeAccept);
|
scriptInterface.pushFunction(playerOnTradeAccept);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||||
@@ -760,7 +717,7 @@ void Events::eventPlayerOnGainExperience(Player* player, Creature* source, uint6
|
|||||||
{
|
{
|
||||||
// Player:onGainExperience(source, exp, rawExp)
|
// Player:onGainExperience(source, exp, rawExp)
|
||||||
// rawExp gives the original exp which is not multiplied
|
// rawExp gives the original exp which is not multiplied
|
||||||
if (info.playerOnGainExperience == -1) {
|
if (playerOnGainExperience == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -770,10 +727,10 @@ void Events::eventPlayerOnGainExperience(Player* player, Creature* source, uint6
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.playerOnGainExperience, &scriptInterface);
|
env->setScriptId(playerOnGainExperience, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.playerOnGainExperience);
|
scriptInterface.pushFunction(playerOnGainExperience);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||||
@@ -781,7 +738,8 @@ void Events::eventPlayerOnGainExperience(Player* player, Creature* source, uint6
|
|||||||
if (source) {
|
if (source) {
|
||||||
LuaScriptInterface::pushUserdata<Creature>(L, source);
|
LuaScriptInterface::pushUserdata<Creature>(L, source);
|
||||||
LuaScriptInterface::setCreatureMetatable(L, -1, source);
|
LuaScriptInterface::setCreatureMetatable(L, -1, source);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -790,7 +748,8 @@ void Events::eventPlayerOnGainExperience(Player* player, Creature* source, uint6
|
|||||||
|
|
||||||
if (scriptInterface.protectedCall(L, 4, 1) != 0) {
|
if (scriptInterface.protectedCall(L, 4, 1) != 0) {
|
||||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
|
exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
@@ -801,7 +760,7 @@ void Events::eventPlayerOnGainExperience(Player* player, Creature* source, uint6
|
|||||||
void Events::eventPlayerOnLoseExperience(Player* player, uint64_t& exp)
|
void Events::eventPlayerOnLoseExperience(Player* player, uint64_t& exp)
|
||||||
{
|
{
|
||||||
// Player:onLoseExperience(exp)
|
// Player:onLoseExperience(exp)
|
||||||
if (info.playerOnLoseExperience == -1) {
|
if (playerOnLoseExperience == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -811,10 +770,10 @@ void Events::eventPlayerOnLoseExperience(Player* player, uint64_t& exp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.playerOnLoseExperience, &scriptInterface);
|
env->setScriptId(playerOnLoseExperience, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.playerOnLoseExperience);
|
scriptInterface.pushFunction(playerOnLoseExperience);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||||
@@ -823,7 +782,8 @@ void Events::eventPlayerOnLoseExperience(Player* player, uint64_t& exp)
|
|||||||
|
|
||||||
if (scriptInterface.protectedCall(L, 2, 1) != 0) {
|
if (scriptInterface.protectedCall(L, 2, 1) != 0) {
|
||||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
|
exp = LuaScriptInterface::getNumber<uint64_t>(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
@@ -834,7 +794,7 @@ void Events::eventPlayerOnLoseExperience(Player* player, uint64_t& exp)
|
|||||||
void Events::eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_t& tries)
|
void Events::eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_t& tries)
|
||||||
{
|
{
|
||||||
// Player:onGainSkillTries(skill, tries)
|
// Player:onGainSkillTries(skill, tries)
|
||||||
if (info.playerOnGainSkillTries == -1) {
|
if (playerOnGainSkillTries == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -844,10 +804,10 @@ void Events::eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
||||||
env->setScriptId(info.playerOnGainSkillTries, &scriptInterface);
|
env->setScriptId(playerOnGainSkillTries, &scriptInterface);
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
lua_State* L = scriptInterface.getLuaState();
|
||||||
scriptInterface.pushFunction(info.playerOnGainSkillTries);
|
scriptInterface.pushFunction(playerOnGainSkillTries);
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Player>(L, player);
|
LuaScriptInterface::pushUserdata<Player>(L, player);
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||||
@@ -857,37 +817,11 @@ void Events::eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_
|
|||||||
|
|
||||||
if (scriptInterface.protectedCall(L, 3, 1) != 0) {
|
if (scriptInterface.protectedCall(L, 3, 1) != 0) {
|
||||||
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
LuaScriptInterface::reportError(nullptr, LuaScriptInterface::popString(L));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
tries = LuaScriptInterface::getNumber<uint64_t>(L, -1);
|
tries = LuaScriptInterface::getNumber<uint64_t>(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptInterface.resetScriptEnv();
|
scriptInterface.resetScriptEnv();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::eventMonsterOnDropLoot(Monster* monster, Container* corpse)
|
|
||||||
{
|
|
||||||
// Monster:onDropLoot(corpse)
|
|
||||||
if (info.monsterOnDropLoot == -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!scriptInterface.reserveScriptEnv()) {
|
|
||||||
std::cout << "[Error - Events::eventMonsterOnDropLoot] Call stack overflow" << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptEnvironment* env = scriptInterface.getScriptEnv();
|
|
||||||
env->setScriptId(info.monsterOnDropLoot, &scriptInterface);
|
|
||||||
|
|
||||||
lua_State* L = scriptInterface.getLuaState();
|
|
||||||
scriptInterface.pushFunction(info.monsterOnDropLoot);
|
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Monster>(L, monster);
|
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Monster");
|
|
||||||
|
|
||||||
LuaScriptInterface::pushUserdata<Container>(L, corpse);
|
|
||||||
LuaScriptInterface::setMetatable(L, -1, "Container");
|
|
||||||
|
|
||||||
return scriptInterface.callVoidFunction(2);
|
|
||||||
}
|
|
||||||
|
|||||||
122
src/events.h
122
src/events.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* The Forgotten Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2016 Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,80 +28,68 @@ class Tile;
|
|||||||
|
|
||||||
class Events
|
class Events
|
||||||
{
|
{
|
||||||
struct EventsInfo {
|
public:
|
||||||
// Creature
|
Events();
|
||||||
int32_t creatureOnChangeOutfit = -1;
|
|
||||||
int32_t creatureOnAreaCombat = -1;
|
|
||||||
int32_t creatureOnTargetCombat = -1;
|
|
||||||
|
|
||||||
// Party
|
void clear();
|
||||||
int32_t partyOnJoin = -1;
|
bool load();
|
||||||
int32_t partyOnLeave = -1;
|
|
||||||
int32_t partyOnDisband = -1;
|
|
||||||
int32_t partyOnShareExperience = -1;
|
|
||||||
|
|
||||||
// Player
|
// Creature
|
||||||
int32_t playerOnBrowseField = -1;
|
bool eventCreatureOnChangeOutfit(Creature* creature, const Outfit_t& outfit);
|
||||||
int32_t playerOnLook = -1;
|
ReturnValue eventCreatureOnAreaCombat(Creature* creature, Tile* tile, bool aggressive);
|
||||||
int32_t playerOnLookInBattleList = -1;
|
ReturnValue eventCreatureOnTargetCombat(Creature* creature, Creature* target);
|
||||||
int32_t playerOnLookInTrade = -1;
|
|
||||||
int32_t playerOnLookInShop = -1;
|
|
||||||
int32_t playerOnMoveItem = -1;
|
|
||||||
int32_t playerOnItemMoved = -1;
|
|
||||||
int32_t playerOnMoveCreature = -1;
|
|
||||||
int32_t playerOnReportRuleViolation = -1;
|
|
||||||
int32_t playerOnReportBug = -1;
|
|
||||||
int32_t playerOnTurn = -1;
|
|
||||||
int32_t playerOnTradeRequest = -1;
|
|
||||||
int32_t playerOnTradeAccept = -1;
|
|
||||||
int32_t playerOnGainExperience = -1;
|
|
||||||
int32_t playerOnLoseExperience = -1;
|
|
||||||
int32_t playerOnGainSkillTries = -1;
|
|
||||||
|
|
||||||
// Monster
|
// Party
|
||||||
int32_t monsterOnDropLoot = -1;
|
bool eventPartyOnJoin(Party* party, Player* player);
|
||||||
};
|
bool eventPartyOnLeave(Party* party, Player* player);
|
||||||
|
bool eventPartyOnDisband(Party* party);
|
||||||
|
void eventPartyOnShareExperience(Party* party, uint64_t& exp);
|
||||||
|
|
||||||
public:
|
// Player
|
||||||
Events();
|
void eventPlayerOnLook(Player* player, const Position& position, Thing* thing, uint8_t stackpos, int32_t lookDistance);
|
||||||
|
void eventPlayerOnLookInBattleList(Player* player, Creature* creature, int32_t lookDistance);
|
||||||
|
void eventPlayerOnLookInTrade(Player* player, Player* partner, Item* item, int32_t lookDistance);
|
||||||
|
bool eventPlayerOnMoveItem(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder);
|
||||||
|
void eventPlayerOnItemMoved(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder);
|
||||||
|
bool eventPlayerOnMoveCreature(Player* player, Creature* creature, const Position& fromPosition, const Position& toPosition);
|
||||||
|
void eventPlayerOnReportRuleViolation(Player* player, const std::string& targetName, uint8_t reportType, uint8_t reportReason, const std::string& comment, const std::string& translation);
|
||||||
|
bool eventPlayerOnReportBug(Player* player, const std::string& message, const Position& position);
|
||||||
|
bool eventPlayerOnTurn(Player* player, Direction direction);
|
||||||
|
bool eventPlayerOnTradeRequest(Player* player, Player* target, Item* item);
|
||||||
|
bool eventPlayerOnTradeAccept(Player* player, Player* target, Item* item, Item* targetItem);
|
||||||
|
void eventPlayerOnGainExperience(Player* player, Creature* source, uint64_t& exp, uint64_t rawExp);
|
||||||
|
void eventPlayerOnLoseExperience(Player* player, uint64_t& exp);
|
||||||
|
void eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_t& tries);
|
||||||
|
|
||||||
bool load();
|
private:
|
||||||
|
LuaScriptInterface scriptInterface;
|
||||||
|
|
||||||
// Creature
|
// Creature
|
||||||
bool eventCreatureOnChangeOutfit(Creature* creature, const Outfit_t& outfit);
|
int32_t creatureOnChangeOutfit;
|
||||||
ReturnValue eventCreatureOnAreaCombat(Creature* creature, Tile* tile, bool aggressive);
|
int32_t creatureOnAreaCombat;
|
||||||
ReturnValue eventCreatureOnTargetCombat(Creature* creature, Creature* target);
|
int32_t creatureOnTargetCombat;
|
||||||
|
|
||||||
// Party
|
// Party
|
||||||
bool eventPartyOnJoin(Party* party, Player* player);
|
int32_t partyOnJoin;
|
||||||
bool eventPartyOnLeave(Party* party, Player* player);
|
int32_t partyOnLeave;
|
||||||
bool eventPartyOnDisband(Party* party);
|
int32_t partyOnDisband;
|
||||||
void eventPartyOnShareExperience(Party* party, uint64_t& exp);
|
int32_t partyOnShareExperience;
|
||||||
|
|
||||||
// Player
|
// Player
|
||||||
bool eventPlayerOnBrowseField(Player* player, const Position& position);
|
int32_t playerOnLook;
|
||||||
void eventPlayerOnLook(Player* player, const Position& position, Thing* thing, uint8_t stackpos, int32_t lookDistance);
|
int32_t playerOnLookInBattleList;
|
||||||
void eventPlayerOnLookInBattleList(Player* player, Creature* creature, int32_t lookDistance);
|
int32_t playerOnLookInTrade;
|
||||||
void eventPlayerOnLookInTrade(Player* player, Player* partner, Item* item, int32_t lookDistance);
|
int32_t playerOnMoveItem;
|
||||||
bool eventPlayerOnLookInShop(Player* player, const ItemType* itemType, uint8_t count);
|
int32_t playerOnItemMoved;
|
||||||
bool eventPlayerOnMoveItem(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder);
|
int32_t playerOnMoveCreature;
|
||||||
void eventPlayerOnItemMoved(Player* player, Item* item, uint16_t count, const Position& fromPosition, const Position& toPosition, Cylinder* fromCylinder, Cylinder* toCylinder);
|
int32_t playerOnReportRuleViolation;
|
||||||
bool eventPlayerOnMoveCreature(Player* player, Creature* creature, const Position& fromPosition, const Position& toPosition);
|
int32_t playerOnReportBug;
|
||||||
void eventPlayerOnReportRuleViolation(Player* player, const std::string& targetName, uint8_t reportType, uint8_t reportReason, const std::string& comment, const std::string& translation);
|
int32_t playerOnTurn;
|
||||||
bool eventPlayerOnReportBug(Player* player, const std::string& message, const Position& position, uint8_t category);
|
int32_t playerOnTradeRequest;
|
||||||
bool eventPlayerOnTurn(Player* player, Direction direction);
|
int32_t playerOnTradeAccept;
|
||||||
bool eventPlayerOnTradeRequest(Player* player, Player* target, Item* item);
|
int32_t playerOnGainExperience;
|
||||||
bool eventPlayerOnTradeAccept(Player* player, Player* target, Item* item, Item* targetItem);
|
int32_t playerOnLoseExperience;
|
||||||
void eventPlayerOnGainExperience(Player* player, Creature* source, uint64_t& exp, uint64_t rawExp);
|
int32_t playerOnGainSkillTries;
|
||||||
void eventPlayerOnLoseExperience(Player* player, uint64_t& exp);
|
|
||||||
void eventPlayerOnGainSkillTries(Player* player, skills_t skill, uint64_t& tries);
|
|
||||||
|
|
||||||
// Monster
|
|
||||||
void eventMonsterOnDropLoot(Monster* monster, Container* corpse);
|
|
||||||
|
|
||||||
private:
|
|
||||||
LuaScriptInterface scriptInterface;
|
|
||||||
EventsInfo info;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,106 +19,387 @@
|
|||||||
|
|
||||||
#include "otpch.h"
|
#include "otpch.h"
|
||||||
|
|
||||||
#include <stack>
|
|
||||||
#include "fileloader.h"
|
#include "fileloader.h"
|
||||||
|
|
||||||
|
FileLoader::~FileLoader()
|
||||||
namespace OTB {
|
|
||||||
|
|
||||||
constexpr Identifier wildcard = {{'\0', '\0', '\0', '\0'}};
|
|
||||||
|
|
||||||
Loader::Loader(const std::string& fileName, const Identifier& acceptedIdentifier):
|
|
||||||
fileContents(fileName)
|
|
||||||
{
|
{
|
||||||
constexpr auto minimalSize = sizeof(Identifier) + sizeof(Node::START) + sizeof(Node::type) + sizeof(Node::END);
|
if (file) {
|
||||||
if (fileContents.size() <= minimalSize) {
|
fclose(file);
|
||||||
throw InvalidOTBFormat{};
|
file = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Identifier fileIdentifier;
|
NodeStruct::clearNet(root);
|
||||||
std::copy(fileContents.begin(), fileContents.begin() + fileIdentifier.size(), fileIdentifier.begin());
|
delete[] buffer;
|
||||||
if (fileIdentifier != acceptedIdentifier && fileIdentifier != wildcard) {
|
|
||||||
throw InvalidOTBFormat{};
|
for (auto& i : cached_data) {
|
||||||
|
delete[] i.data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using NodeStack = std::stack<Node*, std::vector<Node*>>;
|
bool FileLoader::openFile(const char* filename, const char* accept_identifier)
|
||||||
static Node& getCurrentNode(const NodeStack& nodeStack) {
|
{
|
||||||
if (nodeStack.empty()) {
|
file = fopen(filename, "rb");
|
||||||
throw InvalidOTBFormat{};
|
if (!file) {
|
||||||
|
lastError = ERROR_CAN_NOT_OPEN;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return *nodeStack.top();
|
|
||||||
|
char identifier[4];
|
||||||
|
if (fread(identifier, 1, 4, file) < 4) {
|
||||||
|
fclose(file);
|
||||||
|
file = nullptr;
|
||||||
|
lastError = ERROR_EOF;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The first four bytes must either match the accept identifier or be 0x00000000 (wildcard)
|
||||||
|
if (memcmp(identifier, accept_identifier, 4) != 0 && memcmp(identifier, "\0\0\0\0", 4) != 0) {
|
||||||
|
fclose(file);
|
||||||
|
file = nullptr;
|
||||||
|
lastError = ERROR_INVALID_FILE_VERSION;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
int32_t file_size = ftell(file);
|
||||||
|
cache_size = std::min<uint32_t>(32768, std::max<uint32_t>(file_size / 20, 8192)) & ~0x1FFF;
|
||||||
|
|
||||||
|
if (!safeSeek(4)) {
|
||||||
|
lastError = ERROR_INVALID_FORMAT;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete root;
|
||||||
|
root = new NodeStruct();
|
||||||
|
root->start = 4;
|
||||||
|
|
||||||
|
int32_t byte;
|
||||||
|
if (safeSeek(4) && readByte(byte) && byte == NODE_START) {
|
||||||
|
return parseNode(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Node& Loader::parseTree()
|
bool FileLoader::parseNode(NODE node)
|
||||||
{
|
{
|
||||||
auto it = fileContents.begin() + sizeof(Identifier);
|
int32_t byte, pos;
|
||||||
if (static_cast<uint8_t>(*it) != Node::START) {
|
NODE currentNode = node;
|
||||||
throw InvalidOTBFormat{};
|
|
||||||
}
|
|
||||||
root.type = *(++it);
|
|
||||||
root.propsBegin = ++it;
|
|
||||||
NodeStack parseStack;
|
|
||||||
parseStack.push(&root);
|
|
||||||
|
|
||||||
for (; it != fileContents.end(); ++it) {
|
while (readByte(byte)) {
|
||||||
switch(static_cast<uint8_t>(*it)) {
|
currentNode->type = byte;
|
||||||
case Node::START: {
|
bool setPropsSize = false;
|
||||||
auto& currentNode = getCurrentNode(parseStack);
|
|
||||||
if (currentNode.children.empty()) {
|
while (true) {
|
||||||
currentNode.propsEnd = it;
|
if (!readByte(byte)) {
|
||||||
}
|
return false;
|
||||||
currentNode.children.emplace_back();
|
|
||||||
auto& child = currentNode.children.back();
|
|
||||||
if (++it == fileContents.end()) {
|
|
||||||
throw InvalidOTBFormat{};
|
|
||||||
}
|
|
||||||
child.type = *it;
|
|
||||||
child.propsBegin = it + sizeof(Node::type);
|
|
||||||
parseStack.push(&child);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case Node::END: {
|
|
||||||
auto& currentNode = getCurrentNode(parseStack);
|
bool skipNode = false;
|
||||||
if (currentNode.children.empty()) {
|
|
||||||
currentNode.propsEnd = it;
|
switch (byte) {
|
||||||
|
case NODE_START: {
|
||||||
|
//child node start
|
||||||
|
if (!safeTell(pos)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE childNode = new NodeStruct();
|
||||||
|
childNode->start = pos;
|
||||||
|
currentNode->propsSize = pos - currentNode->start - 2;
|
||||||
|
currentNode->child = childNode;
|
||||||
|
|
||||||
|
setPropsSize = true;
|
||||||
|
|
||||||
|
if (!parseNode(childNode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
parseStack.pop();
|
|
||||||
break;
|
case NODE_END: {
|
||||||
}
|
//current node end
|
||||||
case Node::ESCAPE: {
|
if (!setPropsSize) {
|
||||||
if (++it == fileContents.end()) {
|
if (!safeTell(pos)) {
|
||||||
throw InvalidOTBFormat{};
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentNode->propsSize = pos - currentNode->start - 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!readByte(byte)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (byte) {
|
||||||
|
case NODE_START: {
|
||||||
|
//starts next node
|
||||||
|
if (!safeTell(pos)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
skipNode = true;
|
||||||
|
NODE nextNode = new NodeStruct();
|
||||||
|
nextNode->start = pos;
|
||||||
|
currentNode->next = nextNode;
|
||||||
|
currentNode = nextNode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case NODE_END:
|
||||||
|
return safeTell(pos) && safeSeek(pos);
|
||||||
|
|
||||||
|
default:
|
||||||
|
lastError = ERROR_INVALID_FORMAT;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
case ESCAPE_CHAR: {
|
||||||
|
if (!readByte(byte)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
|
||||||
|
if (skipNode) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!parseStack.empty()) {
|
return false;
|
||||||
throw InvalidOTBFormat{};
|
}
|
||||||
|
|
||||||
|
const uint8_t* FileLoader::getProps(const NODE node, size_t& size)
|
||||||
|
{
|
||||||
|
if (!node) {
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node->propsSize >= buffer_size) {
|
||||||
|
delete[] buffer;
|
||||||
|
|
||||||
|
while (node->propsSize >= buffer_size) {
|
||||||
|
buffer_size *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = new uint8_t[buffer_size];
|
||||||
|
}
|
||||||
|
|
||||||
|
//get buffer
|
||||||
|
if (!readBytes(node->propsSize, node->start + 2)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//unscape buffer
|
||||||
|
size_t j = 0;
|
||||||
|
bool escaped = false;
|
||||||
|
for (uint32_t i = 0; i < node->propsSize; ++i, ++j) {
|
||||||
|
if (buffer[i] == ESCAPE_CHAR) {
|
||||||
|
//escape char found, skip it and write next
|
||||||
|
buffer[j] = buffer[++i];
|
||||||
|
//is neede a displacement for next bytes
|
||||||
|
escaped = true;
|
||||||
|
} else if (escaped) {
|
||||||
|
//perform that displacement
|
||||||
|
buffer[j] = buffer[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size = j;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileLoader::getProps(const NODE node, PropStream& props)
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
if (const uint8_t* a = getProps(node, size)) {
|
||||||
|
props.init(reinterpret_cast<const char*>(a), size); // does not break strict aliasing
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
props.init(nullptr, 0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE FileLoader::getChildNode(const NODE parent, uint32_t& type)
|
||||||
|
{
|
||||||
|
if (parent) {
|
||||||
|
NODE child = parent->child;
|
||||||
|
if (child) {
|
||||||
|
type = child->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = root->type;
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Loader::getProps(const Node& node, PropStream& props)
|
NODE FileLoader::getNextNode(const NODE prev, uint32_t& type)
|
||||||
{
|
{
|
||||||
auto size = std::distance(node.propsBegin, node.propsEnd);
|
if (!prev) {
|
||||||
if (size == 0) {
|
return NO_NODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE next = prev->next;
|
||||||
|
if (next) {
|
||||||
|
type = next->type;
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool FileLoader::readByte(int32_t& value)
|
||||||
|
{
|
||||||
|
if (cache_index == NO_VALID_CACHE) {
|
||||||
|
lastError = ERROR_CACHE_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
propBuffer.resize(size);
|
|
||||||
bool lastEscaped = false;
|
|
||||||
|
|
||||||
auto escapedPropEnd = std::copy_if(node.propsBegin, node.propsEnd, propBuffer.begin(), [&lastEscaped](const char& byte) {
|
if (cache_offset >= cached_data[cache_index].size) {
|
||||||
lastEscaped = byte == static_cast<char>(Node::ESCAPE) && !lastEscaped;
|
int32_t pos = cache_offset + cached_data[cache_index].base;
|
||||||
return !lastEscaped;
|
int32_t tmp = getCacheBlock(pos);
|
||||||
});
|
if (tmp < 0) {
|
||||||
props.init(&propBuffer[0], std::distance(propBuffer.begin(), escapedPropEnd));
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_index = tmp;
|
||||||
|
cache_offset = pos - cached_data[cache_index].base;
|
||||||
|
if (cache_offset >= cached_data[cache_index].size) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value = cached_data[cache_index].data[cache_offset++];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} //namespace OTB
|
inline bool FileLoader::readBytes(uint32_t size, int32_t pos)
|
||||||
|
{
|
||||||
|
//seek at pos
|
||||||
|
uint32_t remain = size;
|
||||||
|
uint8_t* buf = this->buffer;
|
||||||
|
do {
|
||||||
|
//prepare cache
|
||||||
|
uint32_t i = getCacheBlock(pos);
|
||||||
|
if (i == NO_VALID_CACHE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_index = i;
|
||||||
|
cache_offset = pos - cached_data[i].base;
|
||||||
|
|
||||||
|
//get maximum read block size and calculate remaining bytes
|
||||||
|
uint32_t reading = std::min<int32_t>(remain, cached_data[i].size - cache_offset);
|
||||||
|
remain -= reading;
|
||||||
|
|
||||||
|
//read it
|
||||||
|
memcpy(buf, cached_data[cache_index].data + cache_offset, reading);
|
||||||
|
|
||||||
|
//update variables
|
||||||
|
cache_offset += reading;
|
||||||
|
buf += reading;
|
||||||
|
pos += reading;
|
||||||
|
} while (remain > 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool FileLoader::safeSeek(uint32_t pos)
|
||||||
|
{
|
||||||
|
uint32_t i = getCacheBlock(pos);
|
||||||
|
if (i == NO_VALID_CACHE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_index = i;
|
||||||
|
cache_offset = pos - cached_data[i].base;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool FileLoader::safeTell(int32_t& pos)
|
||||||
|
{
|
||||||
|
if (cache_index == NO_VALID_CACHE) {
|
||||||
|
lastError = ERROR_CACHE_ERROR;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos = cached_data[cache_index].base + cache_offset - 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t FileLoader::getCacheBlock(uint32_t pos)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
uint32_t i, base_pos = pos & ~(cache_size - 1);
|
||||||
|
|
||||||
|
for (i = 0; i < CACHE_BLOCKS; i++) {
|
||||||
|
if (cached_data[i].loaded) {
|
||||||
|
if (cached_data[i].base == base_pos) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
i = loadCacheBlock(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t FileLoader::loadCacheBlock(uint32_t pos)
|
||||||
|
{
|
||||||
|
int32_t i, loading_cache = -1, base_pos = pos & ~(cache_size - 1);
|
||||||
|
|
||||||
|
for (i = 0; i < CACHE_BLOCKS; i++) {
|
||||||
|
if (!cached_data[i].loaded) {
|
||||||
|
loading_cache = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loading_cache == -1) {
|
||||||
|
for (i = 0; i < CACHE_BLOCKS; i++) {
|
||||||
|
if (std::abs(static_cast<long>(cached_data[i].base) - base_pos) > static_cast<long>(2 * cache_size)) {
|
||||||
|
loading_cache = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loading_cache == -1) {
|
||||||
|
loading_cache = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cached_data[loading_cache].data == nullptr) {
|
||||||
|
cached_data[loading_cache].data = new uint8_t[cache_size];
|
||||||
|
}
|
||||||
|
|
||||||
|
cached_data[loading_cache].base = base_pos;
|
||||||
|
|
||||||
|
if (fseek(file, cached_data[loading_cache].base, SEEK_SET) != 0) {
|
||||||
|
lastError = ERROR_SEEK_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t size = fread(cached_data[loading_cache].data, 1, cache_size, file);
|
||||||
|
cached_data[loading_cache].size = size;
|
||||||
|
|
||||||
|
if (size < (pos - cached_data[loading_cache].base)) {
|
||||||
|
lastError = ERROR_SEEK_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cached_data[loading_cache].loaded = 1;
|
||||||
|
return loading_cache;
|
||||||
|
}
|
||||||
|
|||||||
168
src/fileloader.h
168
src/fileloader.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,53 +22,133 @@
|
|||||||
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/iostreams/device/mapped_file.hpp>
|
|
||||||
|
struct NodeStruct;
|
||||||
|
|
||||||
|
typedef NodeStruct* NODE;
|
||||||
|
|
||||||
|
struct NodeStruct {
|
||||||
|
uint32_t start = 0;
|
||||||
|
uint32_t propsSize = 0;
|
||||||
|
uint32_t type = 0;
|
||||||
|
NodeStruct* next = nullptr;
|
||||||
|
NodeStruct* child = nullptr;
|
||||||
|
|
||||||
|
static void clearNet(NodeStruct* root) {
|
||||||
|
if (root) {
|
||||||
|
clearChild(root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void clearNext(NodeStruct* node) {
|
||||||
|
NodeStruct* deleteNode = node;
|
||||||
|
NodeStruct* nextNode;
|
||||||
|
|
||||||
|
while (deleteNode) {
|
||||||
|
if (deleteNode->child) {
|
||||||
|
clearChild(deleteNode->child);
|
||||||
|
}
|
||||||
|
|
||||||
|
nextNode = deleteNode->next;
|
||||||
|
delete deleteNode;
|
||||||
|
deleteNode = nextNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clearChild(NodeStruct* node) {
|
||||||
|
if (node->child) {
|
||||||
|
clearChild(node->child);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->next) {
|
||||||
|
clearNext(node->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete node;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr auto NO_NODE = nullptr;
|
||||||
|
|
||||||
|
enum FILELOADER_ERRORS {
|
||||||
|
ERROR_NONE,
|
||||||
|
ERROR_INVALID_FILE_VERSION,
|
||||||
|
ERROR_CAN_NOT_OPEN,
|
||||||
|
ERROR_CAN_NOT_CREATE,
|
||||||
|
ERROR_EOF,
|
||||||
|
ERROR_SEEK_ERROR,
|
||||||
|
ERROR_NOT_OPEN,
|
||||||
|
ERROR_INVALID_NODE,
|
||||||
|
ERROR_INVALID_FORMAT,
|
||||||
|
ERROR_TELL_ERROR,
|
||||||
|
ERROR_COULDNOTWRITE,
|
||||||
|
ERROR_CACHE_ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
class PropStream;
|
class PropStream;
|
||||||
|
|
||||||
namespace OTB {
|
class FileLoader
|
||||||
using MappedFile = boost::iostreams::mapped_file_source;
|
|
||||||
using ContentIt = MappedFile::iterator;
|
|
||||||
using Identifier = std::array<char, 4>;
|
|
||||||
|
|
||||||
struct Node
|
|
||||||
{
|
{
|
||||||
using ChildrenVector = std::vector<Node>;
|
public:
|
||||||
|
FileLoader() = default;
|
||||||
|
~FileLoader();
|
||||||
|
|
||||||
ChildrenVector children;
|
// non-copyable
|
||||||
ContentIt propsBegin;
|
FileLoader(const FileLoader&) = delete;
|
||||||
ContentIt propsEnd;
|
FileLoader& operator=(const FileLoader&) = delete;
|
||||||
uint8_t type;
|
|
||||||
enum NodeChar: uint8_t
|
bool openFile(const char* filename, const char* identifier);
|
||||||
{
|
const uint8_t* getProps(const NODE, size_t& size);
|
||||||
ESCAPE = 0xFD,
|
bool getProps(const NODE, PropStream& props);
|
||||||
START = 0xFE,
|
NODE getChildNode(const NODE parent, uint32_t& type);
|
||||||
END = 0xFF,
|
NODE getNextNode(const NODE prev, uint32_t& type);
|
||||||
};
|
|
||||||
|
FILELOADER_ERRORS getError() const {
|
||||||
|
return lastError;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum SPECIAL_BYTES {
|
||||||
|
ESCAPE_CHAR = 0xFD,
|
||||||
|
NODE_START = 0xFE,
|
||||||
|
NODE_END = 0xFF,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool parseNode(NODE node);
|
||||||
|
|
||||||
|
inline bool readByte(int32_t& value);
|
||||||
|
inline bool readBytes(uint32_t size, int32_t pos);
|
||||||
|
inline bool safeSeek(uint32_t pos);
|
||||||
|
inline bool safeTell(int32_t& pos);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
struct cache {
|
||||||
|
uint8_t* data;
|
||||||
|
uint32_t loaded;
|
||||||
|
uint32_t base;
|
||||||
|
uint32_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr int32_t CACHE_BLOCKS = 3;
|
||||||
|
cache cached_data[CACHE_BLOCKS] = {};
|
||||||
|
|
||||||
|
uint8_t* buffer = new uint8_t[1024];
|
||||||
|
NODE root = nullptr;
|
||||||
|
FILE* file = nullptr;
|
||||||
|
|
||||||
|
FILELOADER_ERRORS lastError = ERROR_NONE;
|
||||||
|
uint32_t buffer_size = 1024;
|
||||||
|
|
||||||
|
uint32_t cache_size = 0;
|
||||||
|
static constexpr uint32_t NO_VALID_CACHE = std::numeric_limits<uint32_t>::max();
|
||||||
|
uint32_t cache_index = NO_VALID_CACHE;
|
||||||
|
uint32_t cache_offset = NO_VALID_CACHE;
|
||||||
|
|
||||||
|
inline uint32_t getCacheBlock(uint32_t pos);
|
||||||
|
int32_t loadCacheBlock(uint32_t pos);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LoadError : std::exception {
|
|
||||||
const char* what() const noexcept override = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct InvalidOTBFormat final : LoadError {
|
|
||||||
const char* what() const noexcept override {
|
|
||||||
return "Invalid OTBM file format";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Loader {
|
|
||||||
MappedFile fileContents;
|
|
||||||
Node root;
|
|
||||||
std::vector<char> propBuffer;
|
|
||||||
public:
|
|
||||||
Loader(const std::string& fileName, const Identifier& acceptedIdentifier);
|
|
||||||
bool getProps(const Node& node, PropStream& props);
|
|
||||||
const Node& parseTree();
|
|
||||||
};
|
|
||||||
|
|
||||||
} //namespace OTB
|
|
||||||
|
|
||||||
class PropStream
|
class PropStream
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -120,7 +200,7 @@ class PropStream
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
const char* p = nullptr;
|
const char* p = nullptr;
|
||||||
const char* end = nullptr;
|
const char* end = nullptr;
|
||||||
};
|
};
|
||||||
@@ -160,7 +240,7 @@ class PropWriteStream
|
|||||||
std::copy(str.begin(), str.end(), std::back_inserter(buffer));
|
std::copy(str.begin(), str.end(), std::back_inserter(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
std::vector<char> buffer;
|
std::vector<char> buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
2305
src/game.cpp
2305
src/game.cpp
File diff suppressed because it is too large
Load Diff
118
src/game.h
118
src/game.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -31,7 +31,6 @@
|
|||||||
#include "raids.h"
|
#include "raids.h"
|
||||||
#include "npc.h"
|
#include "npc.h"
|
||||||
#include "wildcardtree.h"
|
#include "wildcardtree.h"
|
||||||
#include "quests.h"
|
|
||||||
|
|
||||||
class ServiceManager;
|
class ServiceManager;
|
||||||
class Creature;
|
class Creature;
|
||||||
@@ -70,6 +69,22 @@ enum LightState_t {
|
|||||||
LIGHT_STATE_SUNRISE,
|
LIGHT_STATE_SUNRISE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RuleViolation {
|
||||||
|
RuleViolation() = default;
|
||||||
|
RuleViolation(uint32_t _reporterId, const std::string& _text) :
|
||||||
|
reporterId(_reporterId),
|
||||||
|
gamemasterId(0),
|
||||||
|
text(_text),
|
||||||
|
pending(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t reporterId;
|
||||||
|
uint32_t gamemasterId;
|
||||||
|
std::string text;
|
||||||
|
bool pending;
|
||||||
|
};
|
||||||
|
|
||||||
static constexpr int32_t EVENT_LIGHTINTERVAL = 10000;
|
static constexpr int32_t EVENT_LIGHTINTERVAL = 10000;
|
||||||
static constexpr int32_t EVENT_DECAYINTERVAL = 250;
|
static constexpr int32_t EVENT_DECAYINTERVAL = 250;
|
||||||
static constexpr int32_t EVENT_DECAY_BUCKETS = 4;
|
static constexpr int32_t EVENT_DECAY_BUCKETS = 4;
|
||||||
@@ -82,7 +97,7 @@ static constexpr int32_t EVENT_DECAY_BUCKETS = 4;
|
|||||||
class Game
|
class Game
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Game();
|
Game() = default;
|
||||||
~Game();
|
~Game();
|
||||||
|
|
||||||
// non-copyable
|
// non-copyable
|
||||||
@@ -204,7 +219,7 @@ class Game
|
|||||||
* \param extendedPos If true, the creature will in first-hand be placed 2 tiles away
|
* \param extendedPos If true, the creature will in first-hand be placed 2 tiles away
|
||||||
* \param force If true, placing the creature will not fail because of obstacles (creatures/items)
|
* \param force If true, placing the creature will not fail because of obstacles (creatures/items)
|
||||||
*/
|
*/
|
||||||
bool placeCreature(Creature* creature, const Position& pos, bool extendedPos = false, bool forced = false);
|
bool placeCreature(Creature* creature, const Position& pos, bool extendedPos = false, bool force = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove Creature from the map.
|
* Remove Creature from the map.
|
||||||
@@ -229,7 +244,7 @@ class Game
|
|||||||
return playersRecord;
|
return playersRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
LightInfo getWorldLightInfo() const;
|
void getWorldLightInfo(LightInfo& lightInfo) const;
|
||||||
|
|
||||||
ReturnValue internalMoveCreature(Creature* creature, Direction direction, uint32_t flags = 0);
|
ReturnValue internalMoveCreature(Creature* creature, Direction direction, uint32_t flags = 0);
|
||||||
ReturnValue internalMoveCreature(Creature& creature, Tile& toTile, uint32_t flags = 0);
|
ReturnValue internalMoveCreature(Creature& creature, Tile& toTile, uint32_t flags = 0);
|
||||||
@@ -307,19 +322,16 @@ class Game
|
|||||||
* \param text The text to say
|
* \param text The text to say
|
||||||
*/
|
*/
|
||||||
bool internalCreatureSay(Creature* creature, SpeakClasses type, const std::string& text,
|
bool internalCreatureSay(Creature* creature, SpeakClasses type, const std::string& text,
|
||||||
bool ghostMode, SpectatorVec* spectatorsPtr = nullptr, const Position* pos = nullptr);
|
bool ghostMode, SpectatorVec* listPtr = nullptr, const Position* pos = nullptr);
|
||||||
|
|
||||||
void loadPlayersRecord();
|
void loadPlayersRecord();
|
||||||
void checkPlayersRecord();
|
void checkPlayersRecord();
|
||||||
|
|
||||||
void sendGuildMotd(uint32_t playerId);
|
|
||||||
void kickPlayer(uint32_t playerId, bool displayEffect);
|
void kickPlayer(uint32_t playerId, bool displayEffect);
|
||||||
void playerReportBug(uint32_t playerId, const std::string& message, const Position& position, uint8_t category);
|
void playerReportBug(uint32_t playerId, const std::string& message);
|
||||||
void playerDebugAssert(uint32_t playerId, const std::string& assertLine, const std::string& date, const std::string& description, const std::string& comment);
|
void playerDebugAssert(uint32_t playerId, const std::string& assertLine, const std::string& date, const std::string& description, const std::string& comment);
|
||||||
void playerAnswerModalWindow(uint32_t playerId, uint32_t modalWindowId, uint8_t button, uint8_t choice);
|
|
||||||
void playerReportRuleViolation(uint32_t playerId, const std::string& targetName, uint8_t reportType, uint8_t reportReason, const std::string& comment, const std::string& translation);
|
|
||||||
|
|
||||||
bool internalStartTrade(Player* player, Player* tradePartner, Item* tradeItem);
|
bool internalStartTrade(Player* player, Player* partner, Item* tradeItem);
|
||||||
void internalCloseTrade(Player* player);
|
void internalCloseTrade(Player* player);
|
||||||
bool playerBroadcastMessage(Player* player, const std::string& text) const;
|
bool playerBroadcastMessage(Player* player, const std::string& text) const;
|
||||||
void broadcastMessage(const std::string& text, MessageClasses type) const;
|
void broadcastMessage(const std::string& text, MessageClasses type) const;
|
||||||
@@ -328,11 +340,10 @@ class Game
|
|||||||
void playerMoveThing(uint32_t playerId, const Position& fromPos, uint16_t spriteId, uint8_t fromStackPos,
|
void playerMoveThing(uint32_t playerId, const Position& fromPos, uint16_t spriteId, uint8_t fromStackPos,
|
||||||
const Position& toPos, uint8_t count);
|
const Position& toPos, uint8_t count);
|
||||||
void playerMoveCreatureByID(uint32_t playerId, uint32_t movingCreatureId, const Position& movingCreatureOrigPos, const Position& toPos);
|
void playerMoveCreatureByID(uint32_t playerId, uint32_t movingCreatureId, const Position& movingCreatureOrigPos, const Position& toPos);
|
||||||
void playerMoveCreature(Player* player, Creature* movingCreature, const Position& movingCreatureOrigPos, Tile* toTile);
|
void playerMoveCreature(Player* playerId, Creature* movingCreature, const Position& movingCreatureOrigPos, Tile* toTile);
|
||||||
void playerMoveItemByPlayerID(uint32_t playerId, const Position& fromPos, uint16_t spriteId, uint8_t fromStackPos, const Position& toPos, uint8_t count);
|
void playerMoveItemByPlayerID(uint32_t playerId, const Position& fromPos, uint16_t spriteId, uint8_t fromStackPos, const Position& toPos, uint8_t count);
|
||||||
void playerMoveItem(Player* player, const Position& fromPos,
|
void playerMoveItem(Player* player, const Position& fromPos,
|
||||||
uint16_t spriteId, uint8_t fromStackPos, const Position& toPos, uint8_t count, Item* item, Cylinder* toCylinder);
|
uint16_t spriteId, uint8_t fromStackPos, const Position& toPos, uint8_t count, Item* item, Cylinder* toCylinder);
|
||||||
void playerEquipItem(uint32_t playerId, uint16_t spriteId);
|
|
||||||
void playerMove(uint32_t playerId, Direction direction);
|
void playerMove(uint32_t playerId, Direction direction);
|
||||||
void playerCreatePrivateChannel(uint32_t playerId);
|
void playerCreatePrivateChannel(uint32_t playerId);
|
||||||
void playerChannelInvite(uint32_t playerId, const std::string& name);
|
void playerChannelInvite(uint32_t playerId, const std::string& name);
|
||||||
@@ -341,7 +352,6 @@ class Game
|
|||||||
void playerOpenChannel(uint32_t playerId, uint16_t channelId);
|
void playerOpenChannel(uint32_t playerId, uint16_t channelId);
|
||||||
void playerCloseChannel(uint32_t playerId, uint16_t channelId);
|
void playerCloseChannel(uint32_t playerId, uint16_t channelId);
|
||||||
void playerOpenPrivateChannel(uint32_t playerId, std::string& receiver);
|
void playerOpenPrivateChannel(uint32_t playerId, std::string& receiver);
|
||||||
void playerCloseNpcChannel(uint32_t playerId);
|
|
||||||
void playerReceivePing(uint32_t playerId);
|
void playerReceivePing(uint32_t playerId);
|
||||||
void playerReceivePingBack(uint32_t playerId);
|
void playerReceivePingBack(uint32_t playerId);
|
||||||
void playerAutoWalk(uint32_t playerId, const std::forward_list<Direction>& listDir);
|
void playerAutoWalk(uint32_t playerId, const std::forward_list<Direction>& listDir);
|
||||||
@@ -355,33 +365,23 @@ class Game
|
|||||||
void playerUpdateContainer(uint32_t playerId, uint8_t cid);
|
void playerUpdateContainer(uint32_t playerId, uint8_t cid);
|
||||||
void playerRotateItem(uint32_t playerId, const Position& pos, uint8_t stackPos, const uint16_t spriteId);
|
void playerRotateItem(uint32_t playerId, const Position& pos, uint8_t stackPos, const uint16_t spriteId);
|
||||||
void playerWriteItem(uint32_t playerId, uint32_t windowTextId, const std::string& text);
|
void playerWriteItem(uint32_t playerId, uint32_t windowTextId, const std::string& text);
|
||||||
void playerBrowseField(uint32_t playerId, const Position& pos);
|
|
||||||
void playerSeekInContainer(uint32_t playerId, uint8_t containerId, uint16_t index);
|
void playerSeekInContainer(uint32_t playerId, uint8_t containerId, uint16_t index);
|
||||||
void playerUpdateHouseWindow(uint32_t playerId, uint8_t listId, uint32_t windowTextId, const std::string& text);
|
void playerUpdateHouseWindow(uint32_t playerId, uint8_t listId, uint32_t windowTextId, const std::string& text);
|
||||||
void playerRequestTrade(uint32_t playerId, const Position& pos, uint8_t stackPos,
|
void playerRequestTrade(uint32_t playerId, const Position& pos, uint8_t stackPos,
|
||||||
uint32_t tradePlayerId, uint16_t spriteId);
|
uint32_t tradePlayerId, uint16_t spriteId);
|
||||||
void playerAcceptTrade(uint32_t playerId);
|
void playerAcceptTrade(uint32_t playerId);
|
||||||
void playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, uint8_t index);
|
void playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, uint8_t index);
|
||||||
void playerPurchaseItem(uint32_t playerId, uint16_t spriteId, uint8_t count, uint8_t amount,
|
|
||||||
bool ignoreCap = false, bool inBackpacks = false);
|
|
||||||
void playerSellItem(uint32_t playerId, uint16_t spriteId, uint8_t count,
|
|
||||||
uint8_t amount, bool ignoreEquipped = false);
|
|
||||||
void playerCloseShop(uint32_t playerId);
|
|
||||||
void playerLookInShop(uint32_t playerId, uint16_t spriteId, uint8_t count);
|
|
||||||
void playerCloseTrade(uint32_t playerId);
|
void playerCloseTrade(uint32_t playerId);
|
||||||
void playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId);
|
void playerSetAttackedCreature(uint32_t playerId, uint32_t creatureId);
|
||||||
void playerFollowCreature(uint32_t playerId, uint32_t creatureId);
|
void playerFollowCreature(uint32_t playerId, uint32_t creatureId);
|
||||||
void playerCancelAttackAndFollow(uint32_t playerId);
|
void playerCancelAttackAndFollow(uint32_t playerId);
|
||||||
void playerSetFightModes(uint32_t playerId, fightMode_t fightMode, bool chaseMode, bool secureMode);
|
void playerSetFightModes(uint32_t playerId, fightMode_t fightMode, chaseMode_t chaseMode, bool secureMode);
|
||||||
void playerLookAt(uint32_t playerId, const Position& pos, uint8_t stackPos);
|
void playerLookAt(uint32_t playerId, const Position& pos, uint8_t stackPos);
|
||||||
void playerLookInBattleList(uint32_t playerId, uint32_t creatureId);
|
void playerLookInBattleList(uint32_t playerId, uint32_t creatureId);
|
||||||
void playerRequestAddVip(uint32_t playerId, const std::string& name);
|
void playerRequestAddVip(uint32_t playerId, const std::string& name);
|
||||||
void playerRequestRemoveVip(uint32_t playerId, uint32_t guid);
|
void playerRequestRemoveVip(uint32_t playerId, uint32_t guid);
|
||||||
void playerRequestEditVip(uint32_t playerId, uint32_t guid, const std::string& description, uint32_t icon, bool notify);
|
|
||||||
void playerTurn(uint32_t playerId, Direction dir);
|
void playerTurn(uint32_t playerId, Direction dir);
|
||||||
void playerRequestOutfit(uint32_t playerId);
|
void playerRequestOutfit(uint32_t playerId);
|
||||||
void playerShowQuestLog(uint32_t playerId);
|
|
||||||
void playerShowQuestLine(uint32_t playerId, uint16_t questId);
|
|
||||||
void playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
|
void playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
|
||||||
const std::string& receiver, const std::string& text);
|
const std::string& receiver, const std::string& text);
|
||||||
void playerChangeOutfit(uint32_t playerId, Outfit_t outfit);
|
void playerChangeOutfit(uint32_t playerId, Outfit_t outfit);
|
||||||
@@ -391,18 +391,15 @@ class Game
|
|||||||
void playerPassPartyLeadership(uint32_t playerId, uint32_t newLeaderId);
|
void playerPassPartyLeadership(uint32_t playerId, uint32_t newLeaderId);
|
||||||
void playerLeaveParty(uint32_t playerId);
|
void playerLeaveParty(uint32_t playerId);
|
||||||
void playerEnableSharedPartyExperience(uint32_t playerId, bool sharedExpActive);
|
void playerEnableSharedPartyExperience(uint32_t playerId, bool sharedExpActive);
|
||||||
void playerToggleMount(uint32_t playerId, bool mount);
|
void playerProcessRuleViolationReport(uint32_t playerId, const std::string& name);
|
||||||
void playerLeaveMarket(uint32_t playerId);
|
void playerCloseRuleViolationReport(uint32_t playerId, const std::string& name);
|
||||||
void playerBrowseMarket(uint32_t playerId, uint16_t spriteId);
|
void playerCancelRuleViolationReport(uint32_t playerId);
|
||||||
void playerBrowseMarketOwnOffers(uint32_t playerId);
|
void playerReportRuleViolationReport(Player* player, const std::string& text);
|
||||||
void playerBrowseMarketOwnHistory(uint32_t playerId);
|
void playerContinueRuleViolationReport(Player* player, const std::string& text);
|
||||||
void playerCreateMarketOffer(uint32_t playerId, uint8_t type, uint16_t spriteId, uint16_t amount, uint32_t price, bool anonymous);
|
|
||||||
void playerCancelMarketOffer(uint32_t playerId, uint32_t timestamp, uint16_t counter);
|
|
||||||
void playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16_t counter, uint16_t amount);
|
|
||||||
|
|
||||||
void parsePlayerExtendedOpcode(uint32_t playerId, uint8_t opcode, const std::string& buffer);
|
void parsePlayerExtendedOpcode(uint32_t playerId, uint8_t opcode, const std::string& buffer);
|
||||||
|
|
||||||
std::forward_list<Item*> getMarketItemList(uint16_t wareId, uint16_t sufficientCount, DepotChest* depotChest, Inbox* inbox);
|
void closeRuleViolationReport(Player* player);
|
||||||
|
void cancelRuleViolationReport(Player* player);
|
||||||
|
|
||||||
static void updatePremium(Account& account);
|
static void updatePremium(Account& account);
|
||||||
|
|
||||||
@@ -413,17 +410,14 @@ class Game
|
|||||||
|
|
||||||
bool canThrowObjectTo(const Position& fromPos, const Position& toPos, bool checkLineOfSight = true,
|
bool canThrowObjectTo(const Position& fromPos, const Position& toPos, bool checkLineOfSight = true,
|
||||||
int32_t rangex = Map::maxClientViewportX, int32_t rangey = Map::maxClientViewportY) const;
|
int32_t rangex = Map::maxClientViewportX, int32_t rangey = Map::maxClientViewportY) const;
|
||||||
bool isSightClear(const Position& fromPos, const Position& toPos, bool floorCheck) const;
|
bool isSightClear(const Position& fromPos, const Position& toPos, bool sameFloor) const;
|
||||||
|
|
||||||
void changeSpeed(Creature* creature, int32_t varSpeedDelta);
|
void changeSpeed(Creature* creature, int32_t varSpeedDelta);
|
||||||
void internalCreatureChangeOutfit(Creature* creature, const Outfit_t& outfit);
|
void internalCreatureChangeOutfit(Creature* creature, const Outfit_t& oufit);
|
||||||
void internalCreatureChangeVisible(Creature* creature, bool visible);
|
void internalCreatureChangeVisible(Creature* creature, bool visible);
|
||||||
void changeLight(const Creature* creature);
|
void changeLight(const Creature* creature);
|
||||||
void updateCreatureSkull(const Creature* creature);
|
void updateCreatureSkull(const Creature* player);
|
||||||
void updatePlayerShield(Player* player);
|
void updatePlayerShield(Player* player);
|
||||||
void updatePlayerHelpers(const Player& player);
|
|
||||||
void updateCreatureType(Creature* creature);
|
|
||||||
void updateCreatureWalkthrough(const Creature* creature);
|
|
||||||
|
|
||||||
GameState_t getGameState() const;
|
GameState_t getGameState() const;
|
||||||
void setGameState(GameState_t newState);
|
void setGameState(GameState_t newState);
|
||||||
@@ -445,11 +439,14 @@ class Game
|
|||||||
|
|
||||||
//animation help functions
|
//animation help functions
|
||||||
void addCreatureHealth(const Creature* target);
|
void addCreatureHealth(const Creature* target);
|
||||||
static void addCreatureHealth(const SpectatorVec& spectators, const Creature* target);
|
static void addCreatureHealth(const SpectatorVec& list, const Creature* target);
|
||||||
void addMagicEffect(const Position& pos, uint8_t effect);
|
void addMagicEffect(const Position& pos, uint8_t effect);
|
||||||
static void addMagicEffect(const SpectatorVec& spectators, const Position& pos, uint8_t effect);
|
static void addMagicEffect(const SpectatorVec& list, const Position& pos, uint8_t effect);
|
||||||
void addDistanceEffect(const Position& fromPos, const Position& toPos, uint8_t effect);
|
void addDistanceEffect(const Position& fromPos, const Position& toPos, uint8_t effect);
|
||||||
static void addDistanceEffect(const SpectatorVec& spectators, const Position& fromPos, const Position& toPos, uint8_t effect);
|
static void addDistanceEffect(const SpectatorVec& list, const Position& fromPos, const Position& toPos, uint8_t effect);
|
||||||
|
void addAnimatedText(const Position& pos, uint8_t color, const std::string& text);
|
||||||
|
static void addAnimatedText(const SpectatorVec& list, const Position& pos, uint8_t color, const std::string& text);
|
||||||
|
void addMonsterSayText(const Position& pos, const std::string& text);
|
||||||
|
|
||||||
void startDecay(Item* item);
|
void startDecay(Item* item);
|
||||||
int32_t getLightHour() const {
|
int32_t getLightHour() const {
|
||||||
@@ -465,8 +462,7 @@ class Game
|
|||||||
uint32_t getMotdNum() const { return motdNum; }
|
uint32_t getMotdNum() const { return motdNum; }
|
||||||
void incrementMotdNum() { motdNum++; }
|
void incrementMotdNum() { motdNum++; }
|
||||||
|
|
||||||
void sendOfflineTrainingDialog(Player* player);
|
const std::unordered_map<uint32_t, RuleViolation>& getRuleViolationReports() const { return ruleViolations; }
|
||||||
|
|
||||||
const std::unordered_map<uint32_t, Player*>& getPlayers() const { return players; }
|
const std::unordered_map<uint32_t, Player*>& getPlayers() const { return players; }
|
||||||
const std::map<uint32_t, Npc*>& getNpcs() const { return npcs; }
|
const std::map<uint32_t, Npc*>& getNpcs() const { return npcs; }
|
||||||
|
|
||||||
@@ -476,55 +472,45 @@ class Game
|
|||||||
void addNpc(Npc* npc);
|
void addNpc(Npc* npc);
|
||||||
void removeNpc(Npc* npc);
|
void removeNpc(Npc* npc);
|
||||||
|
|
||||||
void addMonster(Monster* monster);
|
void addMonster(Monster* npc);
|
||||||
void removeMonster(Monster* monster);
|
void removeMonster(Monster* npc);
|
||||||
|
|
||||||
Guild* getGuild(uint32_t id) const;
|
Guild* getGuild(uint32_t id) const;
|
||||||
void addGuild(Guild* guild);
|
void addGuild(Guild* guild);
|
||||||
void removeGuild(uint32_t guildId);
|
void removeGuild(uint32_t guildId);
|
||||||
void decreaseBrowseFieldRef(const Position& pos);
|
|
||||||
|
|
||||||
std::unordered_map<Tile*, Container*> browseFields;
|
|
||||||
|
|
||||||
void internalRemoveItems(std::vector<Item*> itemList, uint32_t amount, bool stackable);
|
void internalRemoveItems(std::vector<Item*> itemList, uint32_t amount, bool stackable);
|
||||||
|
|
||||||
BedItem* getBedBySleeper(uint32_t guid) const;
|
BedItem* getBedBySleeper(uint32_t guid) const;
|
||||||
void setBedSleeper(BedItem* bed, uint32_t guid);
|
void setBedSleeper(BedItem* bed, uint32_t guid);
|
||||||
void removeBedSleeper(uint32_t guid);
|
void removeBedSleeper(uint32_t guid);
|
||||||
|
|
||||||
Item* getUniqueItem(uint16_t uniqueId);
|
|
||||||
bool addUniqueItem(uint16_t uniqueId, Item* item);
|
|
||||||
void removeUniqueItem(uint16_t uniqueId);
|
|
||||||
|
|
||||||
bool reload(ReloadTypes_t reloadType);
|
bool reload(ReloadTypes_t reloadType);
|
||||||
|
|
||||||
Groups groups;
|
Groups groups;
|
||||||
Map map;
|
Map map;
|
||||||
Mounts mounts;
|
|
||||||
Raids raids;
|
Raids raids;
|
||||||
Quests quests;
|
|
||||||
|
|
||||||
std::forward_list<Item*> toDecayItems;
|
protected:
|
||||||
|
|
||||||
private:
|
|
||||||
bool playerSaySpell(Player* player, SpeakClasses type, const std::string& text);
|
bool playerSaySpell(Player* player, SpeakClasses type, const std::string& text);
|
||||||
void playerWhisper(Player* player, const std::string& text);
|
void playerWhisper(Player* player, const std::string& text);
|
||||||
bool playerYell(Player* player, const std::string& text);
|
bool playerYell(Player* player, const std::string& text);
|
||||||
bool playerSpeakTo(Player* player, SpeakClasses type, const std::string& receiver, const std::string& text);
|
bool playerSpeakTo(Player* player, SpeakClasses type, const std::string& receiver, const std::string& text);
|
||||||
void playerSpeakToNpc(Player* player, const std::string& text);
|
|
||||||
|
|
||||||
void checkDecay();
|
void checkDecay();
|
||||||
void internalDecayItem(Item* item);
|
void internalDecayItem(Item* item);
|
||||||
|
|
||||||
|
//list of reported rule violations, for correct channel listing
|
||||||
|
std::unordered_map<uint32_t, RuleViolation> ruleViolations;
|
||||||
|
|
||||||
std::unordered_map<uint32_t, Player*> players;
|
std::unordered_map<uint32_t, Player*> players;
|
||||||
std::unordered_map<std::string, Player*> mappedPlayerNames;
|
std::unordered_map<std::string, Player*> mappedPlayerNames;
|
||||||
std::unordered_map<uint32_t, Guild*> guilds;
|
std::unordered_map<uint32_t, Guild*> guilds;
|
||||||
std::unordered_map<uint16_t, Item*> uniqueItems;
|
|
||||||
std::map<uint32_t, uint32_t> stages;
|
std::map<uint32_t, uint32_t> stages;
|
||||||
|
|
||||||
std::list<Item*> decayItems[EVENT_DECAY_BUCKETS];
|
std::list<Item*> decayItems[EVENT_DECAY_BUCKETS];
|
||||||
std::list<Creature*> checkCreatureLists[EVENT_CREATURECOUNT];
|
std::list<Creature*> checkCreatureLists[EVENT_CREATURECOUNT];
|
||||||
|
|
||||||
|
std::forward_list<Item*> toDecayItems;
|
||||||
|
|
||||||
std::vector<Creature*> ToReleaseCreatures;
|
std::vector<Creature*> ToReleaseCreatures;
|
||||||
std::vector<Item*> ToReleaseItems;
|
std::vector<Item*> ToReleaseItems;
|
||||||
|
|
||||||
@@ -540,8 +526,6 @@ class Game
|
|||||||
|
|
||||||
std::map<uint32_t, BedItem*> bedSleepersMap;
|
std::map<uint32_t, BedItem*> bedSleepersMap;
|
||||||
|
|
||||||
ModalWindow offlineTrainingWindow { std::numeric_limits<uint32_t>::max(), "Choose a Skill", "Please choose a skill:" };
|
|
||||||
|
|
||||||
static constexpr int32_t LIGHT_LEVEL_DAY = 250;
|
static constexpr int32_t LIGHT_LEVEL_DAY = 250;
|
||||||
static constexpr int32_t LIGHT_LEVEL_NIGHT = 40;
|
static constexpr int32_t LIGHT_LEVEL_NIGHT = 40;
|
||||||
static constexpr int32_t SUNSET = 1305;
|
static constexpr int32_t SUNSET = 1305;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -35,47 +35,44 @@ GlobalEvents::GlobalEvents() :
|
|||||||
|
|
||||||
GlobalEvents::~GlobalEvents()
|
GlobalEvents::~GlobalEvents()
|
||||||
{
|
{
|
||||||
clear(false);
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalEvents::clearMap(GlobalEventMap& map, bool fromLua)
|
void GlobalEvents::clearMap(GlobalEventMap& map)
|
||||||
{
|
{
|
||||||
for (auto it = map.begin(); it != map.end(); ) {
|
for (const auto& it : map) {
|
||||||
if (fromLua == it->second.fromLua) {
|
delete it.second;
|
||||||
it = map.erase(it);
|
|
||||||
} else {
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
map.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalEvents::clear(bool fromLua)
|
void GlobalEvents::clear()
|
||||||
{
|
{
|
||||||
g_scheduler.stopEvent(thinkEventId);
|
g_scheduler.stopEvent(thinkEventId);
|
||||||
thinkEventId = 0;
|
thinkEventId = 0;
|
||||||
g_scheduler.stopEvent(timerEventId);
|
g_scheduler.stopEvent(timerEventId);
|
||||||
timerEventId = 0;
|
timerEventId = 0;
|
||||||
|
|
||||||
clearMap(thinkMap, fromLua);
|
clearMap(thinkMap);
|
||||||
clearMap(serverMap, fromLua);
|
clearMap(serverMap);
|
||||||
clearMap(timerMap, fromLua);
|
clearMap(timerMap);
|
||||||
|
|
||||||
reInitState(fromLua);
|
scriptInterface.reInitState();
|
||||||
}
|
}
|
||||||
|
|
||||||
Event_ptr GlobalEvents::getEvent(const std::string& nodeName)
|
Event* GlobalEvents::getEvent(const std::string& nodeName)
|
||||||
{
|
{
|
||||||
if (strcasecmp(nodeName.c_str(), "globalevent") != 0) {
|
if (strcasecmp(nodeName.c_str(), "globalevent") != 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return Event_ptr(new GlobalEvent(&scriptInterface));
|
return new GlobalEvent(&scriptInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GlobalEvents::registerEvent(Event_ptr event, const pugi::xml_node&)
|
bool GlobalEvents::registerEvent(Event* event, const pugi::xml_node&)
|
||||||
{
|
{
|
||||||
GlobalEvent_ptr globalEvent{static_cast<GlobalEvent*>(event.release())}; //event is guaranteed to be a GlobalEvent
|
GlobalEvent* globalEvent = static_cast<GlobalEvent*>(event); //event is guaranteed to be a GlobalEvent
|
||||||
if (globalEvent->getEventType() == GLOBALEVENT_TIMER) {
|
if (globalEvent->getEventType() == GLOBALEVENT_TIMER) {
|
||||||
auto result = timerMap.emplace(globalEvent->getName(), std::move(*globalEvent));
|
auto result = timerMap.emplace(globalEvent->getName(), globalEvent);
|
||||||
if (result.second) {
|
if (result.second) {
|
||||||
if (timerEventId == 0) {
|
if (timerEventId == 0) {
|
||||||
timerEventId = g_scheduler.addEvent(createSchedulerTask(SCHEDULER_MINTICKS, std::bind(&GlobalEvents::timer, this)));
|
timerEventId = g_scheduler.addEvent(createSchedulerTask(SCHEDULER_MINTICKS, std::bind(&GlobalEvents::timer, this)));
|
||||||
@@ -83,42 +80,12 @@ bool GlobalEvents::registerEvent(Event_ptr event, const pugi::xml_node&)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (globalEvent->getEventType() != GLOBALEVENT_NONE) {
|
} else if (globalEvent->getEventType() != GLOBALEVENT_NONE) {
|
||||||
auto result = serverMap.emplace(globalEvent->getName(), std::move(*globalEvent));
|
auto result = serverMap.emplace(globalEvent->getName(), globalEvent);
|
||||||
if (result.second) {
|
if (result.second) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else { // think event
|
} else { // think event
|
||||||
auto result = thinkMap.emplace(globalEvent->getName(), std::move(*globalEvent));
|
auto result = thinkMap.emplace(globalEvent->getName(), globalEvent);
|
||||||
if (result.second) {
|
|
||||||
if (thinkEventId == 0) {
|
|
||||||
thinkEventId = g_scheduler.addEvent(createSchedulerTask(SCHEDULER_MINTICKS, std::bind(&GlobalEvents::think, this)));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "[Warning - GlobalEvents::configureEvent] Duplicate registered globalevent with name: " << globalEvent->getName() << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GlobalEvents::registerLuaEvent(GlobalEvent* event)
|
|
||||||
{
|
|
||||||
GlobalEvent_ptr globalEvent{ event };
|
|
||||||
if (globalEvent->getEventType() == GLOBALEVENT_TIMER) {
|
|
||||||
auto result = timerMap.emplace(globalEvent->getName(), std::move(*globalEvent));
|
|
||||||
if (result.second) {
|
|
||||||
if (timerEventId == 0) {
|
|
||||||
timerEventId = g_scheduler.addEvent(createSchedulerTask(SCHEDULER_MINTICKS, std::bind(&GlobalEvents::timer, this)));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (globalEvent->getEventType() != GLOBALEVENT_NONE) {
|
|
||||||
auto result = serverMap.emplace(globalEvent->getName(), std::move(*globalEvent));
|
|
||||||
if (result.second) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else { // think event
|
|
||||||
auto result = thinkMap.emplace(globalEvent->getName(), std::move(*globalEvent));
|
|
||||||
if (result.second) {
|
if (result.second) {
|
||||||
if (thinkEventId == 0) {
|
if (thinkEventId == 0) {
|
||||||
thinkEventId = g_scheduler.addEvent(createSchedulerTask(SCHEDULER_MINTICKS, std::bind(&GlobalEvents::think, this)));
|
thinkEventId = g_scheduler.addEvent(createSchedulerTask(SCHEDULER_MINTICKS, std::bind(&GlobalEvents::think, this)));
|
||||||
@@ -144,9 +111,9 @@ void GlobalEvents::timer()
|
|||||||
|
|
||||||
auto it = timerMap.begin();
|
auto it = timerMap.begin();
|
||||||
while (it != timerMap.end()) {
|
while (it != timerMap.end()) {
|
||||||
GlobalEvent& globalEvent = it->second;
|
GlobalEvent* globalEvent = it->second;
|
||||||
|
|
||||||
int64_t nextExecutionTime = globalEvent.getNextExecution() - now;
|
int64_t nextExecutionTime = globalEvent->getNextExecution() - now;
|
||||||
if (nextExecutionTime > 0) {
|
if (nextExecutionTime > 0) {
|
||||||
if (nextExecutionTime < nextScheduledTime) {
|
if (nextExecutionTime < nextScheduledTime) {
|
||||||
nextScheduledTime = nextExecutionTime;
|
nextScheduledTime = nextExecutionTime;
|
||||||
@@ -156,7 +123,7 @@ void GlobalEvents::timer()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!globalEvent.executeEvent()) {
|
if (!globalEvent->executeEvent()) {
|
||||||
it = timerMap.erase(it);
|
it = timerMap.erase(it);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -166,7 +133,7 @@ void GlobalEvents::timer()
|
|||||||
nextScheduledTime = nextExecutionTime;
|
nextScheduledTime = nextExecutionTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
globalEvent.setNextExecution(globalEvent.getNextExecution() + nextExecutionTime);
|
globalEvent->setNextExecution(globalEvent->getNextExecution() + nextExecutionTime);
|
||||||
|
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
@@ -182,10 +149,10 @@ void GlobalEvents::think()
|
|||||||
int64_t now = OTSYS_TIME();
|
int64_t now = OTSYS_TIME();
|
||||||
|
|
||||||
int64_t nextScheduledTime = std::numeric_limits<int64_t>::max();
|
int64_t nextScheduledTime = std::numeric_limits<int64_t>::max();
|
||||||
for (auto& it : thinkMap) {
|
for (const auto& it : thinkMap) {
|
||||||
GlobalEvent& globalEvent = it.second;
|
GlobalEvent* globalEvent = it.second;
|
||||||
|
|
||||||
int64_t nextExecutionTime = globalEvent.getNextExecution() - now;
|
int64_t nextExecutionTime = globalEvent->getNextExecution() - now;
|
||||||
if (nextExecutionTime > 0) {
|
if (nextExecutionTime > 0) {
|
||||||
if (nextExecutionTime < nextScheduledTime) {
|
if (nextExecutionTime < nextScheduledTime) {
|
||||||
nextScheduledTime = nextExecutionTime;
|
nextScheduledTime = nextExecutionTime;
|
||||||
@@ -193,16 +160,16 @@ void GlobalEvents::think()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!globalEvent.executeEvent()) {
|
if (!globalEvent->executeEvent()) {
|
||||||
std::cout << "[Error - GlobalEvents::think] Failed to execute event: " << globalEvent.getName() << std::endl;
|
std::cout << "[Error - GlobalEvents::think] Failed to execute event: " << globalEvent->getName() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextExecutionTime = globalEvent.getInterval();
|
nextExecutionTime = globalEvent->getInterval();
|
||||||
if (nextExecutionTime < nextScheduledTime) {
|
if (nextExecutionTime < nextScheduledTime) {
|
||||||
nextScheduledTime = nextExecutionTime;
|
nextScheduledTime = nextExecutionTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
globalEvent.setNextExecution(globalEvent.getNextExecution() + nextExecutionTime);
|
globalEvent->setNextExecution(globalEvent->getNextExecution() + nextExecutionTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextScheduledTime != std::numeric_limits<int64_t>::max()) {
|
if (nextScheduledTime != std::numeric_limits<int64_t>::max()) {
|
||||||
@@ -213,16 +180,15 @@ void GlobalEvents::think()
|
|||||||
void GlobalEvents::execute(GlobalEvent_t type) const
|
void GlobalEvents::execute(GlobalEvent_t type) const
|
||||||
{
|
{
|
||||||
for (const auto& it : serverMap) {
|
for (const auto& it : serverMap) {
|
||||||
const GlobalEvent& globalEvent = it.second;
|
GlobalEvent* globalEvent = it.second;
|
||||||
if (globalEvent.getEventType() == type) {
|
if (globalEvent->getEventType() == type) {
|
||||||
globalEvent.executeEvent();
|
globalEvent->executeEvent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalEventMap GlobalEvents::getEventMap(GlobalEvent_t type)
|
GlobalEventMap GlobalEvents::getEventMap(GlobalEvent_t type)
|
||||||
{
|
{
|
||||||
// TODO: This should be better implemented. Maybe have a map for every type.
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case GLOBALEVENT_NONE: return thinkMap;
|
case GLOBALEVENT_NONE: return thinkMap;
|
||||||
case GLOBALEVENT_TIMER: return timerMap;
|
case GLOBALEVENT_TIMER: return timerMap;
|
||||||
@@ -231,8 +197,8 @@ GlobalEventMap GlobalEvents::getEventMap(GlobalEvent_t type)
|
|||||||
case GLOBALEVENT_RECORD: {
|
case GLOBALEVENT_RECORD: {
|
||||||
GlobalEventMap retMap;
|
GlobalEventMap retMap;
|
||||||
for (const auto& it : serverMap) {
|
for (const auto& it : serverMap) {
|
||||||
if (it.second.getEventType() == type) {
|
if (it.second->getEventType() == type) {
|
||||||
retMap.emplace(it.first, it.second);
|
retMap[it.first] = it.second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return retMap;
|
return retMap;
|
||||||
@@ -349,7 +315,7 @@ bool GlobalEvent::executeRecord(uint32_t current, uint32_t old)
|
|||||||
return scriptInterface->callFunction(2);
|
return scriptInterface->callFunction(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GlobalEvent::executeEvent() const
|
bool GlobalEvent::executeEvent()
|
||||||
{
|
{
|
||||||
if (!scriptInterface->reserveScriptEnv()) {
|
if (!scriptInterface->reserveScriptEnv()) {
|
||||||
std::cout << "[Error - GlobalEvent::executeEvent] Call stack overflow" << std::endl;
|
std::cout << "[Error - GlobalEvent::executeEvent] Call stack overflow" << std::endl;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -33,8 +33,7 @@ enum GlobalEvent_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class GlobalEvent;
|
class GlobalEvent;
|
||||||
using GlobalEvent_ptr = std::unique_ptr<GlobalEvent>;
|
typedef std::map<std::string, GlobalEvent*> GlobalEventMap;
|
||||||
using GlobalEventMap = std::map<std::string, GlobalEvent>;
|
|
||||||
|
|
||||||
class GlobalEvents final : public BaseEvents
|
class GlobalEvents final : public BaseEvents
|
||||||
{
|
{
|
||||||
@@ -53,20 +52,18 @@ class GlobalEvents final : public BaseEvents
|
|||||||
void execute(GlobalEvent_t type) const;
|
void execute(GlobalEvent_t type) const;
|
||||||
|
|
||||||
GlobalEventMap getEventMap(GlobalEvent_t type);
|
GlobalEventMap getEventMap(GlobalEvent_t type);
|
||||||
static void clearMap(GlobalEventMap& map, bool fromLua);
|
static void clearMap(GlobalEventMap& map);
|
||||||
|
|
||||||
bool registerLuaEvent(GlobalEvent* event);
|
protected:
|
||||||
void clear(bool fromLua) override final;
|
std::string getScriptBaseName() const final {
|
||||||
|
|
||||||
private:
|
|
||||||
std::string getScriptBaseName() const override {
|
|
||||||
return "globalevents";
|
return "globalevents";
|
||||||
}
|
}
|
||||||
|
void clear() final;
|
||||||
|
|
||||||
Event_ptr getEvent(const std::string& nodeName) override;
|
Event* getEvent(const std::string& nodeName) final;
|
||||||
bool registerEvent(Event_ptr event, const pugi::xml_node& node) override;
|
bool registerEvent(Event* event, const pugi::xml_node& node) final;
|
||||||
|
|
||||||
LuaScriptInterface& getScriptInterface() override {
|
LuaScriptInterface& getScriptInterface() final {
|
||||||
return scriptInterface;
|
return scriptInterface;
|
||||||
}
|
}
|
||||||
LuaScriptInterface scriptInterface;
|
LuaScriptInterface scriptInterface;
|
||||||
@@ -80,31 +77,22 @@ class GlobalEvent final : public Event
|
|||||||
public:
|
public:
|
||||||
explicit GlobalEvent(LuaScriptInterface* interface);
|
explicit GlobalEvent(LuaScriptInterface* interface);
|
||||||
|
|
||||||
bool configureEvent(const pugi::xml_node& node) override;
|
bool configureEvent(const pugi::xml_node& node) final;
|
||||||
|
|
||||||
bool executeRecord(uint32_t current, uint32_t old);
|
bool executeRecord(uint32_t current, uint32_t old);
|
||||||
bool executeEvent() const;
|
bool executeEvent();
|
||||||
|
|
||||||
GlobalEvent_t getEventType() const {
|
GlobalEvent_t getEventType() const {
|
||||||
return eventType;
|
return eventType;
|
||||||
}
|
}
|
||||||
void setEventType(GlobalEvent_t type) {
|
|
||||||
eventType = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& getName() const {
|
const std::string& getName() const {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
void setName(std::string eventName) {
|
|
||||||
name = eventName;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t getInterval() const {
|
uint32_t getInterval() const {
|
||||||
return interval;
|
return interval;
|
||||||
}
|
}
|
||||||
void setInterval(uint32_t eventInterval) {
|
|
||||||
interval |= eventInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t getNextExecution() const {
|
int64_t getNextExecution() const {
|
||||||
return nextExecution;
|
return nextExecution;
|
||||||
@@ -113,10 +101,10 @@ class GlobalEvent final : public Event
|
|||||||
nextExecution = time;
|
nextExecution = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
GlobalEvent_t eventType = GLOBALEVENT_NONE;
|
GlobalEvent_t eventType = GLOBALEVENT_NONE;
|
||||||
|
|
||||||
std::string getScriptEventName() const override;
|
std::string getScriptEventName() const final;
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
int64_t nextExecution = 0;
|
int64_t nextExecution = 0;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,47 +24,6 @@
|
|||||||
#include "pugicast.h"
|
#include "pugicast.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
const std::unordered_map<std::string, PlayerFlags> ParsePlayerFlagMap = {
|
|
||||||
{"cannotusecombat", PlayerFlag_CannotUseCombat},
|
|
||||||
{"cannotattackplayer", PlayerFlag_CannotAttackPlayer},
|
|
||||||
{"cannotattackmonster", PlayerFlag_CannotAttackMonster},
|
|
||||||
{"cannotbeattacked", PlayerFlag_CannotBeAttacked},
|
|
||||||
{"canconvinceall", PlayerFlag_CanConvinceAll},
|
|
||||||
{"cansummonall", PlayerFlag_CanSummonAll},
|
|
||||||
{"canillusionall", PlayerFlag_CanIllusionAll},
|
|
||||||
{"cansenseinvisibility", PlayerFlag_CanSenseInvisibility},
|
|
||||||
{"ignoredbymonsters", PlayerFlag_IgnoredByMonsters},
|
|
||||||
{"notgaininfight", PlayerFlag_NotGainInFight},
|
|
||||||
{"hasinfinitemana", PlayerFlag_HasInfiniteMana},
|
|
||||||
{"hasinfinitesoul", PlayerFlag_HasInfiniteSoul},
|
|
||||||
{"hasnoexhaustion", PlayerFlag_HasNoExhaustion},
|
|
||||||
{"cannotusespells", PlayerFlag_CannotUseSpells},
|
|
||||||
{"cannotpickupitem", PlayerFlag_CannotPickupItem},
|
|
||||||
{"canalwayslogin", PlayerFlag_CanAlwaysLogin},
|
|
||||||
{"canbroadcast", PlayerFlag_CanBroadcast},
|
|
||||||
{"canedithouses", PlayerFlag_CanEditHouses},
|
|
||||||
{"cannotbebanned", PlayerFlag_CannotBeBanned},
|
|
||||||
{"cannotbepushed", PlayerFlag_CannotBePushed},
|
|
||||||
{"hasinfinitecapacity", PlayerFlag_HasInfiniteCapacity},
|
|
||||||
{"cannotpushallcreatures", PlayerFlag_CanPushAllCreatures},
|
|
||||||
{"cantalkredprivate", PlayerFlag_CanTalkRedPrivate},
|
|
||||||
{"cantalkredchannel", PlayerFlag_CanTalkRedChannel},
|
|
||||||
{"talkorangehelpchannel", PlayerFlag_TalkOrangeHelpChannel},
|
|
||||||
{"notgainexperience", PlayerFlag_NotGainExperience},
|
|
||||||
{"notgainmana", PlayerFlag_NotGainMana},
|
|
||||||
{"notgainhealth", PlayerFlag_NotGainHealth},
|
|
||||||
{"notgainskill", PlayerFlag_NotGainSkill},
|
|
||||||
{"setmaxspeed", PlayerFlag_SetMaxSpeed},
|
|
||||||
{"specialvip", PlayerFlag_SpecialVIP},
|
|
||||||
{"notgenerateloot", PlayerFlag_NotGenerateLoot},
|
|
||||||
{"cantalkredchannelanonymous", PlayerFlag_CanTalkRedChannelAnonymous},
|
|
||||||
{"ignoreprotectionzone", PlayerFlag_IgnoreProtectionZone},
|
|
||||||
{"ignorespellcheck", PlayerFlag_IgnoreSpellCheck},
|
|
||||||
{"ignoreweaponcheck", PlayerFlag_IgnoreWeaponCheck},
|
|
||||||
{"cannotbemuted", PlayerFlag_CannotBeMuted},
|
|
||||||
{"isalwayspremium", PlayerFlag_IsAlwaysPremium}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool Groups::load()
|
bool Groups::load()
|
||||||
{
|
{
|
||||||
pugi::xml_document doc;
|
pugi::xml_document doc;
|
||||||
@@ -78,24 +37,10 @@ bool Groups::load()
|
|||||||
Group group;
|
Group group;
|
||||||
group.id = pugi::cast<uint32_t>(groupNode.attribute("id").value());
|
group.id = pugi::cast<uint32_t>(groupNode.attribute("id").value());
|
||||||
group.name = groupNode.attribute("name").as_string();
|
group.name = groupNode.attribute("name").as_string();
|
||||||
|
group.flags = pugi::cast<uint64_t>(groupNode.attribute("flags").value());
|
||||||
group.access = groupNode.attribute("access").as_bool();
|
group.access = groupNode.attribute("access").as_bool();
|
||||||
group.maxDepotItems = pugi::cast<uint32_t>(groupNode.attribute("maxdepotitems").value());
|
group.maxDepotItems = pugi::cast<uint32_t>(groupNode.attribute("maxdepotitems").value());
|
||||||
group.maxVipEntries = pugi::cast<uint32_t>(groupNode.attribute("maxvipentries").value());
|
group.maxVipEntries = pugi::cast<uint32_t>(groupNode.attribute("maxvipentries").value());
|
||||||
group.flags = pugi::cast<uint64_t>(groupNode.attribute("flags").value());
|
|
||||||
if (pugi::xml_node node = groupNode.child("flags")) {
|
|
||||||
for (auto flagNode : node.children()) {
|
|
||||||
pugi::xml_attribute attr = flagNode.first_attribute();
|
|
||||||
if (!attr || (attr && !attr.as_bool())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto parseFlag = ParsePlayerFlagMap.find(attr.name());
|
|
||||||
if (parseFlag != ParsePlayerFlagMap.end()) {
|
|
||||||
group.flags |= parseFlag->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
groups.push_back(group);
|
groups.push_back(group);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,18 +28,11 @@ extern Game g_game;
|
|||||||
void Guild::addMember(Player* player)
|
void Guild::addMember(Player* player)
|
||||||
{
|
{
|
||||||
membersOnline.push_back(player);
|
membersOnline.push_back(player);
|
||||||
for (Player* member : membersOnline) {
|
|
||||||
g_game.updatePlayerHelpers(*member);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Guild::removeMember(Player* player)
|
void Guild::removeMember(Player* player)
|
||||||
{
|
{
|
||||||
membersOnline.remove(player);
|
membersOnline.remove(player);
|
||||||
for (Player* member : membersOnline) {
|
|
||||||
g_game.updatePlayerHelpers(*member);
|
|
||||||
}
|
|
||||||
g_game.updatePlayerHelpers(*player);
|
|
||||||
|
|
||||||
if (membersOnline.empty()) {
|
if (membersOnline.empty()) {
|
||||||
g_game.removeGuild(id);
|
g_game.removeGuild(id);
|
||||||
@@ -57,16 +50,6 @@ GuildRank* Guild::getRankById(uint32_t rankId)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GuildRank* Guild::getRankByName(const std::string& name) const
|
|
||||||
{
|
|
||||||
for (const auto& rank : ranks) {
|
|
||||||
if (rank.name == name) {
|
|
||||||
return &rank;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const GuildRank* Guild::getRankByLevel(uint8_t level) const
|
const GuildRank* Guild::getRankByLevel(uint8_t level) const
|
||||||
{
|
{
|
||||||
for (const auto& rank : ranks) {
|
for (const auto& rank : ranks) {
|
||||||
|
|||||||
20
src/guild.h
20
src/guild.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -55,26 +55,14 @@ class Guild
|
|||||||
memberCount = count;
|
memberCount = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<GuildRank>& getRanks() const {
|
GuildRank* getRankById(uint32_t id);
|
||||||
return ranks;
|
|
||||||
}
|
|
||||||
GuildRank* getRankById(uint32_t rankId);
|
|
||||||
const GuildRank* getRankByName(const std::string& name) const;
|
|
||||||
const GuildRank* getRankByLevel(uint8_t level) const;
|
const GuildRank* getRankByLevel(uint8_t level) const;
|
||||||
void addRank(uint32_t rankId, const std::string& rankName, uint8_t level);
|
void addRank(uint32_t id, const std::string& name, uint8_t level);
|
||||||
|
|
||||||
const std::string& getMotd() const {
|
|
||||||
return motd;
|
|
||||||
}
|
|
||||||
void setMotd(const std::string& motd) {
|
|
||||||
this->motd = motd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<Player*> membersOnline;
|
std::list<Player*> membersOnline;
|
||||||
std::vector<GuildRank> ranks;
|
std::vector<GuildRank> ranks;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string motd;
|
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
uint32_t memberCount = 0;
|
uint32_t memberCount = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -41,11 +41,11 @@ void House::addTile(HouseTile* tile)
|
|||||||
void House::setOwner(uint32_t guid, bool updateDatabase/* = true*/, Player* player/* = nullptr*/)
|
void House::setOwner(uint32_t guid, bool updateDatabase/* = true*/, Player* player/* = nullptr*/)
|
||||||
{
|
{
|
||||||
if (updateDatabase && owner != guid) {
|
if (updateDatabase && owner != guid) {
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "UPDATE `houses` SET `owner` = " << guid << ", `bid` = 0, `bid_end` = 0, `last_bid` = 0, `highest_bidder` = 0 WHERE `id` = " << id;
|
query << "UPDATE `houses` SET `owner` = " << guid << ", `bid` = 0, `bid_end` = 0, `last_bid` = 0, `highest_bidder` = 0 WHERE `id` = " << id;
|
||||||
db.executeQuery(query.str());
|
db->executeQuery(query.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isLoaded && owner == guid) {
|
if (isLoaded && owner == guid) {
|
||||||
@@ -85,26 +85,12 @@ void House::setOwner(uint32_t guid, bool updateDatabase/* = true*/, Player* play
|
|||||||
for (Door* door : doorSet) {
|
for (Door* door : doorSet) {
|
||||||
door->setAccessList("");
|
door->setAccessList("");
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
std::string strRentPeriod = asLowerCaseString(g_config.getString(ConfigManager::HOUSE_RENT_PERIOD));
|
|
||||||
time_t currentTime = time(nullptr);
|
|
||||||
if (strRentPeriod == "yearly") {
|
|
||||||
currentTime += 24 * 60 * 60 * 365;
|
|
||||||
} else if (strRentPeriod == "monthly") {
|
|
||||||
currentTime += 24 * 60 * 60 * 30;
|
|
||||||
} else if (strRentPeriod == "weekly") {
|
|
||||||
currentTime += 24 * 60 * 60 * 7;
|
|
||||||
} else if (strRentPeriod == "daily") {
|
|
||||||
currentTime += 24 * 60 * 60;
|
|
||||||
} else {
|
|
||||||
currentTime = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
paidUntil = currentTime;
|
//reset paid date
|
||||||
|
paidUntil = 0;
|
||||||
|
rentWarnings = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rentWarnings = 0;
|
|
||||||
|
|
||||||
if (guid != 0) {
|
if (guid != 0) {
|
||||||
std::string name = IOLoginData::getNameByGuid(guid);
|
std::string name = IOLoginData::getNameByGuid(guid);
|
||||||
if (!name.empty()) {
|
if (!name.empty()) {
|
||||||
@@ -124,9 +110,9 @@ void House::updateDoorDescription() const
|
|||||||
} else {
|
} else {
|
||||||
ss << "It belongs to house '" << houseName << "'. Nobody owns this house.";
|
ss << "It belongs to house '" << houseName << "'. Nobody owns this house.";
|
||||||
|
|
||||||
const int32_t housePrice = g_config.getNumber(ConfigManager::HOUSE_PRICE);
|
const int32_t housePrice = getRent();
|
||||||
if (housePrice != -1) {
|
if (housePrice != -1) {
|
||||||
ss << " It costs " << (houseTiles.size() * housePrice) << " gold coins.";
|
ss << " It costs " << housePrice * 5 << " gold coins.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,6 +216,7 @@ bool House::transferToDepot() const
|
|||||||
transferToDepot(&tmpPlayer);
|
transferToDepot(&tmpPlayer);
|
||||||
IOLoginData::savePlayer(&tmpPlayer);
|
IOLoginData::savePlayer(&tmpPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,8 +245,9 @@ bool House::transferToDepot(Player* player) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Item* item : moveItemList) {
|
for (Item* item : moveItemList) {
|
||||||
g_game.internalMoveItem(item->getParent(), player->getInbox(), INDEX_WHEREEVER, item, item->getItemCount(), nullptr, FLAG_NOLIMIT);
|
g_game.internalMoveItem(item->getParent(), player->getDepotLocker(getTownId(), true), INDEX_WHEREEVER, item, item->getItemCount(), nullptr, FLAG_NOLIMIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,7 +396,7 @@ bool House::executeTransfer(HouseTransferItem* item, Player* newOwner)
|
|||||||
void AccessList::parseList(const std::string& list)
|
void AccessList::parseList(const std::string& list)
|
||||||
{
|
{
|
||||||
playerList.clear();
|
playerList.clear();
|
||||||
guildRankList.clear();
|
guildList.clear();
|
||||||
expressionList.clear();
|
expressionList.clear();
|
||||||
regExList.clear();
|
regExList.clear();
|
||||||
this->list = list;
|
this->list = list;
|
||||||
@@ -433,11 +421,7 @@ void AccessList::parseList(const std::string& list)
|
|||||||
|
|
||||||
std::string::size_type at_pos = line.find("@");
|
std::string::size_type at_pos = line.find("@");
|
||||||
if (at_pos != std::string::npos) {
|
if (at_pos != std::string::npos) {
|
||||||
if (at_pos == 0) {
|
addGuild(line.substr(at_pos + 1));
|
||||||
addGuild(line.substr(1));
|
|
||||||
} else {
|
|
||||||
addGuildRank(line.substr(0, at_pos - 1), line.substr(at_pos + 1));
|
|
||||||
}
|
|
||||||
} else if (line.find("!") != std::string::npos || line.find("*") != std::string::npos || line.find("?") != std::string::npos) {
|
} else if (line.find("!") != std::string::npos || line.find("*") != std::string::npos || line.find("?") != std::string::npos) {
|
||||||
addExpression(line);
|
addExpression(line);
|
||||||
} else {
|
} else {
|
||||||
@@ -459,43 +443,11 @@ void AccessList::addPlayer(const std::string& name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
const Guild* getGuildByName(const std::string& name)
|
|
||||||
{
|
|
||||||
uint32_t guildId = IOGuild::getGuildIdByName(name);
|
|
||||||
if (guildId == 0) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Guild* guild = g_game.getGuild(guildId);
|
|
||||||
if (guild) {
|
|
||||||
return guild;
|
|
||||||
}
|
|
||||||
|
|
||||||
return IOGuild::loadGuild(guildId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessList::addGuild(const std::string& name)
|
void AccessList::addGuild(const std::string& name)
|
||||||
{
|
{
|
||||||
const Guild* guild = getGuildByName(name);
|
uint32_t guildId = IOGuild::getGuildIdByName(name);
|
||||||
if (guild) {
|
if (guildId != 0) {
|
||||||
for (const auto& rank : guild->getRanks()) {
|
guildList.insert(guildId);
|
||||||
guildRankList.insert(rank.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AccessList::addGuildRank(const std::string& name, const std::string& rankName)
|
|
||||||
{
|
|
||||||
const Guild* guild = getGuildByName(name);
|
|
||||||
if (guild) {
|
|
||||||
const GuildRank* rank = guild->getRankByName(rankName);
|
|
||||||
if (rank) {
|
|
||||||
guildRankList.insert(rank->id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -550,8 +502,8 @@ bool AccessList::isInList(const Player* player)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GuildRank* rank = player->getGuildRank();
|
const Guild* guild = player->getGuild();
|
||||||
return rank && guildRankList.find(rank->id) != guildRankList.end();
|
return guild && guildList.find(guild->getId()) != guildList.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AccessList::getList(std::string& list) const
|
void AccessList::getList(std::string& list) const
|
||||||
@@ -715,9 +667,7 @@ void Houses::payHouses(RentPeriod_t rentPeriod) const
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player.getBankBalance() >= rent) {
|
if (g_game.removeMoney(player.getDepotLocker(house->getTownId(), true), house->getRent(), FLAG_NOLIMIT)) {
|
||||||
player.setBankBalance(player.getBankBalance() - rent);
|
|
||||||
|
|
||||||
time_t paidUntil = currentTime;
|
time_t paidUntil = currentTime;
|
||||||
switch (rentPeriod) {
|
switch (rentPeriod) {
|
||||||
case RENTPERIOD_DAILY:
|
case RENTPERIOD_DAILY:
|
||||||
@@ -768,7 +718,7 @@ void Houses::payHouses(RentPeriod_t rentPeriod) const
|
|||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << "Warning! \nThe " << period << " rent of " << house->getRent() << " gold for your house \"" << house->getName() << "\" is payable. Have it within " << daysLeft << " days or you will lose this house.";
|
ss << "Warning! \nThe " << period << " rent of " << house->getRent() << " gold for your house \"" << house->getName() << "\" is payable. Have it within " << daysLeft << " days or you will lose this house.";
|
||||||
letter->setText(ss.str());
|
letter->setText(ss.str());
|
||||||
g_game.internalAddItem(player.getInbox(), letter, INDEX_WHEREEVER, FLAG_NOLIMIT);
|
g_game.internalAddItem(player.getDepotLocker(house->getTownId(), true), letter, INDEX_WHEREEVER, FLAG_NOLIMIT);
|
||||||
house->setPayRentWarnings(house->getPayRentWarnings() + 1);
|
house->setPayRentWarnings(house->getPayRentWarnings() + 1);
|
||||||
} else {
|
} else {
|
||||||
house->setOwner(0, true, &player);
|
house->setOwner(0, true, &player);
|
||||||
|
|||||||
36
src/house.h
36
src/house.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,7 +22,6 @@
|
|||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
#include "container.h"
|
#include "container.h"
|
||||||
#include "housetile.h"
|
#include "housetile.h"
|
||||||
@@ -38,7 +37,6 @@ class AccessList
|
|||||||
void parseList(const std::string& list);
|
void parseList(const std::string& list);
|
||||||
void addPlayer(const std::string& name);
|
void addPlayer(const std::string& name);
|
||||||
void addGuild(const std::string& name);
|
void addGuild(const std::string& name);
|
||||||
void addGuildRank(const std::string& name, const std::string& rankName);
|
|
||||||
void addExpression(const std::string& expression);
|
void addExpression(const std::string& expression);
|
||||||
|
|
||||||
bool isInList(const Player* player);
|
bool isInList(const Player* player);
|
||||||
@@ -48,7 +46,7 @@ class AccessList
|
|||||||
private:
|
private:
|
||||||
std::string list;
|
std::string list;
|
||||||
std::unordered_set<uint32_t> playerList;
|
std::unordered_set<uint32_t> playerList;
|
||||||
std::unordered_set<uint32_t> guildRankList;
|
std::unordered_set<uint32_t> guildList; // TODO: include ranks
|
||||||
std::list<std::string> expressionList;
|
std::list<std::string> expressionList;
|
||||||
std::list<std::pair<std::regex, bool>> regExList;
|
std::list<std::pair<std::regex, bool>> regExList;
|
||||||
};
|
};
|
||||||
@@ -62,10 +60,10 @@ class Door final : public Item
|
|||||||
Door(const Door&) = delete;
|
Door(const Door&) = delete;
|
||||||
Door& operator=(const Door&) = delete;
|
Door& operator=(const Door&) = delete;
|
||||||
|
|
||||||
Door* getDoor() override {
|
Door* getDoor() final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
const Door* getDoor() const override {
|
const Door* getDoor() const final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,8 +72,8 @@ class Door final : public Item
|
|||||||
}
|
}
|
||||||
|
|
||||||
//serialization
|
//serialization
|
||||||
Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream) override;
|
Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream) final;
|
||||||
void serializeAttr(PropWriteStream&) const override {}
|
void serializeAttr(PropWriteStream&) const final {}
|
||||||
|
|
||||||
void setDoorId(uint32_t doorId) {
|
void setDoorId(uint32_t doorId) {
|
||||||
setIntAttr(ITEM_ATTRIBUTE_DOORID, doorId);
|
setIntAttr(ITEM_ATTRIBUTE_DOORID, doorId);
|
||||||
@@ -89,11 +87,12 @@ class Door final : public Item
|
|||||||
void setAccessList(const std::string& textlist);
|
void setAccessList(const std::string& textlist);
|
||||||
bool getAccessList(std::string& list) const;
|
bool getAccessList(std::string& list) const;
|
||||||
|
|
||||||
void onRemoved() override;
|
void onRemoved() final;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
void setHouse(House* house);
|
void setHouse(House* house);
|
||||||
|
|
||||||
|
private:
|
||||||
House* house = nullptr;
|
House* house = nullptr;
|
||||||
std::unique_ptr<AccessList> accessList;
|
std::unique_ptr<AccessList> accessList;
|
||||||
friend class House;
|
friend class House;
|
||||||
@@ -111,8 +110,8 @@ enum AccessHouseLevel_t {
|
|||||||
HOUSE_OWNER = 3,
|
HOUSE_OWNER = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
using HouseTileList = std::list<HouseTile*>;
|
typedef std::list<HouseTile*> HouseTileList;
|
||||||
using HouseBedItemList = std::list<BedItem*>;
|
typedef std::list<BedItem*> HouseBedItemList;
|
||||||
|
|
||||||
class HouseTransferItem final : public Item
|
class HouseTransferItem final : public Item
|
||||||
{
|
{
|
||||||
@@ -121,12 +120,12 @@ class HouseTransferItem final : public Item
|
|||||||
|
|
||||||
explicit HouseTransferItem(House* house) : Item(0), house(house) {}
|
explicit HouseTransferItem(House* house) : Item(0), house(house) {}
|
||||||
|
|
||||||
void onTradeEvent(TradeEvents_t event, Player* owner) override;
|
void onTradeEvent(TradeEvents_t event, Player* owner) final;
|
||||||
bool canTransform() const override {
|
bool canTransform() const final {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
House* house;
|
House* house;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -208,7 +207,7 @@ class House
|
|||||||
|
|
||||||
HouseTransferItem* getTransferItem();
|
HouseTransferItem* getTransferItem();
|
||||||
void resetTransferItem();
|
void resetTransferItem();
|
||||||
bool executeTransfer(HouseTransferItem* item, Player* newOwner);
|
bool executeTransfer(HouseTransferItem* item, Player* player);
|
||||||
|
|
||||||
const HouseTileList& getTiles() const {
|
const HouseTileList& getTiles() const {
|
||||||
return houseTiles;
|
return houseTiles;
|
||||||
@@ -218,6 +217,7 @@ class House
|
|||||||
return doorSet;
|
return doorSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void addBed(BedItem* bed);
|
void addBed(BedItem* bed);
|
||||||
const HouseBedItemList& getBeds() const {
|
const HouseBedItemList& getBeds() const {
|
||||||
return bedsList;
|
return bedsList;
|
||||||
@@ -257,7 +257,7 @@ class House
|
|||||||
bool isLoaded = false;
|
bool isLoaded = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
using HouseMap = std::map<uint32_t, House*>;
|
typedef std::map<uint32_t, House*> HouseMap;
|
||||||
|
|
||||||
enum RentPeriod_t {
|
enum RentPeriod_t {
|
||||||
RENTPERIOD_DAILY,
|
RENTPERIOD_DAILY,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -31,13 +31,13 @@ class HouseTile final : public DynamicTile
|
|||||||
|
|
||||||
//cylinder implementations
|
//cylinder implementations
|
||||||
ReturnValue queryAdd(int32_t index, const Thing& thing, uint32_t count,
|
ReturnValue queryAdd(int32_t index, const Thing& thing, uint32_t count,
|
||||||
uint32_t flags, Creature* actor = nullptr) const override;
|
uint32_t flags, Creature* actor = nullptr) const final;
|
||||||
|
|
||||||
Tile* queryDestination(int32_t& index, const Thing& thing, Item** destItem,
|
Tile* queryDestination(int32_t& index, const Thing& thing, Item** destItem,
|
||||||
uint32_t& flags) override;
|
uint32_t& flags) final;
|
||||||
|
|
||||||
void addThing(int32_t index, Thing* thing) override;
|
void addThing(int32_t index, Thing* thing) final;
|
||||||
void internalAddThing(uint32_t index, Thing* thing) override;
|
void internalAddThing(uint32_t index, Thing* thing) final;
|
||||||
|
|
||||||
House* getHouse() {
|
House* getHouse() {
|
||||||
return house;
|
return house;
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
/**
|
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "otpch.h"
|
|
||||||
|
|
||||||
#include "inbox.h"
|
|
||||||
#include "tools.h"
|
|
||||||
|
|
||||||
Inbox::Inbox(uint16_t type) : Container(type, 30, false, true) {}
|
|
||||||
|
|
||||||
ReturnValue Inbox::queryAdd(int32_t, const Thing& thing, uint32_t,
|
|
||||||
uint32_t flags, Creature*) const
|
|
||||||
{
|
|
||||||
if (!hasBitSet(FLAG_NOLIMIT, flags)) {
|
|
||||||
return RETURNVALUE_CONTAINERNOTENOUGHROOM;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Item* item = thing.getItem();
|
|
||||||
if (!item) {
|
|
||||||
return RETURNVALUE_NOTPOSSIBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item == this) {
|
|
||||||
return RETURNVALUE_THISISIMPOSSIBLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!item->isPickupable()) {
|
|
||||||
return RETURNVALUE_CANNOTPICKUP;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RETURNVALUE_NOERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Inbox::postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t)
|
|
||||||
{
|
|
||||||
Cylinder* parent = getParent();
|
|
||||||
if (parent != nullptr) {
|
|
||||||
parent->postAddNotification(thing, oldParent, index, LINK_PARENT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Inbox::postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t)
|
|
||||||
{
|
|
||||||
Cylinder* parent = getParent();
|
|
||||||
if (parent != nullptr) {
|
|
||||||
parent->postRemoveNotification(thing, newParent, index, LINK_PARENT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Cylinder* Inbox::getParent() const
|
|
||||||
{
|
|
||||||
if (parent) {
|
|
||||||
return parent->getParent();
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
49
src/inbox.h
49
src/inbox.h
@@ -1,49 +0,0 @@
|
|||||||
/**
|
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FS_INBOX_H_C3EF10190329447883B9C3479234EE5C
|
|
||||||
#define FS_INBOX_H_C3EF10190329447883B9C3479234EE5C
|
|
||||||
|
|
||||||
#include "container.h"
|
|
||||||
|
|
||||||
class Inbox final : public Container
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit Inbox(uint16_t type);
|
|
||||||
|
|
||||||
//cylinder implementations
|
|
||||||
ReturnValue queryAdd(int32_t index, const Thing& thing, uint32_t count,
|
|
||||||
uint32_t flags, Creature* actor = nullptr) const override;
|
|
||||||
|
|
||||||
void postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
|
|
||||||
void postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
|
|
||||||
|
|
||||||
//overrides
|
|
||||||
bool canRemove() const override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Cylinder* getParent() const override;
|
|
||||||
Cylinder* getRealParent() const override {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,51 +19,29 @@
|
|||||||
|
|
||||||
#include "otpch.h"
|
#include "otpch.h"
|
||||||
|
|
||||||
#include "database.h"
|
|
||||||
#include "guild.h"
|
|
||||||
#include "ioguild.h"
|
#include "ioguild.h"
|
||||||
|
#include "database.h"
|
||||||
Guild* IOGuild::loadGuild(uint32_t guildId)
|
|
||||||
{
|
|
||||||
Database& db = Database::getInstance();
|
|
||||||
std::ostringstream query;
|
|
||||||
query << "SELECT `name` FROM `guilds` WHERE `id` = " << guildId;
|
|
||||||
if (DBResult_ptr result = db.storeQuery(query.str())) {
|
|
||||||
Guild* guild = new Guild(guildId, result->getString("name"));
|
|
||||||
|
|
||||||
query.str(std::string());
|
|
||||||
query << "SELECT `id`, `name`, `level` FROM `guild_ranks` WHERE `guild_id` = " << guildId;
|
|
||||||
|
|
||||||
if ((result = db.storeQuery(query.str()))) {
|
|
||||||
do {
|
|
||||||
guild->addRank(result->getNumber<uint32_t>("id"), result->getString("name"), result->getNumber<uint16_t>("level"));
|
|
||||||
} while (result->next());
|
|
||||||
}
|
|
||||||
return guild;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t IOGuild::getGuildIdByName(const std::string& name)
|
uint32_t IOGuild::getGuildIdByName(const std::string& name)
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `id` FROM `guilds` WHERE `name` = " << db.escapeString(name);
|
query << "SELECT `id` FROM `guilds` WHERE `name` = " << db->escapeString(name);
|
||||||
|
|
||||||
DBResult_ptr result = db.storeQuery(query.str());
|
DBResult_ptr result = db->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return result->getNumber<uint32_t>("id");
|
return result->getNumber<uint32_t>("id");
|
||||||
}
|
}
|
||||||
|
|
||||||
void IOGuild::getWarList(uint32_t guildId, GuildWarVector& guildWarVector)
|
void IOGuild::getWarList(uint32_t guildId, GuildWarList& guildWarList)
|
||||||
{
|
{
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `guild1`, `guild2` FROM `guild_wars` WHERE (`guild1` = " << guildId << " OR `guild2` = " << guildId << ") AND `ended` = 0 AND `status` = 1";
|
query << "SELECT `guild1`, `guild2` FROM `guild_wars` WHERE (`guild1` = " << guildId << " OR `guild2` = " << guildId << ") AND `ended` = 0 AND `status` = 1";
|
||||||
|
|
||||||
DBResult_ptr result = Database::getInstance().storeQuery(query.str());
|
DBResult_ptr result = Database::getInstance()->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -71,9 +49,9 @@ void IOGuild::getWarList(uint32_t guildId, GuildWarVector& guildWarVector)
|
|||||||
do {
|
do {
|
||||||
uint32_t guild1 = result->getNumber<uint32_t>("guild1");
|
uint32_t guild1 = result->getNumber<uint32_t>("guild1");
|
||||||
if (guildId != guild1) {
|
if (guildId != guild1) {
|
||||||
guildWarVector.push_back(guild1);
|
guildWarList.push_back(guild1);
|
||||||
} else {
|
} else {
|
||||||
guildWarVector.push_back(result->getNumber<uint32_t>("guild2"));
|
guildWarList.push_back(result->getNumber<uint32_t>("guild2"));
|
||||||
}
|
}
|
||||||
} while (result->next());
|
} while (result->next());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -20,15 +20,13 @@
|
|||||||
#ifndef FS_IOGUILD_H_EF9ACEBA0B844C388B70FF52E69F1AFF
|
#ifndef FS_IOGUILD_H_EF9ACEBA0B844C388B70FF52E69F1AFF
|
||||||
#define FS_IOGUILD_H_EF9ACEBA0B844C388B70FF52E69F1AFF
|
#define FS_IOGUILD_H_EF9ACEBA0B844C388B70FF52E69F1AFF
|
||||||
|
|
||||||
class Guild;
|
typedef std::vector<uint32_t> GuildWarList;
|
||||||
using GuildWarVector = std::vector<uint32_t>;
|
|
||||||
|
|
||||||
class IOGuild
|
class IOGuild
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static Guild* loadGuild(uint32_t guildId);
|
|
||||||
static uint32_t getGuildIdByName(const std::string& name);
|
static uint32_t getGuildIdByName(const std::string& name);
|
||||||
static void getWarList(uint32_t guildId, GuildWarVector& guildWarVector);
|
static void getWarList(uint32_t guildId, GuildWarList& guildWarList);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -31,14 +31,13 @@ Account IOLoginData::loadAccount(uint32_t accno)
|
|||||||
Account account;
|
Account account;
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `id`, `name`, `password`, `type`, `premdays`, `lastday` FROM `accounts` WHERE `id` = " << accno;
|
query << "SELECT `id`, `password`, `type`, `premdays`, `lastday` FROM `accounts` WHERE `id` = " << accno;
|
||||||
DBResult_ptr result = Database::getInstance().storeQuery(query.str());
|
DBResult_ptr result = Database::getInstance()->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
account.id = result->getNumber<uint32_t>("id");
|
account.id = result->getNumber<uint32_t>("id");
|
||||||
account.name = result->getString("name");
|
|
||||||
account.accountType = static_cast<AccountType_t>(result->getNumber<int32_t>("type"));
|
account.accountType = static_cast<AccountType_t>(result->getNumber<int32_t>("type"));
|
||||||
account.premiumDays = result->getNumber<uint16_t>("premdays");
|
account.premiumDays = result->getNumber<uint16_t>("premdays");
|
||||||
account.lastDay = result->getNumber<time_t>("lastday");
|
account.lastDay = result->getNumber<time_t>("lastday");
|
||||||
@@ -49,45 +48,16 @@ bool IOLoginData::saveAccount(const Account& acc)
|
|||||||
{
|
{
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "UPDATE `accounts` SET `premdays` = " << acc.premiumDays << ", `lastday` = " << acc.lastDay << " WHERE `id` = " << acc.id;
|
query << "UPDATE `accounts` SET `premdays` = " << acc.premiumDays << ", `lastday` = " << acc.lastDay << " WHERE `id` = " << acc.id;
|
||||||
return Database::getInstance().executeQuery(query.str());
|
return Database::getInstance()->executeQuery(query.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string decodeSecret(const std::string& secret)
|
bool IOLoginData::loginserverAuthentication(uint32_t accountNumber, const std::string& password, Account& account)
|
||||||
{
|
{
|
||||||
// simple base32 decoding
|
Database* db = Database::getInstance();
|
||||||
std::string key;
|
|
||||||
key.reserve(10);
|
|
||||||
|
|
||||||
uint32_t buffer = 0, left = 0;
|
|
||||||
for (const auto& ch : secret) {
|
|
||||||
buffer <<= 5;
|
|
||||||
if (ch >= 'A' && ch <= 'Z') {
|
|
||||||
buffer |= (ch & 0x1F) - 1;
|
|
||||||
} else if (ch >= '2' && ch <= '7') {
|
|
||||||
buffer |= ch - 24;
|
|
||||||
} else {
|
|
||||||
// if a key is broken, return empty and the comparison
|
|
||||||
// will always be false since the token must not be empty
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
left += 5;
|
|
||||||
if (left >= 8) {
|
|
||||||
left -= 8;
|
|
||||||
key.push_back(static_cast<char>(buffer >> left));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IOLoginData::loginserverAuthentication(const std::string& name, const std::string& password, Account& account)
|
|
||||||
{
|
|
||||||
Database& db = Database::getInstance();
|
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `id`, `name`, `password`, `secret`, `type`, `premdays`, `lastday` FROM `accounts` WHERE `name` = " << db.escapeString(name);
|
query << "SELECT `id`, `password`, `type`, `premdays`, `lastday` FROM `accounts` WHERE `id` = " << accountNumber;
|
||||||
DBResult_ptr result = db.storeQuery(query.str());
|
DBResult_ptr result = db->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -97,15 +67,13 @@ bool IOLoginData::loginserverAuthentication(const std::string& name, const std::
|
|||||||
}
|
}
|
||||||
|
|
||||||
account.id = result->getNumber<uint32_t>("id");
|
account.id = result->getNumber<uint32_t>("id");
|
||||||
account.name = result->getString("name");
|
|
||||||
account.key = decodeSecret(result->getString("secret"));
|
|
||||||
account.accountType = static_cast<AccountType_t>(result->getNumber<int32_t>("type"));
|
account.accountType = static_cast<AccountType_t>(result->getNumber<int32_t>("type"));
|
||||||
account.premiumDays = result->getNumber<uint16_t>("premdays");
|
account.premiumDays = result->getNumber<uint16_t>("premdays");
|
||||||
account.lastDay = result->getNumber<time_t>("lastday");
|
account.lastDay = result->getNumber<time_t>("lastday");
|
||||||
|
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "SELECT `name`, `deletion` FROM `players` WHERE `account_id` = " << account.id;
|
query << "SELECT `name`, `deletion` FROM `players` WHERE `account_id` = " << account.id;
|
||||||
result = db.storeQuery(query.str());
|
result = db->storeQuery(query.str());
|
||||||
if (result) {
|
if (result) {
|
||||||
do {
|
do {
|
||||||
if (result->getNumber<uint64_t>("deletion") == 0) {
|
if (result->getNumber<uint64_t>("deletion") == 0) {
|
||||||
@@ -117,29 +85,17 @@ bool IOLoginData::loginserverAuthentication(const std::string& name, const std::
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t IOLoginData::gameworldAuthentication(const std::string& accountName, const std::string& password, std::string& characterName, std::string& token, uint32_t tokenTime)
|
uint32_t IOLoginData::gameworldAuthentication(uint32_t accountNumber, const std::string& password, std::string& characterName)
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `id`, `password`, `secret` FROM `accounts` WHERE `name` = " << db.escapeString(accountName);
|
query << "SELECT `id`, `password` FROM `accounts` WHERE `id` = " << accountNumber;
|
||||||
DBResult_ptr result = db.storeQuery(query.str());
|
DBResult_ptr result = db->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string secret = decodeSecret(result->getString("secret"));
|
|
||||||
if (!secret.empty()) {
|
|
||||||
if (token.empty()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool tokenValid = token == generateToken(secret, tokenTime) || token == generateToken(secret, tokenTime - 1) || token == generateToken(secret, tokenTime + 1);
|
|
||||||
if (!tokenValid) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (transformToSHA1(password) != result->getString("password")) {
|
if (transformToSHA1(password) != result->getString("password")) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -147,8 +103,8 @@ uint32_t IOLoginData::gameworldAuthentication(const std::string& accountName, co
|
|||||||
uint32_t accountId = result->getNumber<uint32_t>("id");
|
uint32_t accountId = result->getNumber<uint32_t>("id");
|
||||||
|
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "SELECT `account_id`, `name`, `deletion` FROM `players` WHERE `name` = " << db.escapeString(characterName);
|
query << "SELECT `account_id`, `name`, `deletion` FROM `players` WHERE `name` = " << db->escapeString(characterName);
|
||||||
result = db.storeQuery(query.str());
|
result = db->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -164,7 +120,7 @@ AccountType_t IOLoginData::getAccountType(uint32_t accountId)
|
|||||||
{
|
{
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `type` FROM `accounts` WHERE `id` = " << accountId;
|
query << "SELECT `type` FROM `accounts` WHERE `id` = " << accountId;
|
||||||
DBResult_ptr result = Database::getInstance().storeQuery(query.str());
|
DBResult_ptr result = Database::getInstance()->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return ACCOUNT_TYPE_NORMAL;
|
return ACCOUNT_TYPE_NORMAL;
|
||||||
}
|
}
|
||||||
@@ -175,7 +131,7 @@ void IOLoginData::setAccountType(uint32_t accountId, AccountType_t accountType)
|
|||||||
{
|
{
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "UPDATE `accounts` SET `type` = " << static_cast<uint16_t>(accountType) << " WHERE `id` = " << accountId;
|
query << "UPDATE `accounts` SET `type` = " << static_cast<uint16_t>(accountType) << " WHERE `id` = " << accountId;
|
||||||
Database::getInstance().executeQuery(query.str());
|
Database::getInstance()->executeQuery(query.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void IOLoginData::updateOnlineStatus(uint32_t guid, bool login)
|
void IOLoginData::updateOnlineStatus(uint32_t guid, bool login)
|
||||||
@@ -190,20 +146,20 @@ void IOLoginData::updateOnlineStatus(uint32_t guid, bool login)
|
|||||||
} else {
|
} else {
|
||||||
query << "DELETE FROM `players_online` WHERE `player_id` = " << guid;
|
query << "DELETE FROM `players_online` WHERE `player_id` = " << guid;
|
||||||
}
|
}
|
||||||
Database::getInstance().executeQuery(query.str());
|
Database::getInstance()->executeQuery(query.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IOLoginData::preloadPlayer(Player* player, const std::string& name)
|
bool IOLoginData::preloadPlayer(Player* player, const std::string& name)
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `id`, `account_id`, `group_id`, `deletion`, (SELECT `type` FROM `accounts` WHERE `accounts`.`id` = `account_id`) AS `account_type`";
|
query << "SELECT `id`, `account_id`, `group_id`, `deletion`, (SELECT `type` FROM `accounts` WHERE `accounts`.`id` = `account_id`) AS `account_type`";
|
||||||
if (!g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
|
if (!g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
|
||||||
query << ", (SELECT `premdays` FROM `accounts` WHERE `accounts`.`id` = `account_id`) AS `premium_days`";
|
query << ", (SELECT `premdays` FROM `accounts` WHERE `accounts`.`id` = `account_id`) AS `premium_days`";
|
||||||
}
|
}
|
||||||
query << " FROM `players` WHERE `name` = " << db.escapeString(name);
|
query << " FROM `players` WHERE `name` = " << db->escapeString(name);
|
||||||
DBResult_ptr result = db.storeQuery(query.str());
|
DBResult_ptr result = db->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -231,18 +187,17 @@ bool IOLoginData::preloadPlayer(Player* player, const std::string& name)
|
|||||||
|
|
||||||
bool IOLoginData::loadPlayerById(Player* player, uint32_t id)
|
bool IOLoginData::loadPlayerById(Player* player, uint32_t id)
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries`, `direction` FROM `players` WHERE `id` = " << id;
|
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id;
|
||||||
return loadPlayer(player, db.storeQuery(query.str()));
|
return loadPlayer(player, Database::getInstance()->storeQuery(query.str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IOLoginData::loadPlayerByName(Player* player, const std::string& name)
|
bool IOLoginData::loadPlayerByName(Player* player, const std::string& name)
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries`, `direction` FROM `players` WHERE `name` = " << db.escapeString(name);
|
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db->escapeString(name);
|
||||||
return loadPlayer(player, db.storeQuery(query.str()));
|
return loadPlayer(player, db->storeQuery(query.str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
||||||
@@ -251,7 +206,7 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
uint32_t accno = result->getNumber<uint32_t>("account_id");
|
uint32_t accno = result->getNumber<uint32_t>("account_id");
|
||||||
Account acc = loadAccount(accno);
|
Account acc = loadAccount(accno);
|
||||||
@@ -297,7 +252,7 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
|||||||
}
|
}
|
||||||
|
|
||||||
player->soul = result->getNumber<uint16_t>("soul");
|
player->soul = result->getNumber<uint16_t>("soul");
|
||||||
player->capacity = result->getNumber<uint32_t>("cap") * 100;
|
player->capacity = std::max<uint32_t>(400, result->getNumber<uint32_t>("cap")) * 100;
|
||||||
player->blessings = result->getNumber<uint16_t>("blessings");
|
player->blessings = result->getNumber<uint16_t>("blessings");
|
||||||
|
|
||||||
unsigned long conditionsSize;
|
unsigned long conditionsSize;
|
||||||
@@ -343,20 +298,17 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
|||||||
player->defaultOutfit.lookFeet = result->getNumber<uint16_t>("lookfeet");
|
player->defaultOutfit.lookFeet = result->getNumber<uint16_t>("lookfeet");
|
||||||
player->defaultOutfit.lookAddons = result->getNumber<uint16_t>("lookaddons");
|
player->defaultOutfit.lookAddons = result->getNumber<uint16_t>("lookaddons");
|
||||||
player->currentOutfit = player->defaultOutfit;
|
player->currentOutfit = player->defaultOutfit;
|
||||||
player->direction = static_cast<Direction> (result->getNumber<uint16_t>("direction"));
|
|
||||||
|
|
||||||
if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) {
|
if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) {
|
||||||
const time_t skullSeconds = result->getNumber<time_t>("skulltime") - time(nullptr);
|
player->playerKillerEnd = result->getNumber<time_t>("skulltime");
|
||||||
if (skullSeconds > 0) {
|
|
||||||
//ensure that we round up the number of ticks
|
|
||||||
player->skullTicks = (skullSeconds + 2);
|
|
||||||
|
|
||||||
uint16_t skull = result->getNumber<uint16_t>("skull");
|
uint16_t skull = result->getNumber<uint16_t>("skull");
|
||||||
if (skull == SKULL_RED) {
|
if (skull == SKULL_RED) {
|
||||||
player->skull = SKULL_RED;
|
player->skull = SKULL_RED;
|
||||||
} else if (skull == SKULL_BLACK) {
|
}
|
||||||
player->skull = SKULL_BLACK;
|
|
||||||
}
|
if (player->playerKillerEnd == 0) {
|
||||||
|
player->skull = SKULL_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,9 +319,6 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
|||||||
player->lastLoginSaved = result->getNumber<time_t>("lastlogin");
|
player->lastLoginSaved = result->getNumber<time_t>("lastlogin");
|
||||||
player->lastLogout = result->getNumber<time_t>("lastlogout");
|
player->lastLogout = result->getNumber<time_t>("lastlogout");
|
||||||
|
|
||||||
player->offlineTrainingTime = result->getNumber<int32_t>("offlinetraining_time") * 1000;
|
|
||||||
player->offlineTrainingSkill = result->getNumber<int32_t>("offlinetraining_skill");
|
|
||||||
|
|
||||||
Town* town = g_game.map.towns.getTown(result->getNumber<uint32_t>("town_id"));
|
Town* town = g_game.map.towns.getTown(result->getNumber<uint32_t>("town_id"));
|
||||||
if (!town) {
|
if (!town) {
|
||||||
std::cout << "[Error - IOLoginData::loadPlayer] " << player->name << " has Town ID " << result->getNumber<uint32_t>("town_id") << " which doesn't exist" << std::endl;
|
std::cout << "[Error - IOLoginData::loadPlayer] " << player->name << " has Town ID " << result->getNumber<uint32_t>("town_id") << " which doesn't exist" << std::endl;
|
||||||
@@ -402,16 +351,38 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
|
|
||||||
|
query << "SELECT `date` FROM `player_murders` WHERE `player_id` = " << player->getGUID() << " ORDER BY `date` ASC";
|
||||||
|
if ((result = db->storeQuery(query.str()))) {
|
||||||
|
do {
|
||||||
|
player->murderTimeStamps.push_back(result->getNumber<time_t>("date"));
|
||||||
|
} while (result->next());
|
||||||
|
}
|
||||||
|
|
||||||
|
query.str(std::string());
|
||||||
query << "SELECT `guild_id`, `rank_id`, `nick` FROM `guild_membership` WHERE `player_id` = " << player->getGUID();
|
query << "SELECT `guild_id`, `rank_id`, `nick` FROM `guild_membership` WHERE `player_id` = " << player->getGUID();
|
||||||
if ((result = db.storeQuery(query.str()))) {
|
if ((result = db->storeQuery(query.str()))) {
|
||||||
uint32_t guildId = result->getNumber<uint32_t>("guild_id");
|
uint32_t guildId = result->getNumber<uint32_t>("guild_id");
|
||||||
uint32_t playerRankId = result->getNumber<uint32_t>("rank_id");
|
uint32_t playerRankId = result->getNumber<uint32_t>("rank_id");
|
||||||
player->guildNick = result->getString("nick");
|
player->guildNick = result->getString("nick");
|
||||||
|
|
||||||
Guild* guild = g_game.getGuild(guildId);
|
Guild* guild = g_game.getGuild(guildId);
|
||||||
if (!guild) {
|
if (!guild) {
|
||||||
guild = IOGuild::loadGuild(guildId);
|
query.str(std::string());
|
||||||
g_game.addGuild(guild);
|
query << "SELECT `name` FROM `guilds` WHERE `id` = " << guildId;
|
||||||
|
if ((result = db->storeQuery(query.str()))) {
|
||||||
|
guild = new Guild(guildId, result->getString("name"));
|
||||||
|
g_game.addGuild(guild);
|
||||||
|
|
||||||
|
query.str(std::string());
|
||||||
|
query << "SELECT `id`, `name`, `level` FROM `guild_ranks` WHERE `guild_id` = " << guildId;
|
||||||
|
|
||||||
|
if ((result = db->storeQuery(query.str()))) {
|
||||||
|
do {
|
||||||
|
guild->addRank(result->getNumber<uint32_t>("id"), result->getString("name"), result->getNumber<uint16_t>("level"));
|
||||||
|
} while (result->next());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (guild) {
|
if (guild) {
|
||||||
@@ -421,7 +392,7 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
|||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "SELECT `id`, `name`, `level` FROM `guild_ranks` WHERE `id` = " << playerRankId;
|
query << "SELECT `id`, `name`, `level` FROM `guild_ranks` WHERE `id` = " << playerRankId;
|
||||||
|
|
||||||
if ((result = db.storeQuery(query.str()))) {
|
if ((result = db->storeQuery(query.str()))) {
|
||||||
guild->addRank(result->getNumber<uint32_t>("id"), result->getString("name"), result->getNumber<uint16_t>("level"));
|
guild->addRank(result->getNumber<uint32_t>("id"), result->getString("name"), result->getNumber<uint16_t>("level"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,11 +404,11 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
|||||||
|
|
||||||
player->guildRank = rank;
|
player->guildRank = rank;
|
||||||
|
|
||||||
IOGuild::getWarList(guildId, player->guildWarVector);
|
IOGuild::getWarList(guildId, player->guildWarList);
|
||||||
|
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "SELECT COUNT(*) AS `members` FROM `guild_membership` WHERE `guild_id` = " << guildId;
|
query << "SELECT COUNT(*) AS `members` FROM `guild_membership` WHERE `guild_id` = " << guildId;
|
||||||
if ((result = db.storeQuery(query.str()))) {
|
if ((result = db->storeQuery(query.str()))) {
|
||||||
guild->setMemberCount(result->getNumber<uint32_t>("members"));
|
guild->setMemberCount(result->getNumber<uint32_t>("members"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -445,7 +416,7 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
|||||||
|
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "SELECT `player_id`, `name` FROM `player_spells` WHERE `player_id` = " << player->getGUID();
|
query << "SELECT `player_id`, `name` FROM `player_spells` WHERE `player_id` = " << player->getGUID();
|
||||||
if ((result = db.storeQuery(query.str()))) {
|
if ((result = db->storeQuery(query.str()))) {
|
||||||
do {
|
do {
|
||||||
player->learnedInstantSpellList.emplace_front(result->getString("name"));
|
player->learnedInstantSpellList.emplace_front(result->getString("name"));
|
||||||
} while (result->next());
|
} while (result->next());
|
||||||
@@ -456,7 +427,7 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
|||||||
|
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "SELECT `pid`, `sid`, `itemtype`, `count`, `attributes` FROM `player_items` WHERE `player_id` = " << player->getGUID() << " ORDER BY `sid` DESC";
|
query << "SELECT `pid`, `sid`, `itemtype`, `count`, `attributes` FROM `player_items` WHERE `player_id` = " << player->getGUID() << " ORDER BY `sid` DESC";
|
||||||
if ((result = db.storeQuery(query.str()))) {
|
if ((result = db->storeQuery(query.str()))) {
|
||||||
loadItems(itemMap, result);
|
loadItems(itemMap, result);
|
||||||
|
|
||||||
for (ItemMap::const_reverse_iterator it = itemMap.rbegin(), end = itemMap.rend(); it != end; ++it) {
|
for (ItemMap::const_reverse_iterator it = itemMap.rbegin(), end = itemMap.rend(); it != end; ++it) {
|
||||||
@@ -484,7 +455,7 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
|||||||
|
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "SELECT `pid`, `sid`, `itemtype`, `count`, `attributes` FROM `player_depotitems` WHERE `player_id` = " << player->getGUID() << " ORDER BY `sid` DESC";
|
query << "SELECT `pid`, `sid`, `itemtype`, `count`, `attributes` FROM `player_depotitems` WHERE `player_id` = " << player->getGUID() << " ORDER BY `sid` DESC";
|
||||||
if ((result = db.storeQuery(query.str()))) {
|
if ((result = db->storeQuery(query.str()))) {
|
||||||
loadItems(itemMap, result);
|
loadItems(itemMap, result);
|
||||||
|
|
||||||
for (ItemMap::const_reverse_iterator it = itemMap.rbegin(), end = itemMap.rend(); it != end; ++it) {
|
for (ItemMap::const_reverse_iterator it = itemMap.rbegin(), end = itemMap.rend(); it != end; ++it) {
|
||||||
@@ -493,9 +464,15 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
|||||||
|
|
||||||
int32_t pid = pair.second;
|
int32_t pid = pair.second;
|
||||||
if (pid >= 0 && pid < 100) {
|
if (pid >= 0 && pid < 100) {
|
||||||
DepotChest* depotChest = player->getDepotChest(pid, true);
|
Container* itemContainer = item->getContainer();
|
||||||
if (depotChest) {
|
if (itemContainer) {
|
||||||
depotChest->internalAddThing(item);
|
DepotLocker* locker = itemContainer->getDepotLocker();
|
||||||
|
if (locker) {
|
||||||
|
DepotLocker* existingLocker = player->getDepotLocker(pid, false);
|
||||||
|
if (!existingLocker) {
|
||||||
|
player->depotLockerMap[pid] = locker;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ItemMap::const_iterator it2 = itemMap.find(pid);
|
ItemMap::const_iterator it2 = itemMap.find(pid);
|
||||||
@@ -511,49 +488,19 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//load inbox items
|
|
||||||
itemMap.clear();
|
|
||||||
|
|
||||||
query.str(std::string());
|
|
||||||
query << "SELECT `pid`, `sid`, `itemtype`, `count`, `attributes` FROM `player_inboxitems` WHERE `player_id` = " << player->getGUID() << " ORDER BY `sid` DESC";
|
|
||||||
if ((result = db.storeQuery(query.str()))) {
|
|
||||||
loadItems(itemMap, result);
|
|
||||||
|
|
||||||
for (ItemMap::const_reverse_iterator it = itemMap.rbegin(), end = itemMap.rend(); it != end; ++it) {
|
|
||||||
const std::pair<Item*, int32_t>& pair = it->second;
|
|
||||||
Item* item = pair.first;
|
|
||||||
int32_t pid = pair.second;
|
|
||||||
|
|
||||||
if (pid >= 0 && pid < 100) {
|
|
||||||
player->getInbox()->internalAddThing(item);
|
|
||||||
} else {
|
|
||||||
ItemMap::const_iterator it2 = itemMap.find(pid);
|
|
||||||
|
|
||||||
if (it2 == itemMap.end()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Container* container = it2->second.first->getContainer();
|
|
||||||
if (container) {
|
|
||||||
container->internalAddThing(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//load storage map
|
//load storage map
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "SELECT `key`, `value` FROM `player_storage` WHERE `player_id` = " << player->getGUID();
|
query << "SELECT `key`, `value` FROM `player_storage` WHERE `player_id` = " << player->getGUID();
|
||||||
if ((result = db.storeQuery(query.str()))) {
|
if ((result = db->storeQuery(query.str()))) {
|
||||||
do {
|
do {
|
||||||
player->addStorageValue(result->getNumber<uint32_t>("key"), result->getNumber<int32_t>("value"), true);
|
player->addStorageValue(result->getNumber<uint32_t>("key"), result->getNumber<int32_t>("value"));
|
||||||
} while (result->next());
|
} while (result->next());
|
||||||
}
|
}
|
||||||
|
|
||||||
//load vip
|
//load vip
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "SELECT `player_id` FROM `account_viplist` WHERE `account_id` = " << player->getAccount();
|
query << "SELECT `player_id` FROM `account_viplist` WHERE `account_id` = " << player->getAccount();
|
||||||
if ((result = db.storeQuery(query.str()))) {
|
if ((result = db->storeQuery(query.str()))) {
|
||||||
do {
|
do {
|
||||||
player->addVIPInternal(result->getNumber<uint32_t>("player_id"));
|
player->addVIPInternal(result->getNumber<uint32_t>("player_id"));
|
||||||
} while (result->next());
|
} while (result->next());
|
||||||
@@ -569,12 +516,12 @@ bool IOLoginData::saveItems(const Player* player, const ItemBlockList& itemList,
|
|||||||
{
|
{
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
|
|
||||||
using ContainerBlock = std::pair<Container*, int32_t>;
|
typedef std::pair<Container*, int32_t> containerBlock;
|
||||||
std::list<ContainerBlock> queue;
|
std::list<containerBlock> queue;
|
||||||
|
|
||||||
int32_t runningId = 100;
|
int32_t runningId = 100;
|
||||||
|
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
for (const auto& it : itemList) {
|
for (const auto& it : itemList) {
|
||||||
int32_t pid = it.first;
|
int32_t pid = it.first;
|
||||||
Item* item = it.second;
|
Item* item = it.second;
|
||||||
@@ -586,7 +533,7 @@ bool IOLoginData::saveItems(const Player* player, const ItemBlockList& itemList,
|
|||||||
size_t attributesSize;
|
size_t attributesSize;
|
||||||
const char* attributes = propWriteStream.getStream(attributesSize);
|
const char* attributes = propWriteStream.getStream(attributesSize);
|
||||||
|
|
||||||
ss << player->getGUID() << ',' << pid << ',' << runningId << ',' << item->getID() << ',' << item->getSubType() << ',' << db.escapeBlob(attributes, attributesSize);
|
ss << player->getGUID() << ',' << pid << ',' << runningId << ',' << item->getID() << ',' << item->getSubType() << ',' << db->escapeBlob(attributes, attributesSize);
|
||||||
if (!query_insert.addRow(ss)) {
|
if (!query_insert.addRow(ss)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -597,7 +544,7 @@ bool IOLoginData::saveItems(const Player* player, const ItemBlockList& itemList,
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (!queue.empty()) {
|
while (!queue.empty()) {
|
||||||
const ContainerBlock& cb = queue.front();
|
const containerBlock& cb = queue.front();
|
||||||
Container* container = cb.first;
|
Container* container = cb.first;
|
||||||
int32_t parentId = cb.second;
|
int32_t parentId = cb.second;
|
||||||
queue.pop_front();
|
queue.pop_front();
|
||||||
@@ -616,7 +563,7 @@ bool IOLoginData::saveItems(const Player* player, const ItemBlockList& itemList,
|
|||||||
size_t attributesSize;
|
size_t attributesSize;
|
||||||
const char* attributes = propWriteStream.getStream(attributesSize);
|
const char* attributes = propWriteStream.getStream(attributesSize);
|
||||||
|
|
||||||
ss << player->getGUID() << ',' << parentId << ',' << runningId << ',' << item->getID() << ',' << item->getSubType() << ',' << db.escapeBlob(attributes, attributesSize);
|
ss << player->getGUID() << ',' << parentId << ',' << runningId << ',' << item->getID() << ',' << item->getSubType() << ',' << db->escapeBlob(attributes, attributesSize);
|
||||||
if (!query_insert.addRow(ss)) {
|
if (!query_insert.addRow(ss)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -631,11 +578,11 @@ bool IOLoginData::savePlayer(Player* player)
|
|||||||
player->changeHealth(1);
|
player->changeHealth(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `save` FROM `players` WHERE `id` = " << player->getGUID();
|
query << "SELECT `save` FROM `players` WHERE `id` = " << player->getGUID();
|
||||||
DBResult_ptr result = db.storeQuery(query.str());
|
DBResult_ptr result = db->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -643,7 +590,7 @@ bool IOLoginData::savePlayer(Player* player)
|
|||||||
if (result->getNumber<uint16_t>("save") == 0) {
|
if (result->getNumber<uint16_t>("save") == 0) {
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "UPDATE `players` SET `lastlogin` = " << player->lastLoginSaved << ", `lastip` = " << player->lastIP << " WHERE `id` = " << player->getGUID();
|
query << "UPDATE `players` SET `lastlogin` = " << player->lastLoginSaved << ", `lastip` = " << player->lastIP << " WHERE `id` = " << player->getGUID();
|
||||||
return db.executeQuery(query.str());
|
return db->executeQuery(query.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
//serialize conditions
|
//serialize conditions
|
||||||
@@ -686,7 +633,7 @@ bool IOLoginData::savePlayer(Player* player)
|
|||||||
query << "`posz` = " << loginPosition.getZ() << ',';
|
query << "`posz` = " << loginPosition.getZ() << ',';
|
||||||
|
|
||||||
query << "`cap` = " << (player->capacity / 100) << ',';
|
query << "`cap` = " << (player->capacity / 100) << ',';
|
||||||
query << "`sex` = " << static_cast<uint16_t>(player->sex) << ',';
|
query << "`sex` = " << player->sex << ',';
|
||||||
|
|
||||||
if (player->lastLoginSaved != 0) {
|
if (player->lastLoginSaved != 0) {
|
||||||
query << "`lastlogin` = " << player->lastLoginSaved << ',';
|
query << "`lastlogin` = " << player->lastLoginSaved << ',';
|
||||||
@@ -696,29 +643,21 @@ bool IOLoginData::savePlayer(Player* player)
|
|||||||
query << "`lastip` = " << player->lastIP << ',';
|
query << "`lastip` = " << player->lastIP << ',';
|
||||||
}
|
}
|
||||||
|
|
||||||
query << "`conditions` = " << db.escapeBlob(conditions, conditionsSize) << ',';
|
query << "`conditions` = " << db->escapeBlob(conditions, conditionsSize) << ',';
|
||||||
|
|
||||||
if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) {
|
if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) {
|
||||||
int64_t skullTime = 0;
|
query << "`skulltime` = " << player->getPlayerKillerEnd() << ',';
|
||||||
|
|
||||||
if (player->skullTicks > 0) {
|
|
||||||
skullTime = time(nullptr) + player->skullTicks;
|
|
||||||
}
|
|
||||||
query << "`skulltime` = " << skullTime << ',';
|
|
||||||
|
|
||||||
Skulls_t skull = SKULL_NONE;
|
Skulls_t skull = SKULL_NONE;
|
||||||
if (player->skull == SKULL_RED) {
|
if (player->skull == SKULL_RED) {
|
||||||
skull = SKULL_RED;
|
skull = SKULL_RED;
|
||||||
} else if (player->skull == SKULL_BLACK) {
|
|
||||||
skull = SKULL_BLACK;
|
|
||||||
}
|
}
|
||||||
query << "`skull` = " << static_cast<int64_t>(skull) << ',';
|
|
||||||
|
query << "`skull` = " << static_cast<uint32_t>(skull) << ',';
|
||||||
}
|
}
|
||||||
|
|
||||||
query << "`lastlogout` = " << player->getLastLogout() << ',';
|
query << "`lastlogout` = " << player->getLastLogout() << ',';
|
||||||
query << "`balance` = " << player->bankBalance << ',';
|
query << "`balance` = " << player->bankBalance << ',';
|
||||||
query << "`offlinetraining_time` = " << player->getOfflineTrainingTime() / 1000 << ',';
|
|
||||||
query << "`offlinetraining_skill` = " << player->getOfflineTrainingSkill() << ',';
|
|
||||||
query << "`stamina` = " << player->getStaminaMinutes() << ',';
|
query << "`stamina` = " << player->getStaminaMinutes() << ',';
|
||||||
|
|
||||||
query << "`skill_fist` = " << player->skills[SKILL_FIST].level << ',';
|
query << "`skill_fist` = " << player->skills[SKILL_FIST].level << ',';
|
||||||
@@ -735,7 +674,6 @@ bool IOLoginData::savePlayer(Player* player)
|
|||||||
query << "`skill_shielding_tries` = " << player->skills[SKILL_SHIELD].tries << ',';
|
query << "`skill_shielding_tries` = " << player->skills[SKILL_SHIELD].tries << ',';
|
||||||
query << "`skill_fishing` = " << player->skills[SKILL_FISHING].level << ',';
|
query << "`skill_fishing` = " << player->skills[SKILL_FISHING].level << ',';
|
||||||
query << "`skill_fishing_tries` = " << player->skills[SKILL_FISHING].tries << ',';
|
query << "`skill_fishing_tries` = " << player->skills[SKILL_FISHING].tries << ',';
|
||||||
query << "`direction` = " << static_cast<uint16_t> (player->getDirection()) << ',';
|
|
||||||
|
|
||||||
if (!player->isOffline()) {
|
if (!player->isOffline()) {
|
||||||
query << "`onlinetime` = `onlinetime` + " << (time(nullptr) - player->lastLoginSaved) << ',';
|
query << "`onlinetime` = `onlinetime` + " << (time(nullptr) - player->lastLoginSaved) << ',';
|
||||||
@@ -748,14 +686,14 @@ bool IOLoginData::savePlayer(Player* player)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!db.executeQuery(query.str())) {
|
if (!db->executeQuery(query.str())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// learned spells
|
// learned spells
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "DELETE FROM `player_spells` WHERE `player_id` = " << player->getGUID();
|
query << "DELETE FROM `player_spells` WHERE `player_id` = " << player->getGUID();
|
||||||
if (!db.executeQuery(query.str())) {
|
if (!db->executeQuery(query.str())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -763,7 +701,7 @@ bool IOLoginData::savePlayer(Player* player)
|
|||||||
|
|
||||||
DBInsert spellsQuery("INSERT INTO `player_spells` (`player_id`, `name` ) VALUES ");
|
DBInsert spellsQuery("INSERT INTO `player_spells` (`player_id`, `name` ) VALUES ");
|
||||||
for (const std::string& spellName : player->learnedInstantSpellList) {
|
for (const std::string& spellName : player->learnedInstantSpellList) {
|
||||||
query << player->getGUID() << ',' << db.escapeString(spellName);
|
query << player->getGUID() << ',' << db->escapeString(spellName);
|
||||||
if (!spellsQuery.addRow(query)) {
|
if (!spellsQuery.addRow(query)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -773,9 +711,31 @@ bool IOLoginData::savePlayer(Player* player)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query.str(std::string());
|
||||||
|
query << "DELETE FROM `player_murders` WHERE `player_id` = " << player->getGUID();
|
||||||
|
|
||||||
|
if (!db->executeQuery(query.str())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
query.str(std::string());
|
||||||
|
|
||||||
|
DBInsert murdersQuery("INSERT INTO `player_murders`(`id`, `player_id`, `date`) VALUES ");
|
||||||
|
for (time_t timestamp : player->murderTimeStamps) {
|
||||||
|
query << "NULL," << player->getGUID() << ',' << timestamp;
|
||||||
|
if (!murdersQuery.addRow(query)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!murdersQuery.execute()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//item saving
|
//item saving
|
||||||
|
query.str(std::string());
|
||||||
query << "DELETE FROM `player_items` WHERE `player_id` = " << player->getGUID();
|
query << "DELETE FROM `player_items` WHERE `player_id` = " << player->getGUID();
|
||||||
if (!db.executeQuery(query.str())) {
|
if (!db->executeQuery(query.str())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -793,51 +753,28 @@ bool IOLoginData::savePlayer(Player* player)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player->lastDepotId != -1) {
|
//save depot items
|
||||||
//save depot items
|
|
||||||
query.str(std::string());
|
|
||||||
query << "DELETE FROM `player_depotitems` WHERE `player_id` = " << player->getGUID();
|
|
||||||
|
|
||||||
if (!db.executeQuery(query.str())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBInsert depotQuery("INSERT INTO `player_depotitems` (`player_id`, `pid`, `sid`, `itemtype`, `count`, `attributes`) VALUES ");
|
|
||||||
itemList.clear();
|
|
||||||
|
|
||||||
for (const auto& it : player->depotChests) {
|
|
||||||
DepotChest* depotChest = it.second;
|
|
||||||
for (Item* item : depotChest->getItemList()) {
|
|
||||||
itemList.emplace_back(it.first, item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!saveItems(player, itemList, depotQuery, propWriteStream)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//save inbox items
|
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "DELETE FROM `player_inboxitems` WHERE `player_id` = " << player->getGUID();
|
query << "DELETE FROM `player_depotitems` WHERE `player_id` = " << player->getGUID();
|
||||||
if (!db.executeQuery(query.str())) {
|
|
||||||
|
if (!db->executeQuery(query.str())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBInsert inboxQuery("INSERT INTO `player_inboxitems` (`player_id`, `pid`, `sid`, `itemtype`, `count`, `attributes`) VALUES ");
|
DBInsert depotQuery("INSERT INTO `player_depotitems` (`player_id`, `pid`, `sid`, `itemtype`, `count`, `attributes`) VALUES ");
|
||||||
itemList.clear();
|
itemList.clear();
|
||||||
|
|
||||||
for (Item* item : player->getInbox()->getItemList()) {
|
for (const auto& it : player->depotLockerMap) {
|
||||||
itemList.emplace_back(0, item);
|
itemList.emplace_back(it.first, it.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!saveItems(player, itemList, inboxQuery, propWriteStream)) {
|
if (!saveItems(player, itemList, depotQuery, propWriteStream)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "DELETE FROM `player_storage` WHERE `player_id` = " << player->getGUID();
|
query << "DELETE FROM `player_storage` WHERE `player_id` = " << player->getGUID();
|
||||||
if (!db.executeQuery(query.str())) {
|
if (!db->executeQuery(query.str())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -865,7 +802,7 @@ std::string IOLoginData::getNameByGuid(uint32_t guid)
|
|||||||
{
|
{
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `name` FROM `players` WHERE `id` = " << guid;
|
query << "SELECT `name` FROM `players` WHERE `id` = " << guid;
|
||||||
DBResult_ptr result = Database::getInstance().storeQuery(query.str());
|
DBResult_ptr result = Database::getInstance()->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
@@ -874,11 +811,11 @@ std::string IOLoginData::getNameByGuid(uint32_t guid)
|
|||||||
|
|
||||||
uint32_t IOLoginData::getGuidByName(const std::string& name)
|
uint32_t IOLoginData::getGuidByName(const std::string& name)
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `id` FROM `players` WHERE `name` = " << db.escapeString(name);
|
query << "SELECT `id` FROM `players` WHERE `name` = " << db->escapeString(name);
|
||||||
DBResult_ptr result = db.storeQuery(query.str());
|
DBResult_ptr result = db->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -887,11 +824,11 @@ uint32_t IOLoginData::getGuidByName(const std::string& name)
|
|||||||
|
|
||||||
bool IOLoginData::getGuidByNameEx(uint32_t& guid, bool& specialVip, std::string& name)
|
bool IOLoginData::getGuidByNameEx(uint32_t& guid, bool& specialVip, std::string& name)
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `name`, `id`, `group_id`, `account_id` FROM `players` WHERE `name` = " << db.escapeString(name);
|
query << "SELECT `name`, `id`, `group_id`, `account_id` FROM `players` WHERE `name` = " << db->escapeString(name);
|
||||||
DBResult_ptr result = db.storeQuery(query.str());
|
DBResult_ptr result = db->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -913,12 +850,12 @@ bool IOLoginData::getGuidByNameEx(uint32_t& guid, bool& specialVip, std::string&
|
|||||||
|
|
||||||
bool IOLoginData::formatPlayerName(std::string& name)
|
bool IOLoginData::formatPlayerName(std::string& name)
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `name` FROM `players` WHERE `name` = " << db.escapeString(name);
|
query << "SELECT `name` FROM `players` WHERE `name` = " << db->escapeString(name);
|
||||||
|
|
||||||
DBResult_ptr result = db.storeQuery(query.str());
|
DBResult_ptr result = db->storeQuery(query.str());
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -957,16 +894,16 @@ void IOLoginData::increaseBankBalance(uint32_t guid, uint64_t bankBalance)
|
|||||||
{
|
{
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "UPDATE `players` SET `balance` = `balance` + " << bankBalance << " WHERE `id` = " << guid;
|
query << "UPDATE `players` SET `balance` = `balance` + " << bankBalance << " WHERE `id` = " << guid;
|
||||||
Database::getInstance().executeQuery(query.str());
|
Database::getInstance()->executeQuery(query.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IOLoginData::hasBiddedOnHouse(uint32_t guid)
|
bool IOLoginData::hasBiddedOnHouse(uint32_t guid)
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `id` FROM `houses` WHERE `highest_bidder` = " << guid << " LIMIT 1";
|
query << "SELECT `id` FROM `houses` WHERE `highest_bidder` = " << guid << " LIMIT 1";
|
||||||
return db.storeQuery(query.str()).get() != nullptr;
|
return db->storeQuery(query.str()).get() != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::forward_list<VIPEntry> IOLoginData::getVIPEntries(uint32_t accountId)
|
std::forward_list<VIPEntry> IOLoginData::getVIPEntries(uint32_t accountId)
|
||||||
@@ -974,58 +911,46 @@ std::forward_list<VIPEntry> IOLoginData::getVIPEntries(uint32_t accountId)
|
|||||||
std::forward_list<VIPEntry> entries;
|
std::forward_list<VIPEntry> entries;
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "SELECT `player_id`, (SELECT `name` FROM `players` WHERE `id` = `player_id`) AS `name`, `description`, `icon`, `notify` FROM `account_viplist` WHERE `account_id` = " << accountId;
|
query << "SELECT `player_id`, (SELECT `name` FROM `players` WHERE `id` = `player_id`) AS `name` FROM `account_viplist` WHERE `account_id` = " << accountId;
|
||||||
|
|
||||||
DBResult_ptr result = Database::getInstance().storeQuery(query.str());
|
DBResult_ptr result = Database::getInstance()->storeQuery(query.str());
|
||||||
if (result) {
|
if (result) {
|
||||||
do {
|
do {
|
||||||
entries.emplace_front(
|
entries.emplace_front(
|
||||||
result->getNumber<uint32_t>("player_id"),
|
result->getNumber<uint32_t>("player_id"),
|
||||||
result->getString("name"),
|
result->getString("name")
|
||||||
result->getString("description"),
|
|
||||||
result->getNumber<uint32_t>("icon"),
|
|
||||||
result->getNumber<uint16_t>("notify") != 0
|
|
||||||
);
|
);
|
||||||
} while (result->next());
|
} while (result->next());
|
||||||
}
|
}
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IOLoginData::addVIPEntry(uint32_t accountId, uint32_t guid, const std::string& description, uint32_t icon, bool notify)
|
void IOLoginData::addVIPEntry(uint32_t accountId, uint32_t guid)
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "INSERT INTO `account_viplist` (`account_id`, `player_id`, `description`, `icon`, `notify`) VALUES (" << accountId << ',' << guid << ',' << db.escapeString(description) << ',' << icon << ',' << notify << ')';
|
query << "INSERT INTO `account_viplist` (`account_id`, `player_id`) VALUES (" << accountId << ',' << guid << ')';
|
||||||
db.executeQuery(query.str());
|
db->executeQuery(query.str());
|
||||||
}
|
|
||||||
|
|
||||||
void IOLoginData::editVIPEntry(uint32_t accountId, uint32_t guid, const std::string& description, uint32_t icon, bool notify)
|
|
||||||
{
|
|
||||||
Database& db = Database::getInstance();
|
|
||||||
|
|
||||||
std::ostringstream query;
|
|
||||||
query << "UPDATE `account_viplist` SET `description` = " << db.escapeString(description) << ", `icon` = " << icon << ", `notify` = " << notify << " WHERE `account_id` = " << accountId << " AND `player_id` = " << guid;
|
|
||||||
db.executeQuery(query.str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IOLoginData::removeVIPEntry(uint32_t accountId, uint32_t guid)
|
void IOLoginData::removeVIPEntry(uint32_t accountId, uint32_t guid)
|
||||||
{
|
{
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "DELETE FROM `account_viplist` WHERE `account_id` = " << accountId << " AND `player_id` = " << guid;
|
query << "DELETE FROM `account_viplist` WHERE `account_id` = " << accountId << " AND `player_id` = " << guid;
|
||||||
Database::getInstance().executeQuery(query.str());
|
Database::getInstance()->executeQuery(query.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void IOLoginData::addPremiumDays(uint32_t accountId, int32_t addDays)
|
void IOLoginData::addPremiumDays(uint32_t accountId, int32_t addDays)
|
||||||
{
|
{
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "UPDATE `accounts` SET `premdays` = `premdays` + " << addDays << " WHERE `id` = " << accountId;
|
query << "UPDATE `accounts` SET `premdays` = `premdays` + " << addDays << " WHERE `id` = " << accountId;
|
||||||
Database::getInstance().executeQuery(query.str());
|
Database::getInstance()->executeQuery(query.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void IOLoginData::removePremiumDays(uint32_t accountId, int32_t removeDays)
|
void IOLoginData::removePremiumDays(uint32_t accountId, int32_t removeDays)
|
||||||
{
|
{
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
query << "UPDATE `accounts` SET `premdays` = `premdays` - " << removeDays << " WHERE `id` = " << accountId;
|
query << "UPDATE `accounts` SET `premdays` = `premdays` - " << removeDays << " WHERE `id` = " << accountId;
|
||||||
Database::getInstance().executeQuery(query.str());
|
Database::getInstance()->executeQuery(query.str());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
|
|
||||||
using ItemBlockList = std::list<std::pair<int32_t, Item*>>;
|
typedef std::list<std::pair<int32_t, Item*>> ItemBlockList;
|
||||||
|
|
||||||
class IOLoginData
|
class IOLoginData
|
||||||
{
|
{
|
||||||
@@ -32,8 +32,8 @@ class IOLoginData
|
|||||||
static Account loadAccount(uint32_t accno);
|
static Account loadAccount(uint32_t accno);
|
||||||
static bool saveAccount(const Account& acc);
|
static bool saveAccount(const Account& acc);
|
||||||
|
|
||||||
static bool loginserverAuthentication(const std::string& name, const std::string& password, Account& account);
|
static bool loginserverAuthentication(uint32_t accountNumber, const std::string& password, Account& account);
|
||||||
static uint32_t gameworldAuthentication(const std::string& accountName, const std::string& password, std::string& characterName, std::string& token, uint32_t tokenTime);
|
static uint32_t gameworldAuthentication(uint32_t accountNumber, const std::string& password, std::string& characterName);
|
||||||
|
|
||||||
static AccountType_t getAccountType(uint32_t accountId);
|
static AccountType_t getAccountType(uint32_t accountId);
|
||||||
static void setAccountType(uint32_t accountId, AccountType_t accountType);
|
static void setAccountType(uint32_t accountId, AccountType_t accountType);
|
||||||
@@ -52,18 +52,17 @@ class IOLoginData
|
|||||||
static bool hasBiddedOnHouse(uint32_t guid);
|
static bool hasBiddedOnHouse(uint32_t guid);
|
||||||
|
|
||||||
static std::forward_list<VIPEntry> getVIPEntries(uint32_t accountId);
|
static std::forward_list<VIPEntry> getVIPEntries(uint32_t accountId);
|
||||||
static void addVIPEntry(uint32_t accountId, uint32_t guid, const std::string& description, uint32_t icon, bool notify);
|
static void addVIPEntry(uint32_t accountId, uint32_t guid);
|
||||||
static void editVIPEntry(uint32_t accountId, uint32_t guid, const std::string& description, uint32_t icon, bool notify);
|
|
||||||
static void removeVIPEntry(uint32_t accountId, uint32_t guid);
|
static void removeVIPEntry(uint32_t accountId, uint32_t guid);
|
||||||
|
|
||||||
static void addPremiumDays(uint32_t accountId, int32_t addDays);
|
static void addPremiumDays(uint32_t accountId, int32_t addDays);
|
||||||
static void removePremiumDays(uint32_t accountId, int32_t removeDays);
|
static void removePremiumDays(uint32_t accountId, int32_t removeDays);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
using ItemMap = std::map<uint32_t, std::pair<Item*, uint32_t>>;
|
typedef std::map<uint32_t, std::pair<Item*, uint32_t>> ItemMap;
|
||||||
|
|
||||||
static void loadItems(ItemMap& itemMap, DBResult_ptr result);
|
static void loadItems(ItemMap& itemMap, DBResult_ptr result);
|
||||||
static bool saveItems(const Player* player, const ItemBlockList& itemList, DBInsert& query_insert, PropWriteStream& propWriteStream);
|
static bool saveItems(const Player* player, const ItemBlockList& itemList, DBInsert& query_insert, PropWriteStream& stream);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
548
src/iomap.cpp
548
src/iomap.cpp
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -66,14 +66,23 @@ Tile* IOMap::createTile(Item*& ground, Item* item, uint16_t x, uint16_t y, uint8
|
|||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IOMap::loadMap(Map* map, const std::string& fileName)
|
bool IOMap::loadMap(Map* map, const std::string& identifier)
|
||||||
{
|
{
|
||||||
int64_t start = OTSYS_TIME();
|
int64_t start = OTSYS_TIME();
|
||||||
OTB::Loader loader{fileName, OTB::Identifier{{'O', 'T', 'B', 'M'}}};
|
|
||||||
auto& root = loader.parseTree();
|
|
||||||
|
|
||||||
|
FileLoader f;
|
||||||
|
if (!f.openFile(identifier.c_str(), "OTBM")) {
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << "Could not open the file " << identifier << '.';
|
||||||
|
setLastErrorString(ss.str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t type;
|
||||||
PropStream propStream;
|
PropStream propStream;
|
||||||
if (!loader.getProps(root, propStream)) {
|
|
||||||
|
NODE root = f.getChildNode(nullptr, type);
|
||||||
|
if (!f.getProps(root, propStream)) {
|
||||||
setLastErrorString("Could not read root property.");
|
setLastErrorString("Could not read root property.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -85,7 +94,7 @@ bool IOMap::loadMap(Map* map, const std::string& fileName)
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t headerVersion = root_header.version;
|
uint32_t headerVersion = root_header.version;
|
||||||
if (headerVersion == 0) {
|
if (headerVersion <= 0) {
|
||||||
//In otbm version 1 the count variable after splashes/fluidcontainers and stackables
|
//In otbm version 1 the count variable after splashes/fluidcontainers and stackables
|
||||||
//are saved as attributes instead, this solves alot of problems with items
|
//are saved as attributes instead, this solves alot of problems with items
|
||||||
//that is changed (stackable/charges/fluidcontainer/splash) during an update.
|
//that is changed (stackable/charges/fluidcontainer/splash) during an update.
|
||||||
@@ -98,66 +107,17 @@ bool IOMap::loadMap(Map* map, const std::string& fileName)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root_header.majorVersionItems < 3) {
|
|
||||||
setLastErrorString("This map need to be upgraded by using the latest map editor version to be able to load correctly.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (root_header.majorVersionItems > Item::items.majorVersion) {
|
|
||||||
setLastErrorString("The map was saved with a different items.otb version, an upgraded items.otb is required.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (root_header.minorVersionItems < CLIENT_VERSION_810) {
|
|
||||||
setLastErrorString("This map needs to be updated.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (root_header.minorVersionItems > Item::items.minorVersion) {
|
|
||||||
std::cout << "[Warning - IOMap::loadMap] This map needs an updated items.otb." << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "> Map size: " << root_header.width << "x" << root_header.height << '.' << std::endl;
|
std::cout << "> Map size: " << root_header.width << "x" << root_header.height << '.' << std::endl;
|
||||||
map->width = root_header.width;
|
map->width = root_header.width;
|
||||||
map->height = root_header.height;
|
map->height = root_header.height;
|
||||||
|
|
||||||
if (root.children.size() != 1 || root.children[0].type != OTBM_MAP_DATA) {
|
NODE nodeMap = f.getChildNode(root, type);
|
||||||
|
if (type != OTBM_MAP_DATA) {
|
||||||
setLastErrorString("Could not read data node.");
|
setLastErrorString("Could not read data node.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& mapNode = root.children[0];
|
if (!f.getProps(nodeMap, propStream)) {
|
||||||
if (!parseMapDataAttributes(loader, mapNode, *map, fileName)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& mapDataNode : mapNode.children) {
|
|
||||||
if (mapDataNode.type == OTBM_TILE_AREA) {
|
|
||||||
if (!parseTileArea(loader, mapDataNode, *map)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (mapDataNode.type == OTBM_TOWNS) {
|
|
||||||
if (!parseTowns(loader, mapDataNode, *map)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (mapDataNode.type == OTBM_WAYPOINTS && headerVersion > 1) {
|
|
||||||
if (!parseWaypoints(loader, mapDataNode, *map)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setLastErrorString("Unknown map node.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "> Map loading time: " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IOMap::parseMapDataAttributes(OTB::Loader& loader, const OTB::Node& mapNode, Map& map, const std::string& fileName)
|
|
||||||
{
|
|
||||||
PropStream propStream;
|
|
||||||
if (!loader.getProps(mapNode, propStream)) {
|
|
||||||
setLastErrorString("Could not read map data attributes.");
|
setLastErrorString("Could not read map data attributes.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -181,8 +141,8 @@ bool IOMap::parseMapDataAttributes(OTB::Loader& loader, const OTB::Node& mapNode
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
map.spawnfile = fileName.substr(0, fileName.rfind('/') + 1);
|
map->spawnfile = identifier.substr(0, identifier.rfind('/') + 1);
|
||||||
map.spawnfile += tmp;
|
map->spawnfile += tmp;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OTBM_ATTR_EXT_HOUSE_FILE:
|
case OTBM_ATTR_EXT_HOUSE_FILE:
|
||||||
@@ -191,8 +151,8 @@ bool IOMap::parseMapDataAttributes(OTB::Loader& loader, const OTB::Node& mapNode
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
map.housefile = fileName.substr(0, fileName.rfind('/') + 1);
|
map->housefile = identifier.substr(0, identifier.rfind('/') + 1);
|
||||||
map.housefile += tmp;
|
map->housefile += tmp;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -200,104 +160,172 @@ bool IOMap::parseMapDataAttributes(OTB::Loader& loader, const OTB::Node& mapNode
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IOMap::parseTileArea(OTB::Loader& loader, const OTB::Node& tileAreaNode, Map& map)
|
NODE nodeMapData = f.getChildNode(nodeMap, type);
|
||||||
{
|
while (nodeMapData != NO_NODE) {
|
||||||
PropStream propStream;
|
if (f.getError() != ERROR_NONE) {
|
||||||
if (!loader.getProps(tileAreaNode, propStream)) {
|
setLastErrorString("Invalid map node.");
|
||||||
setLastErrorString("Invalid map node.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
OTBM_Destination_coords area_coord;
|
|
||||||
if (!propStream.read(area_coord)) {
|
|
||||||
setLastErrorString("Invalid map node.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t base_x = area_coord.x;
|
|
||||||
uint16_t base_y = area_coord.y;
|
|
||||||
uint16_t z = area_coord.z;
|
|
||||||
|
|
||||||
for (auto& tileNode : tileAreaNode.children) {
|
|
||||||
if (tileNode.type != OTBM_TILE && tileNode.type != OTBM_HOUSETILE) {
|
|
||||||
setLastErrorString("Unknown tile node.");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!loader.getProps(tileNode, propStream)) {
|
if (type == OTBM_TILE_AREA) {
|
||||||
setLastErrorString("Could not read node data.");
|
if (!f.getProps(nodeMapData, propStream)) {
|
||||||
return false;
|
setLastErrorString("Invalid map node.");
|
||||||
}
|
|
||||||
|
|
||||||
OTBM_Tile_coords tile_coord;
|
|
||||||
if (!propStream.read(tile_coord)) {
|
|
||||||
setLastErrorString("Could not read tile position.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t x = base_x + tile_coord.x;
|
|
||||||
uint16_t y = base_y + tile_coord.y;
|
|
||||||
|
|
||||||
bool isHouseTile = false;
|
|
||||||
House* house = nullptr;
|
|
||||||
Tile* tile = nullptr;
|
|
||||||
Item* ground_item = nullptr;
|
|
||||||
uint32_t tileflags = TILESTATE_NONE;
|
|
||||||
|
|
||||||
if (tileNode.type == OTBM_HOUSETILE) {
|
|
||||||
uint32_t houseId;
|
|
||||||
if (!propStream.read<uint32_t>(houseId)) {
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Could not read house id.";
|
|
||||||
setLastErrorString(ss.str());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
house = map.houses.addHouse(houseId);
|
OTBM_Destination_coords area_coord;
|
||||||
if (!house) {
|
if (!propStream.read(area_coord)) {
|
||||||
std::ostringstream ss;
|
setLastErrorString("Invalid map node.");
|
||||||
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Could not create house id: " << houseId;
|
|
||||||
setLastErrorString(ss.str());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tile = new HouseTile(x, y, z, house);
|
uint16_t base_x = area_coord.x;
|
||||||
house->addTile(static_cast<HouseTile*>(tile));
|
uint16_t base_y = area_coord.y;
|
||||||
isHouseTile = true;
|
uint16_t z = area_coord.z;
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t attribute;
|
NODE nodeTile = f.getChildNode(nodeMapData, type);
|
||||||
//read tile attributes
|
while (nodeTile != NO_NODE) {
|
||||||
while (propStream.read<uint8_t>(attribute)) {
|
if (f.getError() != ERROR_NONE) {
|
||||||
switch (attribute) {
|
setLastErrorString("Could not read node data.");
|
||||||
case OTBM_ATTR_TILE_FLAGS: {
|
return false;
|
||||||
uint32_t flags;
|
}
|
||||||
if (!propStream.read<uint32_t>(flags)) {
|
|
||||||
|
if (type != OTBM_TILE && type != OTBM_HOUSETILE) {
|
||||||
|
setLastErrorString("Unknown tile node.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!f.getProps(nodeTile, propStream)) {
|
||||||
|
setLastErrorString("Could not read node data.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OTBM_Tile_coords tile_coord;
|
||||||
|
if (!propStream.read(tile_coord)) {
|
||||||
|
setLastErrorString("Could not read tile position.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t x = base_x + tile_coord.x;
|
||||||
|
uint16_t y = base_y + tile_coord.y;
|
||||||
|
|
||||||
|
bool isHouseTile = false;
|
||||||
|
House* house = nullptr;
|
||||||
|
Tile* tile = nullptr;
|
||||||
|
Item* ground_item = nullptr;
|
||||||
|
uint32_t tileflags = TILESTATE_NONE;
|
||||||
|
|
||||||
|
if (type == OTBM_HOUSETILE) {
|
||||||
|
uint32_t houseId;
|
||||||
|
if (!propStream.read<uint32_t>(houseId)) {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Failed to read tile flags.";
|
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Could not read house id.";
|
||||||
setLastErrorString(ss.str());
|
setLastErrorString(ss.str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & OTBM_TILEFLAG_PROTECTIONZONE) != 0) {
|
house = map->houses.addHouse(houseId);
|
||||||
tileflags |= TILESTATE_PROTECTIONZONE;
|
if (!house) {
|
||||||
} else if ((flags & OTBM_TILEFLAG_NOPVPZONE) != 0) {
|
std::ostringstream ss;
|
||||||
tileflags |= TILESTATE_NOPVPZONE;
|
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Could not create house id: " << houseId;
|
||||||
} else if ((flags & OTBM_TILEFLAG_PVPZONE) != 0) {
|
setLastErrorString(ss.str());
|
||||||
tileflags |= TILESTATE_PVPZONE;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flags & OTBM_TILEFLAG_NOLOGOUT) != 0) {
|
tile = new HouseTile(x, y, z, house);
|
||||||
tileflags |= TILESTATE_NOLOGOUT;
|
house->addTile(static_cast<HouseTile*>(tile));
|
||||||
}
|
isHouseTile = true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case OTBM_ATTR_ITEM: {
|
//read tile attributes
|
||||||
Item* item = Item::CreateItem(propStream);
|
while (propStream.read<uint8_t>(attribute)) {
|
||||||
|
switch (attribute) {
|
||||||
|
case OTBM_ATTR_TILE_FLAGS: {
|
||||||
|
uint32_t flags;
|
||||||
|
if (!propStream.read<uint32_t>(flags)) {
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Failed to read tile flags.";
|
||||||
|
setLastErrorString(ss.str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & OTBM_TILEFLAG_PROTECTIONZONE) != 0) {
|
||||||
|
tileflags |= TILESTATE_PROTECTIONZONE;
|
||||||
|
} else if ((flags & OTBM_TILEFLAG_NOPVPZONE) != 0) {
|
||||||
|
tileflags |= TILESTATE_NOPVPZONE;
|
||||||
|
} else if ((flags & OTBM_TILEFLAG_PVPZONE) != 0) {
|
||||||
|
tileflags |= TILESTATE_PVPZONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & OTBM_TILEFLAG_REFRESH) != 0) {
|
||||||
|
tileflags |= TILESTATE_REFRESH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & OTBM_TILEFLAG_NOLOGOUT) != 0) {
|
||||||
|
tileflags |= TILESTATE_NOLOGOUT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OTBM_ATTR_ITEM: {
|
||||||
|
Item* item = Item::CreateItem(propStream);
|
||||||
|
if (!item) {
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Failed to create item.";
|
||||||
|
setLastErrorString(ss.str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isHouseTile && item->isMoveable()) {
|
||||||
|
//std::cout << "[Warning - IOMap::loadMap] Moveable item with ID: " << item->getID() << ", in house: " << house->getId() << ", at position [x: " << x << ", y: " << y << ", z: " << z << "]." << std::endl;
|
||||||
|
delete item;
|
||||||
|
} else {
|
||||||
|
if (item->getItemCount() <= 0) {
|
||||||
|
item->setItemCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tile) {
|
||||||
|
tile->internalAddThing(item);
|
||||||
|
item->startDecaying();
|
||||||
|
item->setLoadedFromMap(true);
|
||||||
|
} else if (item->isGroundTile()) {
|
||||||
|
delete ground_item;
|
||||||
|
ground_item = item;
|
||||||
|
} else {
|
||||||
|
tile = createTile(ground_item, item, x, y, z);
|
||||||
|
tile->internalAddThing(item);
|
||||||
|
item->startDecaying();
|
||||||
|
item->setLoadedFromMap(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Unknown tile attribute.";
|
||||||
|
setLastErrorString(ss.str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE nodeItem = f.getChildNode(nodeTile, type);
|
||||||
|
while (nodeItem) {
|
||||||
|
if (type != OTBM_ITEM) {
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Unknown node type.";
|
||||||
|
setLastErrorString(ss.str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropStream stream;
|
||||||
|
if (!f.getProps(nodeItem, stream)) {
|
||||||
|
setLastErrorString("Invalid item node.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item* item = Item::CreateItem(stream);
|
||||||
if (!item) {
|
if (!item) {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Failed to create item.";
|
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Failed to create item.";
|
||||||
@@ -305,11 +333,19 @@ bool IOMap::parseTileArea(OTB::Loader& loader, const OTB::Node& tileAreaNode, Ma
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!item->unserializeItemNode(f, nodeItem, stream)) {
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Failed to load item " << item->getID() << '.';
|
||||||
|
setLastErrorString(ss.str());
|
||||||
|
delete item;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (isHouseTile && item->isMoveable()) {
|
if (isHouseTile && item->isMoveable()) {
|
||||||
std::cout << "[Warning - IOMap::loadMap] Moveable item with ID: " << item->getID() << ", in house: " << house->getId() << ", at position [x: " << x << ", y: " << y << ", z: " << z << "]." << std::endl;
|
//std::cout << "[Warning - IOMap::loadMap] Moveable item with ID: " << item->getID() << ", in house: " << house->getId() << ", at position [x: " << x << ", y: " << y << ", z: " << z << "]." << std::endl;
|
||||||
delete item;
|
delete item;
|
||||||
} else {
|
} else {
|
||||||
if (item->getItemCount() == 0) {
|
if (item->getItemCount() <= 0) {
|
||||||
item->setItemCount(1);
|
item->setItemCount(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,156 +363,100 @@ bool IOMap::parseTileArea(OTB::Loader& loader, const OTB::Node& tileAreaNode, Ma
|
|||||||
item->setLoadedFromMap(true);
|
item->setLoadedFromMap(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
nodeItem = f.getNextNode(nodeItem, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
if (!tile) {
|
||||||
std::ostringstream ss;
|
tile = createTile(ground_item, nullptr, x, y, z);
|
||||||
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Unknown tile attribute.";
|
}
|
||||||
setLastErrorString(ss.str());
|
|
||||||
|
tile->setFlag(static_cast<tileflags_t>(tileflags));
|
||||||
|
|
||||||
|
map->setTile(x, y, z, tile);
|
||||||
|
|
||||||
|
nodeTile = f.getNextNode(nodeTile, type);
|
||||||
|
}
|
||||||
|
} else if (type == OTBM_TOWNS) {
|
||||||
|
NODE nodeTown = f.getChildNode(nodeMapData, type);
|
||||||
|
while (nodeTown != NO_NODE) {
|
||||||
|
if (type != OTBM_TOWN) {
|
||||||
|
setLastErrorString("Unknown town node.");
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& itemNode : tileNode.children) {
|
|
||||||
if (itemNode.type != OTBM_ITEM) {
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Unknown node type.";
|
|
||||||
setLastErrorString(ss.str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PropStream stream;
|
|
||||||
if (!loader.getProps(itemNode, stream)) {
|
|
||||||
setLastErrorString("Invalid item node.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Item* item = Item::CreateItem(stream);
|
|
||||||
if (!item) {
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Failed to create item.";
|
|
||||||
setLastErrorString(ss.str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!item->unserializeItemNode(loader, itemNode, stream)) {
|
|
||||||
std::ostringstream ss;
|
|
||||||
ss << "[x:" << x << ", y:" << y << ", z:" << z << "] Failed to load item " << item->getID() << '.';
|
|
||||||
setLastErrorString(ss.str());
|
|
||||||
delete item;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isHouseTile && item->isMoveable()) {
|
|
||||||
std::cout << "[Warning - IOMap::loadMap] Moveable item with ID: " << item->getID() << ", in house: " << house->getId() << ", at position [x: " << x << ", y: " << y << ", z: " << z << "]." << std::endl;
|
|
||||||
delete item;
|
|
||||||
} else {
|
|
||||||
if (item->getItemCount() == 0) {
|
|
||||||
item->setItemCount(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tile) {
|
if (!f.getProps(nodeTown, propStream)) {
|
||||||
tile->internalAddThing(item);
|
setLastErrorString("Could not read town data.");
|
||||||
item->startDecaying();
|
return false;
|
||||||
item->setLoadedFromMap(true);
|
|
||||||
} else if (item->isGroundTile()) {
|
|
||||||
delete ground_item;
|
|
||||||
ground_item = item;
|
|
||||||
} else {
|
|
||||||
tile = createTile(ground_item, item, x, y, z);
|
|
||||||
tile->internalAddThing(item);
|
|
||||||
item->startDecaying();
|
|
||||||
item->setLoadedFromMap(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t townId;
|
||||||
|
if (!propStream.read<uint32_t>(townId)) {
|
||||||
|
setLastErrorString("Could not read town id.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Town* town = map->towns.getTown(townId);
|
||||||
|
if (!town) {
|
||||||
|
town = new Town(townId);
|
||||||
|
map->towns.addTown(townId, town);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string townName;
|
||||||
|
if (!propStream.readString(townName)) {
|
||||||
|
setLastErrorString("Could not read town name.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
town->setName(townName);
|
||||||
|
|
||||||
|
OTBM_Destination_coords town_coords;
|
||||||
|
if (!propStream.read(town_coords)) {
|
||||||
|
setLastErrorString("Could not read town coordinates.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
town->setTemplePos(Position(town_coords.x, town_coords.y, town_coords.z));
|
||||||
|
|
||||||
|
nodeTown = f.getNextNode(nodeTown, type);
|
||||||
}
|
}
|
||||||
|
} else if (type == OTBM_WAYPOINTS) {
|
||||||
|
NODE nodeWaypoint = f.getChildNode(nodeMapData, type);
|
||||||
|
while (nodeWaypoint != NO_NODE) {
|
||||||
|
if (type != OTBM_WAYPOINT) {
|
||||||
|
setLastErrorString("Unknown waypoint node.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!f.getProps(nodeWaypoint, propStream)) {
|
||||||
|
setLastErrorString("Could not read waypoint data.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
if (!propStream.readString(name)) {
|
||||||
|
setLastErrorString("Could not read waypoint name.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OTBM_Destination_coords waypoint_coords;
|
||||||
|
if (!propStream.read(waypoint_coords)) {
|
||||||
|
setLastErrorString("Could not read waypoint coordinates.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
map->waypoints[name] = Position(waypoint_coords.x, waypoint_coords.y, waypoint_coords.z);
|
||||||
|
|
||||||
|
nodeWaypoint = f.getNextNode(nodeWaypoint, type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setLastErrorString("Unknown map node.");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tile) {
|
nodeMapData = f.getNextNode(nodeMapData, type);
|
||||||
tile = createTile(ground_item, nullptr, x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
tile->setFlag(static_cast<tileflags_t>(tileflags));
|
|
||||||
|
|
||||||
map.setTile(x, y, z, tile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cout << "> Map loading time: " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IOMap::parseTowns(OTB::Loader& loader, const OTB::Node& townsNode, Map& map)
|
|
||||||
{
|
|
||||||
for (auto& townNode : townsNode.children) {
|
|
||||||
PropStream propStream;
|
|
||||||
if (townNode.type != OTBM_TOWN) {
|
|
||||||
setLastErrorString("Unknown town node.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!loader.getProps(townNode, propStream)) {
|
|
||||||
setLastErrorString("Could not read town data.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t townId;
|
|
||||||
if (!propStream.read<uint32_t>(townId)) {
|
|
||||||
setLastErrorString("Could not read town id.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Town* town = map.towns.getTown(townId);
|
|
||||||
if (!town) {
|
|
||||||
town = new Town(townId);
|
|
||||||
map.towns.addTown(townId, town);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string townName;
|
|
||||||
if (!propStream.readString(townName)) {
|
|
||||||
setLastErrorString("Could not read town name.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
town->setName(townName);
|
|
||||||
|
|
||||||
OTBM_Destination_coords town_coords;
|
|
||||||
if (!propStream.read(town_coords)) {
|
|
||||||
setLastErrorString("Could not read town coordinates.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
town->setTemplePos(Position(town_coords.x, town_coords.y, town_coords.z));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool IOMap::parseWaypoints(OTB::Loader& loader, const OTB::Node& waypointsNode, Map& map)
|
|
||||||
{
|
|
||||||
PropStream propStream;
|
|
||||||
for (auto& node : waypointsNode.children) {
|
|
||||||
if (node.type != OTBM_WAYPOINT) {
|
|
||||||
setLastErrorString("Unknown waypoint node.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!loader.getProps(node, propStream)) {
|
|
||||||
setLastErrorString("Could not read waypoint data.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
if (!propStream.readString(name)) {
|
|
||||||
setLastErrorString("Could not read waypoint name.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
OTBM_Destination_coords waypoint_coords;
|
|
||||||
if (!propStream.read(waypoint_coords)) {
|
|
||||||
setLastErrorString("Could not read waypoint coordinates.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
map.waypoints[name] = Position(waypoint_coords.x, waypoint_coords.y, waypoint_coords.z);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
23
src/iomap.h
23
src/iomap.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -33,7 +33,7 @@ enum OTBM_AttrTypes_t {
|
|||||||
OTBM_ATTR_EXT_FILE = 2,
|
OTBM_ATTR_EXT_FILE = 2,
|
||||||
OTBM_ATTR_TILE_FLAGS = 3,
|
OTBM_ATTR_TILE_FLAGS = 3,
|
||||||
OTBM_ATTR_ACTION_ID = 4,
|
OTBM_ATTR_ACTION_ID = 4,
|
||||||
OTBM_ATTR_UNIQUE_ID = 5,
|
OTBM_ATTR_MOVEMENT_ID = 5,
|
||||||
OTBM_ATTR_TEXT = 6,
|
OTBM_ATTR_TEXT = 6,
|
||||||
OTBM_ATTR_DESC = 7,
|
OTBM_ATTR_DESC = 7,
|
||||||
OTBM_ATTR_TELE_DEST = 8,
|
OTBM_ATTR_TELE_DEST = 8,
|
||||||
@@ -51,6 +51,12 @@ enum OTBM_AttrTypes_t {
|
|||||||
OTBM_ATTR_SLEEPERGUID = 20,
|
OTBM_ATTR_SLEEPERGUID = 20,
|
||||||
OTBM_ATTR_SLEEPSTART = 21,
|
OTBM_ATTR_SLEEPSTART = 21,
|
||||||
OTBM_ATTR_CHARGES = 22,
|
OTBM_ATTR_CHARGES = 22,
|
||||||
|
OTBM_ATTR_KEYNUMBER = 23,
|
||||||
|
OTBM_ATTR_KEYHOLENUMBER = 24,
|
||||||
|
OTBM_ATTR_DOORQUESTNUMBER = 25,
|
||||||
|
OTBM_ATTR_DOORQUESTVALUE = 26,
|
||||||
|
OTBM_ATTR_DOORLEVEL = 27,
|
||||||
|
OTBM_ATTR_CHESTQUESTNUMBER = 28,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum OTBM_NodeTypes_t {
|
enum OTBM_NodeTypes_t {
|
||||||
@@ -76,7 +82,8 @@ enum OTBM_TileFlag_t : uint32_t {
|
|||||||
OTBM_TILEFLAG_PROTECTIONZONE = 1 << 0,
|
OTBM_TILEFLAG_PROTECTIONZONE = 1 << 0,
|
||||||
OTBM_TILEFLAG_NOPVPZONE = 1 << 2,
|
OTBM_TILEFLAG_NOPVPZONE = 1 << 2,
|
||||||
OTBM_TILEFLAG_NOLOGOUT = 1 << 3,
|
OTBM_TILEFLAG_NOLOGOUT = 1 << 3,
|
||||||
OTBM_TILEFLAG_PVPZONE = 1 << 4
|
OTBM_TILEFLAG_PVPZONE = 1 << 4,
|
||||||
|
OTBM_TILEFLAG_REFRESH = 1 << 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
@@ -107,7 +114,7 @@ class IOMap
|
|||||||
static Tile* createTile(Item*& ground, Item* item, uint16_t x, uint16_t y, uint8_t z);
|
static Tile* createTile(Item*& ground, Item* item, uint16_t x, uint16_t y, uint8_t z);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool loadMap(Map* map, const std::string& fileName);
|
bool loadMap(Map* map, const std::string& identifier);
|
||||||
|
|
||||||
/* Load the spawns
|
/* Load the spawns
|
||||||
* \param map pointer to the Map class
|
* \param map pointer to the Map class
|
||||||
@@ -147,11 +154,7 @@ class IOMap
|
|||||||
errorString = error;
|
errorString = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
bool parseMapDataAttributes(OTB::Loader& loader, const OTB::Node& mapNode, Map& map, const std::string& fileName);
|
|
||||||
bool parseWaypoints(OTB::Loader& loader, const OTB::Node& waypointsNode, Map& map);
|
|
||||||
bool parseTowns(OTB::Loader& loader, const OTB::Node& townsNode, Map& map);
|
|
||||||
bool parseTileArea(OTB::Loader& loader, const OTB::Node& tileAreaNode, Map& map);
|
|
||||||
std::string errorString;
|
std::string errorString;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -29,7 +29,7 @@ void IOMapSerialize::loadHouseItems(Map* map)
|
|||||||
{
|
{
|
||||||
int64_t start = OTSYS_TIME();
|
int64_t start = OTSYS_TIME();
|
||||||
|
|
||||||
DBResult_ptr result = Database::getInstance().storeQuery("SELECT `data` FROM `tile_store`");
|
DBResult_ptr result = Database::getInstance()->storeQuery("SELECT `data` FROM `tile_store`");
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -67,7 +67,7 @@ void IOMapSerialize::loadHouseItems(Map* map)
|
|||||||
bool IOMapSerialize::saveHouseItems()
|
bool IOMapSerialize::saveHouseItems()
|
||||||
{
|
{
|
||||||
int64_t start = OTSYS_TIME();
|
int64_t start = OTSYS_TIME();
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
std::ostringstream query;
|
std::ostringstream query;
|
||||||
|
|
||||||
//Start the transaction
|
//Start the transaction
|
||||||
@@ -77,7 +77,7 @@ bool IOMapSerialize::saveHouseItems()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//clear old tile data
|
//clear old tile data
|
||||||
if (!db.executeQuery("DELETE FROM `tile_store`")) {
|
if (!db->executeQuery("DELETE FROM `tile_store`")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ bool IOMapSerialize::saveHouseItems()
|
|||||||
size_t attributesSize;
|
size_t attributesSize;
|
||||||
const char* attributes = stream.getStream(attributesSize);
|
const char* attributes = stream.getStream(attributesSize);
|
||||||
if (attributesSize > 0) {
|
if (attributesSize > 0) {
|
||||||
query << house->getId() << ',' << db.escapeBlob(attributes, attributesSize);
|
query << house->getId() << ',' << db->escapeBlob(attributes, attributesSize);
|
||||||
if (!stmt.addRow(query)) {
|
if (!stmt.addRow(query)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ bool IOMapSerialize::loadItem(PropStream& propStream, Cylinder* parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ItemType& iType = Item::items[id];
|
const ItemType& iType = Item::items[id];
|
||||||
if (iType.moveable || iType.forceSerialize || !tile) {
|
if (iType.moveable || !tile) {
|
||||||
//create a new item
|
//create a new item
|
||||||
Item* item = Item::CreateItem(id);
|
Item* item = Item::CreateItem(id);
|
||||||
if (item) {
|
if (item) {
|
||||||
@@ -247,7 +247,7 @@ void IOMapSerialize::saveTile(PropWriteStream& stream, const Tile* tile)
|
|||||||
const ItemType& it = Item::items[item->getID()];
|
const ItemType& it = Item::items[item->getID()];
|
||||||
|
|
||||||
// Note that these are NEGATED, ie. these are the items that will be saved.
|
// Note that these are NEGATED, ie. these are the items that will be saved.
|
||||||
if (!(it.moveable || it.forceSerialize || item->getDoor() || (item->getContainer() && !item->getContainer()->empty()) || it.canWriteText || item->getBed())) {
|
if (!(it.moveable || item->getDoor() || (item->getContainer() && !item->getContainer()->empty()) || it.canWriteText || item->getBed())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,9 +270,9 @@ void IOMapSerialize::saveTile(PropWriteStream& stream, const Tile* tile)
|
|||||||
|
|
||||||
bool IOMapSerialize::loadHouseInfo()
|
bool IOMapSerialize::loadHouseInfo()
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
DBResult_ptr result = db.storeQuery("SELECT `id`, `owner`, `paid`, `warnings` FROM `houses`");
|
DBResult_ptr result = db->storeQuery("SELECT `id`, `owner`, `paid`, `warnings` FROM `houses`");
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -286,7 +286,7 @@ bool IOMapSerialize::loadHouseInfo()
|
|||||||
}
|
}
|
||||||
} while (result->next());
|
} while (result->next());
|
||||||
|
|
||||||
result = db.storeQuery("SELECT `house_id`, `listid`, `list` FROM `house_lists`");
|
result = db->storeQuery("SELECT `house_id`, `listid`, `list` FROM `house_lists`");
|
||||||
if (result) {
|
if (result) {
|
||||||
do {
|
do {
|
||||||
House* house = g_game.map.houses.getHouse(result->getNumber<uint32_t>("house_id"));
|
House* house = g_game.map.houses.getHouse(result->getNumber<uint32_t>("house_id"));
|
||||||
@@ -300,14 +300,14 @@ bool IOMapSerialize::loadHouseInfo()
|
|||||||
|
|
||||||
bool IOMapSerialize::saveHouseInfo()
|
bool IOMapSerialize::saveHouseInfo()
|
||||||
{
|
{
|
||||||
Database& db = Database::getInstance();
|
Database* db = Database::getInstance();
|
||||||
|
|
||||||
DBTransaction transaction;
|
DBTransaction transaction;
|
||||||
if (!transaction.begin()) {
|
if (!transaction.begin()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!db.executeQuery("DELETE FROM `house_lists`")) {
|
if (!db->executeQuery("DELETE FROM `house_lists`")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,16 +315,16 @@ bool IOMapSerialize::saveHouseInfo()
|
|||||||
for (const auto& it : g_game.map.houses.getHouses()) {
|
for (const auto& it : g_game.map.houses.getHouses()) {
|
||||||
House* house = it.second;
|
House* house = it.second;
|
||||||
query << "SELECT `id` FROM `houses` WHERE `id` = " << house->getId();
|
query << "SELECT `id` FROM `houses` WHERE `id` = " << house->getId();
|
||||||
DBResult_ptr result = db.storeQuery(query.str());
|
DBResult_ptr result = db->storeQuery(query.str());
|
||||||
if (result) {
|
if (result) {
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "UPDATE `houses` SET `owner` = " << house->getOwner() << ", `paid` = " << house->getPaidUntil() << ", `warnings` = " << house->getPayRentWarnings() << ", `name` = " << db.escapeString(house->getName()) << ", `town_id` = " << house->getTownId() << ", `rent` = " << house->getRent() << ", `size` = " << house->getTiles().size() << ", `beds` = " << house->getBedCount() << " WHERE `id` = " << house->getId();
|
query << "UPDATE `houses` SET `owner` = " << house->getOwner() << ", `paid` = " << house->getPaidUntil() << ", `warnings` = " << house->getPayRentWarnings() << ", `name` = " << db->escapeString(house->getName()) << ", `town_id` = " << house->getTownId() << ", `rent` = " << house->getRent() << ", `size` = " << house->getTiles().size() << ", `beds` = " << house->getBedCount() << " WHERE `id` = " << house->getId();
|
||||||
} else {
|
} else {
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
query << "INSERT INTO `houses` (`id`, `owner`, `paid`, `warnings`, `name`, `town_id`, `rent`, `size`, `beds`) VALUES (" << house->getId() << ',' << house->getOwner() << ',' << house->getPaidUntil() << ',' << house->getPayRentWarnings() << ',' << db.escapeString(house->getName()) << ',' << house->getTownId() << ',' << house->getRent() << ',' << house->getTiles().size() << ',' << house->getBedCount() << ')';
|
query << "INSERT INTO `houses` (`id`, `owner`, `paid`, `warnings`, `name`, `town_id`, `rent`, `size`, `beds`) VALUES (" << house->getId() << ',' << house->getOwner() << ',' << house->getPaidUntil() << ',' << house->getPayRentWarnings() << ',' << db->escapeString(house->getName()) << ',' << house->getTownId() << ',' << house->getRent() << ',' << house->getTiles().size() << ',' << house->getBedCount() << ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
db.executeQuery(query.str());
|
db->executeQuery(query.str());
|
||||||
query.str(std::string());
|
query.str(std::string());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,7 +335,7 @@ bool IOMapSerialize::saveHouseInfo()
|
|||||||
|
|
||||||
std::string listText;
|
std::string listText;
|
||||||
if (house->getAccessList(GUEST_LIST, listText) && !listText.empty()) {
|
if (house->getAccessList(GUEST_LIST, listText) && !listText.empty()) {
|
||||||
query << house->getId() << ',' << GUEST_LIST << ',' << db.escapeString(listText);
|
query << house->getId() << ',' << GUEST_LIST << ',' << db->escapeString(listText);
|
||||||
if (!stmt.addRow(query)) {
|
if (!stmt.addRow(query)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -344,7 +344,7 @@ bool IOMapSerialize::saveHouseInfo()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (house->getAccessList(SUBOWNER_LIST, listText) && !listText.empty()) {
|
if (house->getAccessList(SUBOWNER_LIST, listText) && !listText.empty()) {
|
||||||
query << house->getId() << ',' << SUBOWNER_LIST << ',' << db.escapeString(listText);
|
query << house->getId() << ',' << SUBOWNER_LIST << ',' << db->escapeString(listText);
|
||||||
if (!stmt.addRow(query)) {
|
if (!stmt.addRow(query)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -354,7 +354,7 @@ bool IOMapSerialize::saveHouseInfo()
|
|||||||
|
|
||||||
for (Door* door : house->getDoors()) {
|
for (Door* door : house->getDoors()) {
|
||||||
if (door->getAccessList(listText) && !listText.empty()) {
|
if (door->getAccessList(listText) && !listText.empty()) {
|
||||||
query << house->getId() << ',' << door->getDoorId() << ',' << db.escapeString(listText);
|
query << house->getId() << ',' << door->getDoorId() << ',' << db->escapeString(listText);
|
||||||
if (!stmt.addRow(query)) {
|
if (!stmt.addRow(query)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -31,7 +31,7 @@ class IOMapSerialize
|
|||||||
static bool loadHouseInfo();
|
static bool loadHouseInfo();
|
||||||
static bool saveHouseInfo();
|
static bool saveHouseInfo();
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
static void saveItem(PropWriteStream& stream, const Item* item);
|
static void saveItem(PropWriteStream& stream, const Item* item);
|
||||||
static void saveTile(PropWriteStream& stream, const Tile* tile);
|
static void saveTile(PropWriteStream& stream, const Tile* tile);
|
||||||
|
|
||||||
|
|||||||
347
src/iomarket.cpp
347
src/iomarket.cpp
@@ -1,347 +0,0 @@
|
|||||||
/**
|
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "otpch.h"
|
|
||||||
|
|
||||||
#include "iomarket.h"
|
|
||||||
|
|
||||||
#include "configmanager.h"
|
|
||||||
#include "databasetasks.h"
|
|
||||||
#include "iologindata.h"
|
|
||||||
#include "game.h"
|
|
||||||
#include "scheduler.h"
|
|
||||||
|
|
||||||
extern ConfigManager g_config;
|
|
||||||
extern Game g_game;
|
|
||||||
|
|
||||||
MarketOfferList IOMarket::getActiveOffers(MarketAction_t action, uint16_t itemId)
|
|
||||||
{
|
|
||||||
MarketOfferList offerList;
|
|
||||||
|
|
||||||
std::ostringstream query;
|
|
||||||
query << "SELECT `id`, `amount`, `price`, `created`, `anonymous`, (SELECT `name` FROM `players` WHERE `id` = `player_id`) AS `player_name` FROM `market_offers` WHERE `sale` = " << action << " AND `itemtype` = " << itemId;
|
|
||||||
|
|
||||||
DBResult_ptr result = Database::getInstance().storeQuery(query.str());
|
|
||||||
if (!result) {
|
|
||||||
return offerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int32_t marketOfferDuration = g_config.getNumber(ConfigManager::MARKET_OFFER_DURATION);
|
|
||||||
|
|
||||||
do {
|
|
||||||
MarketOffer offer;
|
|
||||||
offer.amount = result->getNumber<uint16_t>("amount");
|
|
||||||
offer.price = result->getNumber<uint32_t>("price");
|
|
||||||
offer.timestamp = result->getNumber<uint32_t>("created") + marketOfferDuration;
|
|
||||||
offer.counter = result->getNumber<uint32_t>("id") & 0xFFFF;
|
|
||||||
if (result->getNumber<uint16_t>("anonymous") == 0) {
|
|
||||||
offer.playerName = result->getString("player_name");
|
|
||||||
} else {
|
|
||||||
offer.playerName = "Anonymous";
|
|
||||||
}
|
|
||||||
offerList.push_back(offer);
|
|
||||||
} while (result->next());
|
|
||||||
return offerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
MarketOfferList IOMarket::getOwnOffers(MarketAction_t action, uint32_t playerId)
|
|
||||||
{
|
|
||||||
MarketOfferList offerList;
|
|
||||||
|
|
||||||
const int32_t marketOfferDuration = g_config.getNumber(ConfigManager::MARKET_OFFER_DURATION);
|
|
||||||
|
|
||||||
std::ostringstream query;
|
|
||||||
query << "SELECT `id`, `amount`, `price`, `created`, `itemtype` FROM `market_offers` WHERE `player_id` = " << playerId << " AND `sale` = " << action;
|
|
||||||
|
|
||||||
DBResult_ptr result = Database::getInstance().storeQuery(query.str());
|
|
||||||
if (!result) {
|
|
||||||
return offerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
MarketOffer offer;
|
|
||||||
offer.amount = result->getNumber<uint16_t>("amount");
|
|
||||||
offer.price = result->getNumber<uint32_t>("price");
|
|
||||||
offer.timestamp = result->getNumber<uint32_t>("created") + marketOfferDuration;
|
|
||||||
offer.counter = result->getNumber<uint32_t>("id") & 0xFFFF;
|
|
||||||
offer.itemId = result->getNumber<uint16_t>("itemtype");
|
|
||||||
offerList.push_back(offer);
|
|
||||||
} while (result->next());
|
|
||||||
return offerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
HistoryMarketOfferList IOMarket::getOwnHistory(MarketAction_t action, uint32_t playerId)
|
|
||||||
{
|
|
||||||
HistoryMarketOfferList offerList;
|
|
||||||
|
|
||||||
std::ostringstream query;
|
|
||||||
query << "SELECT `itemtype`, `amount`, `price`, `expires_at`, `state` FROM `market_history` WHERE `player_id` = " << playerId << " AND `sale` = " << action;
|
|
||||||
|
|
||||||
DBResult_ptr result = Database::getInstance().storeQuery(query.str());
|
|
||||||
if (!result) {
|
|
||||||
return offerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
HistoryMarketOffer offer;
|
|
||||||
offer.itemId = result->getNumber<uint16_t>("itemtype");
|
|
||||||
offer.amount = result->getNumber<uint16_t>("amount");
|
|
||||||
offer.price = result->getNumber<uint32_t>("price");
|
|
||||||
offer.timestamp = result->getNumber<uint32_t>("expires_at");
|
|
||||||
|
|
||||||
MarketOfferState_t offerState = static_cast<MarketOfferState_t>(result->getNumber<uint16_t>("state"));
|
|
||||||
if (offerState == OFFERSTATE_ACCEPTEDEX) {
|
|
||||||
offerState = OFFERSTATE_ACCEPTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
offer.state = offerState;
|
|
||||||
|
|
||||||
offerList.push_back(offer);
|
|
||||||
} while (result->next());
|
|
||||||
return offerList;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IOMarket::processExpiredOffers(DBResult_ptr result, bool)
|
|
||||||
{
|
|
||||||
if (!result) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (!IOMarket::moveOfferToHistory(result->getNumber<uint32_t>("id"), OFFERSTATE_EXPIRED)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32_t playerId = result->getNumber<uint32_t>("player_id");
|
|
||||||
const uint16_t amount = result->getNumber<uint16_t>("amount");
|
|
||||||
if (result->getNumber<uint16_t>("sale") == 1) {
|
|
||||||
const ItemType& itemType = Item::items[result->getNumber<uint16_t>("itemtype")];
|
|
||||||
if (itemType.id == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Player* player = g_game.getPlayerByGUID(playerId);
|
|
||||||
if (!player) {
|
|
||||||
player = new Player(nullptr);
|
|
||||||
if (!IOLoginData::loadPlayerById(player, playerId)) {
|
|
||||||
delete player;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itemType.stackable) {
|
|
||||||
uint16_t tmpAmount = amount;
|
|
||||||
while (tmpAmount > 0) {
|
|
||||||
uint16_t stackCount = std::min<uint16_t>(100, tmpAmount);
|
|
||||||
Item* item = Item::CreateItem(itemType.id, stackCount);
|
|
||||||
if (g_game.internalAddItem(player->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RETURNVALUE_NOERROR) {
|
|
||||||
delete item;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpAmount -= stackCount;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int32_t subType;
|
|
||||||
if (itemType.charges != 0) {
|
|
||||||
subType = itemType.charges;
|
|
||||||
} else {
|
|
||||||
subType = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint16_t i = 0; i < amount; ++i) {
|
|
||||||
Item* item = Item::CreateItem(itemType.id, subType);
|
|
||||||
if (g_game.internalAddItem(player->getInbox(), item, INDEX_WHEREEVER, FLAG_NOLIMIT) != RETURNVALUE_NOERROR) {
|
|
||||||
delete item;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (player->isOffline()) {
|
|
||||||
IOLoginData::savePlayer(player);
|
|
||||||
delete player;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uint64_t totalPrice = result->getNumber<uint64_t>("price") * amount;
|
|
||||||
|
|
||||||
Player* player = g_game.getPlayerByGUID(playerId);
|
|
||||||
if (player) {
|
|
||||||
player->setBankBalance(player->getBankBalance() + totalPrice);
|
|
||||||
} else {
|
|
||||||
IOLoginData::increaseBankBalance(playerId, totalPrice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (result->next());
|
|
||||||
}
|
|
||||||
|
|
||||||
void IOMarket::checkExpiredOffers()
|
|
||||||
{
|
|
||||||
const time_t lastExpireDate = time(nullptr) - g_config.getNumber(ConfigManager::MARKET_OFFER_DURATION);
|
|
||||||
|
|
||||||
std::ostringstream query;
|
|
||||||
query << "SELECT `id`, `amount`, `price`, `itemtype`, `player_id`, `sale` FROM `market_offers` WHERE `created` <= " << lastExpireDate;
|
|
||||||
g_databaseTasks.addTask(query.str(), IOMarket::processExpiredOffers, true);
|
|
||||||
|
|
||||||
int32_t checkExpiredMarketOffersEachMinutes = g_config.getNumber(ConfigManager::CHECK_EXPIRED_MARKET_OFFERS_EACH_MINUTES);
|
|
||||||
if (checkExpiredMarketOffersEachMinutes <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_scheduler.addEvent(createSchedulerTask(checkExpiredMarketOffersEachMinutes * 60 * 1000, IOMarket::checkExpiredOffers));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t IOMarket::getPlayerOfferCount(uint32_t playerId)
|
|
||||||
{
|
|
||||||
std::ostringstream query;
|
|
||||||
query << "SELECT COUNT(*) AS `count` FROM `market_offers` WHERE `player_id` = " << playerId;
|
|
||||||
|
|
||||||
DBResult_ptr result = Database::getInstance().storeQuery(query.str());
|
|
||||||
if (!result) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return result->getNumber<int32_t>("count");
|
|
||||||
}
|
|
||||||
|
|
||||||
MarketOfferEx IOMarket::getOfferByCounter(uint32_t timestamp, uint16_t counter)
|
|
||||||
{
|
|
||||||
MarketOfferEx offer;
|
|
||||||
|
|
||||||
const int32_t created = timestamp - g_config.getNumber(ConfigManager::MARKET_OFFER_DURATION);
|
|
||||||
|
|
||||||
std::ostringstream query;
|
|
||||||
query << "SELECT `id`, `sale`, `itemtype`, `amount`, `created`, `price`, `player_id`, `anonymous`, (SELECT `name` FROM `players` WHERE `id` = `player_id`) AS `player_name` FROM `market_offers` WHERE `created` = " << created << " AND (`id` & 65535) = " << counter << " LIMIT 1";
|
|
||||||
|
|
||||||
DBResult_ptr result = Database::getInstance().storeQuery(query.str());
|
|
||||||
if (!result) {
|
|
||||||
offer.id = 0;
|
|
||||||
return offer;
|
|
||||||
}
|
|
||||||
|
|
||||||
offer.id = result->getNumber<uint32_t>("id");
|
|
||||||
offer.type = static_cast<MarketAction_t>(result->getNumber<uint16_t>("sale"));
|
|
||||||
offer.amount = result->getNumber<uint16_t>("amount");
|
|
||||||
offer.counter = result->getNumber<uint32_t>("id") & 0xFFFF;
|
|
||||||
offer.timestamp = result->getNumber<uint32_t>("created");
|
|
||||||
offer.price = result->getNumber<uint32_t>("price");
|
|
||||||
offer.itemId = result->getNumber<uint16_t>("itemtype");
|
|
||||||
offer.playerId = result->getNumber<uint32_t>("player_id");
|
|
||||||
if (result->getNumber<uint16_t>("anonymous") == 0) {
|
|
||||||
offer.playerName = result->getString("player_name");
|
|
||||||
} else {
|
|
||||||
offer.playerName = "Anonymous";
|
|
||||||
}
|
|
||||||
return offer;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IOMarket::createOffer(uint32_t playerId, MarketAction_t action, uint32_t itemId, uint16_t amount, uint32_t price, bool anonymous)
|
|
||||||
{
|
|
||||||
std::ostringstream query;
|
|
||||||
query << "INSERT INTO `market_offers` (`player_id`, `sale`, `itemtype`, `amount`, `price`, `created`, `anonymous`) VALUES (" << playerId << ',' << action << ',' << itemId << ',' << amount << ',' << price << ',' << time(nullptr) << ',' << anonymous << ')';
|
|
||||||
Database::getInstance().executeQuery(query.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void IOMarket::acceptOffer(uint32_t offerId, uint16_t amount)
|
|
||||||
{
|
|
||||||
std::ostringstream query;
|
|
||||||
query << "UPDATE `market_offers` SET `amount` = `amount` - " << amount << " WHERE `id` = " << offerId;
|
|
||||||
Database::getInstance().executeQuery(query.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void IOMarket::deleteOffer(uint32_t offerId)
|
|
||||||
{
|
|
||||||
std::ostringstream query;
|
|
||||||
query << "DELETE FROM `market_offers` WHERE `id` = " << offerId;
|
|
||||||
Database::getInstance().executeQuery(query.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void IOMarket::appendHistory(uint32_t playerId, MarketAction_t type, uint16_t itemId, uint16_t amount, uint32_t price, time_t timestamp, MarketOfferState_t state)
|
|
||||||
{
|
|
||||||
std::ostringstream query;
|
|
||||||
query << "INSERT INTO `market_history` (`player_id`, `sale`, `itemtype`, `amount`, `price`, `expires_at`, `inserted`, `state`) VALUES ("
|
|
||||||
<< playerId << ',' << type << ',' << itemId << ',' << amount << ',' << price << ','
|
|
||||||
<< timestamp << ',' << time(nullptr) << ',' << state << ')';
|
|
||||||
g_databaseTasks.addTask(query.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IOMarket::moveOfferToHistory(uint32_t offerId, MarketOfferState_t state)
|
|
||||||
{
|
|
||||||
const int32_t marketOfferDuration = g_config.getNumber(ConfigManager::MARKET_OFFER_DURATION);
|
|
||||||
|
|
||||||
Database& db = Database::getInstance();
|
|
||||||
|
|
||||||
std::ostringstream query;
|
|
||||||
query << "SELECT `player_id`, `sale`, `itemtype`, `amount`, `price`, `created` FROM `market_offers` WHERE `id` = " << offerId;
|
|
||||||
|
|
||||||
DBResult_ptr result = db.storeQuery(query.str());
|
|
||||||
if (!result) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
query.str(std::string());
|
|
||||||
query << "DELETE FROM `market_offers` WHERE `id` = " << offerId;
|
|
||||||
if (!db.executeQuery(query.str())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
appendHistory(result->getNumber<uint32_t>("player_id"), static_cast<MarketAction_t>(result->getNumber<uint16_t>("sale")), result->getNumber<uint16_t>("itemtype"), result->getNumber<uint16_t>("amount"), result->getNumber<uint32_t>("price"), result->getNumber<uint32_t>("created") + marketOfferDuration, state);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IOMarket::updateStatistics()
|
|
||||||
{
|
|
||||||
std::ostringstream query;
|
|
||||||
query << "SELECT `sale` AS `sale`, `itemtype` AS `itemtype`, COUNT(`price`) AS `num`, MIN(`price`) AS `min`, MAX(`price`) AS `max`, SUM(`price`) AS `sum` FROM `market_history` WHERE `state` = " << OFFERSTATE_ACCEPTED << " GROUP BY `itemtype`, `sale`";
|
|
||||||
DBResult_ptr result = Database::getInstance().storeQuery(query.str());
|
|
||||||
if (!result) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
MarketStatistics* statistics;
|
|
||||||
if (result->getNumber<uint16_t>("sale") == MARKETACTION_BUY) {
|
|
||||||
statistics = &purchaseStatistics[result->getNumber<uint16_t>("itemtype")];
|
|
||||||
} else {
|
|
||||||
statistics = &saleStatistics[result->getNumber<uint16_t>("itemtype")];
|
|
||||||
}
|
|
||||||
|
|
||||||
statistics->numTransactions = result->getNumber<uint32_t>("num");
|
|
||||||
statistics->lowestPrice = result->getNumber<uint32_t>("min");
|
|
||||||
statistics->totalPrice = result->getNumber<uint64_t>("sum");
|
|
||||||
statistics->highestPrice = result->getNumber<uint32_t>("max");
|
|
||||||
} while (result->next());
|
|
||||||
}
|
|
||||||
|
|
||||||
MarketStatistics* IOMarket::getPurchaseStatistics(uint16_t itemId)
|
|
||||||
{
|
|
||||||
auto it = purchaseStatistics.find(itemId);
|
|
||||||
if (it == purchaseStatistics.end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
MarketStatistics* IOMarket::getSaleStatistics(uint16_t itemId)
|
|
||||||
{
|
|
||||||
auto it = saleStatistics.find(itemId);
|
|
||||||
if (it == saleStatistics.end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &it->second;
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
/**
|
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FS_IOMARKET_H_B981E52C218C42D3B9EF726EBF0E92C9
|
|
||||||
#define FS_IOMARKET_H_B981E52C218C42D3B9EF726EBF0E92C9
|
|
||||||
|
|
||||||
#include "enums.h"
|
|
||||||
#include "database.h"
|
|
||||||
|
|
||||||
class IOMarket
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static IOMarket& getInstance() {
|
|
||||||
static IOMarket instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
static MarketOfferList getActiveOffers(MarketAction_t action, uint16_t itemId);
|
|
||||||
static MarketOfferList getOwnOffers(MarketAction_t action, uint32_t playerId);
|
|
||||||
static HistoryMarketOfferList getOwnHistory(MarketAction_t action, uint32_t playerId);
|
|
||||||
|
|
||||||
static void processExpiredOffers(DBResult_ptr result, bool);
|
|
||||||
static void checkExpiredOffers();
|
|
||||||
|
|
||||||
static uint32_t getPlayerOfferCount(uint32_t playerId);
|
|
||||||
static MarketOfferEx getOfferByCounter(uint32_t timestamp, uint16_t counter);
|
|
||||||
|
|
||||||
static void createOffer(uint32_t playerId, MarketAction_t action, uint32_t itemId, uint16_t amount, uint32_t price, bool anonymous);
|
|
||||||
static void acceptOffer(uint32_t offerId, uint16_t amount);
|
|
||||||
static void deleteOffer(uint32_t offerId);
|
|
||||||
|
|
||||||
static void appendHistory(uint32_t playerId, MarketAction_t type, uint16_t itemId, uint16_t amount, uint32_t price, time_t timestamp, MarketOfferState_t state);
|
|
||||||
static bool moveOfferToHistory(uint32_t offerId, MarketOfferState_t state);
|
|
||||||
|
|
||||||
void updateStatistics();
|
|
||||||
|
|
||||||
MarketStatistics* getPurchaseStatistics(uint16_t itemId);
|
|
||||||
MarketStatistics* getSaleStatistics(uint16_t itemId);
|
|
||||||
|
|
||||||
private:
|
|
||||||
IOMarket() = default;
|
|
||||||
|
|
||||||
std::map<uint16_t, MarketStatistics> purchaseStatistics;
|
|
||||||
std::map<uint16_t, MarketStatistics> saleStatistics;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
953
src/item.cpp
953
src/item.cpp
File diff suppressed because it is too large
Load Diff
527
src/item.h
527
src/item.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -23,12 +23,7 @@
|
|||||||
#include "cylinder.h"
|
#include "cylinder.h"
|
||||||
#include "thing.h"
|
#include "thing.h"
|
||||||
#include "items.h"
|
#include "items.h"
|
||||||
#include "luascript.h"
|
|
||||||
#include "tools.h"
|
|
||||||
#include <typeinfo>
|
|
||||||
|
|
||||||
#include <boost/variant.hpp>
|
|
||||||
#include <boost/lexical_cast.hpp>
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
class Creature;
|
class Creature;
|
||||||
@@ -36,8 +31,8 @@ class Player;
|
|||||||
class Container;
|
class Container;
|
||||||
class Depot;
|
class Depot;
|
||||||
class Teleport;
|
class Teleport;
|
||||||
class TrashHolder;
|
|
||||||
class Mailbox;
|
class Mailbox;
|
||||||
|
class DepotLocker;
|
||||||
class Door;
|
class Door;
|
||||||
class MagicField;
|
class MagicField;
|
||||||
class BedItem;
|
class BedItem;
|
||||||
@@ -55,6 +50,7 @@ enum ITEMPROPERTY {
|
|||||||
CONST_PROP_IMMOVABLENOFIELDBLOCKPATH,
|
CONST_PROP_IMMOVABLENOFIELDBLOCKPATH,
|
||||||
CONST_PROP_NOFIELDBLOCKPATH,
|
CONST_PROP_NOFIELDBLOCKPATH,
|
||||||
CONST_PROP_SUPPORTHANGABLE,
|
CONST_PROP_SUPPORTHANGABLE,
|
||||||
|
CONST_PROP_UNLAY,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TradeEvents_t {
|
enum TradeEvents_t {
|
||||||
@@ -73,7 +69,7 @@ enum AttrTypes_t {
|
|||||||
//ATTR_EXT_FILE = 2,
|
//ATTR_EXT_FILE = 2,
|
||||||
ATTR_TILE_FLAGS = 3,
|
ATTR_TILE_FLAGS = 3,
|
||||||
ATTR_ACTION_ID = 4,
|
ATTR_ACTION_ID = 4,
|
||||||
ATTR_UNIQUE_ID = 5,
|
ATTR_MOVEMENT_ID = 5,
|
||||||
ATTR_TEXT = 6,
|
ATTR_TEXT = 6,
|
||||||
ATTR_DESC = 7,
|
ATTR_DESC = 7,
|
||||||
ATTR_TELE_DEST = 8,
|
ATTR_TELE_DEST = 8,
|
||||||
@@ -91,19 +87,22 @@ enum AttrTypes_t {
|
|||||||
ATTR_SLEEPERGUID = 20,
|
ATTR_SLEEPERGUID = 20,
|
||||||
ATTR_SLEEPSTART = 21,
|
ATTR_SLEEPSTART = 21,
|
||||||
ATTR_CHARGES = 22,
|
ATTR_CHARGES = 22,
|
||||||
ATTR_CONTAINER_ITEMS = 23,
|
ATTR_KEYNUMBER = 23,
|
||||||
ATTR_NAME = 24,
|
ATTR_KEYHOLENUMBER = 24,
|
||||||
ATTR_ARTICLE = 25,
|
ATTR_DOORQUESTNUMBER = 25,
|
||||||
ATTR_PLURALNAME = 26,
|
ATTR_DOORQUESTVALUE = 26,
|
||||||
ATTR_WEIGHT = 27,
|
ATTR_DOORLEVEL = 27,
|
||||||
ATTR_ATTACK = 28,
|
ATTR_CHESTQUESTNUMBER = 28,
|
||||||
ATTR_DEFENSE = 29,
|
// add non-OTBM attributes after here
|
||||||
ATTR_EXTRADEFENSE = 30,
|
ATTR_CONTAINER_ITEMS = 29,
|
||||||
ATTR_ARMOR = 31,
|
ATTR_NAME = 30,
|
||||||
ATTR_HITCHANCE = 32,
|
ATTR_ARTICLE = 31,
|
||||||
ATTR_SHOOTRANGE = 33,
|
ATTR_PLURALNAME = 32,
|
||||||
ATTR_CUSTOM_ATTRIBUTES = 34,
|
ATTR_WEIGHT = 33,
|
||||||
ATTR_DECAYTO = 35
|
ATTR_ATTACK = 34,
|
||||||
|
ATTR_DEFENSE = 35,
|
||||||
|
ATTR_ARMOR = 36,
|
||||||
|
ATTR_SHOOTRANGE = 37,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Attr_ReadValue {
|
enum Attr_ReadValue {
|
||||||
@@ -161,11 +160,53 @@ class ItemAttributes
|
|||||||
return static_cast<uint16_t>(getIntAttr(ITEM_ATTRIBUTE_ACTIONID));
|
return static_cast<uint16_t>(getIntAttr(ITEM_ATTRIBUTE_ACTIONID));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setUniqueId(uint16_t n) {
|
void setMovementID(uint16_t n) {
|
||||||
setIntAttr(ITEM_ATTRIBUTE_UNIQUEID, n);
|
setIntAttr(ITEM_ATTRIBUTE_MOVEMENTID, n);
|
||||||
}
|
}
|
||||||
uint16_t getUniqueId() const {
|
uint16_t getMovementId() const {
|
||||||
return static_cast<uint16_t>(getIntAttr(ITEM_ATTRIBUTE_UNIQUEID));
|
return static_cast<uint16_t>(getIntAttr(ITEM_ATTRIBUTE_MOVEMENTID));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setKeyNumber(uint16_t n) {
|
||||||
|
setIntAttr(ITEM_ATTRIBUTE_KEYNUMBER, n);
|
||||||
|
}
|
||||||
|
uint16_t getKeyNumber() const {
|
||||||
|
return static_cast<uint16_t>(getIntAttr(ITEM_ATTRIBUTE_KEYNUMBER));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setKeyHoleNumber(uint16_t n) {
|
||||||
|
setIntAttr(ITEM_ATTRIBUTE_KEYHOLENUMBER, n);
|
||||||
|
}
|
||||||
|
uint16_t getKeyHoleNumber() const {
|
||||||
|
return static_cast<uint16_t>(getIntAttr(ITEM_ATTRIBUTE_KEYHOLENUMBER));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDoorQuestNumber(uint16_t n) {
|
||||||
|
setIntAttr(ITEM_ATTRIBUTE_DOORQUESTNUMBER, n);
|
||||||
|
}
|
||||||
|
uint16_t getDoorQuestNumber() const {
|
||||||
|
return static_cast<uint16_t>(getIntAttr(ITEM_ATTRIBUTE_DOORQUESTNUMBER));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDoorQuestValue(uint16_t n) {
|
||||||
|
setIntAttr(ITEM_ATTRIBUTE_DOORQUESTVALUE, n);
|
||||||
|
}
|
||||||
|
uint16_t getDoorQuestValue() const {
|
||||||
|
return static_cast<uint16_t>(getIntAttr(ITEM_ATTRIBUTE_DOORQUESTVALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDoorLevel(uint16_t n) {
|
||||||
|
setIntAttr(ITEM_ATTRIBUTE_DOORLEVEL, n);
|
||||||
|
}
|
||||||
|
uint16_t getDoorLevel() const {
|
||||||
|
return static_cast<uint16_t>(getIntAttr(ITEM_ATTRIBUTE_DOORLEVEL));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setChestQuestNumber(uint16_t n) {
|
||||||
|
setIntAttr(ITEM_ATTRIBUTE_CHESTQUESTNUMBER, n);
|
||||||
|
}
|
||||||
|
uint16_t getChestQuestNumber() const {
|
||||||
|
return static_cast<uint16_t>(getIntAttr(ITEM_ATTRIBUTE_CHESTQUESTNUMBER));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCharges(uint16_t n) {
|
void setCharges(uint16_t n) {
|
||||||
@@ -189,13 +230,6 @@ class ItemAttributes
|
|||||||
return getIntAttr(ITEM_ATTRIBUTE_OWNER);
|
return getIntAttr(ITEM_ATTRIBUTE_OWNER);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCorpseOwner(uint32_t corpseOwner) {
|
|
||||||
setIntAttr(ITEM_ATTRIBUTE_CORPSEOWNER, corpseOwner);
|
|
||||||
}
|
|
||||||
uint32_t getCorpseOwner() const {
|
|
||||||
return getIntAttr(ITEM_ATTRIBUTE_CORPSEOWNER);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDuration(int32_t time) {
|
void setDuration(int32_t time) {
|
||||||
setIntAttr(ITEM_ATTRIBUTE_DURATION, time);
|
setIntAttr(ITEM_ATTRIBUTE_DURATION, time);
|
||||||
}
|
}
|
||||||
@@ -213,149 +247,19 @@ class ItemAttributes
|
|||||||
return static_cast<ItemDecayState_t>(getIntAttr(ITEM_ATTRIBUTE_DECAYSTATE));
|
return static_cast<ItemDecayState_t>(getIntAttr(ITEM_ATTRIBUTE_DECAYSTATE));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CustomAttribute
|
protected:
|
||||||
{
|
inline bool hasAttribute(itemAttrTypes type) const {
|
||||||
typedef boost::variant<boost::blank, std::string, int64_t, double, bool> VariantAttribute;
|
|
||||||
VariantAttribute value;
|
|
||||||
|
|
||||||
CustomAttribute() : value(boost::blank()) {}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
explicit CustomAttribute(const T& v) : value(v) {}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void set(const T& v) {
|
|
||||||
value = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
const T& get();
|
|
||||||
|
|
||||||
struct PushLuaVisitor : public boost::static_visitor<> {
|
|
||||||
lua_State* L;
|
|
||||||
|
|
||||||
explicit PushLuaVisitor(lua_State* L) : boost::static_visitor<>(), L(L) {}
|
|
||||||
|
|
||||||
void operator()(const boost::blank&) const {
|
|
||||||
lua_pushnil(L);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()(const std::string& v) const {
|
|
||||||
LuaScriptInterface::pushString(L, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()(bool v) const {
|
|
||||||
LuaScriptInterface::pushBoolean(L, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()(const int64_t& v) const {
|
|
||||||
lua_pushnumber(L, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()(const double& v) const {
|
|
||||||
lua_pushnumber(L, v);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void pushToLua(lua_State* L) const {
|
|
||||||
boost::apply_visitor(PushLuaVisitor(L), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SerializeVisitor : public boost::static_visitor<> {
|
|
||||||
PropWriteStream& propWriteStream;
|
|
||||||
|
|
||||||
explicit SerializeVisitor(PropWriteStream& propWriteStream) : boost::static_visitor<>(), propWriteStream(propWriteStream) {}
|
|
||||||
|
|
||||||
void operator()(const boost::blank&) const {
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator()(const std::string& v) const {
|
|
||||||
propWriteStream.writeString(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void operator()(const T& v) const {
|
|
||||||
propWriteStream.write<T>(v);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void serialize(PropWriteStream& propWriteStream) const {
|
|
||||||
propWriteStream.write<uint8_t>(static_cast<uint8_t>(value.which()));
|
|
||||||
boost::apply_visitor(SerializeVisitor(propWriteStream), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool unserialize(PropStream& propStream) {
|
|
||||||
// This is hard coded so it's not general, depends on the position of the variants.
|
|
||||||
uint8_t pos;
|
|
||||||
if (!propStream.read<uint8_t>(pos)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (pos) {
|
|
||||||
case 1: { // std::string
|
|
||||||
std::string tmp;
|
|
||||||
if (!propStream.readString(tmp)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
value = tmp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 2: { // int64_t
|
|
||||||
int64_t tmp;
|
|
||||||
if (!propStream.read<int64_t>(tmp)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
value = tmp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 3: { // double
|
|
||||||
double tmp;
|
|
||||||
if (!propStream.read<double>(tmp)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
value = tmp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 4: { // bool
|
|
||||||
bool tmp;
|
|
||||||
if (!propStream.read<bool>(tmp)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
value = tmp;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
value = boost::blank();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool hasAttribute(itemAttrTypes type) const {
|
|
||||||
return (type & attributeBits) != 0;
|
return (type & attributeBits) != 0;
|
||||||
}
|
}
|
||||||
void removeAttribute(itemAttrTypes type);
|
void removeAttribute(itemAttrTypes type);
|
||||||
|
|
||||||
static std::string emptyString;
|
static std::string emptyString;
|
||||||
static int64_t emptyInt;
|
|
||||||
static double emptyDouble;
|
|
||||||
static bool emptyBool;
|
|
||||||
|
|
||||||
typedef std::unordered_map<std::string, CustomAttribute> CustomAttributeMap;
|
|
||||||
|
|
||||||
struct Attribute
|
struct Attribute
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
int64_t integer;
|
int64_t integer;
|
||||||
std::string* string;
|
std::string* string;
|
||||||
CustomAttributeMap* custom;
|
|
||||||
} value;
|
} value;
|
||||||
itemAttrTypes type;
|
itemAttrTypes type;
|
||||||
|
|
||||||
@@ -368,8 +272,6 @@ class ItemAttributes
|
|||||||
value.integer = i.value.integer;
|
value.integer = i.value.integer;
|
||||||
} else if (ItemAttributes::isStrAttrType(type)) {
|
} else if (ItemAttributes::isStrAttrType(type)) {
|
||||||
value.string = new std::string(*i.value.string);
|
value.string = new std::string(*i.value.string);
|
||||||
} else if (ItemAttributes::isCustomAttrType(type)) {
|
|
||||||
value.custom = new CustomAttributeMap(*i.value.custom);
|
|
||||||
} else {
|
} else {
|
||||||
memset(&value, 0, sizeof(value));
|
memset(&value, 0, sizeof(value));
|
||||||
}
|
}
|
||||||
@@ -381,8 +283,6 @@ class ItemAttributes
|
|||||||
~Attribute() {
|
~Attribute() {
|
||||||
if (ItemAttributes::isStrAttrType(type)) {
|
if (ItemAttributes::isStrAttrType(type)) {
|
||||||
delete value.string;
|
delete value.string;
|
||||||
} else if (ItemAttributes::isCustomAttrType(type)) {
|
|
||||||
delete value.custom;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Attribute& operator=(Attribute other) {
|
Attribute& operator=(Attribute other) {
|
||||||
@@ -393,8 +293,6 @@ class ItemAttributes
|
|||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
if (ItemAttributes::isStrAttrType(type)) {
|
if (ItemAttributes::isStrAttrType(type)) {
|
||||||
delete value.string;
|
delete value.string;
|
||||||
} else if (ItemAttributes::isCustomAttrType(type)) {
|
|
||||||
delete value.custom;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
value = other.value;
|
value = other.value;
|
||||||
@@ -425,94 +323,12 @@ class ItemAttributes
|
|||||||
const Attribute* getExistingAttr(itemAttrTypes type) const;
|
const Attribute* getExistingAttr(itemAttrTypes type) const;
|
||||||
Attribute& getAttr(itemAttrTypes type);
|
Attribute& getAttr(itemAttrTypes type);
|
||||||
|
|
||||||
CustomAttributeMap* getCustomAttributeMap() {
|
|
||||||
if (!hasAttribute(ITEM_ATTRIBUTE_CUSTOM)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return getAttr(ITEM_ATTRIBUTE_CUSTOM).value.custom;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R>
|
|
||||||
void setCustomAttribute(int64_t key, R value) {
|
|
||||||
std::string tmp = boost::lexical_cast<std::string>(key);
|
|
||||||
setCustomAttribute(tmp, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCustomAttribute(int64_t key, CustomAttribute& value) {
|
|
||||||
std::string tmp = boost::lexical_cast<std::string>(key);
|
|
||||||
setCustomAttribute(tmp, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename R>
|
|
||||||
void setCustomAttribute(std::string& key, R value) {
|
|
||||||
toLowerCaseString(key);
|
|
||||||
if (hasAttribute(ITEM_ATTRIBUTE_CUSTOM)) {
|
|
||||||
removeCustomAttribute(key);
|
|
||||||
} else {
|
|
||||||
getAttr(ITEM_ATTRIBUTE_CUSTOM).value.custom = new CustomAttributeMap();
|
|
||||||
}
|
|
||||||
getAttr(ITEM_ATTRIBUTE_CUSTOM).value.custom->emplace(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCustomAttribute(std::string& key, CustomAttribute& value) {
|
|
||||||
toLowerCaseString(key);
|
|
||||||
if (hasAttribute(ITEM_ATTRIBUTE_CUSTOM)) {
|
|
||||||
removeCustomAttribute(key);
|
|
||||||
} else {
|
|
||||||
getAttr(ITEM_ATTRIBUTE_CUSTOM).value.custom = new CustomAttributeMap();
|
|
||||||
}
|
|
||||||
getAttr(ITEM_ATTRIBUTE_CUSTOM).value.custom->insert(std::make_pair(std::move(key), std::move(value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
const CustomAttribute* getCustomAttribute(int64_t key) {
|
|
||||||
std::string tmp = boost::lexical_cast<std::string>(key);
|
|
||||||
return getCustomAttribute(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
const CustomAttribute* getCustomAttribute(const std::string& key) {
|
|
||||||
if (const CustomAttributeMap* customAttrMap = getCustomAttributeMap()) {
|
|
||||||
auto it = customAttrMap->find(asLowerCaseString(key));
|
|
||||||
if (it != customAttrMap->end()) {
|
|
||||||
return &(it->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool removeCustomAttribute(int64_t key) {
|
|
||||||
std::string tmp = boost::lexical_cast<std::string>(key);
|
|
||||||
return removeCustomAttribute(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool removeCustomAttribute(const std::string& key) {
|
|
||||||
if (CustomAttributeMap* customAttrMap = getCustomAttributeMap()) {
|
|
||||||
auto it = customAttrMap->find(asLowerCaseString(key));
|
|
||||||
if (it != customAttrMap->end()) {
|
|
||||||
customAttrMap->erase(it);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const static uint32_t intAttributeTypes = ITEM_ATTRIBUTE_ACTIONID | ITEM_ATTRIBUTE_UNIQUEID | ITEM_ATTRIBUTE_DATE
|
|
||||||
| ITEM_ATTRIBUTE_WEIGHT | ITEM_ATTRIBUTE_ATTACK | ITEM_ATTRIBUTE_DEFENSE | ITEM_ATTRIBUTE_EXTRADEFENSE
|
|
||||||
| ITEM_ATTRIBUTE_ARMOR | ITEM_ATTRIBUTE_HITCHANCE | ITEM_ATTRIBUTE_SHOOTRANGE | ITEM_ATTRIBUTE_OWNER
|
|
||||||
| ITEM_ATTRIBUTE_DURATION | ITEM_ATTRIBUTE_DECAYSTATE | ITEM_ATTRIBUTE_CORPSEOWNER | ITEM_ATTRIBUTE_CHARGES
|
|
||||||
| ITEM_ATTRIBUTE_FLUIDTYPE | ITEM_ATTRIBUTE_DOORID | ITEM_ATTRIBUTE_DECAYTO;
|
|
||||||
const static uint32_t stringAttributeTypes = ITEM_ATTRIBUTE_DESCRIPTION | ITEM_ATTRIBUTE_TEXT | ITEM_ATTRIBUTE_WRITER
|
|
||||||
| ITEM_ATTRIBUTE_NAME | ITEM_ATTRIBUTE_ARTICLE | ITEM_ATTRIBUTE_PLURALNAME;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static bool isIntAttrType(itemAttrTypes type) {
|
inline static bool isIntAttrType(itemAttrTypes type) {
|
||||||
return (type & intAttributeTypes) == type;
|
return (type & 0xFFFFE13) != 0;
|
||||||
}
|
}
|
||||||
static bool isStrAttrType(itemAttrTypes type) {
|
inline static bool isStrAttrType(itemAttrTypes type) {
|
||||||
return (type & stringAttributeTypes) == type;
|
return (type & 0x1EC) != 0;
|
||||||
}
|
|
||||||
inline static bool isCustomAttrType(itemAttrTypes type) {
|
|
||||||
return (type & ITEM_ATTRIBUTE_CUSTOM) == type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::forward_list<Attribute>& getList() const {
|
const std::forward_list<Attribute>& getList() const {
|
||||||
@@ -543,10 +359,10 @@ class Item : virtual public Thing
|
|||||||
|
|
||||||
bool equals(const Item* otherItem) const;
|
bool equals(const Item* otherItem) const;
|
||||||
|
|
||||||
Item* getItem() override final {
|
Item* getItem() final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
const Item* getItem() const override final {
|
const Item* getItem() const final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
virtual Teleport* getTeleport() {
|
virtual Teleport* getTeleport() {
|
||||||
@@ -555,18 +371,18 @@ class Item : virtual public Thing
|
|||||||
virtual const Teleport* getTeleport() const {
|
virtual const Teleport* getTeleport() const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
virtual TrashHolder* getTrashHolder() {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
virtual const TrashHolder* getTrashHolder() const {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
virtual Mailbox* getMailbox() {
|
virtual Mailbox* getMailbox() {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
virtual const Mailbox* getMailbox() const {
|
virtual const Mailbox* getMailbox() const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
virtual DepotLocker* getDepotLocker() {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
virtual const DepotLocker* getDepotLocker() const {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
virtual Door* getDoor() {
|
virtual Door* getDoor() {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -621,31 +437,6 @@ class Item : virtual public Thing
|
|||||||
return attributes->hasAttribute(type);
|
return attributes->hasAttribute(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename R>
|
|
||||||
void setCustomAttribute(std::string& key, R value) {
|
|
||||||
getAttributes()->setCustomAttribute(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCustomAttribute(std::string& key, ItemAttributes::CustomAttribute& value) {
|
|
||||||
getAttributes()->setCustomAttribute(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ItemAttributes::CustomAttribute* getCustomAttribute(int64_t key) {
|
|
||||||
return getAttributes()->getCustomAttribute(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ItemAttributes::CustomAttribute* getCustomAttribute(const std::string& key) {
|
|
||||||
return getAttributes()->getCustomAttribute(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool removeCustomAttribute(int64_t key) {
|
|
||||||
return getAttributes()->removeCustomAttribute(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool removeCustomAttribute(const std::string& key) {
|
|
||||||
return getAttributes()->removeCustomAttribute(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSpecialDescription(const std::string& desc) {
|
void setSpecialDescription(const std::string& desc) {
|
||||||
setStrAttr(ITEM_ATTRIBUTE_DESCRIPTION, desc);
|
setStrAttr(ITEM_ATTRIBUTE_DESCRIPTION, desc);
|
||||||
}
|
}
|
||||||
@@ -684,10 +475,6 @@ class Item : virtual public Thing
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setActionId(uint16_t n) {
|
void setActionId(uint16_t n) {
|
||||||
if (n < 100) {
|
|
||||||
n = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIntAttr(ITEM_ATTRIBUTE_ACTIONID, n);
|
setIntAttr(ITEM_ATTRIBUTE_ACTIONID, n);
|
||||||
}
|
}
|
||||||
uint16_t getActionId() const {
|
uint16_t getActionId() const {
|
||||||
@@ -697,11 +484,14 @@ class Item : virtual public Thing
|
|||||||
return static_cast<uint16_t>(getIntAttr(ITEM_ATTRIBUTE_ACTIONID));
|
return static_cast<uint16_t>(getIntAttr(ITEM_ATTRIBUTE_ACTIONID));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t getUniqueId() const {
|
void setMovementID(uint16_t n) {
|
||||||
|
setIntAttr(ITEM_ATTRIBUTE_MOVEMENTID, n);
|
||||||
|
}
|
||||||
|
uint16_t getMovementId() const {
|
||||||
if (!attributes) {
|
if (!attributes) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return static_cast<uint16_t>(getIntAttr(ITEM_ATTRIBUTE_UNIQUEID));
|
return static_cast<uint16_t>(getIntAttr(ITEM_ATTRIBUTE_MOVEMENTID));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCharges(uint16_t n) {
|
void setCharges(uint16_t n) {
|
||||||
@@ -767,49 +557,42 @@ class Item : virtual public Thing
|
|||||||
return static_cast<ItemDecayState_t>(getIntAttr(ITEM_ATTRIBUTE_DECAYSTATE));
|
return static_cast<ItemDecayState_t>(getIntAttr(ITEM_ATTRIBUTE_DECAYSTATE));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDecayTo(int32_t decayTo) {
|
|
||||||
setIntAttr(ITEM_ATTRIBUTE_DECAYTO, decayTo);
|
|
||||||
}
|
|
||||||
int32_t getDecayTo() const {
|
|
||||||
if (hasAttribute(ITEM_ATTRIBUTE_DECAYTO)) {
|
|
||||||
return getIntAttr(ITEM_ATTRIBUTE_DECAYTO);
|
|
||||||
}
|
|
||||||
return items[id].decayTo;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string getDescription(const ItemType& it, int32_t lookDistance, const Item* item = nullptr, int32_t subType = -1, bool addArticle = true);
|
static std::string getDescription(const ItemType& it, int32_t lookDistance, const Item* item = nullptr, int32_t subType = -1, bool addArticle = true);
|
||||||
static std::string getNameDescription(const ItemType& it, const Item* item = nullptr, int32_t subType = -1, bool addArticle = true);
|
static std::string getNameDescription(const ItemType& it, const Item* item = nullptr, int32_t subType = -1, bool addArticle = true);
|
||||||
static std::string getWeightDescription(const ItemType& it, uint32_t weight, uint32_t count = 1);
|
static std::string getWeightDescription(const ItemType& it, uint32_t weight, uint32_t count = 1);
|
||||||
|
|
||||||
std::string getDescription(int32_t lookDistance) const override final;
|
std::string getDescription(int32_t lookDistance) const final;
|
||||||
std::string getNameDescription() const;
|
std::string getNameDescription() const;
|
||||||
std::string getWeightDescription() const;
|
std::string getWeightDescription() const;
|
||||||
|
|
||||||
//serialization
|
//serialization
|
||||||
virtual Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream);
|
virtual Attr_ReadValue readAttr(AttrTypes_t attr, PropStream& propStream);
|
||||||
bool unserializeAttr(PropStream& propStream);
|
bool unserializeAttr(PropStream& propStream);
|
||||||
virtual bool unserializeItemNode(OTB::Loader&, const OTB::Node&, PropStream& propStream);
|
virtual bool unserializeItemNode(FileLoader& f, NODE node, PropStream& propStream);
|
||||||
|
|
||||||
virtual void serializeAttr(PropWriteStream& propWriteStream) const;
|
virtual void serializeAttr(PropWriteStream& propWriteStream) const;
|
||||||
|
|
||||||
bool isPushable() const override final {
|
bool isPushable() const final {
|
||||||
return isMoveable();
|
return isMoveable();
|
||||||
}
|
}
|
||||||
int32_t getThrowRange() const override final {
|
int32_t getThrowRange() const final {
|
||||||
return (isPickupable() ? 15 : 2);
|
return (isPickupable() ? 15 : 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t getID() const {
|
uint16_t getID() const {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
uint16_t getClientID() const {
|
|
||||||
return items[id].clientId;
|
|
||||||
}
|
|
||||||
void setID(uint16_t newid);
|
void setID(uint16_t newid);
|
||||||
|
|
||||||
// Returns the player that is holding this item in his inventory
|
// Returns the player that is holding this item in his inventory
|
||||||
Player* getHoldingPlayer() const;
|
Player* getHoldingPlayer() const;
|
||||||
|
|
||||||
|
CombatType_t getDamageType() const {
|
||||||
|
return items[id].damageType;
|
||||||
|
}
|
||||||
|
CombatType_t getCombatType() const {
|
||||||
|
return items[id].combatType;
|
||||||
|
}
|
||||||
WeaponType_t getWeaponType() const {
|
WeaponType_t getWeaponType() const {
|
||||||
return items[id].weaponType;
|
return items[id].weaponType;
|
||||||
}
|
}
|
||||||
@@ -822,7 +605,28 @@ class Item : virtual public Thing
|
|||||||
}
|
}
|
||||||
return items[id].shootRange;
|
return items[id].shootRange;
|
||||||
}
|
}
|
||||||
|
uint8_t getMissileType() const {
|
||||||
|
return items[id].shootType;
|
||||||
|
}
|
||||||
|
uint8_t getFragility() const {
|
||||||
|
return items[id].fragility;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t getAttackStrength() const {
|
||||||
|
return items[id].attackStrength;
|
||||||
|
}
|
||||||
|
int32_t getAttackVariation() const {
|
||||||
|
return items[id].attackVariation;
|
||||||
|
}
|
||||||
|
int32_t getManaConsumption() const {
|
||||||
|
return items[id].manaConsumption;
|
||||||
|
}
|
||||||
|
uint32_t getMinimumLevel() const {
|
||||||
|
return items[id].minReqLevel;
|
||||||
|
}
|
||||||
|
int32_t getWeaponSpecialEffect() const {
|
||||||
|
return items[id].weaponSpecialEffect;
|
||||||
|
}
|
||||||
virtual uint32_t getWeight() const;
|
virtual uint32_t getWeight() const;
|
||||||
uint32_t getBaseWeight() const {
|
uint32_t getBaseWeight() const {
|
||||||
if (hasAttribute(ITEM_ATTRIBUTE_WEIGHT)) {
|
if (hasAttribute(ITEM_ATTRIBUTE_WEIGHT)) {
|
||||||
@@ -848,24 +652,15 @@ class Item : virtual public Thing
|
|||||||
}
|
}
|
||||||
return items[id].defense;
|
return items[id].defense;
|
||||||
}
|
}
|
||||||
int32_t getExtraDefense() const {
|
|
||||||
if (hasAttribute(ITEM_ATTRIBUTE_EXTRADEFENSE)) {
|
|
||||||
return getIntAttr(ITEM_ATTRIBUTE_EXTRADEFENSE);
|
|
||||||
}
|
|
||||||
return items[id].extraDefense;
|
|
||||||
}
|
|
||||||
int32_t getSlotPosition() const {
|
int32_t getSlotPosition() const {
|
||||||
return items[id].slotPosition;
|
return items[id].slotPosition;
|
||||||
}
|
}
|
||||||
int8_t getHitChance() const {
|
uint16_t getDisguiseId() const {
|
||||||
if (hasAttribute(ITEM_ATTRIBUTE_HITCHANCE)) {
|
return items[id].disguiseId;
|
||||||
return getIntAttr(ITEM_ATTRIBUTE_HITCHANCE);
|
|
||||||
}
|
|
||||||
return items[id].hitChance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getWorth() const;
|
uint32_t getWorth() const;
|
||||||
LightInfo getLightInfo() const;
|
void getLight(LightInfo& lightInfo) const;
|
||||||
|
|
||||||
bool hasProperty(ITEMPROPERTY prop) const;
|
bool hasProperty(ITEMPROPERTY prop) const;
|
||||||
bool isBlocking() const {
|
bool isBlocking() const {
|
||||||
@@ -883,15 +678,15 @@ class Item : virtual public Thing
|
|||||||
bool isMagicField() const {
|
bool isMagicField() const {
|
||||||
return items[id].isMagicField();
|
return items[id].isMagicField();
|
||||||
}
|
}
|
||||||
|
bool isSplash() const {
|
||||||
|
return items[id].isSplash();
|
||||||
|
}
|
||||||
bool isMoveable() const {
|
bool isMoveable() const {
|
||||||
return items[id].moveable;
|
return items[id].moveable;
|
||||||
}
|
}
|
||||||
bool isPickupable() const {
|
bool isPickupable() const {
|
||||||
return items[id].pickupable;
|
return items[id].pickupable;
|
||||||
}
|
}
|
||||||
bool isUseable() const {
|
|
||||||
return items[id].useable;
|
|
||||||
}
|
|
||||||
bool isHangable() const {
|
bool isHangable() const {
|
||||||
return items[id].isHangable;
|
return items[id].isHangable;
|
||||||
}
|
}
|
||||||
@@ -899,10 +694,33 @@ class Item : virtual public Thing
|
|||||||
const ItemType& it = items[id];
|
const ItemType& it = items[id];
|
||||||
return it.rotatable && it.rotateTo;
|
return it.rotatable && it.rotateTo;
|
||||||
}
|
}
|
||||||
bool hasWalkStack() const {
|
bool isDisguised() const {
|
||||||
return items[id].walkStack;
|
return items[id].disguise;
|
||||||
|
}
|
||||||
|
bool isChangeUse() const {
|
||||||
|
return items[id].changeUse;
|
||||||
|
}
|
||||||
|
bool isChestQuest() const {
|
||||||
|
return items[id].isChest();
|
||||||
|
}
|
||||||
|
bool hasCollisionEvent() const {
|
||||||
|
return items[id].collisionEvent;
|
||||||
|
}
|
||||||
|
bool hasSeparationEvent() const {
|
||||||
|
return items[id].separationEvent;
|
||||||
|
}
|
||||||
|
bool hasUseEvent() const {
|
||||||
|
return items[id].useEvent;
|
||||||
|
}
|
||||||
|
bool hasMultiUseEvent() const {
|
||||||
|
return items[id].multiUseEvent;
|
||||||
|
}
|
||||||
|
bool canDistUse() const {
|
||||||
|
return items[id].distUse;
|
||||||
|
}
|
||||||
|
bool isRune() const {
|
||||||
|
return items[id].isRune();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& getName() const {
|
const std::string& getName() const {
|
||||||
if (hasAttribute(ITEM_ATTRIBUTE_NAME)) {
|
if (hasAttribute(ITEM_ATTRIBUTE_NAME)) {
|
||||||
return getStrAttr(ITEM_ATTRIBUTE_NAME);
|
return getStrAttr(ITEM_ATTRIBUTE_NAME);
|
||||||
@@ -930,20 +748,12 @@ class Item : virtual public Thing
|
|||||||
count = n;
|
count = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t countByType(const Item* i, int32_t subType) {
|
static uint32_t countByType(const Item* i, int32_t subType);
|
||||||
if (subType == -1 || subType == i->getSubType()) {
|
|
||||||
return i->getItemCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDefaultSubtype();
|
void setDefaultSubtype();
|
||||||
uint16_t getSubType() const;
|
uint16_t getSubType() const;
|
||||||
void setSubType(uint16_t n);
|
void setSubType(uint16_t n);
|
||||||
|
|
||||||
void setUniqueId(uint16_t n);
|
|
||||||
|
|
||||||
void setDefaultDuration() {
|
void setDefaultDuration() {
|
||||||
uint32_t duration = getDefaultDuration();
|
uint32_t duration = getDefaultDuration();
|
||||||
if (duration != 0) {
|
if (duration != 0) {
|
||||||
@@ -966,18 +776,13 @@ class Item : virtual public Thing
|
|||||||
|
|
||||||
virtual void startDecaying();
|
virtual void startDecaying();
|
||||||
|
|
||||||
bool isLoadedFromMap() const {
|
|
||||||
return loadedFromMap;
|
|
||||||
}
|
|
||||||
void setLoadedFromMap(bool value) {
|
void setLoadedFromMap(bool value) {
|
||||||
loadedFromMap = value;
|
loadedFromMap = value;
|
||||||
}
|
}
|
||||||
bool isCleanable() const {
|
bool isCleanable() const {
|
||||||
return !loadedFromMap && canRemove() && isPickupable() && !hasAttribute(ITEM_ATTRIBUTE_UNIQUEID) && !hasAttribute(ITEM_ATTRIBUTE_ACTIONID);
|
return !loadedFromMap && canRemove() && isPickupable() && !hasAttribute(ITEM_ATTRIBUTE_ACTIONID);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasMarketAttributes() const;
|
|
||||||
|
|
||||||
std::unique_ptr<ItemAttributes>& getAttributes() {
|
std::unique_ptr<ItemAttributes>& getAttributes() {
|
||||||
if (!attributes) {
|
if (!attributes) {
|
||||||
attributes.reset(new ItemAttributes());
|
attributes.reset(new ItemAttributes());
|
||||||
@@ -994,32 +799,29 @@ class Item : virtual public Thing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Cylinder* getParent() const override {
|
Cylinder* getParent() const {
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
void setParent(Cylinder* cylinder) override {
|
void setParent(Cylinder* cylinder) {
|
||||||
parent = cylinder;
|
parent = cylinder;
|
||||||
}
|
}
|
||||||
Cylinder* getTopParent();
|
Cylinder* getTopParent();
|
||||||
const Cylinder* getTopParent() const;
|
const Cylinder* getTopParent() const;
|
||||||
Tile* getTile() override;
|
Tile* getTile();
|
||||||
const Tile* getTile() const override;
|
const Tile* getTile() const;
|
||||||
bool isRemoved() const override {
|
bool isRemoved() const {
|
||||||
return !parent || parent->isRemoved();
|
return !parent || parent->isRemoved();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Cylinder* parent = nullptr;
|
|
||||||
|
|
||||||
uint16_t id; // the same id as in ItemType
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string getWeightDescription(uint32_t weight) const;
|
std::string getWeightDescription(uint32_t weight) const;
|
||||||
|
|
||||||
|
Cylinder* parent = nullptr;
|
||||||
std::unique_ptr<ItemAttributes> attributes;
|
std::unique_ptr<ItemAttributes> attributes;
|
||||||
|
|
||||||
uint32_t referenceCounter = 0;
|
uint32_t referenceCounter = 0;
|
||||||
|
|
||||||
|
uint16_t id; // the same id as in ItemType
|
||||||
uint8_t count = 1; // number of stacked items
|
uint8_t count = 1; // number of stacked items
|
||||||
|
|
||||||
bool loadedFromMap = false;
|
bool loadedFromMap = false;
|
||||||
@@ -1027,7 +829,16 @@ class Item : virtual public Thing
|
|||||||
//Don't add variables here, use the ItemAttribute class.
|
//Don't add variables here, use the ItemAttribute class.
|
||||||
};
|
};
|
||||||
|
|
||||||
using ItemList = std::list<Item*>;
|
typedef std::list<Item*> ItemList;
|
||||||
using ItemDeque = std::deque<Item*>;
|
typedef std::deque<Item*> ItemDeque;
|
||||||
|
|
||||||
|
inline uint32_t Item::countByType(const Item* i, int32_t subType)
|
||||||
|
{
|
||||||
|
if (subType == -1 || subType == i->getSubType()) {
|
||||||
|
return i->getItemCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
198
src/itemloader.h
198
src/itemloader.h
@@ -1,198 +0,0 @@
|
|||||||
/**
|
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FS_ITEMLOADER_H_107F1D3EECC94CD0A0F528843010D5D4
|
|
||||||
#define FS_ITEMLOADER_H_107F1D3EECC94CD0A0F528843010D5D4
|
|
||||||
|
|
||||||
#include "fileloader.h"
|
|
||||||
|
|
||||||
enum itemgroup_t {
|
|
||||||
ITEM_GROUP_NONE,
|
|
||||||
|
|
||||||
ITEM_GROUP_GROUND,
|
|
||||||
ITEM_GROUP_CONTAINER,
|
|
||||||
ITEM_GROUP_WEAPON, //deprecated
|
|
||||||
ITEM_GROUP_AMMUNITION, //deprecated
|
|
||||||
ITEM_GROUP_ARMOR, //deprecated
|
|
||||||
ITEM_GROUP_CHARGES,
|
|
||||||
ITEM_GROUP_TELEPORT, //deprecated
|
|
||||||
ITEM_GROUP_MAGICFIELD, //deprecated
|
|
||||||
ITEM_GROUP_WRITEABLE, //deprecated
|
|
||||||
ITEM_GROUP_KEY, //deprecated
|
|
||||||
ITEM_GROUP_SPLASH,
|
|
||||||
ITEM_GROUP_FLUID,
|
|
||||||
ITEM_GROUP_DOOR, //deprecated
|
|
||||||
ITEM_GROUP_DEPRECATED,
|
|
||||||
|
|
||||||
ITEM_GROUP_LAST
|
|
||||||
};
|
|
||||||
|
|
||||||
/////////OTB specific//////////////
|
|
||||||
enum clientVersion_t {
|
|
||||||
CLIENT_VERSION_750 = 1,
|
|
||||||
CLIENT_VERSION_755 = 2,
|
|
||||||
CLIENT_VERSION_760 = 3,
|
|
||||||
CLIENT_VERSION_770 = 3,
|
|
||||||
CLIENT_VERSION_780 = 4,
|
|
||||||
CLIENT_VERSION_790 = 5,
|
|
||||||
CLIENT_VERSION_792 = 6,
|
|
||||||
CLIENT_VERSION_800 = 7,
|
|
||||||
CLIENT_VERSION_810 = 8,
|
|
||||||
CLIENT_VERSION_811 = 9,
|
|
||||||
CLIENT_VERSION_820 = 10,
|
|
||||||
CLIENT_VERSION_830 = 11,
|
|
||||||
CLIENT_VERSION_840 = 12,
|
|
||||||
CLIENT_VERSION_841 = 13,
|
|
||||||
CLIENT_VERSION_842 = 14,
|
|
||||||
CLIENT_VERSION_850 = 15,
|
|
||||||
CLIENT_VERSION_854_BAD = 16,
|
|
||||||
CLIENT_VERSION_854 = 17,
|
|
||||||
CLIENT_VERSION_855 = 18,
|
|
||||||
CLIENT_VERSION_860_OLD = 19,
|
|
||||||
CLIENT_VERSION_860 = 20,
|
|
||||||
CLIENT_VERSION_861 = 21,
|
|
||||||
CLIENT_VERSION_862 = 22,
|
|
||||||
CLIENT_VERSION_870 = 23,
|
|
||||||
CLIENT_VERSION_871 = 24,
|
|
||||||
CLIENT_VERSION_872 = 25,
|
|
||||||
CLIENT_VERSION_873 = 26,
|
|
||||||
CLIENT_VERSION_900 = 27,
|
|
||||||
CLIENT_VERSION_910 = 28,
|
|
||||||
CLIENT_VERSION_920 = 29,
|
|
||||||
CLIENT_VERSION_940 = 30,
|
|
||||||
CLIENT_VERSION_944_V1 = 31,
|
|
||||||
CLIENT_VERSION_944_V2 = 32,
|
|
||||||
CLIENT_VERSION_944_V3 = 33,
|
|
||||||
CLIENT_VERSION_944_V4 = 34,
|
|
||||||
CLIENT_VERSION_946 = 35,
|
|
||||||
CLIENT_VERSION_950 = 36,
|
|
||||||
CLIENT_VERSION_952 = 37,
|
|
||||||
CLIENT_VERSION_953 = 38,
|
|
||||||
CLIENT_VERSION_954 = 39,
|
|
||||||
CLIENT_VERSION_960 = 40,
|
|
||||||
CLIENT_VERSION_961 = 41,
|
|
||||||
CLIENT_VERSION_963 = 42,
|
|
||||||
CLIENT_VERSION_970 = 43,
|
|
||||||
CLIENT_VERSION_980 = 44,
|
|
||||||
CLIENT_VERSION_981 = 45,
|
|
||||||
CLIENT_VERSION_982 = 46,
|
|
||||||
CLIENT_VERSION_983 = 47,
|
|
||||||
CLIENT_VERSION_985 = 48,
|
|
||||||
CLIENT_VERSION_986 = 49,
|
|
||||||
CLIENT_VERSION_1010 = 50,
|
|
||||||
CLIENT_VERSION_1020 = 51,
|
|
||||||
CLIENT_VERSION_1021 = 52,
|
|
||||||
CLIENT_VERSION_1030 = 53,
|
|
||||||
CLIENT_VERSION_1031 = 54,
|
|
||||||
CLIENT_VERSION_1035 = 55,
|
|
||||||
CLIENT_VERSION_1076 = 56,
|
|
||||||
CLIENT_VERSION_1098 = 57,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum rootattrib_ {
|
|
||||||
ROOT_ATTR_VERSION = 0x01,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum itemattrib_t {
|
|
||||||
ITEM_ATTR_FIRST = 0x10,
|
|
||||||
ITEM_ATTR_SERVERID = ITEM_ATTR_FIRST,
|
|
||||||
ITEM_ATTR_CLIENTID,
|
|
||||||
ITEM_ATTR_NAME,
|
|
||||||
ITEM_ATTR_DESCR,
|
|
||||||
ITEM_ATTR_SPEED,
|
|
||||||
ITEM_ATTR_SLOT,
|
|
||||||
ITEM_ATTR_MAXITEMS,
|
|
||||||
ITEM_ATTR_WEIGHT,
|
|
||||||
ITEM_ATTR_WEAPON,
|
|
||||||
ITEM_ATTR_AMU,
|
|
||||||
ITEM_ATTR_ARMOR,
|
|
||||||
ITEM_ATTR_MAGLEVEL,
|
|
||||||
ITEM_ATTR_MAGFIELDTYPE,
|
|
||||||
ITEM_ATTR_WRITEABLE,
|
|
||||||
ITEM_ATTR_ROTATETO,
|
|
||||||
ITEM_ATTR_DECAY,
|
|
||||||
ITEM_ATTR_SPRITEHASH,
|
|
||||||
ITEM_ATTR_MINIMAPCOLOR,
|
|
||||||
ITEM_ATTR_07,
|
|
||||||
ITEM_ATTR_08,
|
|
||||||
ITEM_ATTR_LIGHT,
|
|
||||||
|
|
||||||
//1-byte aligned
|
|
||||||
ITEM_ATTR_DECAY2, //deprecated
|
|
||||||
ITEM_ATTR_WEAPON2, //deprecated
|
|
||||||
ITEM_ATTR_AMU2, //deprecated
|
|
||||||
ITEM_ATTR_ARMOR2, //deprecated
|
|
||||||
ITEM_ATTR_WRITEABLE2, //deprecated
|
|
||||||
ITEM_ATTR_LIGHT2,
|
|
||||||
ITEM_ATTR_TOPORDER,
|
|
||||||
ITEM_ATTR_WRITEABLE3, //deprecated
|
|
||||||
|
|
||||||
ITEM_ATTR_WAREID,
|
|
||||||
|
|
||||||
ITEM_ATTR_LAST
|
|
||||||
};
|
|
||||||
|
|
||||||
enum itemflags_t {
|
|
||||||
FLAG_BLOCK_SOLID = 1 << 0,
|
|
||||||
FLAG_BLOCK_PROJECTILE = 1 << 1,
|
|
||||||
FLAG_BLOCK_PATHFIND = 1 << 2,
|
|
||||||
FLAG_HAS_HEIGHT = 1 << 3,
|
|
||||||
FLAG_USEABLE = 1 << 4,
|
|
||||||
FLAG_PICKUPABLE = 1 << 5,
|
|
||||||
FLAG_MOVEABLE = 1 << 6,
|
|
||||||
FLAG_STACKABLE = 1 << 7,
|
|
||||||
FLAG_FLOORCHANGEDOWN = 1 << 8, // unused
|
|
||||||
FLAG_FLOORCHANGENORTH = 1 << 9, // unused
|
|
||||||
FLAG_FLOORCHANGEEAST = 1 << 10, // unused
|
|
||||||
FLAG_FLOORCHANGESOUTH = 1 << 11, // unused
|
|
||||||
FLAG_FLOORCHANGEWEST = 1 << 12, // unused
|
|
||||||
FLAG_ALWAYSONTOP = 1 << 13,
|
|
||||||
FLAG_READABLE = 1 << 14,
|
|
||||||
FLAG_ROTATABLE = 1 << 15,
|
|
||||||
FLAG_HANGABLE = 1 << 16,
|
|
||||||
FLAG_VERTICAL = 1 << 17,
|
|
||||||
FLAG_HORIZONTAL = 1 << 18,
|
|
||||||
FLAG_CANNOTDECAY = 1 << 19, // unused
|
|
||||||
FLAG_ALLOWDISTREAD = 1 << 20,
|
|
||||||
FLAG_UNUSED = 1 << 21, // unused
|
|
||||||
FLAG_CLIENTCHARGES = 1 << 22, /* deprecated */
|
|
||||||
FLAG_LOOKTHROUGH = 1 << 23,
|
|
||||||
FLAG_ANIMATION = 1 << 24,
|
|
||||||
FLAG_FULLTILE = 1 << 25, // unused
|
|
||||||
FLAG_FORCEUSE = 1 << 26,
|
|
||||||
};
|
|
||||||
|
|
||||||
//1-byte aligned structs
|
|
||||||
#pragma pack(1)
|
|
||||||
|
|
||||||
struct VERSIONINFO {
|
|
||||||
uint32_t dwMajorVersion;
|
|
||||||
uint32_t dwMinorVersion;
|
|
||||||
uint32_t dwBuildNumber;
|
|
||||||
uint8_t CSDVersion[128];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lightBlock2 {
|
|
||||||
uint16_t lightLevel;
|
|
||||||
uint16_t lightColor;
|
|
||||||
};
|
|
||||||
|
|
||||||
#pragma pack()
|
|
||||||
/////////OTB specific//////////////
|
|
||||||
#endif
|
|
||||||
1742
src/items.cpp
1742
src/items.cpp
File diff suppressed because it is too large
Load Diff
218
src/items.h
218
src/items.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
#include "const.h"
|
#include "const.h"
|
||||||
#include "enums.h"
|
#include "enums.h"
|
||||||
#include "itemloader.h"
|
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
|
#include "fileloader.h"
|
||||||
|
|
||||||
enum SlotPositionBits : uint32_t {
|
enum SlotPositionBits : uint32_t {
|
||||||
SLOTP_WHEREEVER = 0xFFFFFFFF,
|
SLOTP_WHEREEVER = 0xFFFFFFFF,
|
||||||
@@ -46,7 +46,6 @@ enum ItemTypes_t {
|
|||||||
ITEM_TYPE_NONE,
|
ITEM_TYPE_NONE,
|
||||||
ITEM_TYPE_DEPOT,
|
ITEM_TYPE_DEPOT,
|
||||||
ITEM_TYPE_MAILBOX,
|
ITEM_TYPE_MAILBOX,
|
||||||
ITEM_TYPE_TRASHHOLDER,
|
|
||||||
ITEM_TYPE_CONTAINER,
|
ITEM_TYPE_CONTAINER,
|
||||||
ITEM_TYPE_DOOR,
|
ITEM_TYPE_DOOR,
|
||||||
ITEM_TYPE_MAGICFIELD,
|
ITEM_TYPE_MAGICFIELD,
|
||||||
@@ -54,117 +53,28 @@ enum ItemTypes_t {
|
|||||||
ITEM_TYPE_BED,
|
ITEM_TYPE_BED,
|
||||||
ITEM_TYPE_KEY,
|
ITEM_TYPE_KEY,
|
||||||
ITEM_TYPE_RUNE,
|
ITEM_TYPE_RUNE,
|
||||||
|
ITEM_TYPE_CHEST,
|
||||||
ITEM_TYPE_LAST
|
ITEM_TYPE_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ItemParseAttributes_t {
|
enum itemgroup_t {
|
||||||
ITEM_PARSE_TYPE,
|
ITEM_GROUP_NONE,
|
||||||
ITEM_PARSE_DESCRIPTION,
|
|
||||||
ITEM_PARSE_RUNESPELLNAME,
|
ITEM_GROUP_GROUND,
|
||||||
ITEM_PARSE_WEIGHT,
|
ITEM_GROUP_WEAPON,
|
||||||
ITEM_PARSE_SHOWCOUNT,
|
ITEM_GROUP_AMMUNITION,
|
||||||
ITEM_PARSE_ARMOR,
|
ITEM_GROUP_ARMOR,
|
||||||
ITEM_PARSE_DEFENSE,
|
ITEM_GROUP_CHARGES,
|
||||||
ITEM_PARSE_EXTRADEF,
|
ITEM_GROUP_TELEPORT,
|
||||||
ITEM_PARSE_ATTACK,
|
ITEM_GROUP_MAGICFIELD,
|
||||||
ITEM_PARSE_ROTATETO,
|
ITEM_GROUP_WRITEABLE,
|
||||||
ITEM_PARSE_MOVEABLE,
|
ITEM_GROUP_KEY,
|
||||||
ITEM_PARSE_BLOCKPROJECTILE,
|
ITEM_GROUP_SPLASH,
|
||||||
ITEM_PARSE_PICKUPABLE,
|
ITEM_GROUP_FLUID,
|
||||||
ITEM_PARSE_FORCESERIALIZE,
|
ITEM_GROUP_DOOR,
|
||||||
ITEM_PARSE_FLOORCHANGE,
|
ITEM_GROUP_DEPRECATED,
|
||||||
ITEM_PARSE_CORPSETYPE,
|
|
||||||
ITEM_PARSE_CONTAINERSIZE,
|
ITEM_GROUP_LAST
|
||||||
ITEM_PARSE_FLUIDSOURCE,
|
|
||||||
ITEM_PARSE_READABLE,
|
|
||||||
ITEM_PARSE_WRITEABLE,
|
|
||||||
ITEM_PARSE_MAXTEXTLEN,
|
|
||||||
ITEM_PARSE_WRITEONCEITEMID,
|
|
||||||
ITEM_PARSE_WEAPONTYPE,
|
|
||||||
ITEM_PARSE_SLOTTYPE,
|
|
||||||
ITEM_PARSE_AMMOTYPE,
|
|
||||||
ITEM_PARSE_SHOOTTYPE,
|
|
||||||
ITEM_PARSE_EFFECT,
|
|
||||||
ITEM_PARSE_RANGE,
|
|
||||||
ITEM_PARSE_STOPDURATION,
|
|
||||||
ITEM_PARSE_DECAYTO,
|
|
||||||
ITEM_PARSE_TRANSFORMEQUIPTO,
|
|
||||||
ITEM_PARSE_TRANSFORMDEEQUIPTO,
|
|
||||||
ITEM_PARSE_DURATION,
|
|
||||||
ITEM_PARSE_SHOWDURATION,
|
|
||||||
ITEM_PARSE_CHARGES,
|
|
||||||
ITEM_PARSE_SHOWCHARGES,
|
|
||||||
ITEM_PARSE_SHOWATTRIBUTES,
|
|
||||||
ITEM_PARSE_HITCHANCE,
|
|
||||||
ITEM_PARSE_MAXHITCHANCE,
|
|
||||||
ITEM_PARSE_INVISIBLE,
|
|
||||||
ITEM_PARSE_SPEED,
|
|
||||||
ITEM_PARSE_HEALTHGAIN,
|
|
||||||
ITEM_PARSE_HEALTHTICKS,
|
|
||||||
ITEM_PARSE_MANAGAIN,
|
|
||||||
ITEM_PARSE_MANATICKS,
|
|
||||||
ITEM_PARSE_MANASHIELD,
|
|
||||||
ITEM_PARSE_SKILLSWORD,
|
|
||||||
ITEM_PARSE_SKILLAXE,
|
|
||||||
ITEM_PARSE_SKILLCLUB,
|
|
||||||
ITEM_PARSE_SKILLDIST,
|
|
||||||
ITEM_PARSE_SKILLFISH,
|
|
||||||
ITEM_PARSE_SKILLSHIELD,
|
|
||||||
ITEM_PARSE_SKILLFIST,
|
|
||||||
ITEM_PARSE_MAXHITPOINTS,
|
|
||||||
ITEM_PARSE_MAXHITPOINTSPERCENT,
|
|
||||||
ITEM_PARSE_MAXMANAPOINTS,
|
|
||||||
ITEM_PARSE_MAXMANAPOINTSPERCENT,
|
|
||||||
ITEM_PARSE_MAGICPOINTS,
|
|
||||||
ITEM_PARSE_MAGICPOINTSPERCENT,
|
|
||||||
ITEM_PARSE_CRITICALHITCHANCE,
|
|
||||||
ITEM_PARSE_CRITICALHITAMOUNT,
|
|
||||||
ITEM_PARSE_LIFELEECHCHANCE,
|
|
||||||
ITEM_PARSE_LIFELEECHAMOUNT,
|
|
||||||
ITEM_PARSE_MANALEECHCHANCE,
|
|
||||||
ITEM_PARSE_MANALEECHAMOUNT,
|
|
||||||
ITEM_PARSE_FIELDABSORBPERCENTENERGY,
|
|
||||||
ITEM_PARSE_FIELDABSORBPERCENTFIRE,
|
|
||||||
ITEM_PARSE_FIELDABSORBPERCENTPOISON,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTALL,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTELEMENTS,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTMAGIC,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTENERGY,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTFIRE,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTPOISON,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTICE,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTHOLY,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTDEATH,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTLIFEDRAIN,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTMANADRAIN,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTDROWN,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTPHYSICAL,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTHEALING,
|
|
||||||
ITEM_PARSE_ABSORBPERCENTUNDEFINED,
|
|
||||||
ITEM_PARSE_SUPPRESSDRUNK,
|
|
||||||
ITEM_PARSE_SUPPRESSENERGY,
|
|
||||||
ITEM_PARSE_SUPPRESSFIRE,
|
|
||||||
ITEM_PARSE_SUPPRESSPOISON,
|
|
||||||
ITEM_PARSE_SUPPRESSDROWN,
|
|
||||||
ITEM_PARSE_SUPPRESSPHYSICAL,
|
|
||||||
ITEM_PARSE_SUPPRESSFREEZE,
|
|
||||||
ITEM_PARSE_SUPPRESSDAZZLE,
|
|
||||||
ITEM_PARSE_SUPPRESSCURSE,
|
|
||||||
ITEM_PARSE_FIELD,
|
|
||||||
ITEM_PARSE_REPLACEABLE,
|
|
||||||
ITEM_PARSE_PARTNERDIRECTION,
|
|
||||||
ITEM_PARSE_LEVELDOOR,
|
|
||||||
ITEM_PARSE_MALETRANSFORMTO,
|
|
||||||
ITEM_PARSE_FEMALETRANSFORMTO,
|
|
||||||
ITEM_PARSE_TRANSFORMTO,
|
|
||||||
ITEM_PARSE_DESTROYTO,
|
|
||||||
ITEM_PARSE_ELEMENTICE,
|
|
||||||
ITEM_PARSE_ELEMENTEARTH,
|
|
||||||
ITEM_PARSE_ELEMENTFIRE,
|
|
||||||
ITEM_PARSE_ELEMENTENERGY,
|
|
||||||
ITEM_PARSE_WALKSTACK,
|
|
||||||
ITEM_PARSE_BLOCKING,
|
|
||||||
ITEM_PARSE_ALLOWDISTREAD,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Abilities {
|
struct Abilities {
|
||||||
@@ -182,7 +92,6 @@ struct Abilities {
|
|||||||
|
|
||||||
//extra skill modifiers
|
//extra skill modifiers
|
||||||
int32_t skills[SKILL_LAST + 1] = { 0 };
|
int32_t skills[SKILL_LAST + 1] = { 0 };
|
||||||
int32_t specialSkills[SPECIALSKILL_LAST + 1] = { 0 };
|
|
||||||
|
|
||||||
int32_t speed = 0;
|
int32_t speed = 0;
|
||||||
|
|
||||||
@@ -192,10 +101,6 @@ struct Abilities {
|
|||||||
//damage abilities modifiers
|
//damage abilities modifiers
|
||||||
int16_t absorbPercent[COMBAT_COUNT] = { 0 };
|
int16_t absorbPercent[COMBAT_COUNT] = { 0 };
|
||||||
|
|
||||||
//elemental damage
|
|
||||||
uint16_t elementDamage = 0;
|
|
||||||
CombatType_t elementType = COMBAT_NONE;
|
|
||||||
|
|
||||||
bool manaShield = false;
|
bool manaShield = false;
|
||||||
bool invisible = false;
|
bool invisible = false;
|
||||||
bool regeneration = false;
|
bool regeneration = false;
|
||||||
@@ -219,7 +124,10 @@ class ItemType
|
|||||||
return group == ITEM_GROUP_GROUND;
|
return group == ITEM_GROUP_GROUND;
|
||||||
}
|
}
|
||||||
bool isContainer() const {
|
bool isContainer() const {
|
||||||
return group == ITEM_GROUP_CONTAINER;
|
return type == ITEM_TYPE_CONTAINER;
|
||||||
|
}
|
||||||
|
bool isChest() const {
|
||||||
|
return type == ITEM_TYPE_CHEST;
|
||||||
}
|
}
|
||||||
bool isSplash() const {
|
bool isSplash() const {
|
||||||
return group == ITEM_GROUP_SPLASH;
|
return group == ITEM_GROUP_SPLASH;
|
||||||
@@ -246,20 +154,11 @@ class ItemType
|
|||||||
bool isMailbox() const {
|
bool isMailbox() const {
|
||||||
return (type == ITEM_TYPE_MAILBOX);
|
return (type == ITEM_TYPE_MAILBOX);
|
||||||
}
|
}
|
||||||
bool isTrashHolder() const {
|
|
||||||
return (type == ITEM_TYPE_TRASHHOLDER);
|
|
||||||
}
|
|
||||||
bool isBed() const {
|
bool isBed() const {
|
||||||
return (type == ITEM_TYPE_BED);
|
return (type == ITEM_TYPE_BED);
|
||||||
}
|
}
|
||||||
bool isRune() const {
|
bool isRune() const {
|
||||||
return (type == ITEM_TYPE_RUNE);
|
return type == ITEM_TYPE_RUNE;
|
||||||
}
|
|
||||||
bool isPickupable() const {
|
|
||||||
return (allowPickupable || pickupable);
|
|
||||||
}
|
|
||||||
bool isUseable() const {
|
|
||||||
return (useable);
|
|
||||||
}
|
}
|
||||||
bool hasSubType() const {
|
bool hasSubType() const {
|
||||||
return (isFluidContainer() || isSplash() || stackable || charges != 0);
|
return (isFluidContainer() || isSplash() || stackable || charges != 0);
|
||||||
@@ -291,9 +190,7 @@ class ItemType
|
|||||||
itemgroup_t group = ITEM_GROUP_NONE;
|
itemgroup_t group = ITEM_GROUP_NONE;
|
||||||
ItemTypes_t type = ITEM_TYPE_NONE;
|
ItemTypes_t type = ITEM_TYPE_NONE;
|
||||||
uint16_t id = 0;
|
uint16_t id = 0;
|
||||||
uint16_t clientId = 0;
|
|
||||||
bool stackable = false;
|
bool stackable = false;
|
||||||
bool isAnimation = false;
|
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string article;
|
std::string article;
|
||||||
@@ -306,35 +203,40 @@ class ItemType
|
|||||||
std::unique_ptr<ConditionDamage> conditionDamage;
|
std::unique_ptr<ConditionDamage> conditionDamage;
|
||||||
|
|
||||||
uint32_t weight = 0;
|
uint32_t weight = 0;
|
||||||
uint32_t levelDoor = 0;
|
|
||||||
uint32_t decayTime = 0;
|
uint32_t decayTime = 0;
|
||||||
uint32_t wieldInfo = 0;
|
uint32_t wieldInfo = 0;
|
||||||
uint32_t minReqLevel = 0;
|
uint32_t minReqLevel = 0;
|
||||||
uint32_t minReqMagicLevel = 0;
|
uint32_t minReqMagicLevel = 0;
|
||||||
uint32_t charges = 0;
|
uint32_t charges = 0;
|
||||||
int32_t maxHitChance = -1;
|
int32_t attackStrength = 0;
|
||||||
|
int32_t attackVariation = 0;
|
||||||
|
int32_t manaConsumption = 0;
|
||||||
|
int32_t vocations = 0;
|
||||||
int32_t decayTo = -1;
|
int32_t decayTo = -1;
|
||||||
int32_t attack = 0;
|
int32_t attack = 0;
|
||||||
int32_t defense = 0;
|
int32_t defense = 0;
|
||||||
int32_t extraDefense = 0;
|
int32_t extraDefense = 0;
|
||||||
int32_t armor = 0;
|
int32_t armor = 0;
|
||||||
uint16_t rotateTo = 0;
|
int32_t rotateTo = 0;
|
||||||
int32_t runeMagLevel = 0;
|
int32_t runeMagLevel = 0;
|
||||||
int32_t runeLevel = 0;
|
int32_t runeLevel = 0;
|
||||||
|
int32_t nutrition = 0;
|
||||||
|
int32_t destroyTarget = 0;
|
||||||
|
|
||||||
CombatType_t combatType = COMBAT_NONE;
|
CombatType_t combatType = COMBAT_NONE;
|
||||||
|
CombatType_t damageType = COMBAT_NONE;
|
||||||
|
|
||||||
uint16_t transformToOnUse[2] = {0, 0};
|
uint16_t transformToOnUse = 0;
|
||||||
uint16_t transformToFree = 0;
|
uint16_t transformToFree = 0;
|
||||||
|
uint16_t disguiseId = 0;
|
||||||
uint16_t destroyTo = 0;
|
uint16_t destroyTo = 0;
|
||||||
uint16_t maxTextLen = 0;
|
uint16_t maxTextLen = 0;
|
||||||
uint16_t writeOnceItemId = 0;
|
uint16_t writeOnceItemId = 0;
|
||||||
uint16_t transformEquipTo = 0;
|
uint16_t transformEquipTo = 0;
|
||||||
uint16_t transformDeEquipTo = 0;
|
uint16_t transformDeEquipTo = 0;
|
||||||
uint16_t maxItems = 8;
|
uint16_t maxItems = 8;
|
||||||
uint16_t slotPosition = SLOTP_HAND;
|
uint16_t slotPosition = SLOTP_RIGHT | SLOTP_LEFT | SLOTP_AMMO;
|
||||||
uint16_t speed = 0;
|
uint16_t speed = 0;
|
||||||
uint16_t wareId = 0;
|
|
||||||
|
|
||||||
MagicEffectClasses magicEffect = CONST_ME_NONE;
|
MagicEffectClasses magicEffect = CONST_ME_NONE;
|
||||||
Direction bedPartnerDir = DIRECTION_NONE;
|
Direction bedPartnerDir = DIRECTION_NONE;
|
||||||
@@ -344,22 +246,30 @@ class ItemType
|
|||||||
RaceType_t corpseType = RACE_NONE;
|
RaceType_t corpseType = RACE_NONE;
|
||||||
FluidTypes_t fluidSource = FLUID_NONE;
|
FluidTypes_t fluidSource = FLUID_NONE;
|
||||||
|
|
||||||
uint8_t floorChange = 0;
|
uint8_t fragility = 0;
|
||||||
uint8_t alwaysOnTopOrder = 0;
|
uint8_t alwaysOnTopOrder = 0;
|
||||||
uint8_t lightLevel = 0;
|
uint8_t lightLevel = 0;
|
||||||
uint8_t lightColor = 0;
|
uint8_t lightColor = 0;
|
||||||
uint8_t shootRange = 1;
|
uint8_t shootRange = 1;
|
||||||
int8_t hitChance = 0;
|
uint8_t weaponSpecialEffect = 0;
|
||||||
|
|
||||||
|
bool collisionEvent = false;
|
||||||
|
bool separationEvent = false;
|
||||||
|
bool useEvent = false;
|
||||||
|
bool multiUseEvent = false;
|
||||||
|
bool distUse = false;
|
||||||
|
bool disguise = false;
|
||||||
bool forceUse = false;
|
bool forceUse = false;
|
||||||
bool forceSerialize = false;
|
bool changeUse = false;
|
||||||
|
bool destroy = false;
|
||||||
|
bool corpse = false;
|
||||||
bool hasHeight = false;
|
bool hasHeight = false;
|
||||||
bool walkStack = true;
|
bool walkStack = true;
|
||||||
bool blockSolid = false;
|
bool blockSolid = false;
|
||||||
bool blockPickupable = false;
|
bool blockPickupable = false;
|
||||||
bool blockProjectile = false;
|
bool blockProjectile = false;
|
||||||
bool blockPathFind = false;
|
bool blockPathFind = false;
|
||||||
bool allowPickupable = false;
|
bool allowPickupable = true;
|
||||||
bool showDuration = false;
|
bool showDuration = false;
|
||||||
bool showCharges = false;
|
bool showCharges = false;
|
||||||
bool showAttributes = false;
|
bool showAttributes = false;
|
||||||
@@ -367,7 +277,7 @@ class ItemType
|
|||||||
bool pickupable = false;
|
bool pickupable = false;
|
||||||
bool rotatable = false;
|
bool rotatable = false;
|
||||||
bool useable = false;
|
bool useable = false;
|
||||||
bool moveable = false;
|
bool moveable = true;
|
||||||
bool alwaysOnTop = false;
|
bool alwaysOnTop = false;
|
||||||
bool canReadText = false;
|
bool canReadText = false;
|
||||||
bool canWriteText = false;
|
bool canWriteText = false;
|
||||||
@@ -383,8 +293,7 @@ class ItemType
|
|||||||
class Items
|
class Items
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using NameMap = std::unordered_multimap<std::string, uint16_t>;
|
using nameMap = std::unordered_multimap<std::string, uint16_t>;
|
||||||
using InventoryVector = std::vector<uint16_t>;
|
|
||||||
|
|
||||||
Items();
|
Items();
|
||||||
|
|
||||||
@@ -395,38 +304,23 @@ class Items
|
|||||||
bool reload();
|
bool reload();
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
bool loadFromOtb(const std::string& file);
|
|
||||||
|
|
||||||
const ItemType& operator[](size_t id) const {
|
const ItemType& operator[](size_t id) const {
|
||||||
return getItemType(id);
|
return getItemType(id);
|
||||||
}
|
}
|
||||||
const ItemType& getItemType(size_t id) const;
|
const ItemType& getItemType(size_t id) const;
|
||||||
ItemType& getItemType(size_t id);
|
ItemType& getItemType(size_t id);
|
||||||
const ItemType& getItemIdByClientId(uint16_t spriteId) const;
|
|
||||||
|
|
||||||
uint16_t getItemIdByName(const std::string& name);
|
uint16_t getItemIdByName(const std::string& name);
|
||||||
|
|
||||||
uint32_t majorVersion = 0;
|
bool loadItems();
|
||||||
uint32_t minorVersion = 0;
|
|
||||||
uint32_t buildNumber = 0;
|
|
||||||
|
|
||||||
bool loadFromXml();
|
inline size_t size() const {
|
||||||
void parseItemNode(const pugi::xml_node& itemNode, uint16_t id);
|
|
||||||
|
|
||||||
void buildInventoryList();
|
|
||||||
const InventoryVector& getInventory() const {
|
|
||||||
return inventory;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() const {
|
|
||||||
return items.size();
|
return items.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
NameMap nameToItems;
|
nameMap nameToItems;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
std::map<uint16_t, uint16_t> reverseItemMap;
|
|
||||||
std::vector<ItemType> items;
|
std::vector<ItemType> items;
|
||||||
InventoryVector inventory;
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,52 +26,37 @@
|
|||||||
|
|
||||||
#include <boost/lockfree/stack.hpp>
|
#include <boost/lockfree/stack.hpp>
|
||||||
|
|
||||||
/*
|
|
||||||
* we use this to avoid instantiating multiple free lists for objects of the
|
|
||||||
* same size and it can be replaced by a variable template in C++14
|
|
||||||
*
|
|
||||||
* template <std::size_t TSize, size_t CAPACITY>
|
|
||||||
* boost::lockfree::stack<void*, boost::lockfree::capacity<CAPACITY> lockfreeFreeList;
|
|
||||||
*/
|
|
||||||
template <std::size_t TSize, size_t CAPACITY>
|
|
||||||
struct LockfreeFreeList
|
|
||||||
{
|
|
||||||
using FreeList = boost::lockfree::stack<void*, boost::lockfree::capacity<CAPACITY>>;
|
|
||||||
static FreeList& get()
|
|
||||||
{
|
|
||||||
static FreeList freeList;
|
|
||||||
return freeList;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, size_t CAPACITY>
|
template <typename T, size_t CAPACITY>
|
||||||
class LockfreePoolingAllocator : public std::allocator<T>
|
class LockfreePoolingAllocator : public std::allocator<T>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LockfreePoolingAllocator() = default;
|
template <typename U>
|
||||||
|
|
||||||
template <typename U, class = typename std::enable_if<!std::is_same<U, T>::value>::type>
|
|
||||||
explicit constexpr LockfreePoolingAllocator(const U&) {}
|
explicit constexpr LockfreePoolingAllocator(const U&) {}
|
||||||
using value_type = T;
|
typedef T value_type;
|
||||||
|
|
||||||
T* allocate(size_t) const {
|
T* allocate(size_t) const {
|
||||||
auto& inst = LockfreeFreeList<sizeof(T), CAPACITY>::get();
|
T* p; // NOTE: p doesn't have to be initialized
|
||||||
void* p; // NOTE: p doesn't have to be initialized
|
if (!getFreeList().pop(p)) {
|
||||||
if (!inst.pop(p)) {
|
|
||||||
//Acquire memory without calling the constructor of T
|
//Acquire memory without calling the constructor of T
|
||||||
p = operator new (sizeof(T));
|
p = static_cast<T*>(operator new (sizeof(T)));
|
||||||
}
|
}
|
||||||
return static_cast<T*>(p);
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void deallocate(T* p, size_t) const {
|
void deallocate(T* p, size_t) const {
|
||||||
auto& inst = LockfreeFreeList<sizeof(T), CAPACITY>::get();
|
if (!getFreeList().bounded_push(p)) {
|
||||||
if (!inst.bounded_push(p)) {
|
|
||||||
//Release memory without calling the destructor of T
|
//Release memory without calling the destructor of T
|
||||||
//(it has already been called at this point)
|
//(it has already been called at this point)
|
||||||
operator delete(p);
|
operator delete(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef boost::lockfree::stack<T*, boost::lockfree::capacity<CAPACITY>> FreeList;
|
||||||
|
static FreeList& getFreeList() {
|
||||||
|
static FreeList freeList;
|
||||||
|
return freeList;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
6283
src/luascript.cpp
6283
src/luascript.cpp
File diff suppressed because it is too large
Load Diff
450
src/luascript.h
450
src/luascript.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -20,11 +20,7 @@
|
|||||||
#ifndef FS_LUASCRIPT_H_5344B2BC907E46E3943EA78574A212D8
|
#ifndef FS_LUASCRIPT_H_5344B2BC907E46E3943EA78574A212D8
|
||||||
#define FS_LUASCRIPT_H_5344B2BC907E46E3943EA78574A212D8
|
#define FS_LUASCRIPT_H_5344B2BC907E46E3943EA78574A212D8
|
||||||
|
|
||||||
#if __has_include("luajit/lua.hpp")
|
|
||||||
#include <luajit/lua.hpp>
|
#include <luajit/lua.hpp>
|
||||||
#else
|
|
||||||
#include <lua.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if LUA_VERSION_NUM >= 502
|
#if LUA_VERSION_NUM >= 502
|
||||||
#ifndef LUA_COMPAT_ALL
|
#ifndef LUA_COMPAT_ALL
|
||||||
@@ -39,7 +35,6 @@
|
|||||||
#include "database.h"
|
#include "database.h"
|
||||||
#include "enums.h"
|
#include "enums.h"
|
||||||
#include "position.h"
|
#include "position.h"
|
||||||
#include <boost/lexical_cast.hpp>
|
|
||||||
|
|
||||||
class Thing;
|
class Thing;
|
||||||
class Creature;
|
class Creature;
|
||||||
@@ -51,7 +46,6 @@ class Combat;
|
|||||||
class Condition;
|
class Condition;
|
||||||
class Npc;
|
class Npc;
|
||||||
class Monster;
|
class Monster;
|
||||||
class InstantSpell;
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
EVENT_ID_LOADING = 1,
|
EVENT_ID_LOADING = 1,
|
||||||
@@ -99,8 +93,7 @@ struct LuaTimerEventDesc {
|
|||||||
class LuaScriptInterface;
|
class LuaScriptInterface;
|
||||||
class Cylinder;
|
class Cylinder;
|
||||||
class Game;
|
class Game;
|
||||||
|
class Npc;
|
||||||
struct LootBlock;
|
|
||||||
|
|
||||||
class ScriptEnvironment
|
class ScriptEnvironment
|
||||||
{
|
{
|
||||||
@@ -155,9 +148,9 @@ class ScriptEnvironment
|
|||||||
void removeItemByUID(uint32_t uid);
|
void removeItemByUID(uint32_t uid);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using VariantVector = std::vector<const LuaVariant*>;
|
typedef std::vector<const LuaVariant*> VariantVector;
|
||||||
using StorageMap = std::map<uint32_t, int32_t>;
|
typedef std::map<uint32_t, int32_t> StorageMap;
|
||||||
using DBResultMap = std::map<uint32_t, DBResult_ptr>;
|
typedef std::map<uint32_t, DBResult_ptr> DBResultMap;
|
||||||
|
|
||||||
LuaScriptInterface* interface;
|
LuaScriptInterface* interface;
|
||||||
|
|
||||||
@@ -216,7 +209,6 @@ class LuaScriptInterface
|
|||||||
|
|
||||||
const std::string& getFileById(int32_t scriptId);
|
const std::string& getFileById(int32_t scriptId);
|
||||||
int32_t getEvent(const std::string& eventName);
|
int32_t getEvent(const std::string& eventName);
|
||||||
int32_t getEvent();
|
|
||||||
int32_t getMetaEvent(const std::string& globalName, const std::string& eventName);
|
int32_t getMetaEvent(const std::string& globalName, const std::string& eventName);
|
||||||
|
|
||||||
static ScriptEnvironment* getScriptEnv() {
|
static ScriptEnvironment* getScriptEnv() {
|
||||||
@@ -279,13 +271,13 @@ class LuaScriptInterface
|
|||||||
|
|
||||||
// Get
|
// Get
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static typename std::enable_if<std::is_enum<T>::value, T>::type
|
inline static typename std::enable_if<std::is_enum<T>::value, T>::type
|
||||||
getNumber(lua_State* L, int32_t arg)
|
getNumber(lua_State* L, int32_t arg)
|
||||||
{
|
{
|
||||||
return static_cast<T>(static_cast<int64_t>(lua_tonumber(L, arg)));
|
return static_cast<T>(static_cast<int64_t>(lua_tonumber(L, arg)));
|
||||||
}
|
}
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static typename std::enable_if<std::is_integral<T>::value || std::is_floating_point<T>::value, T>::type
|
inline static typename std::enable_if<std::is_integral<T>::value || std::is_floating_point<T>::value, T>::type
|
||||||
getNumber(lua_State* L, int32_t arg)
|
getNumber(lua_State* L, int32_t arg)
|
||||||
{
|
{
|
||||||
return static_cast<T>(lua_tonumber(L, arg));
|
return static_cast<T>(lua_tonumber(L, arg));
|
||||||
@@ -309,16 +301,16 @@ class LuaScriptInterface
|
|||||||
return *userdata;
|
return *userdata;
|
||||||
}
|
}
|
||||||
template<class T>
|
template<class T>
|
||||||
static T** getRawUserdata(lua_State* L, int32_t arg)
|
inline static T** getRawUserdata(lua_State* L, int32_t arg)
|
||||||
{
|
{
|
||||||
return static_cast<T**>(lua_touserdata(L, arg));
|
return static_cast<T**>(lua_touserdata(L, arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool getBoolean(lua_State* L, int32_t arg)
|
inline static bool getBoolean(lua_State* L, int32_t arg)
|
||||||
{
|
{
|
||||||
return lua_toboolean(L, arg) != 0;
|
return lua_toboolean(L, arg) != 0;
|
||||||
}
|
}
|
||||||
static bool getBoolean(lua_State* L, int32_t arg, bool defaultValue)
|
inline static bool getBoolean(lua_State* L, int32_t arg, bool defaultValue)
|
||||||
{
|
{
|
||||||
const auto parameters = lua_gettop(L);
|
const auto parameters = lua_gettop(L);
|
||||||
if (parameters == 0 || arg > parameters) {
|
if (parameters == 0 || arg > parameters) {
|
||||||
@@ -328,11 +320,11 @@ class LuaScriptInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
static std::string getString(lua_State* L, int32_t arg);
|
static std::string getString(lua_State* L, int32_t arg);
|
||||||
|
static CombatDamage getCombatDamage(lua_State* L);
|
||||||
static Position getPosition(lua_State* L, int32_t arg, int32_t& stackpos);
|
static Position getPosition(lua_State* L, int32_t arg, int32_t& stackpos);
|
||||||
static Position getPosition(lua_State* L, int32_t arg);
|
static Position getPosition(lua_State* L, int32_t arg);
|
||||||
static Outfit_t getOutfit(lua_State* L, int32_t arg);
|
static Outfit_t getOutfit(lua_State* L, int32_t arg);
|
||||||
static LuaVariant getVariant(lua_State* L, int32_t arg);
|
static LuaVariant getVariant(lua_State* L, int32_t arg);
|
||||||
static InstantSpell* getInstantSpell(lua_State* L, int32_t arg);
|
|
||||||
|
|
||||||
static Thing* getThing(lua_State* L, int32_t arg);
|
static Thing* getThing(lua_State* L, int32_t arg);
|
||||||
static Creature* getCreature(lua_State* L, int32_t arg);
|
static Creature* getCreature(lua_State* L, int32_t arg);
|
||||||
@@ -350,27 +342,27 @@ class LuaScriptInterface
|
|||||||
static LuaDataType getUserdataType(lua_State* L, int32_t arg);
|
static LuaDataType getUserdataType(lua_State* L, int32_t arg);
|
||||||
|
|
||||||
// Is
|
// Is
|
||||||
static bool isNumber(lua_State* L, int32_t arg)
|
inline static bool isNumber(lua_State* L, int32_t arg)
|
||||||
{
|
{
|
||||||
return lua_type(L, arg) == LUA_TNUMBER;
|
return lua_type(L, arg) == LUA_TNUMBER;
|
||||||
}
|
}
|
||||||
static bool isString(lua_State* L, int32_t arg)
|
inline static bool isString(lua_State* L, int32_t arg)
|
||||||
{
|
{
|
||||||
return lua_isstring(L, arg) != 0;
|
return lua_isstring(L, arg) != 0;
|
||||||
}
|
}
|
||||||
static bool isBoolean(lua_State* L, int32_t arg)
|
inline static bool isBoolean(lua_State* L, int32_t arg)
|
||||||
{
|
{
|
||||||
return lua_isboolean(L, arg);
|
return lua_isboolean(L, arg);
|
||||||
}
|
}
|
||||||
static bool isTable(lua_State* L, int32_t arg)
|
inline static bool isTable(lua_State* L, int32_t arg)
|
||||||
{
|
{
|
||||||
return lua_istable(L, arg);
|
return lua_istable(L, arg);
|
||||||
}
|
}
|
||||||
static bool isFunction(lua_State* L, int32_t arg)
|
inline static bool isFunction(lua_State* L, int32_t arg)
|
||||||
{
|
{
|
||||||
return lua_isfunction(L, arg);
|
return lua_isfunction(L, arg);
|
||||||
}
|
}
|
||||||
static bool isUserdata(lua_State* L, int32_t arg)
|
inline static bool isUserdata(lua_State* L, int32_t arg)
|
||||||
{
|
{
|
||||||
return lua_isuserdata(L, arg) != 0;
|
return lua_isuserdata(L, arg) != 0;
|
||||||
}
|
}
|
||||||
@@ -378,19 +370,17 @@ class LuaScriptInterface
|
|||||||
// Push
|
// Push
|
||||||
static void pushBoolean(lua_State* L, bool value);
|
static void pushBoolean(lua_State* L, bool value);
|
||||||
static void pushCombatDamage(lua_State* L, const CombatDamage& damage);
|
static void pushCombatDamage(lua_State* L, const CombatDamage& damage);
|
||||||
static void pushInstantSpell(lua_State* L, const InstantSpell& spell);
|
|
||||||
static void pushPosition(lua_State* L, const Position& position, int32_t stackpos = 0);
|
static void pushPosition(lua_State* L, const Position& position, int32_t stackpos = 0);
|
||||||
static void pushOutfit(lua_State* L, const Outfit_t& outfit);
|
static void pushOutfit(lua_State* L, const Outfit_t& outfit);
|
||||||
static void pushLoot(lua_State* L, const std::vector<LootBlock>& lootList);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
static void setField(lua_State* L, const char* index, lua_Number value)
|
inline static void setField(lua_State* L, const char* index, lua_Number value)
|
||||||
{
|
{
|
||||||
lua_pushnumber(L, value);
|
lua_pushnumber(L, value);
|
||||||
lua_setfield(L, -2, index);
|
lua_setfield(L, -2, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setField(lua_State* L, const char* index, const std::string& value)
|
inline static void setField(lua_State* L, const char* index, const std::string& value)
|
||||||
{
|
{
|
||||||
pushString(L, value);
|
pushString(L, value);
|
||||||
lua_setfield(L, -2, index);
|
lua_setfield(L, -2, index);
|
||||||
@@ -412,21 +402,9 @@ class LuaScriptInterface
|
|||||||
|
|
||||||
void registerFunctions();
|
void registerFunctions();
|
||||||
|
|
||||||
void registerMethod(const std::string& globalName, const std::string& methodName, lua_CFunction func);
|
|
||||||
|
|
||||||
static std::string getErrorDesc(ErrorCode_t code);
|
|
||||||
|
|
||||||
lua_State* luaState = nullptr;
|
|
||||||
|
|
||||||
int32_t eventTableRef = -1;
|
|
||||||
int32_t runningEventId = EVENT_ID_USER;
|
|
||||||
|
|
||||||
//script file cache
|
|
||||||
std::map<int32_t, std::string> cacheFiles;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void registerClass(const std::string& className, const std::string& baseClass, lua_CFunction newFunction = nullptr);
|
void registerClass(const std::string& className, const std::string& baseClass, lua_CFunction newFunction = nullptr);
|
||||||
void registerTable(const std::string& tableName);
|
void registerTable(const std::string& tableName);
|
||||||
|
void registerMethod(const std::string& className, const std::string& methodName, lua_CFunction func);
|
||||||
void registerMetaMethod(const std::string& className, const std::string& methodName, lua_CFunction func);
|
void registerMetaMethod(const std::string& className, const std::string& methodName, lua_CFunction func);
|
||||||
void registerGlobalMethod(const std::string& functionName, lua_CFunction func);
|
void registerGlobalMethod(const std::string& functionName, lua_CFunction func);
|
||||||
void registerVariable(const std::string& tableName, const std::string& name, lua_Number value);
|
void registerVariable(const std::string& tableName, const std::string& name, lua_Number value);
|
||||||
@@ -435,16 +413,28 @@ class LuaScriptInterface
|
|||||||
|
|
||||||
std::string getStackTrace(const std::string& error_desc);
|
std::string getStackTrace(const std::string& error_desc);
|
||||||
|
|
||||||
|
static std::string getErrorDesc(ErrorCode_t code);
|
||||||
static bool getArea(lua_State* L, std::list<uint32_t>& list, uint32_t& rows);
|
static bool getArea(lua_State* L, std::list<uint32_t>& list, uint32_t& rows);
|
||||||
|
|
||||||
//lua functions
|
//lua functions
|
||||||
|
static int luaDoCreateItem(lua_State* L);
|
||||||
|
static int luaDoCreateItemEx(lua_State* L);
|
||||||
|
static int luaDoMoveCreature(lua_State* L);
|
||||||
|
|
||||||
static int luaDoPlayerAddItem(lua_State* L);
|
static int luaDoPlayerAddItem(lua_State* L);
|
||||||
|
static int luaDoTileAddItemEx(lua_State* L);
|
||||||
static int luaDoSetCreatureLight(lua_State* L);
|
static int luaDoSetCreatureLight(lua_State* L);
|
||||||
|
|
||||||
//get item info
|
//get item info
|
||||||
static int luaGetDepotId(lua_State* L);
|
static int luaGetDepotId(lua_State* L);
|
||||||
|
|
||||||
//get world info
|
//get creature info functions
|
||||||
|
static int luaGetPlayerFlagValue(lua_State* L);
|
||||||
|
static int luaGetCreatureCondition(lua_State* L);
|
||||||
|
|
||||||
|
static int luaGetPlayerInstantSpellInfo(lua_State* L);
|
||||||
|
static int luaGetPlayerInstantSpellCount(lua_State* L);
|
||||||
|
|
||||||
static int luaGetWorldTime(lua_State* L);
|
static int luaGetWorldTime(lua_State* L);
|
||||||
static int luaGetWorldLight(lua_State* L);
|
static int luaGetWorldLight(lua_State* L);
|
||||||
static int luaGetWorldUpTime(lua_State* L);
|
static int luaGetWorldUpTime(lua_State* L);
|
||||||
@@ -475,7 +465,12 @@ class LuaScriptInterface
|
|||||||
|
|
||||||
static int luaDoChallengeCreature(lua_State* L);
|
static int luaDoChallengeCreature(lua_State* L);
|
||||||
|
|
||||||
|
static int luaSetCreatureOutfit(lua_State* L);
|
||||||
|
static int luaSetMonsterOutfit(lua_State* L);
|
||||||
|
static int luaSetItemOutfit(lua_State* L);
|
||||||
|
|
||||||
static int luaDebugPrint(lua_State* L);
|
static int luaDebugPrint(lua_State* L);
|
||||||
|
static int luaIsInArray(lua_State* L);
|
||||||
static int luaAddEvent(lua_State* L);
|
static int luaAddEvent(lua_State* L);
|
||||||
static int luaStopEvent(lua_State* L);
|
static int luaStopEvent(lua_State* L);
|
||||||
|
|
||||||
@@ -486,9 +481,6 @@ class LuaScriptInterface
|
|||||||
|
|
||||||
static int luaGetWaypointPositionByName(lua_State* L);
|
static int luaGetWaypointPositionByName(lua_State* L);
|
||||||
|
|
||||||
static int luaSendChannelMessage(lua_State* L);
|
|
||||||
static int luaSendGuildChannelMessage(lua_State* L);
|
|
||||||
|
|
||||||
#ifndef LUAJIT_VERSION
|
#ifndef LUAJIT_VERSION
|
||||||
static int luaBitNot(lua_State* L);
|
static int luaBitNot(lua_State* L);
|
||||||
static int luaBitAnd(lua_State* L);
|
static int luaBitAnd(lua_State* L);
|
||||||
@@ -556,12 +548,9 @@ class LuaScriptInterface
|
|||||||
static int luaGameCreateMonster(lua_State* L);
|
static int luaGameCreateMonster(lua_State* L);
|
||||||
static int luaGameCreateNpc(lua_State* L);
|
static int luaGameCreateNpc(lua_State* L);
|
||||||
static int luaGameCreateTile(lua_State* L);
|
static int luaGameCreateTile(lua_State* L);
|
||||||
static int luaGameCreateMonsterType(lua_State* L);
|
|
||||||
|
|
||||||
static int luaGameStartRaid(lua_State* L);
|
static int luaGameStartRaid(lua_State* L);
|
||||||
|
|
||||||
static int luaGameGetClientVersion(lua_State* L);
|
|
||||||
|
|
||||||
static int luaGameReload(lua_State* L);
|
static int luaGameReload(lua_State* L);
|
||||||
|
|
||||||
// Variant
|
// Variant
|
||||||
@@ -582,6 +571,7 @@ class LuaScriptInterface
|
|||||||
|
|
||||||
static int luaPositionSendMagicEffect(lua_State* L);
|
static int luaPositionSendMagicEffect(lua_State* L);
|
||||||
static int luaPositionSendDistanceEffect(lua_State* L);
|
static int luaPositionSendDistanceEffect(lua_State* L);
|
||||||
|
static int luaPositionSendMonsterSay(lua_State* L);
|
||||||
|
|
||||||
// Tile
|
// Tile
|
||||||
static int luaTileCreate(lua_State* L);
|
static int luaTileCreate(lua_State* L);
|
||||||
@@ -620,8 +610,6 @@ class LuaScriptInterface
|
|||||||
static int luaTileGetThingIndex(lua_State* L);
|
static int luaTileGetThingIndex(lua_State* L);
|
||||||
|
|
||||||
static int luaTileQueryAdd(lua_State* L);
|
static int luaTileQueryAdd(lua_State* L);
|
||||||
static int luaTileAddItem(lua_State* L);
|
|
||||||
static int luaTileAddItemEx(lua_State* L);
|
|
||||||
|
|
||||||
static int luaTileGetHouse(lua_State* L);
|
static int luaTileGetHouse(lua_State* L);
|
||||||
|
|
||||||
@@ -650,34 +638,6 @@ class LuaScriptInterface
|
|||||||
static int luaNetworkMessageSkipBytes(lua_State* L);
|
static int luaNetworkMessageSkipBytes(lua_State* L);
|
||||||
static int luaNetworkMessageSendToPlayer(lua_State* L);
|
static int luaNetworkMessageSendToPlayer(lua_State* L);
|
||||||
|
|
||||||
// ModalWindow
|
|
||||||
static int luaModalWindowCreate(lua_State* L);
|
|
||||||
static int luaModalWindowDelete(lua_State* L);
|
|
||||||
|
|
||||||
static int luaModalWindowGetId(lua_State* L);
|
|
||||||
static int luaModalWindowGetTitle(lua_State* L);
|
|
||||||
static int luaModalWindowGetMessage(lua_State* L);
|
|
||||||
|
|
||||||
static int luaModalWindowSetTitle(lua_State* L);
|
|
||||||
static int luaModalWindowSetMessage(lua_State* L);
|
|
||||||
|
|
||||||
static int luaModalWindowGetButtonCount(lua_State* L);
|
|
||||||
static int luaModalWindowGetChoiceCount(lua_State* L);
|
|
||||||
|
|
||||||
static int luaModalWindowAddButton(lua_State* L);
|
|
||||||
static int luaModalWindowAddChoice(lua_State* L);
|
|
||||||
|
|
||||||
static int luaModalWindowGetDefaultEnterButton(lua_State* L);
|
|
||||||
static int luaModalWindowSetDefaultEnterButton(lua_State* L);
|
|
||||||
|
|
||||||
static int luaModalWindowGetDefaultEscapeButton(lua_State* L);
|
|
||||||
static int luaModalWindowSetDefaultEscapeButton(lua_State* L);
|
|
||||||
|
|
||||||
static int luaModalWindowHasPriority(lua_State* L);
|
|
||||||
static int luaModalWindowSetPriority(lua_State* L);
|
|
||||||
|
|
||||||
static int luaModalWindowSendToPlayer(lua_State* L);
|
|
||||||
|
|
||||||
// Item
|
// Item
|
||||||
static int luaItemCreate(lua_State* L);
|
static int luaItemCreate(lua_State* L);
|
||||||
|
|
||||||
@@ -692,9 +652,11 @@ class LuaScriptInterface
|
|||||||
static int luaItemSplit(lua_State* L);
|
static int luaItemSplit(lua_State* L);
|
||||||
static int luaItemRemove(lua_State* L);
|
static int luaItemRemove(lua_State* L);
|
||||||
|
|
||||||
static int luaItemGetUniqueId(lua_State* L);
|
static int luaItemGetMovementId(lua_State* L);
|
||||||
|
static int luaItemSetMovementId(lua_State* L);
|
||||||
static int luaItemGetActionId(lua_State* L);
|
static int luaItemGetActionId(lua_State* L);
|
||||||
static int luaItemSetActionId(lua_State* L);
|
static int luaItemSetActionId(lua_State* L);
|
||||||
|
static int luaItemGetUniqueId(lua_State* L);
|
||||||
|
|
||||||
static int luaItemGetCount(lua_State* L);
|
static int luaItemGetCount(lua_State* L);
|
||||||
static int luaItemGetCharges(lua_State* L);
|
static int luaItemGetCharges(lua_State* L);
|
||||||
@@ -714,9 +676,6 @@ class LuaScriptInterface
|
|||||||
static int luaItemGetAttribute(lua_State* L);
|
static int luaItemGetAttribute(lua_State* L);
|
||||||
static int luaItemSetAttribute(lua_State* L);
|
static int luaItemSetAttribute(lua_State* L);
|
||||||
static int luaItemRemoveAttribute(lua_State* L);
|
static int luaItemRemoveAttribute(lua_State* L);
|
||||||
static int luaItemGetCustomAttribute(lua_State* L);
|
|
||||||
static int luaItemSetCustomAttribute(lua_State* L);
|
|
||||||
static int luaItemRemoveCustomAttribute(lua_State* L);
|
|
||||||
|
|
||||||
static int luaItemMoveTo(lua_State* L);
|
static int luaItemMoveTo(lua_State* L);
|
||||||
static int luaItemTransform(lua_State* L);
|
static int luaItemTransform(lua_State* L);
|
||||||
@@ -725,7 +684,6 @@ class LuaScriptInterface
|
|||||||
static int luaItemGetDescription(lua_State* L);
|
static int luaItemGetDescription(lua_State* L);
|
||||||
|
|
||||||
static int luaItemHasProperty(lua_State* L);
|
static int luaItemHasProperty(lua_State* L);
|
||||||
static int luaItemIsLoadedFromMap(lua_State* L);
|
|
||||||
|
|
||||||
// Container
|
// Container
|
||||||
static int luaContainerCreate(lua_State* L);
|
static int luaContainerCreate(lua_State* L);
|
||||||
@@ -733,7 +691,7 @@ class LuaScriptInterface
|
|||||||
static int luaContainerGetSize(lua_State* L);
|
static int luaContainerGetSize(lua_State* L);
|
||||||
static int luaContainerGetCapacity(lua_State* L);
|
static int luaContainerGetCapacity(lua_State* L);
|
||||||
static int luaContainerGetEmptySlots(lua_State* L);
|
static int luaContainerGetEmptySlots(lua_State* L);
|
||||||
static int luaContainerGetContentDescription(lua_State* L);
|
|
||||||
static int luaContainerGetItemHoldingCount(lua_State* L);
|
static int luaContainerGetItemHoldingCount(lua_State* L);
|
||||||
static int luaContainerGetItemCountById(lua_State* L);
|
static int luaContainerGetItemCountById(lua_State* L);
|
||||||
|
|
||||||
@@ -741,7 +699,6 @@ class LuaScriptInterface
|
|||||||
static int luaContainerHasItem(lua_State* L);
|
static int luaContainerHasItem(lua_State* L);
|
||||||
static int luaContainerAddItem(lua_State* L);
|
static int luaContainerAddItem(lua_State* L);
|
||||||
static int luaContainerAddItemEx(lua_State* L);
|
static int luaContainerAddItemEx(lua_State* L);
|
||||||
static int luaContainerGetCorpseOwner(lua_State* L);
|
|
||||||
|
|
||||||
// Teleport
|
// Teleport
|
||||||
static int luaTeleportCreate(lua_State* L);
|
static int luaTeleportCreate(lua_State* L);
|
||||||
@@ -759,8 +716,6 @@ class LuaScriptInterface
|
|||||||
static int luaCreatureIsRemoved(lua_State* L);
|
static int luaCreatureIsRemoved(lua_State* L);
|
||||||
static int luaCreatureIsCreature(lua_State* L);
|
static int luaCreatureIsCreature(lua_State* L);
|
||||||
static int luaCreatureIsInGhostMode(lua_State* L);
|
static int luaCreatureIsInGhostMode(lua_State* L);
|
||||||
static int luaCreatureIsHealthHidden(lua_State* L);
|
|
||||||
static int luaCreatureIsImmune(lua_State* L);
|
|
||||||
|
|
||||||
static int luaCreatureCanSee(lua_State* L);
|
static int luaCreatureCanSee(lua_State* L);
|
||||||
static int luaCreatureCanSeeCreature(lua_State* L);
|
static int luaCreatureCanSeeCreature(lua_State* L);
|
||||||
@@ -787,7 +742,6 @@ class LuaScriptInterface
|
|||||||
static int luaCreatureChangeSpeed(lua_State* L);
|
static int luaCreatureChangeSpeed(lua_State* L);
|
||||||
|
|
||||||
static int luaCreatureSetDropLoot(lua_State* L);
|
static int luaCreatureSetDropLoot(lua_State* L);
|
||||||
static int luaCreatureSetSkillLoss(lua_State* L);
|
|
||||||
|
|
||||||
static int luaCreatureGetPosition(lua_State* L);
|
static int luaCreatureGetPosition(lua_State* L);
|
||||||
static int luaCreatureGetTile(lua_State* L);
|
static int luaCreatureGetTile(lua_State* L);
|
||||||
@@ -795,7 +749,6 @@ class LuaScriptInterface
|
|||||||
static int luaCreatureSetDirection(lua_State* L);
|
static int luaCreatureSetDirection(lua_State* L);
|
||||||
|
|
||||||
static int luaCreatureGetHealth(lua_State* L);
|
static int luaCreatureGetHealth(lua_State* L);
|
||||||
static int luaCreatureSetHealth(lua_State* L);
|
|
||||||
static int luaCreatureAddHealth(lua_State* L);
|
static int luaCreatureAddHealth(lua_State* L);
|
||||||
static int luaCreatureGetMaxHealth(lua_State* L);
|
static int luaCreatureGetMaxHealth(lua_State* L);
|
||||||
static int luaCreatureSetMaxHealth(lua_State* L);
|
static int luaCreatureSetMaxHealth(lua_State* L);
|
||||||
@@ -810,7 +763,6 @@ class LuaScriptInterface
|
|||||||
static int luaCreatureGetCondition(lua_State* L);
|
static int luaCreatureGetCondition(lua_State* L);
|
||||||
static int luaCreatureAddCondition(lua_State* L);
|
static int luaCreatureAddCondition(lua_State* L);
|
||||||
static int luaCreatureRemoveCondition(lua_State* L);
|
static int luaCreatureRemoveCondition(lua_State* L);
|
||||||
static int luaCreatureHasCondition(lua_State* L);
|
|
||||||
|
|
||||||
static int luaCreatureRemove(lua_State* L);
|
static int luaCreatureRemove(lua_State* L);
|
||||||
static int luaCreatureTeleportTo(lua_State* L);
|
static int luaCreatureTeleportTo(lua_State* L);
|
||||||
@@ -823,9 +775,6 @@ class LuaScriptInterface
|
|||||||
static int luaCreatureGetDescription(lua_State* L);
|
static int luaCreatureGetDescription(lua_State* L);
|
||||||
|
|
||||||
static int luaCreatureGetPathTo(lua_State* L);
|
static int luaCreatureGetPathTo(lua_State* L);
|
||||||
static int luaCreatureMove(lua_State* L);
|
|
||||||
|
|
||||||
static int luaCreatureGetZone(lua_State* L);
|
|
||||||
|
|
||||||
// Player
|
// Player
|
||||||
static int luaPlayerCreate(lua_State* L);
|
static int luaPlayerCreate(lua_State* L);
|
||||||
@@ -837,6 +786,7 @@ class LuaScriptInterface
|
|||||||
static int luaPlayerGetAccountId(lua_State* L);
|
static int luaPlayerGetAccountId(lua_State* L);
|
||||||
static int luaPlayerGetLastLoginSaved(lua_State* L);
|
static int luaPlayerGetLastLoginSaved(lua_State* L);
|
||||||
static int luaPlayerGetLastLogout(lua_State* L);
|
static int luaPlayerGetLastLogout(lua_State* L);
|
||||||
|
static int luaPlayerHasFlag(lua_State* L);
|
||||||
|
|
||||||
static int luaPlayerGetAccountType(lua_State* L);
|
static int luaPlayerGetAccountType(lua_State* L);
|
||||||
static int luaPlayerSetAccountType(lua_State* L);
|
static int luaPlayerSetAccountType(lua_State* L);
|
||||||
@@ -847,10 +797,10 @@ class LuaScriptInterface
|
|||||||
static int luaPlayerGetFreeCapacity(lua_State* L);
|
static int luaPlayerGetFreeCapacity(lua_State* L);
|
||||||
|
|
||||||
static int luaPlayerGetDepotChest(lua_State* L);
|
static int luaPlayerGetDepotChest(lua_State* L);
|
||||||
static int luaPlayerGetInbox(lua_State* L);
|
|
||||||
|
|
||||||
static int luaPlayerGetSkullTime(lua_State* L);
|
static int luaPlayerGetMurderTimestamps(lua_State* L);
|
||||||
static int luaPlayerSetSkullTime(lua_State* L);
|
static int luaPlayerGetPlayerKillerEnd(lua_State* L);
|
||||||
|
static int luaPlayerSetPlayerKillerEnd(lua_State* L);
|
||||||
static int luaPlayerGetDeathPenalty(lua_State* L);
|
static int luaPlayerGetDeathPenalty(lua_State* L);
|
||||||
|
|
||||||
static int luaPlayerGetExperience(lua_State* L);
|
static int luaPlayerGetExperience(lua_State* L);
|
||||||
@@ -875,17 +825,6 @@ class LuaScriptInterface
|
|||||||
static int luaPlayerGetSkillPercent(lua_State* L);
|
static int luaPlayerGetSkillPercent(lua_State* L);
|
||||||
static int luaPlayerGetSkillTries(lua_State* L);
|
static int luaPlayerGetSkillTries(lua_State* L);
|
||||||
static int luaPlayerAddSkillTries(lua_State* L);
|
static int luaPlayerAddSkillTries(lua_State* L);
|
||||||
static int luaPlayerGetSpecialSkill(lua_State* L);
|
|
||||||
static int luaPlayerAddSpecialSkill(lua_State* L);
|
|
||||||
|
|
||||||
static int luaPlayerAddOfflineTrainingTime(lua_State* L);
|
|
||||||
static int luaPlayerGetOfflineTrainingTime(lua_State* L);
|
|
||||||
static int luaPlayerRemoveOfflineTrainingTime(lua_State* L);
|
|
||||||
|
|
||||||
static int luaPlayerAddOfflineTrainingTries(lua_State* L);
|
|
||||||
|
|
||||||
static int luaPlayerGetOfflineTrainingSkill(lua_State* L);
|
|
||||||
static int luaPlayerSetOfflineTrainingSkill(lua_State* L);
|
|
||||||
|
|
||||||
static int luaPlayerGetItemCount(lua_State* L);
|
static int luaPlayerGetItemCount(lua_State* L);
|
||||||
static int luaPlayerGetItemById(lua_State* L);
|
static int luaPlayerGetItemById(lua_State* L);
|
||||||
@@ -935,7 +874,6 @@ class LuaScriptInterface
|
|||||||
static int luaPlayerShowTextDialog(lua_State* L);
|
static int luaPlayerShowTextDialog(lua_State* L);
|
||||||
|
|
||||||
static int luaPlayerSendTextMessage(lua_State* L);
|
static int luaPlayerSendTextMessage(lua_State* L);
|
||||||
static int luaPlayerSendChannelMessage(lua_State* L);
|
|
||||||
static int luaPlayerSendPrivateMessage(lua_State* L);
|
static int luaPlayerSendPrivateMessage(lua_State* L);
|
||||||
|
|
||||||
static int luaPlayerChannelSay(lua_State* L);
|
static int luaPlayerChannelSay(lua_State* L);
|
||||||
@@ -952,10 +890,6 @@ class LuaScriptInterface
|
|||||||
static int luaPlayerHasOutfit(lua_State* L);
|
static int luaPlayerHasOutfit(lua_State* L);
|
||||||
static int luaPlayerSendOutfitWindow(lua_State* L);
|
static int luaPlayerSendOutfitWindow(lua_State* L);
|
||||||
|
|
||||||
static int luaPlayerAddMount(lua_State* L);
|
|
||||||
static int luaPlayerRemoveMount(lua_State* L);
|
|
||||||
static int luaPlayerHasMount(lua_State* L);
|
|
||||||
|
|
||||||
static int luaPlayerGetPremiumDays(lua_State* L);
|
static int luaPlayerGetPremiumDays(lua_State* L);
|
||||||
static int luaPlayerAddPremiumDays(lua_State* L);
|
static int luaPlayerAddPremiumDays(lua_State* L);
|
||||||
static int luaPlayerRemovePremiumDays(lua_State* L);
|
static int luaPlayerRemovePremiumDays(lua_State* L);
|
||||||
@@ -969,19 +903,12 @@ class LuaScriptInterface
|
|||||||
static int luaPlayerForgetSpell(lua_State* L);
|
static int luaPlayerForgetSpell(lua_State* L);
|
||||||
static int luaPlayerHasLearnedSpell(lua_State* L);
|
static int luaPlayerHasLearnedSpell(lua_State* L);
|
||||||
|
|
||||||
static int luaPlayerSendTutorial(lua_State* L);
|
|
||||||
static int luaPlayerAddMapMark(lua_State* L);
|
|
||||||
|
|
||||||
static int luaPlayerSave(lua_State* L);
|
static int luaPlayerSave(lua_State* L);
|
||||||
static int luaPlayerPopupFYI(lua_State* L);
|
|
||||||
|
|
||||||
static int luaPlayerIsPzLocked(lua_State* L);
|
static int luaPlayerIsPzLocked(lua_State* L);
|
||||||
|
|
||||||
static int luaPlayerGetClient(lua_State* L);
|
static int luaPlayerGetClient(lua_State* L);
|
||||||
|
|
||||||
static int luaPlayerGetHouse(lua_State* L);
|
static int luaPlayerGetHouse(lua_State* L);
|
||||||
static int luaPlayerSendHouseWindow(lua_State* L);
|
|
||||||
static int luaPlayerSetEditHouse(lua_State* L);
|
|
||||||
|
|
||||||
static int luaPlayerSetGhostMode(lua_State* L);
|
static int luaPlayerSetGhostMode(lua_State* L);
|
||||||
|
|
||||||
@@ -989,12 +916,7 @@ class LuaScriptInterface
|
|||||||
static int luaPlayerGetContainerById(lua_State* L);
|
static int luaPlayerGetContainerById(lua_State* L);
|
||||||
static int luaPlayerGetContainerIndex(lua_State* L);
|
static int luaPlayerGetContainerIndex(lua_State* L);
|
||||||
|
|
||||||
static int luaPlayerGetInstantSpells(lua_State* L);
|
static int luaPlayerGetTotalDamage(lua_State* L);
|
||||||
static int luaPlayerCanCast(lua_State* L);
|
|
||||||
|
|
||||||
static int luaPlayerHasChaseMode(lua_State* L);
|
|
||||||
static int luaPlayerHasSecureMode(lua_State* L);
|
|
||||||
static int luaPlayerGetFightMode(lua_State* L);
|
|
||||||
|
|
||||||
// Monster
|
// Monster
|
||||||
static int luaMonsterCreate(lua_State* L);
|
static int luaMonsterCreate(lua_State* L);
|
||||||
@@ -1033,9 +955,6 @@ class LuaScriptInterface
|
|||||||
|
|
||||||
static int luaNpcSetMasterPos(lua_State* L);
|
static int luaNpcSetMasterPos(lua_State* L);
|
||||||
|
|
||||||
static int luaNpcGetSpeechBubble(lua_State* L);
|
|
||||||
static int luaNpcSetSpeechBubble(lua_State* L);
|
|
||||||
|
|
||||||
// Guild
|
// Guild
|
||||||
static int luaGuildCreate(lua_State* L);
|
static int luaGuildCreate(lua_State* L);
|
||||||
|
|
||||||
@@ -1047,9 +966,6 @@ class LuaScriptInterface
|
|||||||
static int luaGuildGetRankById(lua_State* L);
|
static int luaGuildGetRankById(lua_State* L);
|
||||||
static int luaGuildGetRankByLevel(lua_State* L);
|
static int luaGuildGetRankByLevel(lua_State* L);
|
||||||
|
|
||||||
static int luaGuildGetMotd(lua_State* L);
|
|
||||||
static int luaGuildSetMotd(lua_State* L);
|
|
||||||
|
|
||||||
// Group
|
// Group
|
||||||
static int luaGroupCreate(lua_State* L);
|
static int luaGroupCreate(lua_State* L);
|
||||||
|
|
||||||
@@ -1059,13 +975,11 @@ class LuaScriptInterface
|
|||||||
static int luaGroupGetAccess(lua_State* L);
|
static int luaGroupGetAccess(lua_State* L);
|
||||||
static int luaGroupGetMaxDepotItems(lua_State* L);
|
static int luaGroupGetMaxDepotItems(lua_State* L);
|
||||||
static int luaGroupGetMaxVipEntries(lua_State* L);
|
static int luaGroupGetMaxVipEntries(lua_State* L);
|
||||||
static int luaGroupHasFlag(lua_State* L);
|
|
||||||
|
|
||||||
// Vocation
|
// Vocation
|
||||||
static int luaVocationCreate(lua_State* L);
|
static int luaVocationCreate(lua_State* L);
|
||||||
|
|
||||||
static int luaVocationGetId(lua_State* L);
|
static int luaVocationGetId(lua_State* L);
|
||||||
static int luaVocationGetClientId(lua_State* L);
|
|
||||||
static int luaVocationGetName(lua_State* L);
|
static int luaVocationGetName(lua_State* L);
|
||||||
static int luaVocationGetDescription(lua_State* L);
|
static int luaVocationGetDescription(lua_State* L);
|
||||||
|
|
||||||
@@ -1116,68 +1030,59 @@ class LuaScriptInterface
|
|||||||
|
|
||||||
static int luaHouseGetDoors(lua_State* L);
|
static int luaHouseGetDoors(lua_State* L);
|
||||||
static int luaHouseGetDoorCount(lua_State* L);
|
static int luaHouseGetDoorCount(lua_State* L);
|
||||||
static int luaHouseGetDoorIdByPosition(lua_State* L);
|
|
||||||
|
|
||||||
static int luaHouseGetTiles(lua_State* L);
|
static int luaHouseGetTiles(lua_State* L);
|
||||||
static int luaHouseGetItems(lua_State* L);
|
|
||||||
static int luaHouseGetTileCount(lua_State* L);
|
static int luaHouseGetTileCount(lua_State* L);
|
||||||
|
|
||||||
static int luaHouseCanEditAccessList(lua_State* L);
|
|
||||||
static int luaHouseGetAccessList(lua_State* L);
|
static int luaHouseGetAccessList(lua_State* L);
|
||||||
static int luaHouseSetAccessList(lua_State* L);
|
static int luaHouseSetAccessList(lua_State* L);
|
||||||
|
|
||||||
static int luaHouseKickPlayer(lua_State* L);
|
|
||||||
|
|
||||||
// ItemType
|
// ItemType
|
||||||
static int luaItemTypeCreate(lua_State* L);
|
static int luaItemTypeCreate(lua_State* L);
|
||||||
|
|
||||||
static int luaItemTypeIsCorpse(lua_State* L);
|
static int luaItemTypeIsCorpse(lua_State* L);
|
||||||
static int luaItemTypeIsDoor(lua_State* L);
|
static int luaItemTypeIsDoor(lua_State* L);
|
||||||
static int luaItemTypeIsContainer(lua_State* L);
|
static int luaItemTypeIsContainer(lua_State* L);
|
||||||
|
static int luaItemTypeIsChest(lua_State* L);
|
||||||
static int luaItemTypeIsFluidContainer(lua_State* L);
|
static int luaItemTypeIsFluidContainer(lua_State* L);
|
||||||
static int luaItemTypeIsMovable(lua_State* L);
|
static int luaItemTypeIsMovable(lua_State* L);
|
||||||
static int luaItemTypeIsRune(lua_State* L);
|
static int luaItemTypeIsRune(lua_State* L);
|
||||||
static int luaItemTypeIsStackable(lua_State* L);
|
static int luaItemTypeIsStackable(lua_State* L);
|
||||||
static int luaItemTypeIsReadable(lua_State* L);
|
static int luaItemTypeIsReadable(lua_State* L);
|
||||||
static int luaItemTypeIsWritable(lua_State* L);
|
static int luaItemTypeIsWritable(lua_State* L);
|
||||||
static int luaItemTypeIsBlocking(lua_State* L);
|
|
||||||
static int luaItemTypeIsGroundTile(lua_State* L);
|
|
||||||
static int luaItemTypeIsMagicField(lua_State* L);
|
static int luaItemTypeIsMagicField(lua_State* L);
|
||||||
static int luaItemTypeIsUseable(lua_State* L);
|
static int luaItemTypeIsSplash(lua_State* L);
|
||||||
static int luaItemTypeIsPickupable(lua_State* L);
|
static int luaItemTypeIsKey(lua_State* L);
|
||||||
|
static int luaItemTypeIsDisguised(lua_State* L);
|
||||||
|
static int luaItemTypeIsDestroyable(lua_State* L);
|
||||||
|
static int luaItemTypeIsGroundTile(lua_State* L);
|
||||||
|
|
||||||
static int luaItemTypeGetType(lua_State* L);
|
static int luaItemTypeGetType(lua_State* L);
|
||||||
static int luaItemTypeGetId(lua_State* L);
|
static int luaItemTypeGetId(lua_State* L);
|
||||||
static int luaItemTypeGetClientId(lua_State* L);
|
static int luaItemTypeGetDisguiseId(lua_State* L);
|
||||||
static int luaItemTypeGetName(lua_State* L);
|
static int luaItemTypeGetName(lua_State* L);
|
||||||
static int luaItemTypeGetPluralName(lua_State* L);
|
static int luaItemTypeGetPluralName(lua_State* L);
|
||||||
static int luaItemTypeGetArticle(lua_State* L);
|
static int luaItemTypeGetArticle(lua_State* L);
|
||||||
static int luaItemTypeGetDescription(lua_State* L);
|
static int luaItemTypeGetDescription(lua_State* L);
|
||||||
static int luaItemTypeGetSlotPosition(lua_State *L);
|
static int luaItemTypeGetSlotPosition(lua_State *L);
|
||||||
|
static int luaItemTypeGetDestroyTarget(lua_State* L);
|
||||||
|
|
||||||
static int luaItemTypeGetCharges(lua_State* L);
|
static int luaItemTypeGetCharges(lua_State* L);
|
||||||
static int luaItemTypeGetFluidSource(lua_State* L);
|
static int luaItemTypeGetFluidSource(lua_State* L);
|
||||||
static int luaItemTypeGetCapacity(lua_State* L);
|
static int luaItemTypeGetCapacity(lua_State* L);
|
||||||
static int luaItemTypeGetWeight(lua_State* L);
|
static int luaItemTypeGetWeight(lua_State* L);
|
||||||
|
|
||||||
static int luaItemTypeGetHitChance(lua_State* L);
|
|
||||||
static int luaItemTypeGetShootRange(lua_State* L);
|
static int luaItemTypeGetShootRange(lua_State* L);
|
||||||
static int luaItemTypeGetAttack(lua_State* L);
|
static int luaItemTypeGetAttack(lua_State* L);
|
||||||
static int luaItemTypeGetDefense(lua_State* L);
|
static int luaItemTypeGetDefense(lua_State* L);
|
||||||
static int luaItemTypeGetExtraDefense(lua_State* L);
|
|
||||||
static int luaItemTypeGetArmor(lua_State* L);
|
static int luaItemTypeGetArmor(lua_State* L);
|
||||||
static int luaItemTypeGetWeaponType(lua_State* L);
|
static int luaItemTypeGetWeaponType(lua_State* L);
|
||||||
|
|
||||||
static int luaItemTypeGetElementType(lua_State* L);
|
|
||||||
static int luaItemTypeGetElementDamage(lua_State* L);
|
|
||||||
|
|
||||||
static int luaItemTypeGetTransformEquipId(lua_State* L);
|
static int luaItemTypeGetTransformEquipId(lua_State* L);
|
||||||
static int luaItemTypeGetTransformDeEquipId(lua_State* L);
|
static int luaItemTypeGetTransformDeEquipId(lua_State* L);
|
||||||
static int luaItemTypeGetDestroyId(lua_State* L);
|
|
||||||
static int luaItemTypeGetDecayId(lua_State* L);
|
static int luaItemTypeGetDecayId(lua_State* L);
|
||||||
|
static int luaItemTypeGetNutrition(lua_State* L);
|
||||||
static int luaItemTypeGetRequiredLevel(lua_State* L);
|
static int luaItemTypeGetRequiredLevel(lua_State* L);
|
||||||
static int luaItemTypeGetAmmoType(lua_State* L);
|
|
||||||
static int luaItemTypeGetCorpseType(lua_State* L);
|
|
||||||
|
|
||||||
static int luaItemTypeHasSubType(lua_State* L);
|
static int luaItemTypeHasSubType(lua_State* L);
|
||||||
|
|
||||||
@@ -1188,8 +1093,7 @@ class LuaScriptInterface
|
|||||||
static int luaCombatSetFormula(lua_State* L);
|
static int luaCombatSetFormula(lua_State* L);
|
||||||
|
|
||||||
static int luaCombatSetArea(lua_State* L);
|
static int luaCombatSetArea(lua_State* L);
|
||||||
static int luaCombatAddCondition(lua_State* L);
|
static int luaCombatSetCondition(lua_State* L);
|
||||||
static int luaCombatClearConditions(lua_State* L);
|
|
||||||
static int luaCombatSetCallback(lua_State* L);
|
static int luaCombatSetCallback(lua_State* L);
|
||||||
static int luaCombatSetOrigin(lua_State* L);
|
static int luaCombatSetOrigin(lua_State* L);
|
||||||
|
|
||||||
@@ -1211,10 +1115,10 @@ class LuaScriptInterface
|
|||||||
static int luaConditionSetTicks(lua_State* L);
|
static int luaConditionSetTicks(lua_State* L);
|
||||||
|
|
||||||
static int luaConditionSetParameter(lua_State* L);
|
static int luaConditionSetParameter(lua_State* L);
|
||||||
static int luaConditionSetFormula(lua_State* L);
|
static int luaConditionSetSpeedDelta(lua_State* L);
|
||||||
static int luaConditionSetOutfit(lua_State* L);
|
static int luaConditionSetOutfit(lua_State* L);
|
||||||
|
|
||||||
static int luaConditionAddDamage(lua_State* L);
|
static int luaConditionSetTiming(lua_State* L);
|
||||||
|
|
||||||
// MonsterType
|
// MonsterType
|
||||||
static int luaMonsterTypeCreate(lua_State* L);
|
static int luaMonsterTypeCreate(lua_State* L);
|
||||||
@@ -1225,100 +1129,47 @@ class LuaScriptInterface
|
|||||||
static int luaMonsterTypeIsIllusionable(lua_State* L);
|
static int luaMonsterTypeIsIllusionable(lua_State* L);
|
||||||
static int luaMonsterTypeIsHostile(lua_State* L);
|
static int luaMonsterTypeIsHostile(lua_State* L);
|
||||||
static int luaMonsterTypeIsPushable(lua_State* L);
|
static int luaMonsterTypeIsPushable(lua_State* L);
|
||||||
static int luaMonsterTypeIsHealthHidden(lua_State* L);
|
static int luaMonsterTypeIsHealthShown(lua_State* L);
|
||||||
|
|
||||||
static int luaMonsterTypeCanPushItems(lua_State* L);
|
static int luaMonsterTypeCanPushItems(lua_State* L);
|
||||||
static int luaMonsterTypeCanPushCreatures(lua_State* L);
|
static int luaMonsterTypeCanPushCreatures(lua_State* L);
|
||||||
|
|
||||||
static int luaMonsterTypeName(lua_State* L);
|
static int luaMonsterTypeGetName(lua_State* L);
|
||||||
static int luaMonsterTypeNameDescription(lua_State* L);
|
static int luaMonsterTypeGetNameDescription(lua_State* L);
|
||||||
|
|
||||||
static int luaMonsterTypeHealth(lua_State* L);
|
static int luaMonsterTypeGetHealth(lua_State* L);
|
||||||
static int luaMonsterTypeMaxHealth(lua_State* L);
|
static int luaMonsterTypeGetMaxHealth(lua_State* L);
|
||||||
static int luaMonsterTypeRunHealth(lua_State* L);
|
static int luaMonsterTypeGetRunHealth(lua_State* L);
|
||||||
static int luaMonsterTypeExperience(lua_State* L);
|
static int luaMonsterTypeGetExperience(lua_State* L);
|
||||||
|
|
||||||
static int luaMonsterTypeCombatImmunities(lua_State* L);
|
static int luaMonsterTypeGetCombatImmunities(lua_State* L);
|
||||||
static int luaMonsterTypeConditionImmunities(lua_State* L);
|
static int luaMonsterTypeGetConditionImmunities(lua_State* L);
|
||||||
|
|
||||||
static int luaMonsterTypeGetAttackList(lua_State* L);
|
static int luaMonsterTypeGetAttackList(lua_State* L);
|
||||||
static int luaMonsterTypeAddAttack(lua_State* L);
|
|
||||||
|
|
||||||
static int luaMonsterTypeGetDefenseList(lua_State* L);
|
static int luaMonsterTypeGetDefenseList(lua_State* L);
|
||||||
static int luaMonsterTypeAddDefense(lua_State* L);
|
|
||||||
|
|
||||||
static int luaMonsterTypeGetElementList(lua_State* L);
|
static int luaMonsterTypeGetElementList(lua_State* L);
|
||||||
static int luaMonsterTypeAddElement(lua_State* L);
|
|
||||||
|
|
||||||
static int luaMonsterTypeGetVoices(lua_State* L);
|
static int luaMonsterTypeGetVoices(lua_State* L);
|
||||||
static int luaMonsterTypeAddVoice(lua_State* L);
|
|
||||||
|
|
||||||
static int luaMonsterTypeGetLoot(lua_State* L);
|
static int luaMonsterTypeGetLoot(lua_State* L);
|
||||||
static int luaMonsterTypeAddLoot(lua_State* L);
|
|
||||||
|
|
||||||
static int luaMonsterTypeGetCreatureEvents(lua_State* L);
|
static int luaMonsterTypeGetCreatureEvents(lua_State* L);
|
||||||
static int luaMonsterTypeRegisterEvent(lua_State* L);
|
|
||||||
|
|
||||||
static int luaMonsterTypeEventOnCallback(lua_State* L);
|
|
||||||
static int luaMonsterTypeEventType(lua_State* L);
|
|
||||||
|
|
||||||
static int luaMonsterTypeGetSummonList(lua_State* L);
|
static int luaMonsterTypeGetSummonList(lua_State* L);
|
||||||
static int luaMonsterTypeAddSummon(lua_State* L);
|
static int luaMonsterTypeGetMaxSummons(lua_State* L);
|
||||||
|
|
||||||
static int luaMonsterTypeMaxSummons(lua_State* L);
|
static int luaMonsterTypeGetArmor(lua_State* L);
|
||||||
|
static int luaMonsterTypeGetDefense(lua_State* L);
|
||||||
|
static int luaMonsterTypeGetOutfit(lua_State* L);
|
||||||
|
static int luaMonsterTypeGetRace(lua_State* L);
|
||||||
|
static int luaMonsterTypeGetCorpseId(lua_State* L);
|
||||||
|
static int luaMonsterTypeGetManaCost(lua_State* L);
|
||||||
|
static int luaMonsterTypeGetBaseSpeed(lua_State* L);
|
||||||
|
static int luaMonsterTypeGetLight(lua_State* L);
|
||||||
|
|
||||||
static int luaMonsterTypeArmor(lua_State* L);
|
static int luaMonsterTypeGetTargetDistance(lua_State* L);
|
||||||
static int luaMonsterTypeDefense(lua_State* L);
|
static int luaMonsterTypeGetChangeTargetChance(lua_State* L);
|
||||||
static int luaMonsterTypeOutfit(lua_State* L);
|
static int luaMonsterTypeGetChangeTargetSpeed(lua_State* L);
|
||||||
static int luaMonsterTypeRace(lua_State* L);
|
|
||||||
static int luaMonsterTypeCorpseId(lua_State* L);
|
|
||||||
static int luaMonsterTypeManaCost(lua_State* L);
|
|
||||||
static int luaMonsterTypeBaseSpeed(lua_State* L);
|
|
||||||
static int luaMonsterTypeLight(lua_State* L);
|
|
||||||
|
|
||||||
static int luaMonsterTypeStaticAttackChance(lua_State* L);
|
|
||||||
static int luaMonsterTypeTargetDistance(lua_State* L);
|
|
||||||
static int luaMonsterTypeYellChance(lua_State* L);
|
|
||||||
static int luaMonsterTypeYellSpeedTicks(lua_State* L);
|
|
||||||
static int luaMonsterTypeChangeTargetChance(lua_State* L);
|
|
||||||
static int luaMonsterTypeChangeTargetSpeed(lua_State* L);
|
|
||||||
|
|
||||||
// Loot
|
|
||||||
static int luaCreateLoot(lua_State* L);
|
|
||||||
static int luaDeleteLoot(lua_State* L);
|
|
||||||
static int luaLootSetId(lua_State* L);
|
|
||||||
static int luaLootSetMaxCount(lua_State* L);
|
|
||||||
static int luaLootSetSubType(lua_State* L);
|
|
||||||
static int luaLootSetChance(lua_State* L);
|
|
||||||
static int luaLootSetActionId(lua_State* L);
|
|
||||||
static int luaLootSetDescription(lua_State* L);
|
|
||||||
static int luaLootAddChildLoot(lua_State* L);
|
|
||||||
|
|
||||||
// MonsterSpell
|
|
||||||
static int luaCreateMonsterSpell(lua_State* L);
|
|
||||||
static int luaDeleteMonsterSpell(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetType(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetScriptName(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetChance(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetInterval(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetRange(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetCombatValue(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetCombatType(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetAttackValue(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetNeedTarget(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetCombatLength(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetCombatSpread(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetCombatRadius(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetConditionType(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetConditionDamage(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetConditionSpeedChange(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetConditionDuration(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetConditionTickInterval(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetCombatShootEffect(lua_State* L);
|
|
||||||
static int luaMonsterSpellSetCombatEffect(lua_State* L);
|
|
||||||
|
|
||||||
// Party
|
// Party
|
||||||
static int luaPartyCreate(lua_State* L);
|
|
||||||
static int luaPartyDisband(lua_State* L);
|
static int luaPartyDisband(lua_State* L);
|
||||||
|
|
||||||
static int luaPartyGetLeader(lua_State* L);
|
static int luaPartyGetLeader(lua_State* L);
|
||||||
@@ -1341,142 +1192,21 @@ class LuaScriptInterface
|
|||||||
static int luaPartyShareExperience(lua_State* L);
|
static int luaPartyShareExperience(lua_State* L);
|
||||||
static int luaPartySetSharedExperience(lua_State* L);
|
static int luaPartySetSharedExperience(lua_State* L);
|
||||||
|
|
||||||
// Spells
|
|
||||||
static int luaSpellCreate(lua_State* L);
|
|
||||||
|
|
||||||
static int luaSpellOnCastSpell(lua_State* L);
|
|
||||||
static int luaSpellRegister(lua_State* L);
|
|
||||||
static int luaSpellName(lua_State* L);
|
|
||||||
static int luaSpellId(lua_State* L);
|
|
||||||
static int luaSpellGroup(lua_State* L);
|
|
||||||
static int luaSpellCooldown(lua_State* L);
|
|
||||||
static int luaSpellGroupCooldown(lua_State* L);
|
|
||||||
static int luaSpellLevel(lua_State* L);
|
|
||||||
static int luaSpellMagicLevel(lua_State* L);
|
|
||||||
static int luaSpellMana(lua_State* L);
|
|
||||||
static int luaSpellManaPercent(lua_State* L);
|
|
||||||
static int luaSpellSoul(lua_State* L);
|
|
||||||
static int luaSpellRange(lua_State* L);
|
|
||||||
static int luaSpellPremium(lua_State* L);
|
|
||||||
static int luaSpellEnabled(lua_State* L);
|
|
||||||
static int luaSpellNeedTarget(lua_State* L);
|
|
||||||
static int luaSpellNeedWeapon(lua_State* L);
|
|
||||||
static int luaSpellNeedLearn(lua_State* L);
|
|
||||||
static int luaSpellSelfTarget(lua_State* L);
|
|
||||||
static int luaSpellBlocking(lua_State* L);
|
|
||||||
static int luaSpellAggressive(lua_State* L);
|
|
||||||
static int luaSpellVocation(lua_State* L);
|
|
||||||
|
|
||||||
// only for InstantSpells
|
|
||||||
static int luaSpellWords(lua_State* L);
|
|
||||||
static int luaSpellNeedDirection(lua_State* L);
|
|
||||||
static int luaSpellHasParams(lua_State* L);
|
|
||||||
static int luaSpellHasPlayerNameParam(lua_State* L);
|
|
||||||
static int luaSpellNeedCasterTargetOrDirection(lua_State* L);
|
|
||||||
static int luaSpellIsBlockingWalls(lua_State* L);
|
|
||||||
|
|
||||||
// only for RuneSpells
|
|
||||||
static int luaSpellRuneId(lua_State* L);
|
|
||||||
static int luaSpellCharges(lua_State* L);
|
|
||||||
static int luaSpellAllowFarUse(lua_State* L);
|
|
||||||
static int luaSpellBlockWalls(lua_State* L);
|
|
||||||
static int luaSpellCheckFloor(lua_State* L);
|
|
||||||
|
|
||||||
// Actions
|
|
||||||
static int luaCreateAction(lua_State* L);
|
|
||||||
static int luaActionOnUse(lua_State* L);
|
|
||||||
static int luaActionRegister(lua_State* L);
|
|
||||||
static int luaActionItemId(lua_State* L);
|
|
||||||
static int luaActionActionId(lua_State* L);
|
|
||||||
static int luaActionUniqueId(lua_State* L);
|
|
||||||
static int luaActionAllowFarUse(lua_State* L);
|
|
||||||
static int luaActionBlockWalls(lua_State* L);
|
|
||||||
static int luaActionCheckFloor(lua_State* L);
|
|
||||||
|
|
||||||
// Talkactions
|
|
||||||
static int luaCreateTalkaction(lua_State* L);
|
|
||||||
static int luaTalkactionOnSay(lua_State* L);
|
|
||||||
static int luaTalkactionRegister(lua_State* L);
|
|
||||||
static int luaTalkactionSeparator(lua_State* L);
|
|
||||||
|
|
||||||
// CreatureEvents
|
|
||||||
static int luaCreateCreatureEvent(lua_State* L);
|
|
||||||
static int luaCreatureEventType(lua_State* L);
|
|
||||||
static int luaCreatureEventRegister(lua_State* L);
|
|
||||||
static int luaCreatureEventOnCallback(lua_State* L);
|
|
||||||
|
|
||||||
// MoveEvents
|
|
||||||
static int luaCreateMoveEvent(lua_State* L);
|
|
||||||
static int luaMoveEventType(lua_State* L);
|
|
||||||
static int luaMoveEventRegister(lua_State* L);
|
|
||||||
static int luaMoveEventOnCallback(lua_State* L);
|
|
||||||
static int luaMoveEventLevel(lua_State* L);
|
|
||||||
static int luaMoveEventSlot(lua_State* L);
|
|
||||||
static int luaMoveEventMagLevel(lua_State* L);
|
|
||||||
static int luaMoveEventPremium(lua_State* L);
|
|
||||||
static int luaMoveEventVocation(lua_State* L);
|
|
||||||
static int luaMoveEventItemId(lua_State* L);
|
|
||||||
static int luaMoveEventActionId(lua_State* L);
|
|
||||||
static int luaMoveEventUniqueId(lua_State* L);
|
|
||||||
static int luaMoveEventPosition(lua_State* L);
|
|
||||||
|
|
||||||
// GlobalEvents
|
|
||||||
static int luaCreateGlobalEvent(lua_State* L);
|
|
||||||
static int luaGlobalEventType(lua_State* L);
|
|
||||||
static int luaGlobalEventRegister(lua_State* L);
|
|
||||||
static int luaGlobalEventOnCallback(lua_State* L);
|
|
||||||
static int luaGlobalEventTime(lua_State* L);
|
|
||||||
static int luaGlobalEventInterval(lua_State* L);
|
|
||||||
|
|
||||||
// Weapon
|
|
||||||
static int luaCreateWeapon(lua_State* L);
|
|
||||||
static int luaWeaponId(lua_State* L);
|
|
||||||
static int luaWeaponLevel(lua_State* L);
|
|
||||||
static int luaWeaponMagicLevel(lua_State* L);
|
|
||||||
static int luaWeaponMana(lua_State* L);
|
|
||||||
static int luaWeaponManaPercent(lua_State* L);
|
|
||||||
static int luaWeaponHealth(lua_State* L);
|
|
||||||
static int luaWeaponHealthPercent(lua_State* L);
|
|
||||||
static int luaWeaponSoul(lua_State* L);
|
|
||||||
static int luaWeaponPremium(lua_State* L);
|
|
||||||
static int luaWeaponBreakChance(lua_State* L);
|
|
||||||
static int luaWeaponAction(lua_State* L);
|
|
||||||
static int luaWeaponUnproperly(lua_State* L);
|
|
||||||
static int luaWeaponVocation(lua_State* L);
|
|
||||||
static int luaWeaponOnUseWeapon(lua_State* L);
|
|
||||||
static int luaWeaponRegister(lua_State* L);
|
|
||||||
static int luaWeaponElement(lua_State* L);
|
|
||||||
static int luaWeaponAttack(lua_State* L);
|
|
||||||
static int luaWeaponDefense(lua_State* L);
|
|
||||||
static int luaWeaponRange(lua_State* L);
|
|
||||||
static int luaWeaponCharges(lua_State* L);
|
|
||||||
static int luaWeaponDuration(lua_State* L);
|
|
||||||
static int luaWeaponDecayTo(lua_State* L);
|
|
||||||
static int luaWeaponTransformEquipTo(lua_State* L);
|
|
||||||
static int luaWeaponTransformDeEquipTo(lua_State* L);
|
|
||||||
static int luaWeaponSlotType(lua_State* L);
|
|
||||||
static int luaWeaponHitChance(lua_State* L);
|
|
||||||
static int luaWeaponExtraElement(lua_State* L);
|
|
||||||
|
|
||||||
// exclusively for distance weapons
|
|
||||||
static int luaWeaponMaxHitChance(lua_State* L);
|
|
||||||
static int luaWeaponAmmoType(lua_State* L);
|
|
||||||
|
|
||||||
// exclusively for wands
|
|
||||||
static int luaWeaponWandDamage(lua_State* L);
|
|
||||||
|
|
||||||
// exclusively for wands & distance weapons
|
|
||||||
static int luaWeaponShootType(lua_State* L);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
lua_State* luaState = nullptr;
|
||||||
std::string lastLuaError;
|
std::string lastLuaError;
|
||||||
|
|
||||||
std::string interfaceName;
|
std::string interfaceName;
|
||||||
|
int32_t eventTableRef = -1;
|
||||||
|
|
||||||
static ScriptEnvironment scriptEnv[16];
|
static ScriptEnvironment scriptEnv[16];
|
||||||
static int32_t scriptEnvIndex;
|
static int32_t scriptEnvIndex;
|
||||||
|
|
||||||
|
int32_t runningEventId = EVENT_ID_USER;
|
||||||
std::string loadingFile;
|
std::string loadingFile;
|
||||||
|
|
||||||
|
//script file cache
|
||||||
|
std::map<int32_t, std::string> cacheFiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
class LuaEnvironment : public LuaScriptInterface
|
class LuaEnvironment : public LuaScriptInterface
|
||||||
@@ -1489,9 +1219,9 @@ class LuaEnvironment : public LuaScriptInterface
|
|||||||
LuaEnvironment(const LuaEnvironment&) = delete;
|
LuaEnvironment(const LuaEnvironment&) = delete;
|
||||||
LuaEnvironment& operator=(const LuaEnvironment&) = delete;
|
LuaEnvironment& operator=(const LuaEnvironment&) = delete;
|
||||||
|
|
||||||
bool initState() override;
|
bool initState();
|
||||||
bool reInitState();
|
bool reInitState();
|
||||||
bool closeState() override;
|
bool closeState();
|
||||||
|
|
||||||
LuaScriptInterface* getTestInterface();
|
LuaScriptInterface* getTestInterface();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,7 +21,9 @@
|
|||||||
|
|
||||||
#include "mailbox.h"
|
#include "mailbox.h"
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
#include "player.h"
|
||||||
#include "iologindata.h"
|
#include "iologindata.h"
|
||||||
|
#include "town.h"
|
||||||
|
|
||||||
extern Game g_game;
|
extern Game g_game;
|
||||||
|
|
||||||
@@ -91,22 +93,30 @@ void Mailbox::postRemoveNotification(Thing* thing, const Cylinder* newParent, in
|
|||||||
bool Mailbox::sendItem(Item* item) const
|
bool Mailbox::sendItem(Item* item) const
|
||||||
{
|
{
|
||||||
std::string receiver;
|
std::string receiver;
|
||||||
if (!getReceiver(item, receiver)) {
|
std::string townName;
|
||||||
|
if (!getDestination(item, receiver, townName)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**No need to continue if its still empty**/
|
if (receiver.empty() || townName.empty()) {
|
||||||
if (receiver.empty()) {
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Town* town = g_game.map.towns.getTown(townName);
|
||||||
|
if (!town) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player* player = g_game.getPlayerByName(receiver);
|
Player* player = g_game.getPlayerByName(receiver);
|
||||||
if (player) {
|
if (player) {
|
||||||
if (g_game.internalMoveItem(item->getParent(), player->getInbox(), INDEX_WHEREEVER,
|
DepotLocker* depotLocker = player->getDepotLocker(town->getID(), true);
|
||||||
item, item->getItemCount(), nullptr, FLAG_NOLIMIT) == RETURNVALUE_NOERROR) {
|
if (depotLocker) {
|
||||||
g_game.transformItem(item, item->getID() + 1);
|
if (g_game.internalMoveItem(item->getParent(), depotLocker, INDEX_WHEREEVER,
|
||||||
player->onReceiveMail();
|
item, item->getItemCount(), nullptr, FLAG_NOLIMIT) == RETURNVALUE_NOERROR) {
|
||||||
return true;
|
g_game.transformItem(item, item->getID() + 1);
|
||||||
|
player->onReceiveMail(town->getID());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Player tmpPlayer(nullptr);
|
Player tmpPlayer(nullptr);
|
||||||
@@ -114,25 +124,30 @@ bool Mailbox::sendItem(Item* item) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_game.internalMoveItem(item->getParent(), tmpPlayer.getInbox(), INDEX_WHEREEVER,
|
DepotLocker* depotLocker = tmpPlayer.getDepotLocker(town->getID(), true);
|
||||||
item, item->getItemCount(), nullptr, FLAG_NOLIMIT) == RETURNVALUE_NOERROR) {
|
if (depotLocker) {
|
||||||
g_game.transformItem(item, item->getID() + 1);
|
if (g_game.internalMoveItem(item->getParent(), depotLocker, INDEX_WHEREEVER,
|
||||||
IOLoginData::savePlayer(&tmpPlayer);
|
item, item->getItemCount(), nullptr, FLAG_NOLIMIT) == RETURNVALUE_NOERROR) {
|
||||||
return true;
|
g_game.transformItem(item, item->getID() + 1);
|
||||||
|
IOLoginData::savePlayer(&tmpPlayer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mailbox::getReceiver(Item* item, std::string& name) const
|
bool Mailbox::getDestination(Item* item, std::string& name, std::string& town) const
|
||||||
{
|
{
|
||||||
const Container* container = item->getContainer();
|
const Container* container = item->getContainer();
|
||||||
if (container) {
|
if (container) {
|
||||||
for (Item* containerItem : container->getItemList()) {
|
for (Item* containerItem : container->getItemList()) {
|
||||||
if (containerItem->getID() == ITEM_LABEL && getReceiver(containerItem, name)) {
|
if (containerItem->getID() == ITEM_LABEL && getDestination(containerItem, name, town)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,8 +156,24 @@ bool Mailbox::getReceiver(Item* item, std::string& name) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = getFirstLine(text);
|
std::istringstream iss(text, std::istringstream::in);
|
||||||
|
std::string temp;
|
||||||
|
uint32_t currentLine = 1;
|
||||||
|
|
||||||
|
while (getline(iss, temp, '\n')) {
|
||||||
|
if (currentLine == 1) {
|
||||||
|
name = temp;
|
||||||
|
} else if (currentLine == 2) {
|
||||||
|
town = temp;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++currentLine;
|
||||||
|
}
|
||||||
|
|
||||||
trimString(name);
|
trimString(name);
|
||||||
|
trimString(town);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -29,35 +29,35 @@ class Mailbox final : public Item, public Cylinder
|
|||||||
public:
|
public:
|
||||||
explicit Mailbox(uint16_t itemId) : Item(itemId) {}
|
explicit Mailbox(uint16_t itemId) : Item(itemId) {}
|
||||||
|
|
||||||
Mailbox* getMailbox() override {
|
Mailbox* getMailbox() final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
const Mailbox* getMailbox() const override {
|
const Mailbox* getMailbox() const final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
//cylinder implementations
|
//cylinder implementations
|
||||||
ReturnValue queryAdd(int32_t index, const Thing& thing, uint32_t count,
|
ReturnValue queryAdd(int32_t index, const Thing& thing, uint32_t count,
|
||||||
uint32_t flags, Creature* actor = nullptr) const override;
|
uint32_t flags, Creature* actor = nullptr) const final;
|
||||||
ReturnValue queryMaxCount(int32_t index, const Thing& thing, uint32_t count,
|
ReturnValue queryMaxCount(int32_t index, const Thing& thing, uint32_t count,
|
||||||
uint32_t& maxQueryCount, uint32_t flags) const override;
|
uint32_t& maxQueryCount, uint32_t flags) const final;
|
||||||
ReturnValue queryRemove(const Thing& thing, uint32_t count, uint32_t flags) const override;
|
ReturnValue queryRemove(const Thing& thing, uint32_t count, uint32_t flags) const final;
|
||||||
Cylinder* queryDestination(int32_t& index, const Thing& thing, Item** destItem,
|
Cylinder* queryDestination(int32_t& index, const Thing& thing, Item** destItem,
|
||||||
uint32_t& flags) override;
|
uint32_t& flags) final;
|
||||||
|
|
||||||
void addThing(Thing* thing) override;
|
void addThing(Thing* thing) final;
|
||||||
void addThing(int32_t index, Thing* thing) override;
|
void addThing(int32_t index, Thing* thing) final;
|
||||||
|
|
||||||
void updateThing(Thing* thing, uint16_t itemId, uint32_t count) override;
|
void updateThing(Thing* thing, uint16_t itemId, uint32_t count) final;
|
||||||
void replaceThing(uint32_t index, Thing* thing) override;
|
void replaceThing(uint32_t index, Thing* thing) final;
|
||||||
|
|
||||||
void removeThing(Thing* thing, uint32_t count) override;
|
void removeThing(Thing* thing, uint32_t count) final;
|
||||||
|
|
||||||
void postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
|
void postAddNotification(Thing* thing, const Cylinder* oldParent, int32_t index, cylinderlink_t link = LINK_OWNER) final;
|
||||||
void postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t link = LINK_OWNER) override;
|
void postRemoveNotification(Thing* thing, const Cylinder* newParent, int32_t index, cylinderlink_t link = LINK_OWNER) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool getReceiver(Item* item, std::string& name) const;
|
bool getDestination(Item* item, std::string& name, std::string& town) const;
|
||||||
bool sendItem(Item* item) const;
|
bool sendItem(Item* item) const;
|
||||||
|
|
||||||
static bool canSend(const Item* item);
|
static bool canSend(const Item* item);
|
||||||
|
|||||||
83
src/map.cpp
83
src/map.cpp
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
#include "iomapserialize.h"
|
#include "iomapserialize.h"
|
||||||
#include "combat.h"
|
#include "combat.h"
|
||||||
#include "creature.h"
|
#include "creature.h"
|
||||||
|
#include "monster.h"
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
|
||||||
extern Game g_game;
|
extern Game g_game;
|
||||||
@@ -35,6 +36,7 @@ bool Map::loadMap(const std::string& identifier, bool loadHouses)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Npcs::loadNpcs();
|
||||||
if (!IOMap::loadSpawns(this)) {
|
if (!IOMap::loadSpawns(this)) {
|
||||||
std::cout << "[Warning - Map::loadMap] Failed to load spawn data." << std::endl;
|
std::cout << "[Warning - Map::loadMap] Failed to load spawn data." << std::endl;
|
||||||
}
|
}
|
||||||
@@ -161,7 +163,14 @@ bool Map::placeCreature(const Position& centerPos, Creature* creature, bool exte
|
|||||||
Tile* tile = getTile(centerPos.x, centerPos.y, centerPos.z);
|
Tile* tile = getTile(centerPos.x, centerPos.y, centerPos.z);
|
||||||
if (tile) {
|
if (tile) {
|
||||||
placeInPZ = tile->hasFlag(TILESTATE_PROTECTIONZONE);
|
placeInPZ = tile->hasFlag(TILESTATE_PROTECTIONZONE);
|
||||||
ReturnValue ret = tile->queryAdd(0, *creature, 1, FLAG_IGNOREBLOCKITEM);
|
|
||||||
|
ReturnValue ret;
|
||||||
|
if (creature->getPlayer()) {
|
||||||
|
ret = tile->queryAdd(0, *creature, 1, 0);
|
||||||
|
} else {
|
||||||
|
ret = tile->queryAdd(0, *creature, 1, (creature->getMonster() ? FLAG_PLACECHECK : FLAG_IGNOREBLOCKITEM));
|
||||||
|
}
|
||||||
|
|
||||||
foundTile = forceLogin || ret == RETURNVALUE_NOERROR || ret == RETURNVALUE_PLAYERISNOTINVITED;
|
foundTile = forceLogin || ret == RETURNVALUE_NOERROR || ret == RETURNVALUE_PLAYERISNOTINVITED;
|
||||||
} else {
|
} else {
|
||||||
placeInPZ = false;
|
placeInPZ = false;
|
||||||
@@ -200,7 +209,7 @@ bool Map::placeCreature(const Position& centerPos, Creature* creature, bool exte
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tile->queryAdd(0, *creature, 1, 0) == RETURNVALUE_NOERROR) {
|
if (tile->queryAdd(0, *creature, 1, (creature->getMonster() ? FLAG_PLACECHECK : 0)) == RETURNVALUE_NOERROR) {
|
||||||
if (!extendedPos || isSightClear(centerPos, tryPos, false)) {
|
if (!extendedPos || isSightClear(centerPos, tryPos, false)) {
|
||||||
foundTile = true;
|
foundTile = true;
|
||||||
break;
|
break;
|
||||||
@@ -234,13 +243,12 @@ void Map::moveCreature(Creature& creature, Tile& newTile, bool forceTeleport/* =
|
|||||||
|
|
||||||
bool teleport = forceTeleport || !newTile.getGround() || !Position::areInRange<1, 1, 0>(oldPos, newPos);
|
bool teleport = forceTeleport || !newTile.getGround() || !Position::areInRange<1, 1, 0>(oldPos, newPos);
|
||||||
|
|
||||||
SpectatorVec spectators, newPosSpectators;
|
SpectatorVec list;
|
||||||
getSpectators(spectators, oldPos, true);
|
getSpectators(list, oldPos, true);
|
||||||
getSpectators(newPosSpectators, newPos, true);
|
getSpectators(list, newPos, true);
|
||||||
spectators.addSpectators(newPosSpectators);
|
|
||||||
|
|
||||||
std::vector<int32_t> oldStackPosVector;
|
std::vector<int32_t> oldStackPosVector;
|
||||||
for (Creature* spectator : spectators) {
|
for (Creature* spectator : list) {
|
||||||
if (Player* tmpPlayer = spectator->getPlayer()) {
|
if (Player* tmpPlayer = spectator->getPlayer()) {
|
||||||
if (tmpPlayer->canSeeCreature(&creature)) {
|
if (tmpPlayer->canSeeCreature(&creature)) {
|
||||||
oldStackPosVector.push_back(oldTile.getClientIndexOfCreature(tmpPlayer, &creature));
|
oldStackPosVector.push_back(oldTile.getClientIndexOfCreature(tmpPlayer, &creature));
|
||||||
@@ -281,7 +289,7 @@ void Map::moveCreature(Creature& creature, Tile& newTile, bool forceTeleport/* =
|
|||||||
|
|
||||||
//send to client
|
//send to client
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (Creature* spectator : spectators) {
|
for (Creature* spectator : list) {
|
||||||
if (Player* tmpPlayer = spectator->getPlayer()) {
|
if (Player* tmpPlayer = spectator->getPlayer()) {
|
||||||
//Use the correct stackpos
|
//Use the correct stackpos
|
||||||
int32_t stackpos = oldStackPosVector[i++];
|
int32_t stackpos = oldStackPosVector[i++];
|
||||||
@@ -292,7 +300,7 @@ void Map::moveCreature(Creature& creature, Tile& newTile, bool forceTeleport/* =
|
|||||||
}
|
}
|
||||||
|
|
||||||
//event method
|
//event method
|
||||||
for (Creature* spectator : spectators) {
|
for (Creature* spectator : list) {
|
||||||
spectator->onCreatureMove(&creature, &newTile, newPos, &oldTile, oldPos, teleport);
|
spectator->onCreatureMove(&creature, &newTile, newPos, &oldTile, oldPos, teleport);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,7 +308,7 @@ void Map::moveCreature(Creature& creature, Tile& newTile, bool forceTeleport/* =
|
|||||||
newTile.postAddNotification(&creature, &oldTile, 0);
|
newTile.postAddNotification(&creature, &oldTile, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::getSpectatorsInternal(SpectatorVec& spectators, const Position& centerPos, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY, int32_t minRangeZ, int32_t maxRangeZ, bool onlyPlayers) const
|
void Map::getSpectatorsInternal(SpectatorVec& list, const Position& centerPos, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY, int32_t minRangeZ, int32_t maxRangeZ, bool onlyPlayers) const
|
||||||
{
|
{
|
||||||
int_fast16_t min_y = centerPos.y + minRangeY;
|
int_fast16_t min_y = centerPos.y + minRangeY;
|
||||||
int_fast16_t min_x = centerPos.x + minRangeX;
|
int_fast16_t min_x = centerPos.x + minRangeX;
|
||||||
@@ -340,7 +348,7 @@ void Map::getSpectatorsInternal(SpectatorVec& spectators, const Position& center
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
spectators.emplace_back(creature);
|
list.insert(creature);
|
||||||
}
|
}
|
||||||
leafE = leafE->leafE;
|
leafE = leafE->leafE;
|
||||||
} else {
|
} else {
|
||||||
@@ -356,7 +364,7 @@ void Map::getSpectatorsInternal(SpectatorVec& spectators, const Position& center
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Map::getSpectators(SpectatorVec& spectators, const Position& centerPos, bool multifloor /*= false*/, bool onlyPlayers /*= false*/, int32_t minRangeX /*= 0*/, int32_t maxRangeX /*= 0*/, int32_t minRangeY /*= 0*/, int32_t maxRangeY /*= 0*/)
|
void Map::getSpectators(SpectatorVec& list, const Position& centerPos, bool multifloor /*= false*/, bool onlyPlayers /*= false*/, int32_t minRangeX /*= 0*/, int32_t maxRangeX /*= 0*/, int32_t minRangeY /*= 0*/, int32_t maxRangeY /*= 0*/)
|
||||||
{
|
{
|
||||||
if (centerPos.z >= MAP_MAX_LAYERS) {
|
if (centerPos.z >= MAP_MAX_LAYERS) {
|
||||||
return;
|
return;
|
||||||
@@ -374,11 +382,11 @@ void Map::getSpectators(SpectatorVec& spectators, const Position& centerPos, boo
|
|||||||
if (onlyPlayers) {
|
if (onlyPlayers) {
|
||||||
auto it = playersSpectatorCache.find(centerPos);
|
auto it = playersSpectatorCache.find(centerPos);
|
||||||
if (it != playersSpectatorCache.end()) {
|
if (it != playersSpectatorCache.end()) {
|
||||||
if (!spectators.empty()) {
|
if (!list.empty()) {
|
||||||
const SpectatorVec& cachedSpectators = it->second;
|
const SpectatorVec& cachedList = it->second;
|
||||||
spectators.insert(spectators.end(), cachedSpectators.begin(), cachedSpectators.end());
|
list.insert(cachedList.begin(), cachedList.end());
|
||||||
} else {
|
} else {
|
||||||
spectators = it->second;
|
list = it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
foundCache = true;
|
foundCache = true;
|
||||||
@@ -389,17 +397,17 @@ void Map::getSpectators(SpectatorVec& spectators, const Position& centerPos, boo
|
|||||||
auto it = spectatorCache.find(centerPos);
|
auto it = spectatorCache.find(centerPos);
|
||||||
if (it != spectatorCache.end()) {
|
if (it != spectatorCache.end()) {
|
||||||
if (!onlyPlayers) {
|
if (!onlyPlayers) {
|
||||||
if (!spectators.empty()) {
|
if (!list.empty()) {
|
||||||
const SpectatorVec& cachedSpectators = it->second;
|
const SpectatorVec& cachedList = it->second;
|
||||||
spectators.insert(spectators.end(), cachedSpectators.begin(), cachedSpectators.end());
|
list.insert(cachedList.begin(), cachedList.end());
|
||||||
} else {
|
} else {
|
||||||
spectators = it->second;
|
list = it->second;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const SpectatorVec& cachedSpectators = it->second;
|
const SpectatorVec& cachedList = it->second;
|
||||||
for (Creature* spectator : cachedSpectators) {
|
for (Creature* spectator : cachedList) {
|
||||||
if (spectator->getPlayer()) {
|
if (spectator->getPlayer()) {
|
||||||
spectators.emplace_back(spectator);
|
list.insert(spectator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -437,13 +445,13 @@ void Map::getSpectators(SpectatorVec& spectators, const Position& centerPos, boo
|
|||||||
maxRangeZ = centerPos.z;
|
maxRangeZ = centerPos.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
getSpectatorsInternal(spectators, centerPos, minRangeX, maxRangeX, minRangeY, maxRangeY, minRangeZ, maxRangeZ, onlyPlayers);
|
getSpectatorsInternal(list, centerPos, minRangeX, maxRangeX, minRangeY, maxRangeY, minRangeZ, maxRangeZ, onlyPlayers);
|
||||||
|
|
||||||
if (cacheResult) {
|
if (cacheResult) {
|
||||||
if (onlyPlayers) {
|
if (onlyPlayers) {
|
||||||
playersSpectatorCache[centerPos] = spectators;
|
playersSpectatorCache[centerPos] = list;
|
||||||
} else {
|
} else {
|
||||||
spectatorCache[centerPos] = spectators;
|
spectatorCache[centerPos] = list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -452,10 +460,6 @@ void Map::getSpectators(SpectatorVec& spectators, const Position& centerPos, boo
|
|||||||
void Map::clearSpectatorCache()
|
void Map::clearSpectatorCache()
|
||||||
{
|
{
|
||||||
spectatorCache.clear();
|
spectatorCache.clear();
|
||||||
}
|
|
||||||
|
|
||||||
void Map::clearPlayersSpectatorCache()
|
|
||||||
{
|
|
||||||
playersSpectatorCache.clear();
|
playersSpectatorCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,7 +563,7 @@ const Tile* Map::canWalkTo(const Creature& creature, const Position& pos) const
|
|||||||
//used for non-cached tiles
|
//used for non-cached tiles
|
||||||
Tile* tile = getTile(pos.x, pos.y, pos.z);
|
Tile* tile = getTile(pos.x, pos.y, pos.z);
|
||||||
if (creature.getTile() != tile) {
|
if (creature.getTile() != tile) {
|
||||||
if (!tile || tile->queryAdd(0, creature, 1, FLAG_PATHFINDING | FLAG_IGNOREFIELDDAMAGE) != RETURNVALUE_NOERROR) {
|
if (!tile || tile->queryAdd(0, creature, 1, FLAG_PATHFINDING) != RETURNVALUE_NOERROR) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -842,16 +846,25 @@ int_fast32_t AStarNodes::getTileWalkCost(const Creature& creature, const Tile* t
|
|||||||
{
|
{
|
||||||
int_fast32_t cost = 0;
|
int_fast32_t cost = 0;
|
||||||
if (tile->getTopVisibleCreature(&creature) != nullptr) {
|
if (tile->getTopVisibleCreature(&creature) != nullptr) {
|
||||||
|
if (const Monster* monster = creature.getMonster()) {
|
||||||
|
if (monster->canPushCreatures()) {
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//destroy creature cost
|
//destroy creature cost
|
||||||
cost += MAP_NORMALWALKCOST * 3;
|
cost += MAP_NORMALWALKCOST * 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const MagicField* field = tile->getFieldItem()) {
|
if (const MagicField* field = tile->getFieldItem()) {
|
||||||
CombatType_t combatType = field->getCombatType();
|
CombatType_t combatType = field->getCombatType();
|
||||||
if (!creature.isImmune(combatType) && !creature.hasCondition(Combat::DamageToConditionType(combatType))) {
|
if (combatType != COMBAT_NONE) {
|
||||||
cost += MAP_NORMALWALKCOST * 18;
|
if (!creature.isImmune(combatType) && !creature.hasCondition(Combat::DamageToConditionType(combatType))) {
|
||||||
|
cost += MAP_NORMALWALKCOST * 18;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
src/map.h
25
src/map.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -73,7 +73,7 @@ class AStarNodes
|
|||||||
int_fast32_t closedNodes;
|
int_fast32_t closedNodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
using SpectatorCache = std::map<Position, SpectatorVec>;
|
typedef std::map<Position, SpectatorVec> SpectatorCache;
|
||||||
|
|
||||||
static constexpr int32_t FLOOR_BITS = 3;
|
static constexpr int32_t FLOOR_BITS = 3;
|
||||||
static constexpr int32_t FLOOR_SIZE = (1 << FLOOR_BITS);
|
static constexpr int32_t FLOOR_SIZE = (1 << FLOOR_BITS);
|
||||||
@@ -110,7 +110,7 @@ class QTreeNode
|
|||||||
QTreeLeafNode* getLeaf(uint32_t x, uint32_t y);
|
QTreeLeafNode* getLeaf(uint32_t x, uint32_t y);
|
||||||
|
|
||||||
template<typename Leaf, typename Node>
|
template<typename Leaf, typename Node>
|
||||||
static Leaf getLeafStatic(Node node, uint32_t x, uint32_t y)
|
inline static Leaf getLeafStatic(Node node, uint32_t x, uint32_t y)
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
node = node->child[((x & 0x8000) >> 15) | ((y & 0x8000) >> 14)];
|
node = node->child[((x & 0x8000) >> 15) | ((y & 0x8000) >> 14)];
|
||||||
@@ -127,11 +127,10 @@ class QTreeNode
|
|||||||
QTreeLeafNode* createLeaf(uint32_t x, uint32_t y, uint32_t level);
|
QTreeLeafNode* createLeaf(uint32_t x, uint32_t y, uint32_t level);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool leaf = false;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QTreeNode* child[4] = {};
|
QTreeNode* child[4] = {};
|
||||||
|
|
||||||
|
bool leaf = false;
|
||||||
|
|
||||||
friend class Map;
|
friend class Map;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -153,7 +152,7 @@ class QTreeLeafNode final : public QTreeNode
|
|||||||
void addCreature(Creature* c);
|
void addCreature(Creature* c);
|
||||||
void removeCreature(Creature* c);
|
void removeCreature(Creature* c);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
static bool newLeaf;
|
static bool newLeaf;
|
||||||
QTreeLeafNode* leafS = nullptr;
|
QTreeLeafNode* leafS = nullptr;
|
||||||
QTreeLeafNode* leafE = nullptr;
|
QTreeLeafNode* leafE = nullptr;
|
||||||
@@ -197,7 +196,7 @@ class Map
|
|||||||
* \returns A pointer to that tile.
|
* \returns A pointer to that tile.
|
||||||
*/
|
*/
|
||||||
Tile* getTile(uint16_t x, uint16_t y, uint8_t z) const;
|
Tile* getTile(uint16_t x, uint16_t y, uint8_t z) const;
|
||||||
Tile* getTile(const Position& pos) const {
|
inline Tile* getTile(const Position& pos) const {
|
||||||
return getTile(pos.x, pos.y, pos.z);
|
return getTile(pos.x, pos.y, pos.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,12 +219,11 @@ class Map
|
|||||||
|
|
||||||
void moveCreature(Creature& creature, Tile& newTile, bool forceTeleport = false);
|
void moveCreature(Creature& creature, Tile& newTile, bool forceTeleport = false);
|
||||||
|
|
||||||
void getSpectators(SpectatorVec& spectators, const Position& centerPos, bool multifloor = false, bool onlyPlayers = false,
|
void getSpectators(SpectatorVec& list, const Position& centerPos, bool multifloor = false, bool onlyPlayers = false,
|
||||||
int32_t minRangeX = 0, int32_t maxRangeX = 0,
|
int32_t minRangeX = 0, int32_t maxRangeX = 0,
|
||||||
int32_t minRangeY = 0, int32_t maxRangeY = 0);
|
int32_t minRangeY = 0, int32_t maxRangeY = 0);
|
||||||
|
|
||||||
void clearSpectatorCache();
|
void clearSpectatorCache();
|
||||||
void clearPlayersSpectatorCache();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if you can throw an object to that position
|
* Checks if you can throw an object to that position
|
||||||
@@ -264,8 +262,7 @@ class Map
|
|||||||
Spawns spawns;
|
Spawns spawns;
|
||||||
Towns towns;
|
Towns towns;
|
||||||
Houses houses;
|
Houses houses;
|
||||||
|
protected:
|
||||||
private:
|
|
||||||
SpectatorCache spectatorCache;
|
SpectatorCache spectatorCache;
|
||||||
SpectatorCache playersSpectatorCache;
|
SpectatorCache playersSpectatorCache;
|
||||||
|
|
||||||
@@ -278,7 +275,7 @@ class Map
|
|||||||
uint32_t height = 0;
|
uint32_t height = 0;
|
||||||
|
|
||||||
// Actually scans the map for spectators
|
// Actually scans the map for spectators
|
||||||
void getSpectatorsInternal(SpectatorVec& spectators, const Position& centerPos,
|
void getSpectatorsInternal(SpectatorVec& list, const Position& centerPos,
|
||||||
int32_t minRangeX, int32_t maxRangeX,
|
int32_t minRangeX, int32_t maxRangeX,
|
||||||
int32_t minRangeY, int32_t maxRangeY,
|
int32_t minRangeY, int32_t maxRangeY,
|
||||||
int32_t minRangeZ, int32_t maxRangeZ, bool onlyPlayers) const;
|
int32_t minRangeZ, int32_t maxRangeZ, bool onlyPlayers) const;
|
||||||
|
|||||||
677
src/monster.cpp
677
src/monster.cpp
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,11 +22,11 @@
|
|||||||
#include "monster.h"
|
#include "monster.h"
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
#include "spells.h"
|
#include "spells.h"
|
||||||
#include "events.h"
|
#include "configmanager.h"
|
||||||
|
|
||||||
|
extern ConfigManager g_config;
|
||||||
extern Game g_game;
|
extern Game g_game;
|
||||||
extern Monsters g_monsters;
|
extern Monsters g_monsters;
|
||||||
extern Events* g_events;
|
|
||||||
|
|
||||||
int32_t Monster::despawnRange;
|
int32_t Monster::despawnRange;
|
||||||
int32_t Monster::despawnRadius;
|
int32_t Monster::despawnRadius;
|
||||||
@@ -42,10 +42,10 @@ Monster* Monster::createMonster(const std::string& name)
|
|||||||
return new Monster(mType);
|
return new Monster(mType);
|
||||||
}
|
}
|
||||||
|
|
||||||
Monster::Monster(MonsterType* mType) :
|
Monster::Monster(MonsterType* mtype) :
|
||||||
Creature(),
|
Creature(),
|
||||||
strDescription(mType->nameDescription),
|
strDescription(asLowerCaseString(mtype->nameDescription)),
|
||||||
mType(mType)
|
mType(mtype)
|
||||||
{
|
{
|
||||||
defaultOutfit = mType->info.outfit;
|
defaultOutfit = mType->info.outfit;
|
||||||
currentOutfit = mType->info.outfit;
|
currentOutfit = mType->info.outfit;
|
||||||
@@ -80,31 +80,45 @@ void Monster::removeList()
|
|||||||
g_game.removeMonster(this);
|
g_game.removeMonster(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t Monster::getDefense()
|
||||||
|
{
|
||||||
|
int32_t totalDefense = mType->info.defense + 1;
|
||||||
|
int32_t defenseSkill = mType->info.skill;
|
||||||
|
|
||||||
|
fightMode_t attackMode = FIGHTMODE_BALANCED;
|
||||||
|
|
||||||
|
if ((followCreature || !attackedCreature) && earliestAttackTime <= OTSYS_TIME()) {
|
||||||
|
attackMode = FIGHTMODE_DEFENSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attackMode == FIGHTMODE_ATTACK) {
|
||||||
|
totalDefense -= 4 * totalDefense / 10;
|
||||||
|
} else if (attackMode == FIGHTMODE_DEFENSE) {
|
||||||
|
totalDefense += 8 * totalDefense / 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalDefense) {
|
||||||
|
int32_t formula = (5 * (defenseSkill) + 50) * totalDefense;
|
||||||
|
int32_t randresult = rand() % 100;
|
||||||
|
|
||||||
|
totalDefense = formula * ((rand() % 100 + randresult) / 2) / 10000.;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalDefense;
|
||||||
|
}
|
||||||
|
|
||||||
bool Monster::canSee(const Position& pos) const
|
bool Monster::canSee(const Position& pos) const
|
||||||
{
|
{
|
||||||
return Creature::canSee(getPosition(), pos, 9, 9);
|
return Creature::canSee(getPosition(), pos, 9, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Monster::canWalkOnFieldType(CombatType_t combatType) const
|
void Monster::onAttackedCreature(Creature* creature)
|
||||||
{
|
{
|
||||||
switch (combatType) {
|
if (isSummon() && getMaster()) {
|
||||||
case COMBAT_ENERGYDAMAGE:
|
master->onAttackedCreature(creature);
|
||||||
return mType->info.canWalkOnEnergy;
|
|
||||||
case COMBAT_FIREDAMAGE:
|
|
||||||
return mType->info.canWalkOnFire;
|
|
||||||
case COMBAT_EARTHDAMAGE:
|
|
||||||
return mType->info.canWalkOnPoison;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Monster::onAttackedCreatureDisappear(bool)
|
|
||||||
{
|
|
||||||
attackTicks = 0;
|
|
||||||
extraMeleeAttack = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Monster::onCreatureAppear(Creature* creature, bool isLogin)
|
void Monster::onCreatureAppear(Creature* creature, bool isLogin)
|
||||||
{
|
{
|
||||||
Creature::onCreatureAppear(creature, isLogin);
|
Creature::onCreatureAppear(creature, isLogin);
|
||||||
@@ -238,7 +252,7 @@ void Monster::onCreatureMove(Creature* creature, const Tile* newTile, const Posi
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (canSeeNewPos && isSummon() && getMaster() == creature) {
|
if (canSeeNewPos && isSummon() && getMaster() == creature) {
|
||||||
isMasterInRange = true; //Follow master again
|
isMasterInRange = true; //Follow master again
|
||||||
}
|
}
|
||||||
|
|
||||||
updateIdleStatus();
|
updateIdleStatus();
|
||||||
@@ -250,7 +264,7 @@ void Monster::onCreatureMove(Creature* creature, const Tile* newTile, const Posi
|
|||||||
|
|
||||||
int32_t offset_x = Position::getDistanceX(followPosition, position);
|
int32_t offset_x = Position::getDistanceX(followPosition, position);
|
||||||
int32_t offset_y = Position::getDistanceY(followPosition, position);
|
int32_t offset_y = Position::getDistanceY(followPosition, position);
|
||||||
if ((offset_x > 1 || offset_y > 1) && mType->info.changeTargetChance > 0) {
|
if ((offset_x > 1 || offset_y > 1) && mType->info.changeTargetChance > 0 && targetChangeCooldown <= 0) {
|
||||||
Direction dir = getDirectionTo(position, followPosition);
|
Direction dir = getDirectionTo(position, followPosition);
|
||||||
const Position& checkPosition = getNextPosition(dir, position);
|
const Position& checkPosition = getNextPosition(dir, position);
|
||||||
|
|
||||||
@@ -365,10 +379,10 @@ void Monster::updateTargetList()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SpectatorVec spectators;
|
SpectatorVec list;
|
||||||
g_game.map.getSpectators(spectators, position, true);
|
g_game.map.getSpectators(list, position, true);
|
||||||
spectators.erase(this);
|
list.erase(this);
|
||||||
for (Creature* spectator : spectators) {
|
for (Creature* spectator : list) {
|
||||||
if (canSee(spectator->getPosition())) {
|
if (canSee(spectator->getPosition())) {
|
||||||
onCreatureFound(spectator);
|
onCreatureFound(spectator);
|
||||||
}
|
}
|
||||||
@@ -481,14 +495,14 @@ void Monster::onCreatureLeave(Creature* creature)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Monster::searchTarget(TargetSearchType_t searchType /*= TARGETSEARCH_DEFAULT*/)
|
bool Monster::searchTarget(TargetSearchType_t searchType)
|
||||||
{
|
{
|
||||||
std::list<Creature*> resultList;
|
std::list<Creature*> resultList;
|
||||||
const Position& myPos = getPosition();
|
const Position& myPos = getPosition();
|
||||||
|
|
||||||
for (Creature* creature : targetList) {
|
for (Creature* creature : targetList) {
|
||||||
if (followCreature != creature && isTarget(creature)) {
|
if (followCreature != creature && isTarget(creature)) {
|
||||||
if (searchType == TARGETSEARCH_RANDOM || canUseAttack(myPos, creature)) {
|
if (searchType == TARGETSEARCH_ANY || canUseAttack(myPos, creature)) {
|
||||||
resultList.push_back(creature);
|
resultList.push_back(creature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -497,32 +511,31 @@ bool Monster::searchTarget(TargetSearchType_t searchType /*= TARGETSEARCH_DEFAUL
|
|||||||
switch (searchType) {
|
switch (searchType) {
|
||||||
case TARGETSEARCH_NEAREST: {
|
case TARGETSEARCH_NEAREST: {
|
||||||
Creature* target = nullptr;
|
Creature* target = nullptr;
|
||||||
|
|
||||||
|
int32_t minRange = 0;
|
||||||
|
if (attackedCreature) {
|
||||||
|
const Position& targetPosition = attackedCreature->getPosition();
|
||||||
|
minRange = Position::getDistanceX(myPos, targetPosition) + Position::getDistanceY(myPos, targetPosition);
|
||||||
|
}
|
||||||
|
|
||||||
if (!resultList.empty()) {
|
if (!resultList.empty()) {
|
||||||
auto it = resultList.begin();
|
for (Creature* creature : resultList) {
|
||||||
target = *it;
|
const Position& targetPosition = creature->getPosition();
|
||||||
|
|
||||||
if (++it != resultList.end()) {
|
int32_t distance = Position::getDistanceX(myPos, targetPosition) + Position::getDistanceY(myPos, targetPosition);
|
||||||
const Position& targetPosition = target->getPosition();
|
if (distance < minRange) {
|
||||||
int32_t minRange = Position::getDistanceX(myPos, targetPosition) + Position::getDistanceY(myPos, targetPosition);
|
target = creature;
|
||||||
do {
|
minRange = distance;
|
||||||
const Position& pos = (*it)->getPosition();
|
}
|
||||||
|
|
||||||
int32_t distance = Position::getDistanceX(myPos, pos) + Position::getDistanceY(myPos, pos);
|
|
||||||
if (distance < minRange) {
|
|
||||||
target = *it;
|
|
||||||
minRange = distance;
|
|
||||||
}
|
|
||||||
} while (++it != resultList.end());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int32_t minRange = std::numeric_limits<int32_t>::max();
|
|
||||||
for (Creature* creature : targetList) {
|
for (Creature* creature : targetList) {
|
||||||
if (!isTarget(creature)) {
|
if (!isTarget(creature)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Position& pos = creature->getPosition();
|
const Position& targetPosition = creature->getPosition();
|
||||||
int32_t distance = Position::getDistanceX(myPos, pos) + Position::getDistanceY(myPos, pos);
|
int32_t distance = Position::getDistanceX(myPos, targetPosition) + Position::getDistanceY(myPos, targetPosition);
|
||||||
if (distance < minRange) {
|
if (distance < minRange) {
|
||||||
target = creature;
|
target = creature;
|
||||||
minRange = distance;
|
minRange = distance;
|
||||||
@@ -535,10 +548,79 @@ bool Monster::searchTarget(TargetSearchType_t searchType /*= TARGETSEARCH_DEFAUL
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case TARGETSEARCH_WEAKEST: {
|
||||||
|
Creature* target = nullptr;
|
||||||
|
|
||||||
case TARGETSEARCH_DEFAULT:
|
int32_t health = 0;
|
||||||
case TARGETSEARCH_ATTACKRANGE:
|
if (attackedCreature) {
|
||||||
case TARGETSEARCH_RANDOM:
|
health = attackedCreature->getMaxHealth();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resultList.empty()) {
|
||||||
|
for (Creature* creature : resultList) {
|
||||||
|
if (creature->getMaxHealth() < health) {
|
||||||
|
target = creature;
|
||||||
|
health = creature->getMaxHealth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (Creature* creature : targetList) {
|
||||||
|
if (creature->getMaxHealth() < health) {
|
||||||
|
target = creature;
|
||||||
|
health = creature->getMaxHealth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target && selectTarget(target)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TARGETSEARCH_MOSTDAMAGE: {
|
||||||
|
Creature* target = nullptr;
|
||||||
|
|
||||||
|
int32_t maxDamage = 0;
|
||||||
|
|
||||||
|
if (!resultList.empty()) {
|
||||||
|
for (Creature* creature : resultList) {
|
||||||
|
auto it = damageMap.find(creature->getID());
|
||||||
|
if (it == damageMap.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t damage = it->second.total;
|
||||||
|
|
||||||
|
if (OTSYS_TIME() - it->second.ticks <= g_config.getNumber(ConfigManager::PZ_LOCKED)) {
|
||||||
|
if (damage > maxDamage) {
|
||||||
|
target = creature;
|
||||||
|
maxDamage = damage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (Creature* creature : targetList) {
|
||||||
|
auto it = damageMap.find(creature->getID());
|
||||||
|
if (it == damageMap.end()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t damage = it->second.total;
|
||||||
|
|
||||||
|
if (OTSYS_TIME() - it->second.ticks <= g_config.getNumber(ConfigManager::PZ_LOCKED)) {
|
||||||
|
if (damage > maxDamage) {
|
||||||
|
target = creature;
|
||||||
|
maxDamage = damage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target && selectTarget(target)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
if (!resultList.empty()) {
|
if (!resultList.empty()) {
|
||||||
auto it = resultList.begin();
|
auto it = resultList.begin();
|
||||||
@@ -546,20 +628,19 @@ bool Monster::searchTarget(TargetSearchType_t searchType /*= TARGETSEARCH_DEFAUL
|
|||||||
return selectTarget(*it);
|
return selectTarget(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchType == TARGETSEARCH_ATTACKRANGE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//lets just pick the first target in the list
|
//lets just pick the first target in the list if we do not have a target
|
||||||
for (Creature* target : targetList) {
|
if (!attackedCreature) {
|
||||||
if (followCreature != target && selectTarget(target)) {
|
for (Creature* target : targetList) {
|
||||||
return true;
|
if (followCreature != target && selectTarget(target)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,6 +718,10 @@ bool Monster::selectTarget(Creature* creature)
|
|||||||
g_dispatcher.addTask(createTask(std::bind(&Game::checkCreatureAttack, &g_game, getID())));
|
g_dispatcher.addTask(createTask(std::bind(&Game::checkCreatureAttack, &g_game, getID())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// without this task, monster would randomly start dancing until next game round
|
||||||
|
g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
|
||||||
|
targetChangeCooldown += 3000;
|
||||||
return setFollowCreature(creature);
|
return setFollowCreature(creature);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -673,7 +758,7 @@ void Monster::updateIdleStatus()
|
|||||||
|
|
||||||
void Monster::onAddCondition(ConditionType_t type)
|
void Monster::onAddCondition(ConditionType_t type)
|
||||||
{
|
{
|
||||||
if (type == CONDITION_FIRE || type == CONDITION_ENERGY || type == CONDITION_POISON) {
|
if (type == CONDITION_FIRE || type == CONDITION_ENERGY || type == CONDITION_POISON || type == CONDITION_AGGRESSIVE) {
|
||||||
updateMapCache();
|
updateMapCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -682,8 +767,7 @@ void Monster::onAddCondition(ConditionType_t type)
|
|||||||
|
|
||||||
void Monster::onEndCondition(ConditionType_t type)
|
void Monster::onEndCondition(ConditionType_t type)
|
||||||
{
|
{
|
||||||
if (type == CONDITION_FIRE || type == CONDITION_ENERGY || type == CONDITION_POISON) {
|
if (type == CONDITION_FIRE || type == CONDITION_ENERGY || type == CONDITION_POISON || type == CONDITION_AGGRESSIVE) {
|
||||||
ignoreFieldDamage = false;
|
|
||||||
updateMapCache();
|
updateMapCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -692,6 +776,10 @@ void Monster::onEndCondition(ConditionType_t type)
|
|||||||
|
|
||||||
void Monster::onThink(uint32_t interval)
|
void Monster::onThink(uint32_t interval)
|
||||||
{
|
{
|
||||||
|
if (OTSYS_TIME() < earliestWakeUpTime) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Creature::onThink(interval);
|
Creature::onThink(interval);
|
||||||
|
|
||||||
if (mType->info.thinkEvent != -1) {
|
if (mType->info.thinkEvent != -1) {
|
||||||
@@ -718,9 +806,10 @@ void Monster::onThink(uint32_t interval)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isInSpawnRange(position)) {
|
if (!isInSpawnRange(position) || (lifetime > 0 && (OTSYS_TIME() >= lifetime))) {
|
||||||
g_game.internalTeleport(this, masterPos);
|
// Despawn creatures if they are out of their spawn zone
|
||||||
setIdle(true);
|
g_game.removeCreature(this);
|
||||||
|
g_game.addMagicEffect(getPosition(), CONST_ME_POFF);
|
||||||
} else {
|
} else {
|
||||||
updateIdleStatus();
|
updateIdleStatus();
|
||||||
|
|
||||||
@@ -730,7 +819,6 @@ void Monster::onThink(uint32_t interval)
|
|||||||
if (isSummon()) {
|
if (isSummon()) {
|
||||||
if (!attackedCreature) {
|
if (!attackedCreature) {
|
||||||
if (getMaster() && getMaster()->getAttackedCreature()) {
|
if (getMaster() && getMaster()->getAttackedCreature()) {
|
||||||
//This happens if the monster is summoned during combat
|
|
||||||
selectTarget(getMaster()->getAttackedCreature());
|
selectTarget(getMaster()->getAttackedCreature());
|
||||||
} else if (getMaster() != followCreature) {
|
} else if (getMaster() != followCreature) {
|
||||||
//Our master has not ordered us to attack anything, lets follow him around instead.
|
//Our master has not ordered us to attack anything, lets follow him around instead.
|
||||||
@@ -739,15 +827,23 @@ void Monster::onThink(uint32_t interval)
|
|||||||
} else if (attackedCreature == this) {
|
} else if (attackedCreature == this) {
|
||||||
setFollowCreature(nullptr);
|
setFollowCreature(nullptr);
|
||||||
} else if (followCreature != attackedCreature) {
|
} else if (followCreature != attackedCreature) {
|
||||||
//This happens just after a master orders an attack, so lets follow it aswell.
|
|
||||||
setFollowCreature(attackedCreature);
|
setFollowCreature(attackedCreature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (master) {
|
||||||
|
if (Monster* monster = master->getMonster()) {
|
||||||
|
if (monster->mType->info.targetDistance <= 1 && !monster->hasFollowPath) {
|
||||||
|
setFollowCreature(master);
|
||||||
|
setAttackedCreature(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (!targetList.empty()) {
|
} else if (!targetList.empty()) {
|
||||||
if (!followCreature || !hasFollowPath) {
|
if (!followCreature || !hasFollowPath) {
|
||||||
searchTarget();
|
searchTarget(TARGETSEARCH_ANY);
|
||||||
} else if (isFleeing()) {
|
} else if (isFleeing()) {
|
||||||
if (attackedCreature && !canUseAttack(getPosition(), attackedCreature)) {
|
if (attackedCreature && !canUseAttack(getPosition(), attackedCreature)) {
|
||||||
searchTarget(TARGETSEARCH_ATTACKRANGE);
|
searchTarget(TARGETSEARCH_NEAREST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -759,56 +855,43 @@ void Monster::onThink(uint32_t interval)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Monster::doAttacking(uint32_t interval)
|
void Monster::doAttacking(uint32_t)
|
||||||
{
|
{
|
||||||
if (!attackedCreature || (isSummon() && attackedCreature == this)) {
|
if (!attackedCreature || (isSummon() && attackedCreature == this)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool updateLook = true;
|
|
||||||
bool resetTicks = interval != 0;
|
|
||||||
attackTicks += interval;
|
|
||||||
|
|
||||||
const Position& myPos = getPosition();
|
const Position& myPos = getPosition();
|
||||||
const Position& targetPos = attackedCreature->getPosition();
|
const Position& targetPos = attackedCreature->getPosition();
|
||||||
|
|
||||||
for (const spellBlock_t& spellBlock : mType->info.attackSpells) {
|
bool updateLook = false;
|
||||||
bool inRange = false;
|
|
||||||
|
|
||||||
if (attackedCreature == nullptr) {
|
if (OTSYS_TIME() >= earliestAttackTime && !isFleeing()) {
|
||||||
break;
|
updateLook = true;
|
||||||
|
if (Combat::closeAttack(this, attackedCreature, FIGHTMODE_BALANCED)) {
|
||||||
|
egibleToDance = true;
|
||||||
|
earliestAttackTime = OTSYS_TIME() + 2000;
|
||||||
|
removeCondition(CONDITION_AGGRESSIVE, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (canUseSpell(myPos, targetPos, spellBlock, interval, inRange, resetTicks)) {
|
for (spellBlock_t& spellBlock : mType->info.attackSpells) {
|
||||||
if (spellBlock.chance >= static_cast<uint32_t>(uniform_random(1, 100))) {
|
if (spellBlock.range != 0 && std::max<uint32_t>(Position::getDistanceX(myPos, targetPos), Position::getDistanceY(myPos, targetPos)) <= spellBlock.range) {
|
||||||
if (updateLook) {
|
if (uniform_random(0, spellBlock.chance) == 0 && (master || health > mType->info.runAwayHealth || uniform_random(1, 3) == 1)) {
|
||||||
updateLookDirection();
|
updateLookDirection();
|
||||||
updateLook = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
minCombatValue = spellBlock.minCombatValue;
|
minCombatValue = spellBlock.minCombatValue;
|
||||||
maxCombatValue = spellBlock.maxCombatValue;
|
maxCombatValue = spellBlock.maxCombatValue;
|
||||||
|
|
||||||
spellBlock.spell->castSpell(this, attackedCreature);
|
spellBlock.spell->castSpell(this, attackedCreature);
|
||||||
|
egibleToDance = true;
|
||||||
if (spellBlock.isMelee) {
|
|
||||||
extraMeleeAttack = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inRange && spellBlock.isMelee) {
|
|
||||||
//melee swing out of reach
|
|
||||||
extraMeleeAttack = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateLook) {
|
if (updateLook) {
|
||||||
updateLookDirection();
|
updateLookDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resetTicks) {
|
|
||||||
attackTicks = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Monster::canUseAttack(const Position& pos, const Creature* target) const
|
bool Monster::canUseAttack(const Position& pos, const Creature* target) const
|
||||||
@@ -826,40 +909,6 @@ bool Monster::canUseAttack(const Position& pos, const Creature* target) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Monster::canUseSpell(const Position& pos, const Position& targetPos,
|
|
||||||
const spellBlock_t& sb, uint32_t interval, bool& inRange, bool& resetTicks)
|
|
||||||
{
|
|
||||||
inRange = true;
|
|
||||||
|
|
||||||
if (sb.isMelee && isFleeing()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extraMeleeAttack) {
|
|
||||||
lastMeleeAttack = OTSYS_TIME();
|
|
||||||
} else if (sb.isMelee && (OTSYS_TIME() - lastMeleeAttack) < 1500) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sb.isMelee || !extraMeleeAttack) {
|
|
||||||
if (sb.speed > attackTicks) {
|
|
||||||
resetTicks = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attackTicks % sb.speed >= interval) {
|
|
||||||
//already used this spell for this round
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sb.range != 0 && std::max<uint32_t>(Position::getDistanceX(pos, targetPos), Position::getDistanceY(pos, targetPos)) > sb.range) {
|
|
||||||
inRange = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Monster::onThinkTarget(uint32_t interval)
|
void Monster::onThinkTarget(uint32_t interval)
|
||||||
{
|
{
|
||||||
if (!isSummon()) {
|
if (!isSummon()) {
|
||||||
@@ -882,13 +931,42 @@ void Monster::onThinkTarget(uint32_t interval)
|
|||||||
|
|
||||||
if (targetChangeTicks >= mType->info.changeTargetSpeed) {
|
if (targetChangeTicks >= mType->info.changeTargetSpeed) {
|
||||||
targetChangeTicks = 0;
|
targetChangeTicks = 0;
|
||||||
targetChangeCooldown = mType->info.changeTargetSpeed;
|
|
||||||
|
|
||||||
if (mType->info.changeTargetChance >= uniform_random(1, 100)) {
|
if (mType->info.changeTargetChance > uniform_random(0, 99)) {
|
||||||
if (mType->info.targetDistance <= 1) {
|
// search target strategies, if no strategy succeeds, target is not switched
|
||||||
searchTarget(TARGETSEARCH_RANDOM);
|
int32_t random = uniform_random(0, 99);
|
||||||
} else {
|
int32_t current_strategy = 0;
|
||||||
searchTarget(TARGETSEARCH_NEAREST);
|
|
||||||
|
TargetSearchType_t searchType = TARGETSEARCH_ANY;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
int32_t strategy = 0;
|
||||||
|
|
||||||
|
if (current_strategy == 0) {
|
||||||
|
strategy = mType->info.strategyNearestEnemy;
|
||||||
|
searchType = TARGETSEARCH_NEAREST;
|
||||||
|
} else if (current_strategy == 1) {
|
||||||
|
strategy = mType->info.strategyWeakestEnemy;
|
||||||
|
searchType = TARGETSEARCH_WEAKEST;
|
||||||
|
} else if (current_strategy == 2) {
|
||||||
|
strategy = mType->info.strategyMostDamageEnemy;
|
||||||
|
searchType = TARGETSEARCH_MOSTDAMAGE;
|
||||||
|
} else if (current_strategy == 3) {
|
||||||
|
strategy = mType->info.strategyRandomEnemy;
|
||||||
|
searchType = TARGETSEARCH_RANDOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (random < strategy) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_strategy++;
|
||||||
|
random -= strategy;
|
||||||
|
} while (current_strategy <= 3);
|
||||||
|
|
||||||
|
if (searchType != TARGETSEARCH_ANY) {
|
||||||
|
searchTarget(searchType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -897,23 +975,10 @@ void Monster::onThinkTarget(uint32_t interval)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Monster::onThinkDefense(uint32_t interval)
|
void Monster::onThinkDefense(uint32_t)
|
||||||
{
|
{
|
||||||
bool resetTicks = true;
|
|
||||||
defenseTicks += interval;
|
|
||||||
|
|
||||||
for (const spellBlock_t& spellBlock : mType->info.defenseSpells) {
|
for (const spellBlock_t& spellBlock : mType->info.defenseSpells) {
|
||||||
if (spellBlock.speed > defenseTicks) {
|
if (uniform_random(0, spellBlock.chance) == 0 && (master || health > mType->info.runAwayHealth || uniform_random(1, 3) == 1)) {
|
||||||
resetTicks = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defenseTicks % spellBlock.speed >= interval) {
|
|
||||||
//already used this spell for this round
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((spellBlock.chance >= static_cast<uint32_t>(uniform_random(1, 100)))) {
|
|
||||||
minCombatValue = spellBlock.minCombatValue;
|
minCombatValue = spellBlock.minCombatValue;
|
||||||
maxCombatValue = spellBlock.maxCombatValue;
|
maxCombatValue = spellBlock.maxCombatValue;
|
||||||
spellBlock.spell->castSpell(this, this);
|
spellBlock.spell->castSpell(this, this);
|
||||||
@@ -922,20 +987,10 @@ void Monster::onThinkDefense(uint32_t interval)
|
|||||||
|
|
||||||
if (!isSummon() && summons.size() < mType->info.maxSummons && hasFollowPath) {
|
if (!isSummon() && summons.size() < mType->info.maxSummons && hasFollowPath) {
|
||||||
for (const summonBlock_t& summonBlock : mType->info.summons) {
|
for (const summonBlock_t& summonBlock : mType->info.summons) {
|
||||||
if (summonBlock.speed > defenseTicks) {
|
|
||||||
resetTicks = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (summons.size() >= mType->info.maxSummons) {
|
if (summons.size() >= mType->info.maxSummons) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defenseTicks % summonBlock.speed >= interval) {
|
|
||||||
//already used this spell for this round
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t summonCount = 0;
|
uint32_t summonCount = 0;
|
||||||
for (Creature* summon : summons) {
|
for (Creature* summon : summons) {
|
||||||
if (summon->getName() == summonBlock.name) {
|
if (summon->getName() == summonBlock.name) {
|
||||||
@@ -947,49 +1002,41 @@ void Monster::onThinkDefense(uint32_t interval)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (summonBlock.chance < static_cast<uint32_t>(uniform_random(1, 100))) {
|
if (normal_random(0, summonBlock.chance) == 0 && (health > mType->info.runAwayHealth || normal_random(1, 3) == 1)) {
|
||||||
continue;
|
Monster* summon = Monster::createMonster(summonBlock.name);
|
||||||
}
|
if (summon) {
|
||||||
|
const Position& summonPos = getPosition();
|
||||||
|
|
||||||
Monster* summon = Monster::createMonster(summonBlock.name);
|
addSummon(summon);
|
||||||
if (summon) {
|
|
||||||
if (g_game.placeCreature(summon, getPosition(), false, summonBlock.force)) {
|
if (!g_game.placeCreature(summon, summonPos, false, summonBlock.force)) {
|
||||||
summon->setDropLoot(false);
|
removeSummon(summon);
|
||||||
summon->setSkillLoss(false);
|
} else {
|
||||||
summon->setMaster(this);
|
g_game.addMagicEffect(getPosition(), CONST_ME_MAGIC_BLUE);
|
||||||
g_game.addMagicEffect(getPosition(), CONST_ME_MAGIC_BLUE);
|
g_game.addMagicEffect(summon->getPosition(), CONST_ME_TELEPORT);
|
||||||
g_game.addMagicEffect(summon->getPosition(), CONST_ME_TELEPORT);
|
}
|
||||||
} else {
|
|
||||||
delete summon;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resetTicks) {
|
|
||||||
defenseTicks = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Monster::onThinkYell(uint32_t interval)
|
void Monster::onThinkYell(uint32_t)
|
||||||
{
|
{
|
||||||
if (mType->info.yellSpeedTicks == 0) {
|
if (mType->info.voiceVector.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
yellTicks += interval;
|
int32_t randomResult = rand();
|
||||||
if (yellTicks >= mType->info.yellSpeedTicks) {
|
if (rand() == 50 * (randomResult / 50)) {
|
||||||
yellTicks = 0;
|
int32_t totalVoices = mType->info.voiceVector.size();
|
||||||
|
const voiceBlock_t& voice = mType->info.voiceVector[rand() % totalVoices + 1];
|
||||||
|
|
||||||
if (!mType->info.voiceVector.empty() && (mType->info.yellChance >= static_cast<uint32_t>(uniform_random(1, 100)))) {
|
if (voice.yellText) {
|
||||||
uint32_t index = uniform_random(0, mType->info.voiceVector.size() - 1);
|
g_game.internalCreatureSay(this, TALKTYPE_MONSTER_YELL, voice.text, false);
|
||||||
const voiceBlock_t& vb = mType->info.voiceVector[index];
|
}
|
||||||
|
else {
|
||||||
if (vb.yellText) {
|
g_game.internalCreatureSay(this, TALKTYPE_MONSTER_SAY, voice.text, false);
|
||||||
g_game.internalCreatureSay(this, TALKTYPE_MONSTER_YELL, vb.text, false);
|
|
||||||
} else {
|
|
||||||
g_game.internalCreatureSay(this, TALKTYPE_MONSTER_SAY, vb.text, false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1112,27 +1159,117 @@ bool Monster::getNextStep(Direction& direction, uint32_t& flags)
|
|||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if ((!followCreature || !hasFollowPath) && (!isSummon() || !isMasterInRange)) {
|
if ((!followCreature || !hasFollowPath) && (!isSummon() || !isMasterInRange)) {
|
||||||
if (getTimeSinceLastMove() >= 1000) {
|
if (OTSYS_TIME() >= nextDanceStepRound) {
|
||||||
randomStepping = true;
|
updateLookDirection();
|
||||||
|
nextDanceStepRound = OTSYS_TIME() + getStepDuration();
|
||||||
|
|
||||||
//choose a random direction
|
//choose a random direction
|
||||||
result = getRandomStep(getPosition(), direction);
|
result = getRandomStep(getPosition(), direction);
|
||||||
}
|
}
|
||||||
} else if ((isSummon() && isMasterInRange) || followCreature) {
|
} else if ((isSummon() && isMasterInRange) || followCreature) {
|
||||||
randomStepping = false;
|
|
||||||
result = Creature::getNextStep(direction, flags);
|
result = Creature::getNextStep(direction, flags);
|
||||||
if (result) {
|
if (result) {
|
||||||
flags |= FLAG_PATHFINDING;
|
flags |= FLAG_PATHFINDING;
|
||||||
} else {
|
} else {
|
||||||
if (ignoreFieldDamage) {
|
|
||||||
ignoreFieldDamage = false;
|
|
||||||
updateMapCache();
|
|
||||||
}
|
|
||||||
//target dancing
|
//target dancing
|
||||||
if (attackedCreature && attackedCreature == followCreature) {
|
if (attackedCreature && attackedCreature == followCreature) {
|
||||||
if (isFleeing()) {
|
if (isFleeing()) {
|
||||||
result = getDanceStep(getPosition(), direction, false, false);
|
result = getDanceStep(getPosition(), direction, false, false);
|
||||||
} else if (mType->info.staticAttackChance < static_cast<uint32_t>(uniform_random(1, 100))) {
|
} else if (egibleToDance && OTSYS_TIME() >= earliestDanceTime) {
|
||||||
result = getDanceStep(getPosition(), direction);
|
if (mType->info.targetDistance >= 4) {
|
||||||
|
const Position& myPos = getPosition();
|
||||||
|
const Position targetPos = attackedCreature->getPosition();
|
||||||
|
|
||||||
|
if (Position::getDistanceX(myPos, targetPos) == 4 || Position::getDistanceY(myPos, targetPos) == 4) {
|
||||||
|
int32_t currentX = myPos.x;
|
||||||
|
int32_t currentY = myPos.y;
|
||||||
|
int32_t danceRandom = rand();
|
||||||
|
int32_t danceRandomResult = danceRandom % 5;
|
||||||
|
|
||||||
|
if (danceRandom % 5 == 1) {
|
||||||
|
direction = DIRECTION_EAST;
|
||||||
|
currentX++;
|
||||||
|
} else if (danceRandomResult <= 1) {
|
||||||
|
if (danceRandom == 5 * (danceRandom / 5)) {
|
||||||
|
direction = DIRECTION_WEST;
|
||||||
|
currentX--;
|
||||||
|
}
|
||||||
|
} else if (danceRandomResult == 2) {
|
||||||
|
direction = DIRECTION_NORTH;
|
||||||
|
currentY--;
|
||||||
|
} else if (danceRandomResult == 3) {
|
||||||
|
direction = DIRECTION_SOUTH;
|
||||||
|
currentY++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (danceRandomResult <= 3 && canWalkTo(myPos, direction)) {
|
||||||
|
int32_t xTest = targetPos.x - currentX;
|
||||||
|
if (currentX - targetPos.x > -1) {
|
||||||
|
xTest = currentX - targetPos.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t yTest = targetPos.y - currentY;
|
||||||
|
if (currentY - targetPos.y > -1) {
|
||||||
|
yTest = currentY - targetPos.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t realTest = yTest;
|
||||||
|
|
||||||
|
if (xTest >= yTest) {
|
||||||
|
realTest = xTest;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (realTest == 4) {
|
||||||
|
result = true;
|
||||||
|
egibleToDance = false;
|
||||||
|
earliestWakeUpTime = OTSYS_TIME() + 1000;
|
||||||
|
earliestDanceTime = OTSYS_TIME() + 1000 + getStepDuration();
|
||||||
|
earliestAttackTime += 200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const Position& myPos = getPosition();
|
||||||
|
const Position targetPos = attackedCreature->getPosition();
|
||||||
|
|
||||||
|
if (Position::areInRange<1, 1>(myPos, targetPos)) {
|
||||||
|
int32_t danceRandom = rand();
|
||||||
|
int32_t danceRandomResult = danceRandom % 5;
|
||||||
|
|
||||||
|
int32_t currentX = myPos.x;
|
||||||
|
int32_t currentY = myPos.y;
|
||||||
|
|
||||||
|
if (danceRandom % 5 == 1) {
|
||||||
|
direction = DIRECTION_EAST;
|
||||||
|
currentX++;
|
||||||
|
} else if (danceRandomResult <= 1) {
|
||||||
|
if (danceRandom == 5 * (danceRandom / 5)) {
|
||||||
|
direction = DIRECTION_WEST;
|
||||||
|
currentX--;
|
||||||
|
}
|
||||||
|
} else if (danceRandomResult == 2) {
|
||||||
|
direction = DIRECTION_NORTH;
|
||||||
|
currentY--;
|
||||||
|
} else if (danceRandomResult == 3) {
|
||||||
|
direction = DIRECTION_SOUTH;
|
||||||
|
currentY++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Position position = myPos;
|
||||||
|
position.x = currentX;
|
||||||
|
position.y = currentY;
|
||||||
|
|
||||||
|
if (danceRandomResult <= 3 &&
|
||||||
|
canWalkTo(myPos, direction) &&
|
||||||
|
Position::areInRange<1, 1>(position, targetPos)) {
|
||||||
|
result = true;
|
||||||
|
egibleToDance = false;
|
||||||
|
earliestWakeUpTime = OTSYS_TIME() + 1000;
|
||||||
|
earliestDanceTime = OTSYS_TIME() + 1000 + getStepDuration();
|
||||||
|
earliestAttackTime += 200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1776,7 +1913,8 @@ void Monster::death(Creature*)
|
|||||||
|
|
||||||
for (Creature* summon : summons) {
|
for (Creature* summon : summons) {
|
||||||
summon->changeHealth(-summon->getHealth());
|
summon->changeHealth(-summon->getHealth());
|
||||||
summon->removeMaster();
|
summon->setMaster(nullptr);
|
||||||
|
summon->decrementReferenceCounter();
|
||||||
}
|
}
|
||||||
summons.clear();
|
summons.clear();
|
||||||
|
|
||||||
@@ -1855,61 +1993,86 @@ void Monster::updateLookDirection()
|
|||||||
//look EAST/WEST
|
//look EAST/WEST
|
||||||
if (offsetx < 0) {
|
if (offsetx < 0) {
|
||||||
newDir = DIRECTION_WEST;
|
newDir = DIRECTION_WEST;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
newDir = DIRECTION_EAST;
|
newDir = DIRECTION_EAST;
|
||||||
}
|
}
|
||||||
} else if (dx < dy) {
|
}
|
||||||
|
else if (dx < dy) {
|
||||||
//look NORTH/SOUTH
|
//look NORTH/SOUTH
|
||||||
if (offsety < 0) {
|
if (offsety < 0) {
|
||||||
newDir = DIRECTION_NORTH;
|
newDir = DIRECTION_NORTH;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
newDir = DIRECTION_SOUTH;
|
newDir = DIRECTION_SOUTH;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
Direction dir = getDirection();
|
Direction dir = getDirection();
|
||||||
if (offsetx < 0 && offsety < 0) {
|
if (offsetx < 0 && offsety < 0) {
|
||||||
|
if (offsetx == -1 && offsety == -1) {
|
||||||
|
if (dir == DIRECTION_NORTH) {
|
||||||
|
newDir = DIRECTION_WEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (dir == DIRECTION_SOUTH) {
|
if (dir == DIRECTION_SOUTH) {
|
||||||
newDir = DIRECTION_WEST;
|
newDir = DIRECTION_WEST;
|
||||||
} else if (dir == DIRECTION_NORTH) {
|
}
|
||||||
newDir = DIRECTION_WEST;
|
else if (dir == DIRECTION_EAST) {
|
||||||
} else if (dir == DIRECTION_EAST) {
|
|
||||||
newDir = DIRECTION_NORTH;
|
newDir = DIRECTION_NORTH;
|
||||||
}
|
}
|
||||||
} else if (offsetx < 0 && offsety > 0) {
|
}
|
||||||
|
else if (offsetx < 0 && offsety > 0) {
|
||||||
|
if (offsetx == -1 && offsety == 1) {
|
||||||
|
if (dir == DIRECTION_SOUTH) {
|
||||||
|
newDir = DIRECTION_WEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (dir == DIRECTION_NORTH) {
|
if (dir == DIRECTION_NORTH) {
|
||||||
newDir = DIRECTION_WEST;
|
newDir = DIRECTION_WEST;
|
||||||
} else if (dir == DIRECTION_SOUTH) {
|
}
|
||||||
newDir = DIRECTION_WEST;
|
else if (dir == DIRECTION_EAST) {
|
||||||
} else if (dir == DIRECTION_EAST) {
|
|
||||||
newDir = DIRECTION_SOUTH;
|
newDir = DIRECTION_SOUTH;
|
||||||
}
|
}
|
||||||
} else if (offsetx > 0 && offsety < 0) {
|
}
|
||||||
|
else if (offsetx > 0 && offsety < 0) {
|
||||||
|
if (offsetx == 1 && offsety == -1) {
|
||||||
|
if (dir == DIRECTION_NORTH) {
|
||||||
|
newDir = DIRECTION_EAST;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (dir == DIRECTION_SOUTH) {
|
if (dir == DIRECTION_SOUTH) {
|
||||||
newDir = DIRECTION_EAST;
|
newDir = DIRECTION_EAST;
|
||||||
} else if (dir == DIRECTION_NORTH) {
|
}
|
||||||
newDir = DIRECTION_EAST;
|
else if (dir == DIRECTION_WEST) {
|
||||||
} else if (dir == DIRECTION_WEST) {
|
|
||||||
newDir = DIRECTION_NORTH;
|
newDir = DIRECTION_NORTH;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
|
if (offsetx == 1 && offsety == 1) {
|
||||||
|
if (dir == DIRECTION_SOUTH) {
|
||||||
|
newDir = DIRECTION_EAST;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (dir == DIRECTION_NORTH) {
|
if (dir == DIRECTION_NORTH) {
|
||||||
newDir = DIRECTION_EAST;
|
newDir = DIRECTION_EAST;
|
||||||
} else if (dir == DIRECTION_SOUTH) {
|
}
|
||||||
newDir = DIRECTION_EAST;
|
else if (dir == DIRECTION_WEST) {
|
||||||
} else if (dir == DIRECTION_WEST) {
|
|
||||||
newDir = DIRECTION_SOUTH;
|
newDir = DIRECTION_SOUTH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_game.internalCreatureTurn(this, newDir);
|
if (direction != newDir) {
|
||||||
|
g_game.internalCreatureTurn(this, newDir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Monster::dropLoot(Container* corpse, Creature*)
|
void Monster::dropLoot(Container* corpse, Creature*)
|
||||||
{
|
{
|
||||||
if (corpse && lootDrop) {
|
if (corpse && lootDrop) {
|
||||||
g_events->eventMonsterOnDropLoot(this, corpse);
|
mType->createLoot(corpse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1921,12 +2084,6 @@ void Monster::setNormalCreatureLight()
|
|||||||
void Monster::drainHealth(Creature* attacker, int32_t damage)
|
void Monster::drainHealth(Creature* attacker, int32_t damage)
|
||||||
{
|
{
|
||||||
Creature::drainHealth(attacker, damage);
|
Creature::drainHealth(attacker, damage);
|
||||||
|
|
||||||
if (damage > 0 && randomStepping) {
|
|
||||||
ignoreFieldDamage = true;
|
|
||||||
updateMapCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isInvisible()) {
|
if (isInvisible()) {
|
||||||
removeCondition(CONDITION_INVISIBLE);
|
removeCondition(CONDITION_INVISIBLE);
|
||||||
}
|
}
|
||||||
@@ -1947,12 +2104,70 @@ bool Monster::challengeCreature(Creature* creature)
|
|||||||
|
|
||||||
bool result = selectTarget(creature);
|
bool result = selectTarget(creature);
|
||||||
if (result) {
|
if (result) {
|
||||||
targetChangeCooldown = 8000;
|
targetChangeCooldown = 1000;
|
||||||
targetChangeTicks = 0;
|
targetChangeTicks = 0;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Monster::convinceCreature(Creature* creature)
|
||||||
|
{
|
||||||
|
Player* player = creature->getPlayer();
|
||||||
|
if (player && !player->hasFlag(PlayerFlag_CanConvinceAll)) {
|
||||||
|
if (!mType->info.isConvinceable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSummon()) {
|
||||||
|
if (getMaster() == creature) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Creature* oldMaster = getMaster();
|
||||||
|
oldMaster->removeSummon(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
creature->addSummon(this);
|
||||||
|
|
||||||
|
setFollowCreature(nullptr);
|
||||||
|
setAttackedCreature(nullptr);
|
||||||
|
|
||||||
|
//destroy summons
|
||||||
|
for (Creature* summon : summons) {
|
||||||
|
summon->changeHealth(-summon->getHealth());
|
||||||
|
summon->setMaster(nullptr);
|
||||||
|
summon->decrementReferenceCounter();
|
||||||
|
}
|
||||||
|
summons.clear();
|
||||||
|
|
||||||
|
isMasterInRange = true;
|
||||||
|
updateTargetList();
|
||||||
|
updateIdleStatus();
|
||||||
|
|
||||||
|
//Notify surrounding about the change
|
||||||
|
SpectatorVec list;
|
||||||
|
g_game.map.getSpectators(list, getPosition(), true);
|
||||||
|
g_game.map.getSpectators(list, creature->getPosition(), true);
|
||||||
|
for (Creature* spectator : list) {
|
||||||
|
spectator->onCreatureConvinced(creature, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spawn) {
|
||||||
|
spawn->removeMonster(this);
|
||||||
|
spawn = nullptr;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Monster::onCreatureConvinced(const Creature* convincer, const Creature* creature)
|
||||||
|
{
|
||||||
|
if (convincer != this && (isFriend(creature) || isOpponent(creature))) {
|
||||||
|
updateTargetList();
|
||||||
|
updateIdleStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Monster::getPathSearchParams(const Creature* creature, FindPathParams& fpp) const
|
void Monster::getPathSearchParams(const Creature* creature, FindPathParams& fpp) const
|
||||||
{
|
{
|
||||||
Creature::getPathSearchParams(creature, fpp);
|
Creature::getPathSearchParams(creature, fpp);
|
||||||
|
|||||||
146
src/monster.h
146
src/monster.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,15 +26,17 @@
|
|||||||
class Creature;
|
class Creature;
|
||||||
class Game;
|
class Game;
|
||||||
class Spawn;
|
class Spawn;
|
||||||
|
class Combat;
|
||||||
|
|
||||||
using CreatureHashSet = std::unordered_set<Creature*>;
|
typedef std::unordered_set<Creature*> CreatureHashSet;
|
||||||
using CreatureList = std::list<Creature*>;
|
typedef std::list<Creature*> CreatureList;
|
||||||
|
|
||||||
enum TargetSearchType_t {
|
enum TargetSearchType_t {
|
||||||
TARGETSEARCH_DEFAULT,
|
TARGETSEARCH_ANY,
|
||||||
TARGETSEARCH_RANDOM,
|
TARGETSEARCH_RANDOM,
|
||||||
TARGETSEARCH_ATTACKRANGE,
|
|
||||||
TARGETSEARCH_NEAREST,
|
TARGETSEARCH_NEAREST,
|
||||||
|
TARGETSEARCH_WEAKEST,
|
||||||
|
TARGETSEARCH_MOSTDAMAGE,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Monster final : public Creature
|
class Monster final : public Creature
|
||||||
@@ -44,43 +46,39 @@ class Monster final : public Creature
|
|||||||
static int32_t despawnRange;
|
static int32_t despawnRange;
|
||||||
static int32_t despawnRadius;
|
static int32_t despawnRadius;
|
||||||
|
|
||||||
explicit Monster(MonsterType* mType);
|
explicit Monster(MonsterType* mtype);
|
||||||
~Monster();
|
~Monster();
|
||||||
|
|
||||||
// non-copyable
|
// non-copyable
|
||||||
Monster(const Monster&) = delete;
|
Monster(const Monster&) = delete;
|
||||||
Monster& operator=(const Monster&) = delete;
|
Monster& operator=(const Monster&) = delete;
|
||||||
|
|
||||||
Monster* getMonster() override {
|
Monster* getMonster() final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
const Monster* getMonster() const override {
|
const Monster* getMonster() const final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setID() override {
|
void setID() final {
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
id = monsterAutoID++;
|
id = monsterAutoID++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeList() override;
|
void removeList() final;
|
||||||
void addList() override;
|
void addList() final;
|
||||||
|
|
||||||
const std::string& getName() const override {
|
const std::string& getName() const final {
|
||||||
return mType->name;
|
return mType->name;
|
||||||
}
|
}
|
||||||
const std::string& getNameDescription() const override {
|
const std::string& getNameDescription() const final {
|
||||||
return mType->nameDescription;
|
return mType->nameDescription;
|
||||||
}
|
}
|
||||||
std::string getDescription(int32_t) const override {
|
std::string getDescription(int32_t) const final {
|
||||||
return strDescription + '.';
|
return strDescription + '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
CreatureType_t getType() const override {
|
|
||||||
return CREATURETYPE_MONSTER;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Position& getMasterPos() const {
|
const Position& getMasterPos() const {
|
||||||
return masterPos;
|
return masterPos;
|
||||||
}
|
}
|
||||||
@@ -88,19 +86,22 @@ class Monster final : public Creature
|
|||||||
masterPos = pos;
|
masterPos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
RaceType_t getRace() const override {
|
RaceType_t getRace() const final {
|
||||||
return mType->info.race;
|
return mType->info.race;
|
||||||
}
|
}
|
||||||
int32_t getArmor() const override {
|
int32_t getArmor() const final {
|
||||||
return mType->info.armor;
|
int32_t armor = mType->info.armor;
|
||||||
|
if (armor > 1) {
|
||||||
|
return rand() % (mType->info.armor >> 1) + (mType->info.armor >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return armor;
|
||||||
}
|
}
|
||||||
int32_t getDefense() const override {
|
int32_t getDefense() final;
|
||||||
return mType->info.defense;
|
bool isPushable() const final {
|
||||||
}
|
|
||||||
bool isPushable() const override {
|
|
||||||
return mType->info.pushable && baseSpeed != 0;
|
return mType->info.pushable && baseSpeed != 0;
|
||||||
}
|
}
|
||||||
bool isAttackable() const override {
|
bool isAttackable() const final {
|
||||||
return mType->info.isAttackable;
|
return mType->info.isAttackable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,8 +114,8 @@ class Monster final : public Creature
|
|||||||
bool isHostile() const {
|
bool isHostile() const {
|
||||||
return mType->info.isHostile;
|
return mType->info.isHostile;
|
||||||
}
|
}
|
||||||
bool canSee(const Position& pos) const override;
|
bool canSee(const Position& pos) const final;
|
||||||
bool canSeeInvisibility() const override {
|
bool canSeeInvisibility() const final {
|
||||||
return isImmune(CONDITION_INVISIBLE);
|
return isImmune(CONDITION_INVISIBLE);
|
||||||
}
|
}
|
||||||
uint32_t getManaCost() const {
|
uint32_t getManaCost() const {
|
||||||
@@ -123,35 +124,31 @@ class Monster final : public Creature
|
|||||||
void setSpawn(Spawn* spawn) {
|
void setSpawn(Spawn* spawn) {
|
||||||
this->spawn = spawn;
|
this->spawn = spawn;
|
||||||
}
|
}
|
||||||
bool canWalkOnFieldType(CombatType_t combatType) const;
|
|
||||||
|
|
||||||
|
void onAttackedCreature(Creature* creature) final;
|
||||||
|
|
||||||
void onAttackedCreatureDisappear(bool isLogout) override;
|
void onCreatureAppear(Creature* creature, bool isLogin) final;
|
||||||
|
void onRemoveCreature(Creature* creature, bool isLogout) final;
|
||||||
|
void onCreatureMove(Creature* creature, const Tile* newTile, const Position& newPos, const Tile* oldTile, const Position& oldPos, bool teleport) final;
|
||||||
|
void onCreatureSay(Creature* creature, SpeakClasses type, const std::string& text) final;
|
||||||
|
|
||||||
void onCreatureAppear(Creature* creature, bool isLogin) override;
|
void drainHealth(Creature* attacker, int32_t damage) final;
|
||||||
void onRemoveCreature(Creature* creature, bool isLogout) override;
|
void changeHealth(int32_t healthChange, bool sendHealthChange = true) final;
|
||||||
void onCreatureMove(Creature* creature, const Tile* newTile, const Position& newPos, const Tile* oldTile, const Position& oldPos, bool teleport) override;
|
void onWalk() final;
|
||||||
void onCreatureSay(Creature* creature, SpeakClasses type, const std::string& text) override;
|
bool getNextStep(Direction& direction, uint32_t& flags) final;
|
||||||
|
void onFollowCreatureComplete(const Creature* creature) final;
|
||||||
|
|
||||||
void drainHealth(Creature* attacker, int32_t damage) override;
|
void onThink(uint32_t interval) final;
|
||||||
void changeHealth(int32_t healthChange, bool sendHealthChange = true) override;
|
|
||||||
void onWalk() override;
|
|
||||||
bool getNextStep(Direction& direction, uint32_t& flags) override;
|
|
||||||
void onFollowCreatureComplete(const Creature* creature) override;
|
|
||||||
|
|
||||||
void onThink(uint32_t interval) override;
|
bool challengeCreature(Creature* creature) final;
|
||||||
|
bool convinceCreature(Creature* creature) final;
|
||||||
|
|
||||||
bool challengeCreature(Creature* creature) override;
|
void setNormalCreatureLight() final;
|
||||||
|
bool getCombatValues(int32_t& min, int32_t& max) final;
|
||||||
|
|
||||||
void setNormalCreatureLight() override;
|
void doAttacking(uint32_t interval) final;
|
||||||
bool getCombatValues(int32_t& min, int32_t& max) override;
|
|
||||||
|
|
||||||
void doAttacking(uint32_t interval) override;
|
bool searchTarget(TargetSearchType_t searchType);
|
||||||
bool hasExtraSwing() override {
|
|
||||||
return extraMeleeAttack;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool searchTarget(TargetSearchType_t searchType = TARGETSEARCH_DEFAULT);
|
|
||||||
bool selectTarget(Creature* creature);
|
bool selectTarget(Creature* creature);
|
||||||
|
|
||||||
const CreatureList& getTargetList() const {
|
const CreatureList& getTargetList() const {
|
||||||
@@ -170,12 +167,9 @@ class Monster final : public Creature
|
|||||||
bool isTargetNearby() const {
|
bool isTargetNearby() const {
|
||||||
return stepDuration >= 1;
|
return stepDuration >= 1;
|
||||||
}
|
}
|
||||||
bool isIgnoringFieldDamage() const {
|
|
||||||
return ignoreFieldDamage;
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockType_t blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage,
|
BlockType_t blockHit(Creature* attacker, CombatType_t combatType, int32_t& damage,
|
||||||
bool checkDefense = false, bool checkArmor = false, bool field = false) override;
|
bool checkDefense = false, bool checkArmor = false, bool field = false);
|
||||||
|
|
||||||
static uint32_t monsterAutoID;
|
static uint32_t monsterAutoID;
|
||||||
|
|
||||||
@@ -188,13 +182,13 @@ class Monster final : public Creature
|
|||||||
MonsterType* mType;
|
MonsterType* mType;
|
||||||
Spawn* spawn = nullptr;
|
Spawn* spawn = nullptr;
|
||||||
|
|
||||||
int64_t lastMeleeAttack = 0;
|
int64_t lifetime = 0;
|
||||||
|
int64_t nextDanceStepRound = 0;
|
||||||
|
int64_t earliestAttackTime = 0;
|
||||||
|
int64_t earliestWakeUpTime = 0;
|
||||||
|
int64_t earliestDanceTime = 0;
|
||||||
|
|
||||||
uint32_t attackTicks = 0;
|
|
||||||
uint32_t targetTicks = 0;
|
|
||||||
uint32_t targetChangeTicks = 0;
|
uint32_t targetChangeTicks = 0;
|
||||||
uint32_t defenseTicks = 0;
|
|
||||||
uint32_t yellTicks = 0;
|
|
||||||
int32_t minCombatValue = 0;
|
int32_t minCombatValue = 0;
|
||||||
int32_t maxCombatValue = 0;
|
int32_t maxCombatValue = 0;
|
||||||
int32_t targetChangeCooldown = 0;
|
int32_t targetChangeCooldown = 0;
|
||||||
@@ -203,10 +197,8 @@ class Monster final : public Creature
|
|||||||
Position masterPos;
|
Position masterPos;
|
||||||
|
|
||||||
bool isIdle = true;
|
bool isIdle = true;
|
||||||
bool extraMeleeAttack = false;
|
|
||||||
bool isMasterInRange = false;
|
bool isMasterInRange = false;
|
||||||
bool randomStepping = false;
|
bool egibleToDance = true;
|
||||||
bool ignoreFieldDamage = false;
|
|
||||||
|
|
||||||
void onCreatureEnter(Creature* creature);
|
void onCreatureEnter(Creature* creature);
|
||||||
void onCreatureLeave(Creature* creature);
|
void onCreatureLeave(Creature* creature);
|
||||||
@@ -223,8 +215,8 @@ class Monster final : public Creature
|
|||||||
void clearTargetList();
|
void clearTargetList();
|
||||||
void clearFriendList();
|
void clearFriendList();
|
||||||
|
|
||||||
void death(Creature* lastHitCreature) override;
|
void death(Creature* lastHitCreature) final;
|
||||||
Item* getCorpse(Creature* lastHitCreature, Creature* mostDamageCreature) override;
|
Item* getCorpse(Creature* lastHitCreature, Creature* mostDamageCreature) final;
|
||||||
|
|
||||||
void setIdle(bool idle);
|
void setIdle(bool idle);
|
||||||
void updateIdleStatus();
|
void updateIdleStatus();
|
||||||
@@ -232,12 +224,11 @@ class Monster final : public Creature
|
|||||||
return isIdle;
|
return isIdle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onAddCondition(ConditionType_t type) override;
|
void onAddCondition(ConditionType_t type) final;
|
||||||
void onEndCondition(ConditionType_t type) override;
|
void onEndCondition(ConditionType_t type) final;
|
||||||
|
void onCreatureConvinced(const Creature* convincer, const Creature* creature) final;
|
||||||
|
|
||||||
bool canUseAttack(const Position& pos, const Creature* target) const;
|
bool canUseAttack(const Position& pos, const Creature* target) const;
|
||||||
bool canUseSpell(const Position& pos, const Position& targetPos,
|
|
||||||
const spellBlock_t& sb, uint32_t interval, bool& inRange, bool& resetTicks);
|
|
||||||
bool getRandomStep(const Position& creaturePos, Direction& direction) const;
|
bool getRandomStep(const Position& creaturePos, Direction& direction) const;
|
||||||
bool getDanceStep(const Position& creaturePos, Direction& direction,
|
bool getDanceStep(const Position& creaturePos, Direction& direction,
|
||||||
bool keepAttack = true, bool keepDistance = true);
|
bool keepAttack = true, bool keepDistance = true);
|
||||||
@@ -256,25 +247,28 @@ class Monster final : public Creature
|
|||||||
bool isFriend(const Creature* creature) const;
|
bool isFriend(const Creature* creature) const;
|
||||||
bool isOpponent(const Creature* creature) const;
|
bool isOpponent(const Creature* creature) const;
|
||||||
|
|
||||||
uint64_t getLostExperience() const override {
|
uint64_t getLostExperience() const final {
|
||||||
return skillLoss ? mType->info.experience : 0;
|
return skillLoss ? mType->info.experience : 0;
|
||||||
}
|
}
|
||||||
uint16_t getLookCorpse() const override {
|
uint16_t getLookCorpse() const final {
|
||||||
return mType->info.lookcorpse;
|
return mType->info.lookcorpse;
|
||||||
}
|
}
|
||||||
void dropLoot(Container* corpse, Creature* lastHitCreature) override;
|
void dropLoot(Container* corpse, Creature* lastHitCreature) final;
|
||||||
uint32_t getDamageImmunities() const override {
|
uint32_t getDamageImmunities() const final {
|
||||||
return mType->info.damageImmunities;
|
return mType->info.damageImmunities;
|
||||||
}
|
}
|
||||||
uint32_t getConditionImmunities() const override {
|
uint32_t getConditionImmunities() const final {
|
||||||
return mType->info.conditionImmunities;
|
return mType->info.conditionImmunities;
|
||||||
}
|
}
|
||||||
void getPathSearchParams(const Creature* creature, FindPathParams& fpp) const override;
|
void getPathSearchParams(const Creature* creature, FindPathParams& fpp) const final;
|
||||||
bool useCacheMap() const override {
|
bool useCacheMap() const final {
|
||||||
return !randomStepping;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend class LuaScriptInterface;
|
friend class LuaScriptInterface;
|
||||||
|
friend class AreaSpawnEvent;
|
||||||
|
friend class Combat;
|
||||||
|
friend class Creature;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
828
src/monsters.cpp
828
src/monsters.cpp
File diff suppressed because it is too large
Load Diff
112
src/monsters.h
112
src/monsters.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,9 +22,8 @@
|
|||||||
|
|
||||||
#include "creature.h"
|
#include "creature.h"
|
||||||
|
|
||||||
|
#define MAX_LOOTCHANCE 1000
|
||||||
const uint32_t MAX_LOOTCHANCE = 100000;
|
#define MAX_STATICWALK 100
|
||||||
const uint32_t MAX_STATICWALK = 100;
|
|
||||||
|
|
||||||
struct LootBlock {
|
struct LootBlock {
|
||||||
uint16_t id;
|
uint16_t id;
|
||||||
@@ -39,7 +38,7 @@ struct LootBlock {
|
|||||||
std::vector<LootBlock> childLoot;
|
std::vector<LootBlock> childLoot;
|
||||||
LootBlock() {
|
LootBlock() {
|
||||||
id = 0;
|
id = 0;
|
||||||
countmax = 1;
|
countmax = 0;
|
||||||
chance = 0;
|
chance = 0;
|
||||||
|
|
||||||
subType = -1;
|
subType = -1;
|
||||||
@@ -47,21 +46,9 @@ struct LootBlock {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Loot {
|
|
||||||
public:
|
|
||||||
Loot() = default;
|
|
||||||
|
|
||||||
// non-copyable
|
|
||||||
Loot(const Loot&) = delete;
|
|
||||||
Loot& operator=(const Loot&) = delete;
|
|
||||||
|
|
||||||
LootBlock lootBlock;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct summonBlock_t {
|
struct summonBlock_t {
|
||||||
std::string name;
|
std::string name;
|
||||||
uint32_t chance;
|
uint32_t chance;
|
||||||
uint32_t speed;
|
|
||||||
uint32_t max;
|
uint32_t max;
|
||||||
bool force = false;
|
bool force = false;
|
||||||
};
|
};
|
||||||
@@ -75,23 +62,23 @@ struct spellBlock_t {
|
|||||||
spellBlock_t(spellBlock_t&& other) :
|
spellBlock_t(spellBlock_t&& other) :
|
||||||
spell(other.spell),
|
spell(other.spell),
|
||||||
chance(other.chance),
|
chance(other.chance),
|
||||||
speed(other.speed),
|
|
||||||
range(other.range),
|
range(other.range),
|
||||||
minCombatValue(other.minCombatValue),
|
minCombatValue(other.minCombatValue),
|
||||||
maxCombatValue(other.maxCombatValue),
|
maxCombatValue(other.maxCombatValue),
|
||||||
combatSpell(other.combatSpell),
|
attack(other.attack),
|
||||||
isMelee(other.isMelee) {
|
skill(other.skill),
|
||||||
|
combatSpell(other.combatSpell) {
|
||||||
other.spell = nullptr;
|
other.spell = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseSpell* spell = nullptr;
|
BaseSpell* spell = nullptr;
|
||||||
uint32_t chance = 100;
|
uint32_t chance = 100;
|
||||||
uint32_t speed = 2000;
|
|
||||||
uint32_t range = 0;
|
uint32_t range = 0;
|
||||||
int32_t minCombatValue = 0;
|
int32_t minCombatValue = 0;
|
||||||
int32_t maxCombatValue = 0;
|
int32_t maxCombatValue = 0;
|
||||||
|
int32_t attack = 0;
|
||||||
|
int32_t skill = 0;
|
||||||
bool combatSpell = false;
|
bool combatSpell = false;
|
||||||
bool isMelee = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct voiceBlock_t {
|
struct voiceBlock_t {
|
||||||
@@ -124,14 +111,11 @@ class MonsterType
|
|||||||
uint64_t experience = 0;
|
uint64_t experience = 0;
|
||||||
|
|
||||||
uint32_t manaCost = 0;
|
uint32_t manaCost = 0;
|
||||||
uint32_t yellChance = 0;
|
|
||||||
uint32_t yellSpeedTicks = 0;
|
|
||||||
uint32_t staticAttackChance = 95;
|
|
||||||
uint32_t maxSummons = 0;
|
uint32_t maxSummons = 0;
|
||||||
uint32_t changeTargetSpeed = 0;
|
uint32_t changeTargetSpeed = 0;
|
||||||
uint32_t conditionImmunities = 0;
|
uint32_t conditionImmunities = 0;
|
||||||
uint32_t damageImmunities = 0;
|
uint32_t damageImmunities = 0;
|
||||||
uint32_t baseSpeed = 200;
|
uint32_t baseSpeed = 70;
|
||||||
|
|
||||||
int32_t creatureAppearEvent = -1;
|
int32_t creatureAppearEvent = -1;
|
||||||
int32_t creatureDisappearEvent = -1;
|
int32_t creatureDisappearEvent = -1;
|
||||||
@@ -143,8 +127,15 @@ class MonsterType
|
|||||||
int32_t health = 100;
|
int32_t health = 100;
|
||||||
int32_t healthMax = 100;
|
int32_t healthMax = 100;
|
||||||
int32_t changeTargetChance = 0;
|
int32_t changeTargetChance = 0;
|
||||||
int32_t defense = 0;
|
int32_t strategyNearestEnemy = 0;
|
||||||
|
int32_t strategyWeakestEnemy = 0;
|
||||||
|
int32_t strategyMostDamageEnemy = 0;
|
||||||
|
int32_t strategyRandomEnemy = 0;
|
||||||
int32_t armor = 0;
|
int32_t armor = 0;
|
||||||
|
int32_t defense = 0;
|
||||||
|
int32_t attack = 0;
|
||||||
|
int32_t skill = 0;
|
||||||
|
int32_t poison = 0;
|
||||||
|
|
||||||
bool canPushItems = false;
|
bool canPushItems = false;
|
||||||
bool canPushCreatures = false;
|
bool canPushCreatures = false;
|
||||||
@@ -155,11 +146,6 @@ class MonsterType
|
|||||||
bool isAttackable = true;
|
bool isAttackable = true;
|
||||||
bool isHostile = true;
|
bool isHostile = true;
|
||||||
bool hiddenHealth = false;
|
bool hiddenHealth = false;
|
||||||
bool canWalkOnEnergy = true;
|
|
||||||
bool canWalkOnFire = true;
|
|
||||||
bool canWalkOnPoison = true;
|
|
||||||
|
|
||||||
MonstersEvent_t eventType = MONSTERS_EVENT_NONE;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -169,57 +155,14 @@ class MonsterType
|
|||||||
MonsterType(const MonsterType&) = delete;
|
MonsterType(const MonsterType&) = delete;
|
||||||
MonsterType& operator=(const MonsterType&) = delete;
|
MonsterType& operator=(const MonsterType&) = delete;
|
||||||
|
|
||||||
bool loadCallback(LuaScriptInterface* scriptInterface);
|
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string nameDescription;
|
std::string nameDescription;
|
||||||
|
|
||||||
MonsterInfo info;
|
MonsterInfo info;
|
||||||
|
|
||||||
void loadLoot(MonsterType* monsterType, LootBlock lootblock);
|
void createLoot(Container* corpse);
|
||||||
};
|
bool createLootContainer(Container* parent, const LootBlock& lootblock);
|
||||||
|
std::vector<Item*> createLootItem(const LootBlock& lootBlock);
|
||||||
class MonsterSpell
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MonsterSpell() = default;
|
|
||||||
|
|
||||||
MonsterSpell(const MonsterSpell&) = delete;
|
|
||||||
MonsterSpell& operator=(const MonsterSpell&) = delete;
|
|
||||||
|
|
||||||
std::string name = "";
|
|
||||||
std::string scriptName = "";
|
|
||||||
|
|
||||||
uint8_t chance = 100;
|
|
||||||
uint8_t range = 0;
|
|
||||||
|
|
||||||
uint16_t interval = 2000;
|
|
||||||
|
|
||||||
int32_t minCombatValue = 0;
|
|
||||||
int32_t maxCombatValue = 0;
|
|
||||||
int32_t attack = 0;
|
|
||||||
int32_t skill = 0;
|
|
||||||
int32_t length = 0;
|
|
||||||
int32_t spread = 0;
|
|
||||||
int32_t radius = 0;
|
|
||||||
int32_t conditionMinDamage = 0;
|
|
||||||
int32_t conditionMaxDamage = 0;
|
|
||||||
int32_t conditionStartDamage = 0;
|
|
||||||
int32_t tickInterval = 0;
|
|
||||||
int32_t speedChange = 0;
|
|
||||||
int32_t duration = 0;
|
|
||||||
|
|
||||||
bool isScripted = false;
|
|
||||||
bool needTarget = false;
|
|
||||||
bool needDirection = false;
|
|
||||||
bool combatSpell = false;
|
|
||||||
bool isMelee = false;
|
|
||||||
|
|
||||||
Outfit_t outfit = {};
|
|
||||||
ShootType_t shoot = CONST_ANI_NONE;
|
|
||||||
MagicEffectClasses effect = CONST_ME_NONE;
|
|
||||||
ConditionType_t conditionType = CONDITION_NONE;
|
|
||||||
CombatType_t combatType = COMBAT_UNDEFINEDDAMAGE;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Monsters
|
class Monsters
|
||||||
@@ -237,23 +180,20 @@ class Monsters
|
|||||||
bool reload();
|
bool reload();
|
||||||
|
|
||||||
MonsterType* getMonsterType(const std::string& name);
|
MonsterType* getMonsterType(const std::string& name);
|
||||||
void addMonsterType(const std::string& name, MonsterType* mType);
|
|
||||||
bool deserializeSpell(MonsterSpell* spell, spellBlock_t& sb, const std::string& description = "");
|
|
||||||
|
|
||||||
std::unique_ptr<LuaScriptInterface> scriptInterface;
|
static uint32_t getLootRandom();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConditionDamage* getDamageCondition(ConditionType_t conditionType,
|
ConditionDamage* getDamageCondition(ConditionType_t conditionType, int32_t cycles, int32_t count, int32_t max_count);
|
||||||
int32_t maxDamage, int32_t minDamage, int32_t startDamage, uint32_t tickInterval);
|
|
||||||
bool deserializeSpell(const pugi::xml_node& node, spellBlock_t& sb, const std::string& description = "");
|
bool deserializeSpell(const pugi::xml_node& node, spellBlock_t& sb, const std::string& description = "");
|
||||||
|
|
||||||
MonsterType* loadMonster(const std::string& file, const std::string& monsterName, bool reloading = false);
|
bool loadMonster(const std::string& file, const std::string& monsterName, std::list<std::pair<MonsterType*, std::string>>& monsterScriptList, bool reloading = false);
|
||||||
|
|
||||||
void loadLootContainer(const pugi::xml_node& node, LootBlock&);
|
void loadLootContainer(const pugi::xml_node& node, LootBlock&);
|
||||||
bool loadLootItem(const pugi::xml_node& node, LootBlock&);
|
bool loadLootItem(const pugi::xml_node& node, LootBlock&);
|
||||||
|
|
||||||
std::map<std::string, MonsterType> monsters;
|
std::map<std::string, MonsterType> monsters;
|
||||||
std::map<std::string, std::string> unloadedMonsters;
|
std::unique_ptr<LuaScriptInterface> scriptInterface;
|
||||||
|
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,82 +0,0 @@
|
|||||||
/**
|
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "otpch.h"
|
|
||||||
|
|
||||||
#include "mounts.h"
|
|
||||||
|
|
||||||
#include "pugicast.h"
|
|
||||||
#include "tools.h"
|
|
||||||
|
|
||||||
bool Mounts::reload()
|
|
||||||
{
|
|
||||||
mounts.clear();
|
|
||||||
return loadFromXml();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Mounts::loadFromXml()
|
|
||||||
{
|
|
||||||
pugi::xml_document doc;
|
|
||||||
pugi::xml_parse_result result = doc.load_file("data/XML/mounts.xml");
|
|
||||||
if (!result) {
|
|
||||||
printXMLError("Error - Mounts::loadFromXml", "data/XML/mounts.xml", result);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto mountNode : doc.child("mounts").children()) {
|
|
||||||
mounts.emplace_back(
|
|
||||||
static_cast<uint8_t>(pugi::cast<uint16_t>(mountNode.attribute("id").value())),
|
|
||||||
pugi::cast<uint16_t>(mountNode.attribute("clientid").value()),
|
|
||||||
mountNode.attribute("name").as_string(),
|
|
||||||
pugi::cast<int32_t>(mountNode.attribute("speed").value()),
|
|
||||||
mountNode.attribute("premium").as_bool()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
mounts.shrink_to_fit();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mount* Mounts::getMountByID(uint8_t id)
|
|
||||||
{
|
|
||||||
auto it = std::find_if(mounts.begin(), mounts.end(), [id](const Mount& mount) {
|
|
||||||
return mount.id == id;
|
|
||||||
});
|
|
||||||
|
|
||||||
return it != mounts.end() ? &*it : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mount* Mounts::getMountByName(const std::string& name) {
|
|
||||||
auto mountName = name.c_str();
|
|
||||||
for (auto& it : mounts) {
|
|
||||||
if (strcasecmp(mountName, it.name.c_str()) == 0) {
|
|
||||||
return ⁢
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mount* Mounts::getMountByClientID(uint16_t clientId)
|
|
||||||
{
|
|
||||||
auto it = std::find_if(mounts.begin(), mounts.end(), [clientId](const Mount& mount) {
|
|
||||||
return mount.clientId == clientId;
|
|
||||||
});
|
|
||||||
|
|
||||||
return it != mounts.end() ? &*it : nullptr;
|
|
||||||
}
|
|
||||||
52
src/mounts.h
52
src/mounts.h
@@ -1,52 +0,0 @@
|
|||||||
/**
|
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef FS_MOUNTS_H_73716D11906A4C5C9F4A7B68D34C9BA6
|
|
||||||
#define FS_MOUNTS_H_73716D11906A4C5C9F4A7B68D34C9BA6
|
|
||||||
|
|
||||||
struct Mount
|
|
||||||
{
|
|
||||||
Mount(uint8_t id, uint16_t clientId, std::string name, int32_t speed, bool premium) :
|
|
||||||
name(std::move(name)), speed(speed), clientId(clientId), id(id), premium(premium) {}
|
|
||||||
|
|
||||||
std::string name;
|
|
||||||
int32_t speed;
|
|
||||||
uint16_t clientId;
|
|
||||||
uint8_t id;
|
|
||||||
bool premium;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Mounts
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool reload();
|
|
||||||
bool loadFromXml();
|
|
||||||
Mount* getMountByID(uint8_t id);
|
|
||||||
Mount* getMountByName(const std::string& name);
|
|
||||||
Mount* getMountByClientID(uint16_t clientId);
|
|
||||||
|
|
||||||
const std::vector<Mount>& getMounts() const {
|
|
||||||
return mounts;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<Mount> mounts;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
379
src/movement.cpp
379
src/movement.cpp
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -36,49 +36,43 @@ MoveEvents::MoveEvents() :
|
|||||||
|
|
||||||
MoveEvents::~MoveEvents()
|
MoveEvents::~MoveEvents()
|
||||||
{
|
{
|
||||||
clear(false);
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveEvents::clearMap(MoveListMap& map, bool fromLua)
|
void MoveEvents::clearMap(MoveListMap& map)
|
||||||
{
|
{
|
||||||
for (auto it = map.begin(); it != map.end(); ++it) {
|
std::unordered_set<MoveEvent*> set;
|
||||||
for (int eventType = MOVE_EVENT_STEP_IN; eventType < MOVE_EVENT_LAST; ++eventType) {
|
for (const auto& it : map) {
|
||||||
auto& moveEvents = it->second.moveEvent[eventType];
|
const MoveEventList& moveEventList = it.second;
|
||||||
for (auto find = moveEvents.begin(); find != moveEvents.end(); ) {
|
for (const auto& i : moveEventList.moveEvent) {
|
||||||
if (fromLua == find->fromLua) {
|
for (MoveEvent* moveEvent : i) {
|
||||||
find = moveEvents.erase(find);
|
set.insert(moveEvent);
|
||||||
} else {
|
|
||||||
++find;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
map.clear();
|
||||||
|
|
||||||
void MoveEvents::clearPosMap(MovePosListMap& map, bool fromLua)
|
for (MoveEvent* moveEvent : set) {
|
||||||
{
|
delete moveEvent;
|
||||||
for (auto it = map.begin(); it != map.end(); ++it) {
|
|
||||||
for (int eventType = MOVE_EVENT_STEP_IN; eventType < MOVE_EVENT_LAST; ++eventType) {
|
|
||||||
auto& moveEvents = it->second.moveEvent[eventType];
|
|
||||||
for (auto find = moveEvents.begin(); find != moveEvents.end(); ) {
|
|
||||||
if (fromLua == find->fromLua) {
|
|
||||||
find = moveEvents.erase(find);
|
|
||||||
} else {
|
|
||||||
++find;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveEvents::clear(bool fromLua)
|
void MoveEvents::clear()
|
||||||
{
|
{
|
||||||
clearMap(itemIdMap, fromLua);
|
clearMap(itemIdMap);
|
||||||
clearMap(actionIdMap, fromLua);
|
clearMap(movementIdMap);
|
||||||
clearMap(uniqueIdMap, fromLua);
|
|
||||||
clearPosMap(positionMap, fromLua);
|
|
||||||
|
|
||||||
reInitState(fromLua);
|
for (const auto& it : positionMap) {
|
||||||
|
const MoveEventList& moveEventList = it.second;
|
||||||
|
for (const auto& i : moveEventList.moveEvent) {
|
||||||
|
for (MoveEvent* moveEvent : i) {
|
||||||
|
delete moveEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
positionMap.clear();
|
||||||
|
|
||||||
|
scriptInterface.reInitState();
|
||||||
}
|
}
|
||||||
|
|
||||||
LuaScriptInterface& MoveEvents::getScriptInterface()
|
LuaScriptInterface& MoveEvents::getScriptInterface()
|
||||||
@@ -91,17 +85,17 @@ std::string MoveEvents::getScriptBaseName() const
|
|||||||
return "movements";
|
return "movements";
|
||||||
}
|
}
|
||||||
|
|
||||||
Event_ptr MoveEvents::getEvent(const std::string& nodeName)
|
Event* MoveEvents::getEvent(const std::string& nodeName)
|
||||||
{
|
{
|
||||||
if (strcasecmp(nodeName.c_str(), "movevent") != 0) {
|
if (strcasecmp(nodeName.c_str(), "movevent") != 0) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return Event_ptr(new MoveEvent(&scriptInterface));
|
return new MoveEvent(&scriptInterface);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MoveEvents::registerEvent(Event_ptr event, const pugi::xml_node& node)
|
bool MoveEvents::registerEvent(Event* event, const pugi::xml_node& node)
|
||||||
{
|
{
|
||||||
MoveEvent_ptr moveEvent{static_cast<MoveEvent*>(event.release())}; //event is guaranteed to be a MoveEvent
|
MoveEvent* moveEvent = static_cast<MoveEvent*>(event); //event is guaranteed to be a MoveEvent
|
||||||
|
|
||||||
const MoveEvent_t eventType = moveEvent->getEventType();
|
const MoveEvent_t eventType = moveEvent->getEventType();
|
||||||
if (eventType == MOVE_EVENT_ADD_ITEM || eventType == MOVE_EVENT_REMOVE_ITEM) {
|
if (eventType == MOVE_EVENT_ADD_ITEM || eventType == MOVE_EVENT_REMOVE_ITEM) {
|
||||||
@@ -123,6 +117,7 @@ bool MoveEvents::registerEvent(Event_ptr event, const pugi::xml_node& node)
|
|||||||
pugi::xml_attribute attr;
|
pugi::xml_attribute attr;
|
||||||
if ((attr = node.attribute("itemid"))) {
|
if ((attr = node.attribute("itemid"))) {
|
||||||
int32_t id = pugi::cast<int32_t>(attr.value());
|
int32_t id = pugi::cast<int32_t>(attr.value());
|
||||||
|
addEvent(moveEvent, id, itemIdMap);
|
||||||
if (moveEvent->getEventType() == MOVE_EVENT_EQUIP) {
|
if (moveEvent->getEventType() == MOVE_EVENT_EQUIP) {
|
||||||
ItemType& it = Item::items.getItemType(id);
|
ItemType& it = Item::items.getItemType(id);
|
||||||
it.wieldInfo = moveEvent->getWieldInfo();
|
it.wieldInfo = moveEvent->getWieldInfo();
|
||||||
@@ -130,12 +125,11 @@ bool MoveEvents::registerEvent(Event_ptr event, const pugi::xml_node& node)
|
|||||||
it.minReqMagicLevel = moveEvent->getReqMagLv();
|
it.minReqMagicLevel = moveEvent->getReqMagLv();
|
||||||
it.vocationString = moveEvent->getVocationString();
|
it.vocationString = moveEvent->getVocationString();
|
||||||
}
|
}
|
||||||
addEvent(std::move(*moveEvent), id, itemIdMap);
|
|
||||||
} else if ((attr = node.attribute("fromid"))) {
|
} else if ((attr = node.attribute("fromid"))) {
|
||||||
uint32_t id = pugi::cast<uint32_t>(attr.value());
|
uint32_t id = pugi::cast<uint32_t>(attr.value());
|
||||||
uint32_t endId = pugi::cast<uint32_t>(node.attribute("toid").value());
|
uint32_t endId = pugi::cast<uint32_t>(node.attribute("toid").value());
|
||||||
|
|
||||||
addEvent(*moveEvent, id, itemIdMap);
|
addEvent(moveEvent, id, itemIdMap);
|
||||||
|
|
||||||
if (moveEvent->getEventType() == MOVE_EVENT_EQUIP) {
|
if (moveEvent->getEventType() == MOVE_EVENT_EQUIP) {
|
||||||
ItemType& it = Item::items.getItemType(id);
|
ItemType& it = Item::items.getItemType(id);
|
||||||
@@ -145,7 +139,7 @@ bool MoveEvents::registerEvent(Event_ptr event, const pugi::xml_node& node)
|
|||||||
it.vocationString = moveEvent->getVocationString();
|
it.vocationString = moveEvent->getVocationString();
|
||||||
|
|
||||||
while (++id <= endId) {
|
while (++id <= endId) {
|
||||||
addEvent(*moveEvent, id, itemIdMap);
|
addEvent(moveEvent, id, itemIdMap);
|
||||||
|
|
||||||
ItemType& tit = Item::items.getItemType(id);
|
ItemType& tit = Item::items.getItemType(id);
|
||||||
tit.wieldInfo = moveEvent->getWieldInfo();
|
tit.wieldInfo = moveEvent->getWieldInfo();
|
||||||
@@ -155,26 +149,17 @@ bool MoveEvents::registerEvent(Event_ptr event, const pugi::xml_node& node)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (++id <= endId) {
|
while (++id <= endId) {
|
||||||
addEvent(*moveEvent, id, itemIdMap);
|
addEvent(moveEvent, id, itemIdMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ((attr = node.attribute("uniqueid"))) {
|
} else if ((attr = node.attribute("movementid"))) {
|
||||||
addEvent(std::move(*moveEvent), pugi::cast<int32_t>(attr.value()), uniqueIdMap);
|
addEvent(moveEvent, pugi::cast<int32_t>(attr.value()), movementIdMap);
|
||||||
} else if ((attr = node.attribute("fromuid"))) {
|
} else if ((attr = node.attribute("frommovementid"))) {
|
||||||
uint32_t id = pugi::cast<uint32_t>(attr.value());
|
uint32_t id = pugi::cast<uint32_t>(attr.value());
|
||||||
uint32_t endId = pugi::cast<uint32_t>(node.attribute("touid").value());
|
uint32_t endId = pugi::cast<uint32_t>(node.attribute("tomovementid").value());
|
||||||
addEvent(*moveEvent, id, uniqueIdMap);
|
addEvent(moveEvent, id, movementIdMap);
|
||||||
while (++id <= endId) {
|
while (++id <= endId) {
|
||||||
addEvent(*moveEvent, id, uniqueIdMap);
|
addEvent(moveEvent, id, movementIdMap);
|
||||||
}
|
|
||||||
} else if ((attr = node.attribute("actionid"))) {
|
|
||||||
addEvent(std::move(*moveEvent), pugi::cast<int32_t>(attr.value()), actionIdMap);
|
|
||||||
} else if ((attr = node.attribute("fromaid"))) {
|
|
||||||
uint32_t id = pugi::cast<uint32_t>(attr.value());
|
|
||||||
uint32_t endId = pugi::cast<uint32_t>(node.attribute("toaid").value());
|
|
||||||
addEvent(*moveEvent, id, actionIdMap);
|
|
||||||
while (++id <= endId) {
|
|
||||||
addEvent(*moveEvent, id, actionIdMap);
|
|
||||||
}
|
}
|
||||||
} else if ((attr = node.attribute("pos"))) {
|
} else if ((attr = node.attribute("pos"))) {
|
||||||
std::vector<int32_t> posList = vectorAtoi(explodeString(attr.as_string(), ";"));
|
std::vector<int32_t> posList = vectorAtoi(explodeString(attr.as_string(), ";"));
|
||||||
@@ -183,125 +168,28 @@ bool MoveEvents::registerEvent(Event_ptr event, const pugi::xml_node& node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Position pos(posList[0], posList[1], posList[2]);
|
Position pos(posList[0], posList[1], posList[2]);
|
||||||
addEvent(std::move(*moveEvent), pos, positionMap);
|
addEvent(moveEvent, pos, positionMap);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MoveEvents::registerLuaFunction(MoveEvent* event)
|
void MoveEvents::addEvent(MoveEvent* moveEvent, int32_t id, MoveListMap& map)
|
||||||
{
|
|
||||||
MoveEvent_ptr moveEvent{ event };
|
|
||||||
if (moveEvent->getItemIdRange().size() > 0) {
|
|
||||||
if (moveEvent->getItemIdRange().size() == 1) {
|
|
||||||
uint32_t id = moveEvent->getItemIdRange().at(0);
|
|
||||||
addEvent(*moveEvent, id, itemIdMap);
|
|
||||||
if (moveEvent->getEventType() == MOVE_EVENT_EQUIP) {
|
|
||||||
ItemType& it = Item::items.getItemType(id);
|
|
||||||
it.wieldInfo = moveEvent->getWieldInfo();
|
|
||||||
it.minReqLevel = moveEvent->getReqLevel();
|
|
||||||
it.minReqMagicLevel = moveEvent->getReqMagLv();
|
|
||||||
it.vocationString = moveEvent->getVocationString();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uint32_t iterId = 0;
|
|
||||||
while (++iterId < moveEvent->getItemIdRange().size()) {
|
|
||||||
if (moveEvent->getEventType() == MOVE_EVENT_EQUIP) {
|
|
||||||
ItemType& it = Item::items.getItemType(moveEvent->getItemIdRange().at(iterId));
|
|
||||||
it.wieldInfo = moveEvent->getWieldInfo();
|
|
||||||
it.minReqLevel = moveEvent->getReqLevel();
|
|
||||||
it.minReqMagicLevel = moveEvent->getReqMagLv();
|
|
||||||
it.vocationString = moveEvent->getVocationString();
|
|
||||||
}
|
|
||||||
addEvent(*moveEvent, moveEvent->getItemIdRange().at(iterId), itemIdMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MoveEvents::registerLuaEvent(MoveEvent* event)
|
|
||||||
{
|
|
||||||
MoveEvent_ptr moveEvent{ event };
|
|
||||||
if (moveEvent->getItemIdRange().size() > 0) {
|
|
||||||
if (moveEvent->getItemIdRange().size() == 1) {
|
|
||||||
uint32_t id = moveEvent->getItemIdRange().at(0);
|
|
||||||
addEvent(*moveEvent, id, itemIdMap);
|
|
||||||
if (moveEvent->getEventType() == MOVE_EVENT_EQUIP) {
|
|
||||||
ItemType& it = Item::items.getItemType(id);
|
|
||||||
it.wieldInfo = moveEvent->getWieldInfo();
|
|
||||||
it.minReqLevel = moveEvent->getReqLevel();
|
|
||||||
it.minReqMagicLevel = moveEvent->getReqMagLv();
|
|
||||||
it.vocationString = moveEvent->getVocationString();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
auto v = moveEvent->getItemIdRange();
|
|
||||||
for (auto i = v.begin(); i != v.end(); i++) {
|
|
||||||
if (moveEvent->getEventType() == MOVE_EVENT_EQUIP) {
|
|
||||||
ItemType& it = Item::items.getItemType(*i);
|
|
||||||
it.wieldInfo = moveEvent->getWieldInfo();
|
|
||||||
it.minReqLevel = moveEvent->getReqLevel();
|
|
||||||
it.minReqMagicLevel = moveEvent->getReqMagLv();
|
|
||||||
it.vocationString = moveEvent->getVocationString();
|
|
||||||
}
|
|
||||||
addEvent(*moveEvent, *i, itemIdMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (moveEvent->getActionIdRange().size() > 0) {
|
|
||||||
if (moveEvent->getActionIdRange().size() == 1) {
|
|
||||||
int32_t id = moveEvent->getActionIdRange().at(0);
|
|
||||||
addEvent(*moveEvent, id, actionIdMap);
|
|
||||||
} else {
|
|
||||||
auto v = moveEvent->getActionIdRange();
|
|
||||||
for (auto i = v.begin(); i != v.end(); i++) {
|
|
||||||
addEvent(*moveEvent, *i, actionIdMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (moveEvent->getUniqueIdRange().size() > 0) {
|
|
||||||
if (moveEvent->getUniqueIdRange().size() == 1) {
|
|
||||||
int32_t id = moveEvent->getUniqueIdRange().at(0);
|
|
||||||
addEvent(*moveEvent, id, uniqueIdMap);
|
|
||||||
} else {
|
|
||||||
auto v = moveEvent->getUniqueIdRange();
|
|
||||||
for (auto i = v.begin(); i != v.end(); i++) {
|
|
||||||
addEvent(*moveEvent, *i, uniqueIdMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (moveEvent->getPosList().size() > 0) {
|
|
||||||
if (moveEvent->getPosList().size() == 1) {
|
|
||||||
Position pos = moveEvent->getPosList().at(0);
|
|
||||||
addEvent(*moveEvent, pos, positionMap);
|
|
||||||
} else {
|
|
||||||
auto v = moveEvent->getPosList();
|
|
||||||
for (auto i = v.begin(); i != v.end(); i++) {
|
|
||||||
addEvent(*moveEvent, *i, positionMap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveEvents::addEvent(MoveEvent moveEvent, int32_t id, MoveListMap& map)
|
|
||||||
{
|
{
|
||||||
auto it = map.find(id);
|
auto it = map.find(id);
|
||||||
if (it == map.end()) {
|
if (it == map.end()) {
|
||||||
MoveEventList moveEventList;
|
MoveEventList moveEventList;
|
||||||
moveEventList.moveEvent[moveEvent.getEventType()].push_back(std::move(moveEvent));
|
moveEventList.moveEvent[moveEvent->getEventType()].push_back(moveEvent);
|
||||||
map[id] = moveEventList;
|
map[id] = moveEventList;
|
||||||
} else {
|
} else {
|
||||||
std::list<MoveEvent>& moveEventList = it->second.moveEvent[moveEvent.getEventType()];
|
std::list<MoveEvent*>& moveEventList = it->second.moveEvent[moveEvent->getEventType()];
|
||||||
for (MoveEvent& existingMoveEvent : moveEventList) {
|
for (MoveEvent* existingMoveEvent : moveEventList) {
|
||||||
if (existingMoveEvent.getSlot() == moveEvent.getSlot()) {
|
if (existingMoveEvent->getSlot() == moveEvent->getSlot()) {
|
||||||
std::cout << "[Warning - MoveEvents::addEvent] Duplicate move event found: " << id << std::endl;
|
std::cout << "[Warning - MoveEvents::addEvent] Duplicate move event found: " << id << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
moveEventList.push_back(std::move(moveEvent));
|
moveEventList.push_back(moveEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,10 +212,10 @@ MoveEvent* MoveEvents::getEvent(Item* item, MoveEvent_t eventType, slots_t slot)
|
|||||||
|
|
||||||
auto it = itemIdMap.find(item->getID());
|
auto it = itemIdMap.find(item->getID());
|
||||||
if (it != itemIdMap.end()) {
|
if (it != itemIdMap.end()) {
|
||||||
std::list<MoveEvent>& moveEventList = it->second.moveEvent[eventType];
|
std::list<MoveEvent*>& moveEventList = it->second.moveEvent[eventType];
|
||||||
for (MoveEvent& moveEvent : moveEventList) {
|
for (MoveEvent* moveEvent : moveEventList) {
|
||||||
if ((moveEvent.getSlot() & slotp) != 0) {
|
if ((moveEvent->getSlot() & slotp) != 0) {
|
||||||
return &moveEvent;
|
return moveEvent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -338,50 +226,45 @@ MoveEvent* MoveEvents::getEvent(Item* item, MoveEvent_t eventType)
|
|||||||
{
|
{
|
||||||
MoveListMap::iterator it;
|
MoveListMap::iterator it;
|
||||||
|
|
||||||
if (item->hasAttribute(ITEM_ATTRIBUTE_UNIQUEID)) {
|
if (item->hasAttribute(ITEM_ATTRIBUTE_MOVEMENTID)) {
|
||||||
it = uniqueIdMap.find(item->getUniqueId());
|
it = movementIdMap.find(item->getMovementId());
|
||||||
if (it != uniqueIdMap.end()) {
|
if (it != movementIdMap.end()) {
|
||||||
std::list<MoveEvent>& moveEventList = it->second.moveEvent[eventType];
|
std::list<MoveEvent*>& moveEventList = it->second.moveEvent[eventType];
|
||||||
if (!moveEventList.empty()) {
|
if (!moveEventList.empty()) {
|
||||||
return &(*moveEventList.begin());
|
return *moveEventList.begin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->hasAttribute(ITEM_ATTRIBUTE_ACTIONID)) {
|
if (!item->hasCollisionEvent() && !item->hasSeparationEvent()) {
|
||||||
it = actionIdMap.find(item->getActionId());
|
return nullptr;
|
||||||
if (it != actionIdMap.end()) {
|
|
||||||
std::list<MoveEvent>& moveEventList = it->second.moveEvent[eventType];
|
|
||||||
if (!moveEventList.empty()) {
|
|
||||||
return &(*moveEventList.begin());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
it = itemIdMap.find(item->getID());
|
it = itemIdMap.find(item->getID());
|
||||||
if (it != itemIdMap.end()) {
|
if (it != itemIdMap.end()) {
|
||||||
std::list<MoveEvent>& moveEventList = it->second.moveEvent[eventType];
|
std::list<MoveEvent*>& moveEventList = it->second.moveEvent[eventType];
|
||||||
if (!moveEventList.empty()) {
|
if (!moveEventList.empty()) {
|
||||||
return &(*moveEventList.begin());
|
return *moveEventList.begin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoveEvents::addEvent(MoveEvent moveEvent, const Position& pos, MovePosListMap& map)
|
void MoveEvents::addEvent(MoveEvent* moveEvent, const Position& pos, MovePosListMap& map)
|
||||||
{
|
{
|
||||||
auto it = map.find(pos);
|
auto it = map.find(pos);
|
||||||
if (it == map.end()) {
|
if (it == map.end()) {
|
||||||
MoveEventList moveEventList;
|
MoveEventList moveEventList;
|
||||||
moveEventList.moveEvent[moveEvent.getEventType()].push_back(std::move(moveEvent));
|
moveEventList.moveEvent[moveEvent->getEventType()].push_back(moveEvent);
|
||||||
map[pos] = moveEventList;
|
map[pos] = moveEventList;
|
||||||
} else {
|
} else {
|
||||||
std::list<MoveEvent>& moveEventList = it->second.moveEvent[moveEvent.getEventType()];
|
std::list<MoveEvent*>& moveEventList = it->second.moveEvent[moveEvent->getEventType()];
|
||||||
if (!moveEventList.empty()) {
|
if (!moveEventList.empty()) {
|
||||||
std::cout << "[Warning - MoveEvents::addEvent] Duplicate move event found: " << pos << std::endl;
|
std::cout << "[Warning - MoveEvents::addEvent] Duplicate move event found: " << pos << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
moveEventList.push_back(std::move(moveEvent));
|
moveEventList.push_back(moveEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,9 +272,9 @@ MoveEvent* MoveEvents::getEvent(const Tile* tile, MoveEvent_t eventType)
|
|||||||
{
|
{
|
||||||
auto it = positionMap.find(tile->getPosition());
|
auto it = positionMap.find(tile->getPosition());
|
||||||
if (it != positionMap.end()) {
|
if (it != positionMap.end()) {
|
||||||
std::list<MoveEvent>& moveEventList = it->second.moveEvent[eventType];
|
std::list<MoveEvent*>& moveEventList = it->second.moveEvent[eventType];
|
||||||
if (!moveEventList.empty()) {
|
if (!moveEventList.empty()) {
|
||||||
return &(*moveEventList.begin());
|
return *moveEventList.begin();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -442,7 +325,7 @@ uint32_t MoveEvents::onPlayerDeEquip(Player* player, Item* item, slots_t slot)
|
|||||||
if (!moveEvent) {
|
if (!moveEvent) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return moveEvent->fireEquip(player, item, slot, false);
|
return moveEvent->fireEquip(player, item, slot, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t MoveEvents::onItemMove(Item* item, Tile* tile, bool isAdd)
|
uint32_t MoveEvents::onItemMove(Item* item, Tile* tile, bool isAdd)
|
||||||
@@ -488,6 +371,20 @@ uint32_t MoveEvents::onItemMove(Item* item, Tile* tile, bool isAdd)
|
|||||||
|
|
||||||
MoveEvent::MoveEvent(LuaScriptInterface* interface) : Event(interface) {}
|
MoveEvent::MoveEvent(LuaScriptInterface* interface) : Event(interface) {}
|
||||||
|
|
||||||
|
MoveEvent::MoveEvent(const MoveEvent* copy) :
|
||||||
|
Event(copy),
|
||||||
|
eventType(copy->eventType),
|
||||||
|
stepFunction(copy->stepFunction),
|
||||||
|
moveFunction(copy->moveFunction),
|
||||||
|
equipFunction(copy->equipFunction),
|
||||||
|
slot(copy->slot),
|
||||||
|
reqLevel(copy->reqLevel),
|
||||||
|
reqMagLevel(copy->reqMagLevel),
|
||||||
|
premium(copy->premium),
|
||||||
|
vocationString(copy->vocationString),
|
||||||
|
wieldInfo(copy->wieldInfo),
|
||||||
|
vocEquipMap(copy->vocEquipMap) {}
|
||||||
|
|
||||||
std::string MoveEvent::getScriptEventName() const
|
std::string MoveEvent::getScriptEventName() const
|
||||||
{
|
{
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
@@ -624,6 +521,40 @@ bool MoveEvent::configureEvent(const pugi::xml_node& node)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MoveEvent::loadFunction(const pugi::xml_attribute& attr)
|
||||||
|
{
|
||||||
|
const char* functionName = attr.as_string();
|
||||||
|
if (strcasecmp(functionName, "onstepinfield") == 0) {
|
||||||
|
stepFunction = StepInField;
|
||||||
|
} else if (strcasecmp(functionName, "onstepoutfield") == 0) {
|
||||||
|
stepFunction = StepOutField;
|
||||||
|
} else if (strcasecmp(functionName, "onaddfield") == 0) {
|
||||||
|
moveFunction = AddItemField;
|
||||||
|
} else if (strcasecmp(functionName, "onremovefield") == 0) {
|
||||||
|
moveFunction = RemoveItemField;
|
||||||
|
} else if (strcasecmp(functionName, "onequipitem") == 0) {
|
||||||
|
equipFunction = EquipItem;
|
||||||
|
} else if (strcasecmp(functionName, "ondeequipitem") == 0) {
|
||||||
|
equipFunction = DeEquipItem;
|
||||||
|
} else {
|
||||||
|
std::cout << "[Warning - MoveEvent::loadFunction] Function \"" << functionName << "\" does not exist." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
scripted = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MoveEvent_t MoveEvent::getEventType() const
|
||||||
|
{
|
||||||
|
return eventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoveEvent::setEventType(MoveEvent_t type)
|
||||||
|
{
|
||||||
|
eventType = type;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t MoveEvent::StepInField(Creature* creature, Item* item, const Position&)
|
uint32_t MoveEvent::StepInField(Creature* creature, Item* item, const Position&)
|
||||||
{
|
{
|
||||||
MagicField* field = item->getMagicField();
|
MagicField* field = item->getMagicField();
|
||||||
@@ -715,6 +646,10 @@ uint32_t MoveEvent::EquipItem(MoveEvent* moveEvent, Player* player, Item* item,
|
|||||||
player->sendIcons();
|
player->sendIcons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (it.abilities->absorbPercent[combatTypeToIndex(COMBAT_DROWNDAMAGE)] == 100) {
|
||||||
|
player->removeCondition(CONDITION_DROWN);
|
||||||
|
}
|
||||||
|
|
||||||
if (it.abilities->regeneration) {
|
if (it.abilities->regeneration) {
|
||||||
Condition* condition = Condition::createCondition(static_cast<ConditionId_t>(slot), CONDITION_REGENERATION, -1, 0);
|
Condition* condition = Condition::createCondition(static_cast<ConditionId_t>(slot), CONDITION_REGENERATION, -1, 0);
|
||||||
|
|
||||||
@@ -747,13 +682,6 @@ uint32_t MoveEvent::EquipItem(MoveEvent* moveEvent, Player* player, Item* item,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int32_t i = SPECIALSKILL_FIRST; i <= SPECIALSKILL_LAST; ++i) {
|
|
||||||
if (it.abilities->specialSkills[i]) {
|
|
||||||
needUpdateSkills = true;
|
|
||||||
player->setVarSpecialSkill(static_cast<SpecialSkills_t>(i), it.abilities->specialSkills[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needUpdateSkills) {
|
if (needUpdateSkills) {
|
||||||
player->sendSkills();
|
player->sendSkills();
|
||||||
}
|
}
|
||||||
@@ -829,13 +757,6 @@ uint32_t MoveEvent::DeEquipItem(MoveEvent*, Player* player, Item* item, slots_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int32_t i = SPECIALSKILL_FIRST; i <= SPECIALSKILL_LAST; ++i) {
|
|
||||||
if (it.abilities->specialSkills[i] != 0) {
|
|
||||||
needUpdateSkills = true;
|
|
||||||
player->setVarSpecialSkill(static_cast<SpecialSkills_t>(i), -it.abilities->specialSkills[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needUpdateSkills) {
|
if (needUpdateSkills) {
|
||||||
player->sendSkills();
|
player->sendSkills();
|
||||||
}
|
}
|
||||||
@@ -862,44 +783,6 @@ uint32_t MoveEvent::DeEquipItem(MoveEvent*, Player* player, Item* item, slots_t
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MoveEvent::loadFunction(const pugi::xml_attribute& attr, bool isScripted)
|
|
||||||
{
|
|
||||||
const char* functionName = attr.as_string();
|
|
||||||
if (strcasecmp(functionName, "onstepinfield") == 0) {
|
|
||||||
stepFunction = StepInField;
|
|
||||||
} else if (strcasecmp(functionName, "onstepoutfield") == 0) {
|
|
||||||
stepFunction = StepOutField;
|
|
||||||
} else if (strcasecmp(functionName, "onaddfield") == 0) {
|
|
||||||
moveFunction = AddItemField;
|
|
||||||
} else if (strcasecmp(functionName, "onremovefield") == 0) {
|
|
||||||
moveFunction = RemoveItemField;
|
|
||||||
} else if (strcasecmp(functionName, "onequipitem") == 0) {
|
|
||||||
equipFunction = EquipItem;
|
|
||||||
} else if (strcasecmp(functionName, "ondeequipitem") == 0) {
|
|
||||||
equipFunction = DeEquipItem;
|
|
||||||
} else {
|
|
||||||
if (!isScripted) {
|
|
||||||
std::cout << "[Warning - MoveEvent::loadFunction] Function \"" << functionName << "\" does not exist." << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isScripted) {
|
|
||||||
scripted = false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
MoveEvent_t MoveEvent::getEventType() const
|
|
||||||
{
|
|
||||||
return eventType;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MoveEvent::setEventType(MoveEvent_t type)
|
|
||||||
{
|
|
||||||
eventType = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t MoveEvent::fireStepEvent(Creature* creature, Item* item, const Position& pos)
|
uint32_t MoveEvent::fireStepEvent(Creature* creature, Item* item, const Position& pos)
|
||||||
{
|
{
|
||||||
if (scripted) {
|
if (scripted) {
|
||||||
@@ -933,24 +816,19 @@ bool MoveEvent::executeStep(Creature* creature, Item* item, const Position& pos)
|
|||||||
return scriptInterface->callFunction(4);
|
return scriptInterface->callFunction(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t MoveEvent::fireEquip(Player* player, Item* item, slots_t slot, bool isCheck)
|
uint32_t MoveEvent::fireEquip(Player* player, Item* item, slots_t slot, bool boolean)
|
||||||
{
|
{
|
||||||
if (scripted) {
|
if (scripted) {
|
||||||
if (!equipFunction || equipFunction(this, player, item, slot, isCheck) == 1) {
|
return executeEquip(player, item, slot);
|
||||||
if (executeEquip(player, item, slot, isCheck)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} else {
|
} else {
|
||||||
return equipFunction(this, player, item, slot, isCheck);
|
return equipFunction(this, player, item, slot, boolean);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MoveEvent::executeEquip(Player* player, Item* item, slots_t slot, bool isCheck)
|
bool MoveEvent::executeEquip(Player* player, Item* item, slots_t slot)
|
||||||
{
|
{
|
||||||
//onEquip(player, item, slot, isCheck)
|
//onEquip(player, item, slot)
|
||||||
//onDeEquip(player, item, slot, isCheck)
|
//onDeEquip(player, item, slot)
|
||||||
if (!scriptInterface->reserveScriptEnv()) {
|
if (!scriptInterface->reserveScriptEnv()) {
|
||||||
std::cout << "[Error - MoveEvent::executeEquip] Call stack overflow" << std::endl;
|
std::cout << "[Error - MoveEvent::executeEquip] Call stack overflow" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
@@ -966,9 +844,8 @@ bool MoveEvent::executeEquip(Player* player, Item* item, slots_t slot, bool isCh
|
|||||||
LuaScriptInterface::setMetatable(L, -1, "Player");
|
LuaScriptInterface::setMetatable(L, -1, "Player");
|
||||||
LuaScriptInterface::pushThing(L, item);
|
LuaScriptInterface::pushThing(L, item);
|
||||||
lua_pushnumber(L, slot);
|
lua_pushnumber(L, slot);
|
||||||
LuaScriptInterface::pushBoolean(L, isCheck);
|
|
||||||
|
|
||||||
return scriptInterface->callFunction(4);
|
return scriptInterface->callFunction(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t MoveEvent::fireAddRemItem(Item* item, Item* tileItem, const Position& pos)
|
uint32_t MoveEvent::fireAddRemItem(Item* item, Item* tileItem, const Position& pos)
|
||||||
|
|||||||
160
src/movement.h
160
src/movement.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -23,9 +23,6 @@
|
|||||||
#include "baseevents.h"
|
#include "baseevents.h"
|
||||||
#include "item.h"
|
#include "item.h"
|
||||||
#include "luascript.h"
|
#include "luascript.h"
|
||||||
#include "vocation.h"
|
|
||||||
|
|
||||||
extern Vocations g_vocations;
|
|
||||||
|
|
||||||
enum MoveEvent_t {
|
enum MoveEvent_t {
|
||||||
MOVE_EVENT_STEP_IN,
|
MOVE_EVENT_STEP_IN,
|
||||||
@@ -42,13 +39,12 @@ enum MoveEvent_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class MoveEvent;
|
class MoveEvent;
|
||||||
using MoveEvent_ptr = std::unique_ptr<MoveEvent>;
|
|
||||||
|
|
||||||
struct MoveEventList {
|
struct MoveEventList {
|
||||||
std::list<MoveEvent> moveEvent[MOVE_EVENT_LAST];
|
std::list<MoveEvent*> moveEvent[MOVE_EVENT_LAST];
|
||||||
};
|
};
|
||||||
|
|
||||||
using VocEquipMap = std::map<uint16_t, bool>;
|
typedef std::map<uint16_t, bool> VocEquipMap;
|
||||||
|
|
||||||
class MoveEvents final : public BaseEvents
|
class MoveEvents final : public BaseEvents
|
||||||
{
|
{
|
||||||
@@ -67,54 +63,51 @@ class MoveEvents final : public BaseEvents
|
|||||||
|
|
||||||
MoveEvent* getEvent(Item* item, MoveEvent_t eventType);
|
MoveEvent* getEvent(Item* item, MoveEvent_t eventType);
|
||||||
|
|
||||||
bool registerLuaEvent(MoveEvent* event);
|
protected:
|
||||||
bool registerLuaFunction(MoveEvent* event);
|
typedef std::map<int32_t, MoveEventList> MoveListMap;
|
||||||
void clear(bool fromLua) override final;
|
void clearMap(MoveListMap& map);
|
||||||
|
|
||||||
private:
|
typedef std::map<Position, MoveEventList> MovePosListMap;
|
||||||
using MoveListMap = std::map<int32_t, MoveEventList>;
|
void clear() final;
|
||||||
using MovePosListMap = std::map<Position, MoveEventList>;
|
LuaScriptInterface& getScriptInterface() final;
|
||||||
void clearMap(MoveListMap& map, bool fromLua);
|
std::string getScriptBaseName() const final;
|
||||||
void clearPosMap(MovePosListMap& map, bool fromLua);
|
Event* getEvent(const std::string& nodeName) final;
|
||||||
|
bool registerEvent(Event* event, const pugi::xml_node& node) final;
|
||||||
|
|
||||||
LuaScriptInterface& getScriptInterface() override;
|
void addEvent(MoveEvent* moveEvent, int32_t id, MoveListMap& map);
|
||||||
std::string getScriptBaseName() const override;
|
|
||||||
Event_ptr getEvent(const std::string& nodeName) override;
|
|
||||||
bool registerEvent(Event_ptr event, const pugi::xml_node& node) override;
|
|
||||||
|
|
||||||
void addEvent(MoveEvent moveEvent, int32_t id, MoveListMap& map);
|
void addEvent(MoveEvent* moveEvent, const Position& pos, MovePosListMap& map);
|
||||||
|
|
||||||
void addEvent(MoveEvent moveEvent, const Position& pos, MovePosListMap& map);
|
|
||||||
MoveEvent* getEvent(const Tile* tile, MoveEvent_t eventType);
|
MoveEvent* getEvent(const Tile* tile, MoveEvent_t eventType);
|
||||||
|
|
||||||
MoveEvent* getEvent(Item* item, MoveEvent_t eventType, slots_t slot);
|
MoveEvent* getEvent(Item* item, MoveEvent_t eventType, slots_t slot);
|
||||||
|
|
||||||
MoveListMap uniqueIdMap;
|
|
||||||
MoveListMap actionIdMap;
|
MoveListMap movementIdMap;
|
||||||
MoveListMap itemIdMap;
|
MoveListMap itemIdMap;
|
||||||
MovePosListMap positionMap;
|
MovePosListMap positionMap;
|
||||||
|
|
||||||
LuaScriptInterface scriptInterface;
|
LuaScriptInterface scriptInterface;
|
||||||
};
|
};
|
||||||
|
|
||||||
using StepFunction = std::function<uint32_t(Creature* creature, Item* item, const Position& pos)>;
|
typedef uint32_t (StepFunction)(Creature* creature, Item* item, const Position& pos);
|
||||||
using MoveFunction = std::function<uint32_t(Item* item, Item* tileItem, const Position& pos)>;
|
typedef uint32_t (MoveFunction)(Item* item, Item* tileItem, const Position& pos);
|
||||||
using EquipFunction = std::function<uint32_t(MoveEvent* moveEvent, Player* player, Item* item, slots_t slot, bool boolean)>;
|
typedef uint32_t (EquipFunction)(MoveEvent* moveEvent, Player* player, Item* item, slots_t slot, bool boolean);
|
||||||
|
|
||||||
class MoveEvent final : public Event
|
class MoveEvent final : public Event
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit MoveEvent(LuaScriptInterface* interface);
|
explicit MoveEvent(LuaScriptInterface* interface);
|
||||||
|
explicit MoveEvent(const MoveEvent* copy);
|
||||||
|
|
||||||
MoveEvent_t getEventType() const;
|
MoveEvent_t getEventType() const;
|
||||||
void setEventType(MoveEvent_t type);
|
void setEventType(MoveEvent_t type);
|
||||||
|
|
||||||
bool configureEvent(const pugi::xml_node& node) override;
|
bool configureEvent(const pugi::xml_node& node) final;
|
||||||
bool loadFunction(const pugi::xml_attribute& attr, bool isScripted) override;
|
bool loadFunction(const pugi::xml_attribute& attr) final;
|
||||||
|
|
||||||
uint32_t fireStepEvent(Creature* creature, Item* item, const Position& pos);
|
uint32_t fireStepEvent(Creature* creature, Item* item, const Position& pos);
|
||||||
uint32_t fireAddRemItem(Item* item, Item* tileItem, const Position& pos);
|
uint32_t fireAddRemItem(Item* item, Item* tileItem, const Position& pos);
|
||||||
uint32_t fireEquip(Player* player, Item* item, slots_t slot, bool isCheck);
|
uint32_t fireEquip(Player* player, Item* item, slots_t slot, bool boolean);
|
||||||
|
|
||||||
uint32_t getSlot() const {
|
uint32_t getSlot() const {
|
||||||
return slot;
|
return slot;
|
||||||
@@ -122,7 +115,7 @@ class MoveEvent final : public Event
|
|||||||
|
|
||||||
//scripting
|
//scripting
|
||||||
bool executeStep(Creature* creature, Item* item, const Position& pos);
|
bool executeStep(Creature* creature, Item* item, const Position& pos);
|
||||||
bool executeEquip(Player* player, Item* item, slots_t slot, bool isCheck);
|
bool executeEquip(Player* player, Item* item, slots_t slot);
|
||||||
bool executeAddRemItem(Item* item, Item* tileItem, const Position& pos);
|
bool executeAddRemItem(Item* item, Item* tileItem, const Position& pos);
|
||||||
//
|
//
|
||||||
|
|
||||||
@@ -139,104 +132,29 @@ class MoveEvent final : public Event
|
|||||||
const std::string& getVocationString() const {
|
const std::string& getVocationString() const {
|
||||||
return vocationString;
|
return vocationString;
|
||||||
}
|
}
|
||||||
void setVocationString(const std::string& str) {
|
|
||||||
vocationString = str;
|
|
||||||
}
|
|
||||||
uint32_t getWieldInfo() const {
|
uint32_t getWieldInfo() const {
|
||||||
return wieldInfo;
|
return wieldInfo;
|
||||||
}
|
}
|
||||||
const VocEquipMap& getVocEquipMap() const {
|
const VocEquipMap& getVocEquipMap() const {
|
||||||
return vocEquipMap;
|
return vocEquipMap;
|
||||||
}
|
}
|
||||||
void addVocEquipMap(std::string vocName) {
|
|
||||||
int32_t vocationId = g_vocations.getVocationId(vocName);
|
|
||||||
if (vocationId != -1) {
|
|
||||||
vocEquipMap[vocationId] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool getTileItem() const {
|
|
||||||
return tileItem;
|
|
||||||
}
|
|
||||||
void setTileItem(bool b) {
|
|
||||||
tileItem = b;
|
|
||||||
}
|
|
||||||
std::vector<uint32_t> getItemIdRange() {
|
|
||||||
return itemIdRange;
|
|
||||||
}
|
|
||||||
void addItemId(uint32_t id) {
|
|
||||||
itemIdRange.emplace_back(id);
|
|
||||||
}
|
|
||||||
std::vector<uint32_t> getActionIdRange() {
|
|
||||||
return actionIdRange;
|
|
||||||
}
|
|
||||||
void addActionId(uint32_t id) {
|
|
||||||
actionIdRange.emplace_back(id);
|
|
||||||
}
|
|
||||||
std::vector<uint32_t> getUniqueIdRange() {
|
|
||||||
return uniqueIdRange;
|
|
||||||
}
|
|
||||||
void addUniqueId(uint32_t id) {
|
|
||||||
uniqueIdRange.emplace_back(id);
|
|
||||||
}
|
|
||||||
std::vector<Position> getPosList() {
|
|
||||||
return posList;
|
|
||||||
}
|
|
||||||
void addPosList(Position pos) {
|
|
||||||
posList.emplace_back(pos);
|
|
||||||
}
|
|
||||||
std::string getSlotName() {
|
|
||||||
return slotName;
|
|
||||||
}
|
|
||||||
void setSlotName(std::string name) {
|
|
||||||
slotName = name;
|
|
||||||
}
|
|
||||||
void setSlot(uint32_t s) {
|
|
||||||
slot = s;
|
|
||||||
}
|
|
||||||
uint32_t getRequiredLevel() {
|
|
||||||
return reqLevel;
|
|
||||||
}
|
|
||||||
void setRequiredLevel(uint32_t level) {
|
|
||||||
reqLevel = level;
|
|
||||||
}
|
|
||||||
uint32_t getRequiredMagLevel() {
|
|
||||||
return reqMagLevel;
|
|
||||||
}
|
|
||||||
void setRequiredMagLevel(uint32_t level) {
|
|
||||||
reqMagLevel = level;
|
|
||||||
}
|
|
||||||
bool needPremium() {
|
|
||||||
return premium;
|
|
||||||
}
|
|
||||||
void setNeedPremium(bool b) {
|
|
||||||
premium = b;
|
|
||||||
}
|
|
||||||
uint32_t getWieldInfo() {
|
|
||||||
return wieldInfo;
|
|
||||||
}
|
|
||||||
void setWieldInfo(WieldInfo_t info) {
|
|
||||||
wieldInfo |= info;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t StepInField(Creature* creature, Item* item, const Position& pos);
|
protected:
|
||||||
static uint32_t StepOutField(Creature* creature, Item* item, const Position& pos);
|
std::string getScriptEventName() const final;
|
||||||
|
|
||||||
static uint32_t AddItemField(Item* item, Item* tileItem, const Position& pos);
|
static StepFunction StepInField;
|
||||||
static uint32_t RemoveItemField(Item* item, Item* tileItem, const Position& pos);
|
static StepFunction StepOutField;
|
||||||
|
|
||||||
static uint32_t EquipItem(MoveEvent* moveEvent, Player* player, Item* item, slots_t slot, bool boolean);
|
static MoveFunction AddItemField;
|
||||||
static uint32_t DeEquipItem(MoveEvent* moveEvent, Player* player, Item* item, slots_t slot, bool boolean);
|
static MoveFunction RemoveItemField;
|
||||||
|
static EquipFunction EquipItem;
|
||||||
|
static EquipFunction DeEquipItem;
|
||||||
|
|
||||||
MoveEvent_t eventType = MOVE_EVENT_NONE;
|
MoveEvent_t eventType = MOVE_EVENT_NONE;
|
||||||
StepFunction stepFunction;
|
StepFunction* stepFunction = nullptr;
|
||||||
MoveFunction moveFunction;
|
MoveFunction* moveFunction = nullptr;
|
||||||
EquipFunction equipFunction;
|
EquipFunction* equipFunction = nullptr;
|
||||||
|
|
||||||
private:
|
|
||||||
std::string getScriptEventName() const override;
|
|
||||||
|
|
||||||
uint32_t slot = SLOTP_WHEREEVER;
|
uint32_t slot = SLOTP_WHEREEVER;
|
||||||
std::string slotName;
|
|
||||||
|
|
||||||
//onEquip information
|
//onEquip information
|
||||||
uint32_t reqLevel = 0;
|
uint32_t reqLevel = 0;
|
||||||
@@ -245,12 +163,6 @@ class MoveEvent final : public Event
|
|||||||
std::string vocationString;
|
std::string vocationString;
|
||||||
uint32_t wieldInfo = 0;
|
uint32_t wieldInfo = 0;
|
||||||
VocEquipMap vocEquipMap;
|
VocEquipMap vocEquipMap;
|
||||||
bool tileItem = false;
|
|
||||||
|
|
||||||
std::vector<uint32_t> itemIdRange;
|
|
||||||
std::vector<uint32_t> actionIdRange;
|
|
||||||
std::vector<uint32_t> uniqueIdRange;
|
|
||||||
std::vector<Position> posList;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -99,18 +99,16 @@ void NetworkMessage::addItem(uint16_t id, uint8_t count)
|
|||||||
{
|
{
|
||||||
const ItemType& it = Item::items[id];
|
const ItemType& it = Item::items[id];
|
||||||
|
|
||||||
add<uint16_t>(it.clientId);
|
if (it.disguise) {
|
||||||
|
add<uint16_t>(it.disguiseId);
|
||||||
addByte(0xFF); // MARK_UNMARKED
|
} else {
|
||||||
|
add<uint16_t>(it.id);
|
||||||
|
}
|
||||||
|
|
||||||
if (it.stackable) {
|
if (it.stackable) {
|
||||||
addByte(count);
|
addByte(count);
|
||||||
} else if (it.isSplash() || it.isFluidContainer()) {
|
} else if (it.isSplash() || it.isFluidContainer()) {
|
||||||
addByte(fluidMap[count & 7]);
|
addByte(getLiquidColor(count));
|
||||||
}
|
|
||||||
|
|
||||||
if (it.isAnimation) {
|
|
||||||
addByte(0xFE); // random phase (0xFF for async)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,21 +116,20 @@ void NetworkMessage::addItem(const Item* item)
|
|||||||
{
|
{
|
||||||
const ItemType& it = Item::items[item->getID()];
|
const ItemType& it = Item::items[item->getID()];
|
||||||
|
|
||||||
add<uint16_t>(it.clientId);
|
if (it.disguise) {
|
||||||
addByte(0xFF); // MARK_UNMARKED
|
add<uint16_t>(it.disguiseId);
|
||||||
|
} else {
|
||||||
|
add<uint16_t>(it.id);
|
||||||
|
}
|
||||||
|
|
||||||
if (it.stackable) {
|
if (it.stackable) {
|
||||||
addByte(std::min<uint16_t>(0xFF, item->getItemCount()));
|
addByte(std::min<uint16_t>(0xFF, item->getItemCount()));
|
||||||
} else if (it.isSplash() || it.isFluidContainer()) {
|
} else if (it.isSplash() || it.isFluidContainer()) {
|
||||||
addByte(fluidMap[item->getFluidType() & 7]);
|
addByte(getLiquidColor(item->getFluidType()));
|
||||||
}
|
|
||||||
|
|
||||||
if (it.isAnimation) {
|
|
||||||
addByte(0xFE); // random phase (0xFF for async)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkMessage::addItemId(uint16_t itemId)
|
void NetworkMessage::addItemId(uint16_t itemId)
|
||||||
{
|
{
|
||||||
add<uint16_t>(Item::items[itemId].clientId);
|
add<uint16_t>(itemId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -31,16 +31,14 @@ class RSA;
|
|||||||
class NetworkMessage
|
class NetworkMessage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using MsgSize_t = uint16_t;
|
typedef uint16_t MsgSize_t;
|
||||||
// Headers:
|
// Headers:
|
||||||
// 2 bytes for unencrypted message size
|
// 2 bytes for unencrypted message size
|
||||||
// 4 bytes for checksum
|
|
||||||
// 2 bytes for encrypted message size
|
// 2 bytes for encrypted message size
|
||||||
static constexpr MsgSize_t INITIAL_BUFFER_POSITION = 8;
|
static constexpr MsgSize_t INITIAL_BUFFER_POSITION = 4;
|
||||||
enum { HEADER_LENGTH = 2 };
|
enum { HEADER_LENGTH = 2 };
|
||||||
enum { CHECKSUM_LENGTH = 4 };
|
|
||||||
enum { XTEA_MULTIPLE = 8 };
|
enum { XTEA_MULTIPLE = 8 };
|
||||||
enum { MAX_BODY_LENGTH = NETWORKMESSAGE_MAXSIZE - HEADER_LENGTH - CHECKSUM_LENGTH - XTEA_MULTIPLE };
|
enum { MAX_BODY_LENGTH = NETWORKMESSAGE_MAXSIZE - HEADER_LENGTH - XTEA_MULTIPLE };
|
||||||
enum { MAX_PROTOCOL_BODY_LENGTH = MAX_BODY_LENGTH - 10 };
|
enum { MAX_PROTOCOL_BODY_LENGTH = MAX_BODY_LENGTH - 10 };
|
||||||
|
|
||||||
NetworkMessage() = default;
|
NetworkMessage() = default;
|
||||||
@@ -150,6 +148,18 @@ class NetworkMessage
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
inline bool canAdd(size_t size) const {
|
||||||
|
return (size + info.position) < MAX_BODY_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool canRead(int32_t size) {
|
||||||
|
if ((info.position + size) > (info.length + 8) || size >= (NETWORKMESSAGE_MAXSIZE - info.position)) {
|
||||||
|
info.overrun = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
struct NetworkMessageInfo {
|
struct NetworkMessageInfo {
|
||||||
MsgSize_t length = 0;
|
MsgSize_t length = 0;
|
||||||
MsgSize_t position = INITIAL_BUFFER_POSITION;
|
MsgSize_t position = INITIAL_BUFFER_POSITION;
|
||||||
@@ -158,19 +168,6 @@ class NetworkMessage
|
|||||||
|
|
||||||
NetworkMessageInfo info;
|
NetworkMessageInfo info;
|
||||||
uint8_t buffer[NETWORKMESSAGE_MAXSIZE];
|
uint8_t buffer[NETWORKMESSAGE_MAXSIZE];
|
||||||
|
|
||||||
private:
|
|
||||||
bool canAdd(size_t size) const {
|
|
||||||
return (size + info.position) < MAX_BODY_LENGTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool canRead(int32_t size) {
|
|
||||||
if ((info.position + size) > (info.length + 8) || size >= (NETWORKMESSAGE_MAXSIZE - info.position)) {
|
|
||||||
info.overrun = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // #ifndef __NETWORK_MESSAGE_H__
|
#endif // #ifndef __NETWORK_MESSAGE_H__
|
||||||
|
|||||||
1148
src/npc.cpp
1148
src/npc.cpp
File diff suppressed because it is too large
Load Diff
171
src/npc.h
171
src/npc.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,86 +21,20 @@
|
|||||||
#define FS_NPC_H_B090D0CB549D4435AFA03647195D156F
|
#define FS_NPC_H_B090D0CB549D4435AFA03647195D156F
|
||||||
|
|
||||||
#include "creature.h"
|
#include "creature.h"
|
||||||
#include "luascript.h"
|
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
class Npc;
|
class Npc;
|
||||||
class Player;
|
class Player;
|
||||||
|
class BehaviourDatabase;
|
||||||
|
|
||||||
class Npcs
|
class Npcs
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static void loadNpcs();
|
||||||
static void reload();
|
static void reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
class NpcScriptInterface final : public LuaScriptInterface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NpcScriptInterface();
|
|
||||||
|
|
||||||
bool loadNpcLib(const std::string& file);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void registerFunctions();
|
|
||||||
|
|
||||||
static int luaActionSay(lua_State* L);
|
|
||||||
static int luaActionMove(lua_State* L);
|
|
||||||
static int luaActionMoveTo(lua_State* L);
|
|
||||||
static int luaActionTurn(lua_State* L);
|
|
||||||
static int luaActionFollow(lua_State* L);
|
|
||||||
static int luagetDistanceTo(lua_State* L);
|
|
||||||
static int luaSetNpcFocus(lua_State* L);
|
|
||||||
static int luaGetNpcCid(lua_State* L);
|
|
||||||
static int luaGetNpcParameter(lua_State* L);
|
|
||||||
static int luaOpenShopWindow(lua_State* L);
|
|
||||||
static int luaCloseShopWindow(lua_State* L);
|
|
||||||
static int luaDoSellItem(lua_State* L);
|
|
||||||
|
|
||||||
// metatable
|
|
||||||
static int luaNpcGetParameter(lua_State* L);
|
|
||||||
static int luaNpcSetFocus(lua_State* L);
|
|
||||||
|
|
||||||
static int luaNpcOpenShopWindow(lua_State* L);
|
|
||||||
static int luaNpcCloseShopWindow(lua_State* L);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool initState() override;
|
|
||||||
bool closeState() override;
|
|
||||||
|
|
||||||
bool libLoaded;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NpcEventsHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
NpcEventsHandler(const std::string& file, Npc* npc);
|
|
||||||
|
|
||||||
void onCreatureAppear(Creature* creature);
|
|
||||||
void onCreatureDisappear(Creature* creature);
|
|
||||||
void onCreatureMove(Creature* creature, const Position& oldPos, const Position& newPos);
|
|
||||||
void onCreatureSay(Creature* creature, SpeakClasses, const std::string& text);
|
|
||||||
void onPlayerTrade(Player* player, int32_t callback, uint16_t itemId, uint8_t count, uint8_t amount, bool ignore = false, bool inBackpacks = false);
|
|
||||||
void onPlayerCloseChannel(Player* player);
|
|
||||||
void onPlayerEndTrade(Player* player);
|
|
||||||
void onThink();
|
|
||||||
|
|
||||||
bool isLoaded() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Npc* npc;
|
|
||||||
NpcScriptInterface* scriptInterface;
|
|
||||||
|
|
||||||
int32_t creatureAppearEvent = -1;
|
|
||||||
int32_t creatureDisappearEvent = -1;
|
|
||||||
int32_t creatureMoveEvent = -1;
|
|
||||||
int32_t creatureSayEvent = -1;
|
|
||||||
int32_t playerCloseChannelEvent = -1;
|
|
||||||
int32_t playerEndTradeEvent = -1;
|
|
||||||
int32_t thinkEvent = -1;
|
|
||||||
bool loaded = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Npc final : public Creature
|
class Npc final : public Creature
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -110,53 +44,41 @@ class Npc final : public Creature
|
|||||||
Npc(const Npc&) = delete;
|
Npc(const Npc&) = delete;
|
||||||
Npc& operator=(const Npc&) = delete;
|
Npc& operator=(const Npc&) = delete;
|
||||||
|
|
||||||
Npc* getNpc() override {
|
Npc* getNpc() final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
const Npc* getNpc() const override {
|
const Npc* getNpc() const final {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPushable() const override {
|
bool isPushable() const final {
|
||||||
return pushable && walkTicks != 0;
|
return baseSpeed > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setID() override {
|
void setID() final {
|
||||||
if (id == 0) {
|
if (id == 0) {
|
||||||
id = npcAutoID++;
|
id = npcAutoID++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeList() override;
|
void removeList() final;
|
||||||
void addList() override;
|
void addList() final;
|
||||||
|
|
||||||
static Npc* createNpc(const std::string& name);
|
static Npc* createNpc(const std::string& name);
|
||||||
|
|
||||||
bool canSee(const Position& pos) const override;
|
bool canSee(const Position& pos) const final;
|
||||||
|
|
||||||
bool load();
|
bool load();
|
||||||
void reload();
|
void reload();
|
||||||
|
|
||||||
const std::string& getName() const override {
|
const std::string& getName() const final {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
const std::string& getNameDescription() const override {
|
const std::string& getNameDescription() const final {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
CreatureType_t getType() const override {
|
|
||||||
return CREATURETYPE_NPC;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t getSpeechBubble() const override {
|
|
||||||
return speechBubble;
|
|
||||||
}
|
|
||||||
void setSpeechBubble(const uint8_t bubble) {
|
|
||||||
speechBubble = bubble;
|
|
||||||
}
|
|
||||||
|
|
||||||
void doSay(const std::string& text);
|
void doSay(const std::string& text);
|
||||||
void doSayToPlayer(Player* player, const std::string& text);
|
|
||||||
|
|
||||||
void doMoveTo(const Position& pos);
|
void doMoveTo(const Position& pos);
|
||||||
|
|
||||||
@@ -168,45 +90,38 @@ class Npc final : public Creature
|
|||||||
}
|
}
|
||||||
void setMasterPos(Position pos, int32_t radius = 1) {
|
void setMasterPos(Position pos, int32_t radius = 1) {
|
||||||
masterPos = pos;
|
masterPos = pos;
|
||||||
if (masterRadius == -1) {
|
if (masterRadius == 0) {
|
||||||
masterRadius = radius;
|
masterRadius = radius;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onPlayerCloseChannel(Player* player);
|
|
||||||
void onPlayerTrade(Player* player, int32_t callback, uint16_t itemId, uint8_t count,
|
|
||||||
uint8_t amount, bool ignore = false, bool inBackpacks = false);
|
|
||||||
void onPlayerEndTrade(Player* player, int32_t buyCallback, int32_t sellCallback);
|
|
||||||
|
|
||||||
void turnToCreature(Creature* creature);
|
void turnToCreature(Creature* creature);
|
||||||
void setCreatureFocus(Creature* creature);
|
void setCreatureFocus(Creature* creature);
|
||||||
|
|
||||||
NpcScriptInterface* getScriptInterface();
|
|
||||||
|
|
||||||
static uint32_t npcAutoID;
|
static uint32_t npcAutoID;
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
explicit Npc(const std::string& name);
|
explicit Npc(const std::string& name);
|
||||||
|
|
||||||
void onCreatureAppear(Creature* creature, bool isLogin) override;
|
void onCreatureAppear(Creature* creature, bool isLogin) final;
|
||||||
void onRemoveCreature(Creature* creature, bool isLogout) override;
|
void onRemoveCreature(Creature* creature, bool isLogout) final;
|
||||||
void onCreatureMove(Creature* creature, const Tile* newTile, const Position& newPos,
|
void onCreatureMove(Creature* creature, const Tile* newTile, const Position& newPos,
|
||||||
const Tile* oldTile, const Position& oldPos, bool teleport) override;
|
const Tile* oldTile, const Position& oldPos, bool teleport) final;
|
||||||
|
|
||||||
void onCreatureSay(Creature* creature, SpeakClasses type, const std::string& text) override;
|
void onCreatureSay(Creature* creature, SpeakClasses type, const std::string& text) final;
|
||||||
void onThink(uint32_t interval) override;
|
void onThink(uint32_t interval) final;
|
||||||
std::string getDescription(int32_t lookDistance) const override;
|
std::string getDescription(int32_t lookDistance) const final;
|
||||||
|
|
||||||
bool isImmune(CombatType_t) const override {
|
bool isImmune(CombatType_t) const final {
|
||||||
return !attackable;
|
return true;
|
||||||
}
|
}
|
||||||
bool isImmune(ConditionType_t) const override {
|
bool isImmune(ConditionType_t) const final {
|
||||||
return !attackable;
|
return true;
|
||||||
}
|
}
|
||||||
bool isAttackable() const override {
|
bool isAttackable() const final {
|
||||||
return attackable;
|
return false;
|
||||||
}
|
}
|
||||||
bool getNextStep(Direction& dir, uint32_t& flags) override;
|
bool getNextStep(Direction& dir, uint32_t& flags) final;
|
||||||
|
|
||||||
void setIdle(bool idle);
|
void setIdle(bool idle);
|
||||||
void updateIdleStatus();
|
void updateIdleStatus();
|
||||||
@@ -215,41 +130,29 @@ class Npc final : public Creature
|
|||||||
bool getRandomStep(Direction& dir) const;
|
bool getRandomStep(Direction& dir) const;
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
bool loadFromXml();
|
|
||||||
|
|
||||||
void addShopPlayer(Player* player);
|
|
||||||
void removeShopPlayer(Player* player);
|
|
||||||
void closeAllShopWindows();
|
|
||||||
|
|
||||||
std::map<std::string, std::string> parameters;
|
|
||||||
|
|
||||||
std::set<Player*> shopPlayerSet;
|
|
||||||
std::set<Player*> spectators;
|
std::set<Player*> spectators;
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string filename;
|
std::string filename;
|
||||||
|
|
||||||
NpcEventsHandler* npcEventHandler;
|
|
||||||
|
|
||||||
Position masterPos;
|
Position masterPos;
|
||||||
|
|
||||||
uint32_t walkTicks;
|
uint32_t lastTalkCreature;
|
||||||
int32_t focusCreature;
|
uint32_t focusCreature;
|
||||||
int32_t masterRadius;
|
uint32_t masterRadius;
|
||||||
|
|
||||||
uint8_t speechBubble;
|
int64_t conversationStartTime;
|
||||||
|
int64_t conversationEndTime;
|
||||||
|
int64_t staticMovementTime;
|
||||||
|
|
||||||
bool floorChange;
|
|
||||||
bool attackable;
|
|
||||||
bool ignoreHeight;
|
|
||||||
bool loaded;
|
bool loaded;
|
||||||
bool isIdle;
|
bool isIdle;
|
||||||
bool pushable;
|
|
||||||
|
|
||||||
static NpcScriptInterface* scriptInterface;
|
BehaviourDatabase* behaviourDatabase;
|
||||||
|
|
||||||
friend class Npcs;
|
friend class Npcs;
|
||||||
friend class NpcScriptInterface;
|
friend class BehaviourDatabase;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -23,19 +23,18 @@
|
|||||||
|
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
|
||||||
#include "iomarket.h"
|
#ifndef _WIN32
|
||||||
|
#include <csignal> // for sigemptyset()
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "configmanager.h"
|
#include "configmanager.h"
|
||||||
#include "scriptmanager.h"
|
#include "scriptmanager.h"
|
||||||
#include "rsa.h"
|
#include "rsa.h"
|
||||||
#include "protocolold.h"
|
|
||||||
#include "protocollogin.h"
|
#include "protocollogin.h"
|
||||||
#include "protocolstatus.h"
|
#include "protocolstatus.h"
|
||||||
#include "databasemanager.h"
|
#include "databasemanager.h"
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "databasetasks.h"
|
#include "databasetasks.h"
|
||||||
#include "script.h"
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
DatabaseTasks g_databaseTasks;
|
DatabaseTasks g_databaseTasks;
|
||||||
Dispatcher g_dispatcher;
|
Dispatcher g_dispatcher;
|
||||||
@@ -45,7 +44,6 @@ Game g_game;
|
|||||||
ConfigManager g_config;
|
ConfigManager g_config;
|
||||||
Monsters g_monsters;
|
Monsters g_monsters;
|
||||||
Vocations g_vocations;
|
Vocations g_vocations;
|
||||||
extern Scripts* g_scripts;
|
|
||||||
RSA g_RSA;
|
RSA g_RSA;
|
||||||
|
|
||||||
std::mutex g_loaderLock;
|
std::mutex g_loaderLock;
|
||||||
@@ -58,9 +56,9 @@ void startupErrorMessage(const std::string& errorStr)
|
|||||||
g_loaderSignal.notify_all();
|
g_loaderSignal.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mainLoader(int argc, char* argv[], ServiceManager* services);
|
void mainLoader(int argc, char* argv[], ServiceManager* servicer);
|
||||||
|
|
||||||
[[noreturn]] void badAllocationHandler()
|
void badAllocationHandler()
|
||||||
{
|
{
|
||||||
// Use functions that only use stack allocation
|
// Use functions that only use stack allocation
|
||||||
puts("Allocation failed, server out of memory.\nDecrease the size of your map or compile in 64 bits mode.\n");
|
puts("Allocation failed, server out of memory.\nDecrease the size of your map or compile in 64 bits mode.\n");
|
||||||
@@ -73,6 +71,15 @@ int main(int argc, char* argv[])
|
|||||||
// Setup bad allocation handler
|
// Setup bad allocation handler
|
||||||
std::set_new_handler(badAllocationHandler);
|
std::set_new_handler(badAllocationHandler);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
// ignore sigpipe...
|
||||||
|
struct sigaction sigh;
|
||||||
|
sigh.sa_handler = SIG_IGN;
|
||||||
|
sigh.sa_flags = 0;
|
||||||
|
sigemptyset(&sigh.sa_mask);
|
||||||
|
sigaction(SIGPIPE, &sigh, nullptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
ServiceManager serviceManager;
|
ServiceManager serviceManager;
|
||||||
|
|
||||||
g_dispatcher.start();
|
g_dispatcher.start();
|
||||||
@@ -84,6 +91,19 @@ int main(int argc, char* argv[])
|
|||||||
|
|
||||||
if (serviceManager.is_running()) {
|
if (serviceManager.is_running()) {
|
||||||
std::cout << ">> " << g_config.getString(ConfigManager::SERVER_NAME) << " Server Online!" << std::endl << std::endl;
|
std::cout << ">> " << g_config.getString(ConfigManager::SERVER_NAME) << " Server Online!" << std::endl << std::endl;
|
||||||
|
#ifdef _WIN32
|
||||||
|
SetConsoleCtrlHandler([](DWORD) -> BOOL {
|
||||||
|
g_dispatcher.addTask(createTask([]() {
|
||||||
|
g_dispatcher.addTask(createTask(
|
||||||
|
std::bind(&Game::shutdown, &g_game)
|
||||||
|
));
|
||||||
|
g_scheduler.stop();
|
||||||
|
g_databaseTasks.stop();
|
||||||
|
g_dispatcher.stop();
|
||||||
|
}));
|
||||||
|
ExitThread(0);
|
||||||
|
}, 1);
|
||||||
|
#endif
|
||||||
serviceManager.run();
|
serviceManager.run();
|
||||||
} else {
|
} else {
|
||||||
std::cout << ">> No services running. The server is NOT online." << std::endl;
|
std::cout << ">> No services running. The server is NOT online." << std::endl;
|
||||||
@@ -126,21 +146,6 @@ void mainLoader(int, char*[], ServiceManager* services)
|
|||||||
std::cout << "Visit our forum for updates, support, and resources: http://otland.net/." << std::endl;
|
std::cout << "Visit our forum for updates, support, and resources: http://otland.net/." << std::endl;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
// check if config.lua or config.lua.dist exist
|
|
||||||
std::ifstream c_test("./config.lua");
|
|
||||||
if (!c_test.is_open()) {
|
|
||||||
std::ifstream config_lua_dist("./config.lua.dist");
|
|
||||||
if (config_lua_dist.is_open()) {
|
|
||||||
std::cout << ">> copying config.lua.dist to config.lua" << std::endl;
|
|
||||||
std::ofstream config_lua("config.lua");
|
|
||||||
config_lua << config_lua_dist.rdbuf();
|
|
||||||
config_lua.close();
|
|
||||||
config_lua_dist.close();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c_test.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// read global config
|
// read global config
|
||||||
std::cout << ">> Loading config" << std::endl;
|
std::cout << ">> Loading config" << std::endl;
|
||||||
if (!g_config.load()) {
|
if (!g_config.load()) {
|
||||||
@@ -160,14 +165,16 @@ void mainLoader(int, char*[], ServiceManager* services)
|
|||||||
//set RSA key
|
//set RSA key
|
||||||
try {
|
try {
|
||||||
g_RSA.loadPEM("key.pem");
|
g_RSA.loadPEM("key.pem");
|
||||||
} catch(const std::exception& e) {
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
startupErrorMessage(e.what());
|
startupErrorMessage(e.what());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << ">> Establishing database connection..." << std::flush;
|
std::cout << ">> Establishing database connection..." << std::flush;
|
||||||
|
|
||||||
if (!Database::getInstance().connect()) {
|
Database* db = Database::getInstance();
|
||||||
|
if (!db->connect()) {
|
||||||
startupErrorMessage("Failed to connect to database.");
|
startupErrorMessage("Failed to connect to database.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -183,8 +190,6 @@ void mainLoader(int, char*[], ServiceManager* services)
|
|||||||
}
|
}
|
||||||
g_databaseTasks.start();
|
g_databaseTasks.start();
|
||||||
|
|
||||||
DatabaseManager::updateDatabase();
|
|
||||||
|
|
||||||
if (g_config.getBoolean(ConfigManager::OPTIMIZE_DATABASE) && !DatabaseManager::optimizeTables()) {
|
if (g_config.getBoolean(ConfigManager::OPTIMIZE_DATABASE) && !DatabaseManager::optimizeTables()) {
|
||||||
std::cout << "> No tables were optimized." << std::endl;
|
std::cout << "> No tables were optimized." << std::endl;
|
||||||
}
|
}
|
||||||
@@ -198,42 +203,26 @@ void mainLoader(int, char*[], ServiceManager* services)
|
|||||||
|
|
||||||
// load item data
|
// load item data
|
||||||
std::cout << ">> Loading items" << std::endl;
|
std::cout << ">> Loading items" << std::endl;
|
||||||
if (!Item::items.loadFromOtb("data/items/items.otb")) {
|
if (!Item::items.loadItems()) {
|
||||||
startupErrorMessage("Unable to load items (OTB)!");
|
startupErrorMessage("Unable to load items (SRV)!");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Item::items.loadFromXml()) {
|
|
||||||
startupErrorMessage("Unable to load items (XML)!");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << ">> Loading script systems" << std::endl;
|
std::cout << ">> Loading script systems" << std::endl;
|
||||||
if (!ScriptingManager::getInstance().loadScriptSystems()) {
|
if (!ScriptingManager::getInstance()->loadScriptSystems()) {
|
||||||
startupErrorMessage("Failed to load script systems");
|
startupErrorMessage("Failed to load script systems");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << ">> Loading lua scripts" << std::endl;
|
|
||||||
if (!g_scripts->loadScripts("scripts", false, false)) {
|
|
||||||
startupErrorMessage("Failed to load lua scripts");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << ">> Loading monsters" << std::endl;
|
std::cout << ">> Loading monsters" << std::endl;
|
||||||
if (!g_monsters.loadFromXml()) {
|
if (!g_monsters.loadFromXml()) {
|
||||||
startupErrorMessage("Unable to load monsters!");
|
startupErrorMessage("Unable to load monsters!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << ">> Loading lua monsters" << std::endl;
|
|
||||||
if (!g_scripts->loadScripts("monster", false, false)) {
|
|
||||||
startupErrorMessage("Failed to load lua monsters");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << ">> Loading outfits" << std::endl;
|
std::cout << ">> Loading outfits" << std::endl;
|
||||||
if (!Outfits::getInstance().loadFromXml()) {
|
auto& outfits = Outfits::getInstance();
|
||||||
|
if (!outfits.loadFromXml()) {
|
||||||
startupErrorMessage("Unable to load outfits!");
|
startupErrorMessage("Unable to load outfits!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -266,14 +255,11 @@ void mainLoader(int, char*[], ServiceManager* services)
|
|||||||
g_game.setGameState(GAME_STATE_INIT);
|
g_game.setGameState(GAME_STATE_INIT);
|
||||||
|
|
||||||
// Game client protocols
|
// Game client protocols
|
||||||
services->add<ProtocolGame>(static_cast<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT)));
|
services->add<ProtocolGame>(g_config.getNumber(ConfigManager::GAME_PORT));
|
||||||
services->add<ProtocolLogin>(static_cast<uint16_t>(g_config.getNumber(ConfigManager::LOGIN_PORT)));
|
services->add<ProtocolLogin>(g_config.getNumber(ConfigManager::LOGIN_PORT));
|
||||||
|
|
||||||
// OT protocols
|
// OT protocols
|
||||||
services->add<ProtocolStatus>(static_cast<uint16_t>(g_config.getNumber(ConfigManager::STATUS_PORT)));
|
services->add<ProtocolStatus>(g_config.getNumber(ConfigManager::STATUS_PORT));
|
||||||
|
|
||||||
// Legacy login protocol
|
|
||||||
services->add<ProtocolOld>(static_cast<uint16_t>(g_config.getNumber(ConfigManager::LOGIN_PORT)));
|
|
||||||
|
|
||||||
RentPeriod_t rentPeriod;
|
RentPeriod_t rentPeriod;
|
||||||
std::string strRentPeriod = asLowerCaseString(g_config.getString(ConfigManager::HOUSE_RENT_PERIOD));
|
std::string strRentPeriod = asLowerCaseString(g_config.getString(ConfigManager::HOUSE_RENT_PERIOD));
|
||||||
@@ -292,9 +278,6 @@ void mainLoader(int, char*[], ServiceManager* services)
|
|||||||
|
|
||||||
g_game.map.houses.payHouses(rentPeriod);
|
g_game.map.houses.payHouses(rentPeriod);
|
||||||
|
|
||||||
IOMarket::checkExpiredOffers();
|
|
||||||
IOMarket::getInstance().updateStatistics();
|
|
||||||
|
|
||||||
std::cout << ">> Loaded all modules, server starting up..." << std::endl;
|
std::cout << ">> Loaded all modules, server starting up..." << std::endl;
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -29,6 +29,14 @@ extern Scheduler g_scheduler;
|
|||||||
const uint16_t OUTPUTMESSAGE_FREE_LIST_CAPACITY = 2048;
|
const uint16_t OUTPUTMESSAGE_FREE_LIST_CAPACITY = 2048;
|
||||||
const std::chrono::milliseconds OUTPUTMESSAGE_AUTOSEND_DELAY {10};
|
const std::chrono::milliseconds OUTPUTMESSAGE_AUTOSEND_DELAY {10};
|
||||||
|
|
||||||
|
class OutputMessageAllocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef OutputMessage value_type;
|
||||||
|
template<typename U>
|
||||||
|
struct rebind {typedef LockfreePoolingAllocator<U, OUTPUTMESSAGE_FREE_LIST_CAPACITY> other;};
|
||||||
|
};
|
||||||
|
|
||||||
void OutputMessagePool::scheduleSendAll()
|
void OutputMessagePool::scheduleSendAll()
|
||||||
{
|
{
|
||||||
auto functor = std::bind(&OutputMessagePool::sendAll, this);
|
auto functor = std::bind(&OutputMessagePool::sendAll, this);
|
||||||
@@ -71,7 +79,5 @@ void OutputMessagePool::removeProtocolFromAutosend(const Protocol_ptr& protocol)
|
|||||||
|
|
||||||
OutputMessage_ptr OutputMessagePool::getOutputMessage()
|
OutputMessage_ptr OutputMessagePool::getOutputMessage()
|
||||||
{
|
{
|
||||||
// LockfreePoolingAllocator<void,...> will leave (void* allocate) ill-formed because
|
return std::allocate_shared<OutputMessage>(OutputMessageAllocator());
|
||||||
// of sizeof(T), so this guaranatees that only one list will be initialized
|
|
||||||
return std::allocate_shared<OutputMessage>(LockfreePoolingAllocator<void, OUTPUTMESSAGE_FREE_LIST_CAPACITY>());
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,80 +28,76 @@ class Protocol;
|
|||||||
|
|
||||||
class OutputMessage : public NetworkMessage
|
class OutputMessage : public NetworkMessage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OutputMessage() = default;
|
OutputMessage() = default;
|
||||||
|
|
||||||
// non-copyable
|
// non-copyable
|
||||||
OutputMessage(const OutputMessage&) = delete;
|
OutputMessage(const OutputMessage&) = delete;
|
||||||
OutputMessage& operator=(const OutputMessage&) = delete;
|
OutputMessage& operator=(const OutputMessage&) = delete;
|
||||||
|
|
||||||
uint8_t* getOutputBuffer() {
|
uint8_t* getOutputBuffer() {
|
||||||
return buffer + outputBufferStart;
|
return buffer + outputBufferStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeMessageLength() {
|
void writeMessageLength() {
|
||||||
add_header(info.length);
|
add_header(info.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addCryptoHeader(bool addChecksum) {
|
void addCryptoHeader() {
|
||||||
if (addChecksum) {
|
writeMessageLength();
|
||||||
add_header(adlerChecksum(buffer + outputBufferStart, info.length));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
writeMessageLength();
|
inline void append(const NetworkMessage& msg) {
|
||||||
}
|
auto msgLen = msg.getLength();
|
||||||
|
memcpy(buffer + info.position, msg.getBuffer() + 4, msgLen);
|
||||||
|
info.length += msgLen;
|
||||||
|
info.position += msgLen;
|
||||||
|
}
|
||||||
|
|
||||||
void append(const NetworkMessage& msg) {
|
inline void append(const OutputMessage_ptr& msg) {
|
||||||
auto msgLen = msg.getLength();
|
auto msgLen = msg->getLength();
|
||||||
memcpy(buffer + info.position, msg.getBuffer() + 8, msgLen);
|
memcpy(buffer + info.position, msg->getBuffer() + 4, msgLen);
|
||||||
info.length += msgLen;
|
info.length += msgLen;
|
||||||
info.position += msgLen;
|
info.position += msgLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
void append(const OutputMessage_ptr& msg) {
|
protected:
|
||||||
auto msgLen = msg->getLength();
|
template <typename T>
|
||||||
memcpy(buffer + info.position, msg->getBuffer() + 8, msgLen);
|
inline void add_header(T add) {
|
||||||
info.length += msgLen;
|
assert(outputBufferStart >= sizeof(T));
|
||||||
info.position += msgLen;
|
outputBufferStart -= sizeof(T);
|
||||||
}
|
memcpy(buffer + outputBufferStart, &add, sizeof(T));
|
||||||
|
//added header size to the message size
|
||||||
|
info.length += sizeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
MsgSize_t outputBufferStart = INITIAL_BUFFER_POSITION;
|
||||||
template <typename T>
|
|
||||||
void add_header(T add) {
|
|
||||||
assert(outputBufferStart >= sizeof(T));
|
|
||||||
outputBufferStart -= sizeof(T);
|
|
||||||
memcpy(buffer + outputBufferStart, &add, sizeof(T));
|
|
||||||
//added header size to the message size
|
|
||||||
info.length += sizeof(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
MsgSize_t outputBufferStart = INITIAL_BUFFER_POSITION;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class OutputMessagePool
|
class OutputMessagePool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// non-copyable
|
// non-copyable
|
||||||
OutputMessagePool(const OutputMessagePool&) = delete;
|
OutputMessagePool(const OutputMessagePool&) = delete;
|
||||||
OutputMessagePool& operator=(const OutputMessagePool&) = delete;
|
OutputMessagePool& operator=(const OutputMessagePool&) = delete;
|
||||||
|
|
||||||
static OutputMessagePool& getInstance() {
|
static OutputMessagePool& getInstance() {
|
||||||
static OutputMessagePool instance;
|
static OutputMessagePool instance;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendAll();
|
void sendAll();
|
||||||
void scheduleSendAll();
|
void scheduleSendAll();
|
||||||
|
|
||||||
static OutputMessage_ptr getOutputMessage();
|
static OutputMessage_ptr getOutputMessage();
|
||||||
|
|
||||||
void addProtocolToAutosend(Protocol_ptr protocol);
|
void addProtocolToAutosend(Protocol_ptr protocol);
|
||||||
void removeProtocolFromAutosend(const Protocol_ptr& protocol);
|
void removeProtocolFromAutosend(const Protocol_ptr& protocol);
|
||||||
private:
|
private:
|
||||||
OutputMessagePool() = default;
|
OutputMessagePool() = default;
|
||||||
//NOTE: A vector is used here because this container is mostly read
|
//NOTE: A vector is used here because this container is mostly read
|
||||||
//and relatively rarely modified (only when a client connects/disconnects)
|
//and relatively rarely modified (only when a client connects/disconnects)
|
||||||
std::vector<Protocol_ptr> bufferedProtocols;
|
std::vector<Protocol_ptr> bufferedProtocols;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -39,13 +39,13 @@ void Party::disband()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Player* currentLeader = leader;
|
Player* currentLeader = leader;
|
||||||
leader = nullptr;
|
leader = nullptr;
|
||||||
|
|
||||||
currentLeader->setParty(nullptr);
|
currentLeader->setParty(nullptr);
|
||||||
currentLeader->sendClosePrivate(CHANNEL_PARTY);
|
currentLeader->sendClosePrivate(CHANNEL_PARTY);
|
||||||
g_game.updatePlayerShield(currentLeader);
|
g_game.updatePlayerShield(currentLeader);
|
||||||
g_game.updatePlayerHelpers(*currentLeader);
|
|
||||||
currentLeader->sendCreatureSkull(currentLeader);
|
currentLeader->sendCreatureSkull(currentLeader);
|
||||||
currentLeader->sendTextMessage(MESSAGE_INFO_DESCR, "Your party has been disbanded.");
|
currentLeader->sendTextMessage(MESSAGE_INFO_DESCR, "Your party has been disbanded.");
|
||||||
|
|
||||||
@@ -70,8 +70,8 @@ void Party::disband()
|
|||||||
|
|
||||||
member->sendCreatureSkull(currentLeader);
|
member->sendCreatureSkull(currentLeader);
|
||||||
currentLeader->sendCreatureSkull(member);
|
currentLeader->sendCreatureSkull(member);
|
||||||
g_game.updatePlayerHelpers(*member);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memberList.clear();
|
memberList.clear();
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
@@ -112,12 +112,10 @@ bool Party::leaveParty(Player* player)
|
|||||||
player->setParty(nullptr);
|
player->setParty(nullptr);
|
||||||
player->sendClosePrivate(CHANNEL_PARTY);
|
player->sendClosePrivate(CHANNEL_PARTY);
|
||||||
g_game.updatePlayerShield(player);
|
g_game.updatePlayerShield(player);
|
||||||
g_game.updatePlayerHelpers(*player);
|
|
||||||
|
|
||||||
for (Player* member : memberList) {
|
for (Player* member : memberList) {
|
||||||
member->sendCreatureSkull(player);
|
member->sendCreatureSkull(player);
|
||||||
player->sendPlayerPartyIcons(member);
|
player->sendPlayerPartyIcons(member);
|
||||||
g_game.updatePlayerHelpers(*member);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
leader->sendCreatureSkull(player);
|
leader->sendCreatureSkull(player);
|
||||||
@@ -127,6 +125,7 @@ bool Party::leaveParty(Player* player)
|
|||||||
player->sendTextMessage(MESSAGE_INFO_DESCR, "You have left the party.");
|
player->sendTextMessage(MESSAGE_INFO_DESCR, "You have left the party.");
|
||||||
|
|
||||||
updateSharedExperience();
|
updateSharedExperience();
|
||||||
|
updateVocationsList();
|
||||||
|
|
||||||
clearPlayerPoints(player);
|
clearPlayerPoints(player);
|
||||||
|
|
||||||
@@ -213,10 +212,9 @@ bool Party::joinParty(Player& player)
|
|||||||
|
|
||||||
memberList.push_back(&player);
|
memberList.push_back(&player);
|
||||||
|
|
||||||
g_game.updatePlayerHelpers(player);
|
|
||||||
|
|
||||||
player.removePartyInvitation(this);
|
player.removePartyInvitation(this);
|
||||||
updateSharedExperience();
|
updateSharedExperience();
|
||||||
|
updateVocationsList();
|
||||||
|
|
||||||
const std::string& leaderName = leader->getName();
|
const std::string& leaderName = leader->getName();
|
||||||
ss.str(std::string());
|
ss.str(std::string());
|
||||||
@@ -244,12 +242,6 @@ bool Party::removeInvite(Player& player, bool removeFromPlayer/* = true*/)
|
|||||||
|
|
||||||
if (empty()) {
|
if (empty()) {
|
||||||
disband();
|
disband();
|
||||||
} else {
|
|
||||||
for (Player* member : memberList) {
|
|
||||||
g_game.updatePlayerHelpers(*member);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_game.updatePlayerHelpers(*leader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -277,7 +269,7 @@ bool Party::invitePlayer(Player& player)
|
|||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << player.getName() << " has been invited.";
|
ss << player.getName() << " has been invited.";
|
||||||
|
|
||||||
if (empty()) {
|
if (memberList.empty() && inviteList.empty()) {
|
||||||
ss << " Open the party channel to communicate with your members.";
|
ss << " Open the party channel to communicate with your members.";
|
||||||
g_game.updatePlayerShield(leader);
|
g_game.updatePlayerShield(leader);
|
||||||
leader->sendCreatureSkull(leader);
|
leader->sendCreatureSkull(leader);
|
||||||
@@ -287,11 +279,6 @@ bool Party::invitePlayer(Player& player)
|
|||||||
|
|
||||||
inviteList.push_back(&player);
|
inviteList.push_back(&player);
|
||||||
|
|
||||||
for (Player* member : memberList) {
|
|
||||||
g_game.updatePlayerHelpers(*member);
|
|
||||||
}
|
|
||||||
g_game.updatePlayerHelpers(*leader);
|
|
||||||
|
|
||||||
leader->sendCreatureShield(&player);
|
leader->sendCreatureShield(&player);
|
||||||
player.sendCreatureShield(leader);
|
player.sendCreatureShield(leader);
|
||||||
|
|
||||||
@@ -336,6 +323,15 @@ void Party::broadcastPartyMessage(MessageClasses msgClass, const std::string& ms
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Party::broadcastPartyLoot(const std::string& loot)
|
||||||
|
{
|
||||||
|
leader->sendTextMessage(MESSAGE_INFO_DESCR, loot);
|
||||||
|
|
||||||
|
for (Player* member : memberList) {
|
||||||
|
member->sendTextMessage(MESSAGE_INFO_DESCR, loot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Party::updateSharedExperience()
|
void Party::updateSharedExperience()
|
||||||
{
|
{
|
||||||
if (sharedExpActive) {
|
if (sharedExpActive) {
|
||||||
@@ -347,6 +343,30 @@ void Party::updateSharedExperience()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Party::updateVocationsList()
|
||||||
|
{
|
||||||
|
std::set<uint32_t> vocationIds;
|
||||||
|
|
||||||
|
uint32_t vocationId = leader->getVocation()->getFromVocation();
|
||||||
|
if (vocationId != VOCATION_NONE) {
|
||||||
|
vocationIds.insert(vocationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const Player* member : memberList) {
|
||||||
|
vocationId = member->getVocation()->getFromVocation();
|
||||||
|
if (vocationId != VOCATION_NONE) {
|
||||||
|
vocationIds.insert(vocationId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size = vocationIds.size();
|
||||||
|
if (size > 1) {
|
||||||
|
extraExpRate = static_cast<float>(size * (10 + (size - 1) * 5)) / 100.f;
|
||||||
|
} else {
|
||||||
|
extraExpRate = 0.20f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Party::setSharedExperience(Player* player, bool sharedExpActive)
|
bool Party::setSharedExperience(Player* player, bool sharedExpActive)
|
||||||
{
|
{
|
||||||
if (!player || leader != player) {
|
if (!player || leader != player) {
|
||||||
@@ -399,7 +419,7 @@ bool Party::canUseSharedExperience(const Player* player) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t minLevel = static_cast<uint32_t>(std::ceil((static_cast<float>(highestLevel) * 2) / 3));
|
uint32_t minLevel = static_cast<int32_t>(std::ceil((static_cast<float>(highestLevel) * 2) / 3));
|
||||||
if (player->getLevel() < minLevel) {
|
if (player->getLevel() < minLevel) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/party.h
15
src/party.h
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* The Forgotten Server - a free and open-source MMORPG server emulator
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
||||||
* Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
class Player;
|
class Player;
|
||||||
class Party;
|
class Party;
|
||||||
|
|
||||||
using PlayerVector = std::vector<Player*>;
|
typedef std::vector<Player*> PlayerVector;
|
||||||
|
|
||||||
class Party
|
class Party
|
||||||
{
|
{
|
||||||
@@ -61,12 +61,13 @@ class Party
|
|||||||
bool isPlayerInvited(const Player* player) const;
|
bool isPlayerInvited(const Player* player) const;
|
||||||
void updateAllPartyIcons();
|
void updateAllPartyIcons();
|
||||||
void broadcastPartyMessage(MessageClasses msgClass, const std::string& msg, bool sendToInvitations = false);
|
void broadcastPartyMessage(MessageClasses msgClass, const std::string& msg, bool sendToInvitations = false);
|
||||||
|
void broadcastPartyLoot(const std::string& loot);
|
||||||
bool empty() const {
|
bool empty() const {
|
||||||
return memberList.empty() && inviteList.empty();
|
return memberList.empty() && inviteList.empty();
|
||||||
}
|
}
|
||||||
bool canOpenCorpse(uint32_t ownerId) const;
|
bool canOpenCorpse(uint32_t ownerId) const;
|
||||||
|
|
||||||
void shareExperience(uint64_t experience, Creature* source = nullptr);
|
void shareExperience(uint64_t experience, Creature* source/* = nullptr*/);
|
||||||
bool setSharedExperience(Player* player, bool sharedExpActive);
|
bool setSharedExperience(Player* player, bool sharedExpActive);
|
||||||
bool isSharedExperienceActive() const {
|
bool isSharedExperienceActive() const {
|
||||||
return sharedExpActive;
|
return sharedExpActive;
|
||||||
@@ -77,10 +78,12 @@ class Party
|
|||||||
bool canUseSharedExperience(const Player* player) const;
|
bool canUseSharedExperience(const Player* player) const;
|
||||||
void updateSharedExperience();
|
void updateSharedExperience();
|
||||||
|
|
||||||
|
void updateVocationsList();
|
||||||
|
|
||||||
void updatePlayerTicks(Player* player, uint32_t points);
|
void updatePlayerTicks(Player* player, uint32_t points);
|
||||||
void clearPlayerPoints(Player* player);
|
void clearPlayerPoints(Player* player);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
bool canEnableSharedExperience();
|
bool canEnableSharedExperience();
|
||||||
|
|
||||||
std::map<uint32_t, int64_t> ticksMap;
|
std::map<uint32_t, int64_t> ticksMap;
|
||||||
@@ -90,6 +93,8 @@ class Party
|
|||||||
|
|
||||||
Player* leader;
|
Player* leader;
|
||||||
|
|
||||||
|
float extraExpRate = 0.20f;
|
||||||
|
|
||||||
bool sharedExpActive = false;
|
bool sharedExpActive = false;
|
||||||
bool sharedExpEnabled = false;
|
bool sharedExpEnabled = false;
|
||||||
};
|
};
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user