introduce changes from streamside fork

This commit is contained in:
ErikasKontenis
2019-09-16 20:38:16 +03:00
parent f2cbc2dc1c
commit ad03b0eb3e
162 changed files with 2485 additions and 698 deletions

View File

@@ -1,6 +1,6 @@
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017 Alejandro Mujica <alejandrodemujica@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
* it under the terms of the GNU General Public License as published by
@@ -22,9 +22,9 @@
#include "pugicast.h"
#include "items.h"
#include "commands.h"
#include "creature.h"
#include "monster.h"
#include "events.h"
#include "game.h"
#include "actions.h"
#include "iologindata.h"
@@ -36,6 +36,7 @@
#include "bed.h"
#include "scheduler.h"
#include "databasetasks.h"
#include "movement.h"
extern ConfigManager g_config;
extern Actions* g_actions;
@@ -44,6 +45,10 @@ extern TalkActions* g_talkActions;
extern Spells* g_spells;
extern Vocations g_vocations;
extern GlobalEvents* g_globalEvents;
extern Events* g_events;
extern CreatureEvents* g_creatureEvents;
extern Monsters g_monsters;
extern MoveEvents* g_moveEvents;
Game::~Game()
{
@@ -84,8 +89,6 @@ void Game::setGameState(GameState_t newState)
gameState = newState;
switch (newState) {
case GAME_STATE_INIT: {
commands.loadFromXml();
loadExperienceStages();
groups.load();
@@ -219,7 +222,7 @@ Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index
}
case STACKPOS_USEITEM: {
thing = tile->getUseItem();
thing = tile->getUseItem(index);
break;
}
@@ -231,7 +234,7 @@ Thing* Game::internalGetThing(Player* player, const Position& pos, int32_t index
case STACKPOS_USETARGET: {
thing = tile->getTopCreature();
if (!thing) {
thing = tile->getUseItem();
thing = tile->getUseItem(index);
}
break;
}
@@ -651,6 +654,13 @@ void Game::playerMoveCreature(Player* player, Creature* movingCreature, const Po
player->setNextActionTask(nullptr);
if (g_config.getBoolean(ConfigManager::BLOCK_HEIGHT)) {
if (toTile->getHeight() > 1) {
player->sendCancelMessage(RETURNVALUE_NOTPOSSIBLE);
return;
}
}
if (!Position::areInRange<1, 1, 0>(movingCreatureOrigPos, player->getPosition())) {
//need to walk to the creature first before moving it
std::forward_list<Direction> listDir;
@@ -705,6 +715,10 @@ void Game::playerMoveCreature(Player* player, Creature* movingCreature, const Po
}
}
if (!g_events->eventPlayerOnMoveCreature(player, movingCreature, movingCreaturePos, toPos)) {
return;
}
ReturnValue ret = internalMoveCreature(*movingCreature, *toTile);
if (ret != RETURNVALUE_NOERROR) {
player->sendCancelMessage(ret);
@@ -729,7 +743,8 @@ ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction,
internalCreatureTurn(creature, DIRECTION_NORTH);
}
}
} else {
}
else {
//try go down
Tile* tmpTile = map.getTile(destPos.x, destPos.y, destPos.z);
if (currentPos.z != 7 && (tmpTile == nullptr || (tmpTile->getGround() == nullptr && !tmpTile->hasFlag(TILESTATE_BLOCKSOLID)))) {
@@ -742,11 +757,37 @@ ReturnValue Game::internalMoveCreature(Creature* creature, Direction direction,
}
}
ReturnValue ret = RETURNVALUE_NOTPOSSIBLE;
Tile* toTile = map.getTile(destPos);
if (!toTile) {
return RETURNVALUE_NOTPOSSIBLE;
Tile* toPos = map.getTile(destPos.x, destPos.y, destPos.z);
Tile* fromPos = map.getTile(currentPos.x, currentPos.y, currentPos.z);
if (g_config.getBoolean(ConfigManager::BLOCK_HEIGHT)) {
if (toTile) {
if (currentPos.z > destPos.z && toPos->getHeight() > 1);
// not possible
else if ((((toPos->getHeight() - fromPos->getHeight()) < 2)) ||
(fromPos->hasHeight(3) && (currentPos.z == destPos.z)) ||
((currentPos.z < destPos.z) && (toPos->hasHeight(3) && (fromPos->getHeight() < 2))))
ret = internalMoveCreature(*creature, *toTile, flags);
}
if (ret != RETURNVALUE_NOERROR) {
if (Player* player = creature->getPlayer()) {
player->sendCancelMessage(ret);
player->sendCancelWalk();
}
}
return ret;
}
else {
if (!toTile) {
return RETURNVALUE_NOTPOSSIBLE;
}
return internalMoveCreature(*creature, *toTile, flags);
}
return internalMoveCreature(*creature, *toTile, flags);
}
ReturnValue Game::internalMoveCreature(Creature& creature, Tile& toTile, uint32_t flags /*= 0*/)
@@ -964,6 +1005,10 @@ void Game::playerMoveItem(Player* player, const Position& fromPos,
return;
}
if (!g_events->eventPlayerOnMoveItem(player, item, count, fromPos, toPos, fromCylinder, toCylinder)) {
return;
}
uint8_t toIndex = 0;
if (toPos.x == 0xFFFF) {
if (toPos.y & 0x40) {
@@ -976,6 +1021,8 @@ void Game::playerMoveItem(Player* player, const Position& fromPos,
ReturnValue ret = internalMoveItem(fromCylinder, toCylinder, toIndex, item, count, nullptr, 0, player);
if (ret != RETURNVALUE_NOERROR) {
player->sendCancelMessage(ret);
} else {
g_events->eventPlayerOnItemMoved(player, item, count, fromPos, toPos, fromCylinder, toCylinder);
}
}
@@ -2316,6 +2363,10 @@ void Game::playerRequestTrade(uint32_t playerId, const Position& pos, uint8_t st
return;
}
if (!g_events->eventPlayerOnTradeRequest(player, tradePartner, tradeItem)) {
return;
}
internalStartTrade(player, tradePartner, tradeItem);
}
@@ -2379,6 +2430,11 @@ void Game::playerAcceptTrade(uint32_t playerId)
Item* tradeItem1 = player->tradeItem;
Item* tradeItem2 = tradePartner->tradeItem;
if (!g_events->eventPlayerOnTradeAccept(player, tradePartner, tradeItem1, tradeItem2)) {
internalCloseTrade(player);
return;
}
player->setTradeState(TRADE_TRANSFER);
tradePartner->setTradeState(TRADE_TRANSFER);
@@ -2508,10 +2564,8 @@ void Game::playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, uint8_t
int32_t lookDistance = std::max<int32_t>(Position::getDistanceX(playerPosition, tradeItemPosition),
Position::getDistanceY(playerPosition, tradeItemPosition));
std::stringstream ss;
if (index == 0) {
ss << "You see " << tradeItem->getDescription(lookDistance);
player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
g_events->eventPlayerOnLookInTrade(player, tradePartner, tradeItem, lookDistance);
return;
}
@@ -2531,8 +2585,7 @@ void Game::playerLookInTrade(uint32_t playerId, bool lookAtCounterOffer, uint8_t
}
if (--index == 0) {
ss << "You see " << item->getDescription(lookDistance);
player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
g_events->eventPlayerOnLookInTrade(player, tradePartner, item, lookDistance);
return;
}
}
@@ -2624,52 +2677,7 @@ void Game::playerLookAt(uint32_t playerId, const Position& pos, uint8_t stackPos
lookDistance = -1;
}
std::ostringstream ss;
ss << "You see " << thing->getDescription(lookDistance);
if (player->isAccessPlayer()) {
Item* item = thing->getItem();
if (item) {
ss << std::endl << "ItemID: [" << item->getID() << ']';
uint16_t actionId = item->getActionId();
if (actionId != 0) {
ss << ", ActionID: [" << actionId << ']';
}
uint16_t movementID = item->getMovementId();
if (movementID != 0) {
ss << ", MovementID: [" << movementID << ']';
}
ss << '.';
const ItemType& it = Item::items[item->getID()];
if (it.transformEquipTo) {
ss << std::endl << "TransformTo: [" << it.transformEquipTo << "] (onEquip).";
} else if (it.transformDeEquipTo) {
ss << std::endl << "TransformTo: [" << it.transformDeEquipTo << "] (onDeEquip).";
}
if (it.decayTo != -1) {
ss << std::endl << "DecayTo: [" << it.decayTo << "].";
}
}
if (const Creature* creature = thing->getCreature()) {
ss << std::endl << "Health: [" << creature->getHealth() << " / " << creature->getMaxHealth() << ']';
if (creature->getMaxMana() > 0) {
ss << ", Mana: [" << creature->getMana() << " / " << creature->getMaxMana() << ']';
}
ss << '.';
}
ss << std::endl << "Position: [X: " << thingPos.x << "] [Y: " << thingPos.y << "] [Z: " << thingPos.getZ() << "].";
}
player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
g_events->eventPlayerOnLook(player, pos, thing, stackPos, lookDistance);
}
void Game::playerLookInBattleList(uint32_t playerId, uint32_t creatureId)
@@ -2704,21 +2712,7 @@ void Game::playerLookInBattleList(uint32_t playerId, uint32_t creatureId)
lookDistance = -1;
}
std::ostringstream ss;
ss << "You see " << creature->getDescription(lookDistance);
if (player->isAccessPlayer()) {
ss << std::endl << "Health: [" << creature->getHealth() << " / " << creature->getMaxHealth() << ']';
if (creature->getMaxMana() > 0) {
ss << ", Mana: [" << creature->getMana() << " / " << creature->getMaxMana() << ']';
}
ss << '.' << std::endl;
ss << "Position: [X: " << creaturePos.x << "] [Y: " << creaturePos.y << "] [Z: " << creaturePos.getZ() << "].";
}
player->sendTextMessage(MESSAGE_INFO_DESCR, ss.str());
g_events->eventPlayerOnLookInBattleList(player, creature, lookDistance);
}
void Game::playerCancelAttackAndFollow(uint32_t playerId)
@@ -2847,6 +2841,10 @@ void Game::playerTurn(uint32_t playerId, Direction dir)
return;
}
if (!g_events->eventPlayerOnTurn(player, dir)) {
return;
}
player->resetIdleTime();
internalCreatureTurn(player, dir);
}
@@ -2897,6 +2895,10 @@ void Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
player->resetIdleTime();
if (playerSaySpell(player, type, text)) {
return;
}
uint32_t muteTime = player->isMuted();
if (muteTime > 0) {
std::ostringstream ss;
@@ -2905,14 +2907,6 @@ void Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
return;
}
if (playerSayCommand(player, text)) {
return;
}
if (playerSaySpell(player, type, text)) {
return;
}
if (!text.empty() && text.front() == '/' && player->isAccessPlayer()) {
return;
}
@@ -2966,23 +2960,6 @@ void Game::playerSay(uint32_t playerId, uint16_t channelId, SpeakClasses type,
}
}
bool Game::playerSayCommand(Player* player, const std::string& text)
{
if (text.empty()) {
return false;
}
char firstCharacter = text.front();
for (char commandTag : commandTags) {
if (commandTag == firstCharacter) {
if (commands.exeCommand(*player, text)) {
return true;
}
}
}
return false;
}
bool Game::playerSaySpell(Player* player, SpeakClasses type, const std::string& text)
{
std::string words = text;
@@ -3234,6 +3211,10 @@ void Game::changeSpeed(Creature* creature, int32_t varSpeedDelta)
void Game::internalCreatureChangeOutfit(Creature* creature, const Outfit_t& outfit)
{
if (!g_events->eventCreatureOnChangeOutfit(creature, outfit)) {
return;
}
creature->setCurrentOutfit(outfit);
if (creature->isInvisible()) {
@@ -3403,6 +3384,17 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
return false;
}
if (damage.origin != ORIGIN_NONE) {
const auto& events = target->getCreatureEvents(CREATURE_EVENT_HEALTHCHANGE);
if (!events.empty()) {
for (CreatureEvent* creatureEvent : events) {
creatureEvent->executeHealthChange(target, attacker, damage);
}
damage.origin = ORIGIN_NONE;
return combatChangeHealth(attacker, target, damage);
}
}
int32_t realHealthChange = target->getHealth();
target->gainHealth(attacker, damage.value);
realHealthChange = target->getHealth() - realHealthChange;
@@ -3410,7 +3402,8 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
if (realHealthChange > 0 && !target->isInGhostMode()) {
addMagicEffect(targetPos, CONST_ME_MAGIC_BLUE);
}
} else {
}
else {
if (Monster* monster = target->getMonster()) {
// makes monsters aggressive when damaged
// basically stands for UNDERATTACK stance under CipSoft servers
@@ -3431,7 +3424,8 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
Player* attackerPlayer;
if (attacker) {
attackerPlayer = attacker->getPlayer();
} else {
}
else {
attackerPlayer = nullptr;
}
damage.value = std::abs(damage.value);
@@ -3440,25 +3434,39 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
if (healthChange == 0) {
return true;
}
Player* targetPlayer = target->getPlayer();
SpectatorVec list;
if (target->hasCondition(CONDITION_MANASHIELD) && damage.type != COMBAT_UNDEFINEDDAMAGE) {
int32_t manaDamage = std::min<int32_t>(target->getMana(), healthChange);
int32_t manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);
if (manaDamage != 0) {
target->drainMana(attacker, manaDamage);
if (damage.origin != ORIGIN_NONE) {
const auto& events = target->getCreatureEvents(CREATURE_EVENT_MANACHANGE);
if (!events.empty()) {
for (CreatureEvent* creatureEvent : events) {
creatureEvent->executeManaChange(target, attacker, damage);
}
healthChange = damage.value;
if (healthChange == 0) {
return true;
}
manaDamage = std::min<int32_t>(targetPlayer->getMana(), healthChange);
}
}
targetPlayer->drainMana(attacker, manaDamage);
map.getSpectators(list, targetPos, true, true);
addMagicEffect(list, targetPos, CONST_ME_LOSEENERGY);
std::string damageString = std::to_string(manaDamage);
Player* targetPlayer = target->getPlayer();
if (targetPlayer) {
std::stringstream ss;
if (!attacker) {
ss << "You lose " << damageString << " mana.";
} else if (targetPlayer == attackerPlayer) {
}
else if (targetPlayer == attackerPlayer) {
ss << "You lose " << damageString << " mana due to your own attack.";
} else {
}
else {
ss << "You lose " << damageString << " mana due to an attack by " << attacker->getNameDescription() << '.';
}
targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str());
@@ -3489,19 +3497,11 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
realDamage = damage.value;
if (realDamage == 0) {
return true;
} else if (realDamage >= targetHealth) {
for (CreatureEvent* creatureEvent : target->getCreatureEvents(CREATURE_EVENT_PREPAREDEATH)) {
if (!creatureEvent->executeOnPrepareDeath(target, attacker)) {
return false;
}
}
}
target->drainHealth(attacker, realDamage);
if (list.empty()) {
map.getSpectators(list, targetPos, true, true);
}
addCreatureHealth(list, target);
TextColor_t color = TEXTCOLOR_NONE;
uint8_t hitEffect;
@@ -3514,15 +3514,15 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
if (color != TEXTCOLOR_NONE) {
std::string damageString = std::to_string(realDamage) + (realDamage != 1 ? " hitpoints" : " hitpoint");
Player* targetPlayer = target->getPlayer();
if (targetPlayer) {
std::stringstream ss;
if (!attacker) {
ss << "You lose " << damageString << ".";
} else if (targetPlayer == attackerPlayer) {
}
else if (targetPlayer == attackerPlayer) {
ss << "You lose " << damageString << " due to your own attack.";
} else {
}
else {
ss << "You lose " << damageString << " due to an attack by " << attacker->getNameDescription() << '.';
}
targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str());
@@ -3534,16 +3534,43 @@ bool Game::combatChangeHealth(Creature* attacker, Creature* target, CombatDamage
tmpPlayer->sendAnimatedText(targetPos, color, realDamageStr);
}
}
if (realDamage >= targetHealth) {
for (CreatureEvent* creatureEvent : target->getCreatureEvents(CREATURE_EVENT_PREPAREDEATH)) {
if (!creatureEvent->executeOnPrepareDeath(target, attacker)) {
return false;
}
}
}
target->drainHealth(attacker, realDamage);
addCreatureHealth(list, target);
}
return true;
}
bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaChange)
bool Game::combatChangeMana(Creature* attacker, Creature* target, CombatDamage& damage)
{
Player* targetPlayer = target->getPlayer();
if (!targetPlayer) {
return true;
}
int32_t manaChange = damage.value;
if (manaChange > 0) {
target->changeMana(manaChange);
} else {
if (damage.origin != ORIGIN_NONE) {
const auto& events = target->getCreatureEvents(CREATURE_EVENT_MANACHANGE);
if (!events.empty()) {
for (CreatureEvent* creatureEvent : events) {
creatureEvent->executeManaChange(target, attacker, damage);
}
damage.origin = ORIGIN_NONE;
return combatChangeMana(attacker, target, damage);
}
}
targetPlayer->changeMana(manaChange);
}
else {
const Position& targetPos = target->getPosition();
if (!target->isAttackable()) {
if (!target->isInGhostMode()) {
@@ -3555,11 +3582,12 @@ bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaCh
Player* attackerPlayer;
if (attacker) {
attackerPlayer = attacker->getPlayer();
} else {
}
else {
attackerPlayer = nullptr;
}
int32_t manaLoss = std::min<int32_t>(target->getMana(), -manaChange);
int32_t manaLoss = std::min<int32_t>(targetPlayer->getMana(), -manaChange);
BlockType_t blockType = target->blockHit(attacker, COMBAT_MANADRAIN, manaLoss);
if (blockType != BLOCK_NONE) {
addMagicEffect(targetPos, CONST_ME_POFF);
@@ -3570,11 +3598,20 @@ bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaCh
return true;
}
target->drainMana(attacker, manaLoss);
if (damage.origin != ORIGIN_NONE) {
const auto& events = target->getCreatureEvents(CREATURE_EVENT_MANACHANGE);
if (!events.empty()) {
for (CreatureEvent* creatureEvent : events) {
creatureEvent->executeManaChange(target, attacker, damage);
}
damage.origin = ORIGIN_NONE;
return combatChangeMana(attacker, target, damage);
}
}
targetPlayer->drainMana(attacker, manaLoss);
std::string damageString = std::to_string(manaLoss);
Player* targetPlayer = target->getPlayer();
SpectatorVec list;
map.getSpectators(list, targetPos, false, true);
@@ -3582,9 +3619,11 @@ bool Game::combatChangeMana(Creature* attacker, Creature* target, int32_t manaCh
std::stringstream ss;
if (!attacker) {
ss << "You lose " << damageString << " mana.";
} else if (targetPlayer == attackerPlayer) {
}
else if (targetPlayer == attackerPlayer) {
ss << "You lose " << damageString << " mana due to your own attack.";
} else {
}
else {
ss << "You lose " << damageString << " mana due to an attack by " << attacker->getNameDescription() << '.';
}
targetPlayer->sendTextMessage(MESSAGE_EVENT_DEFAULT, ss.str());
@@ -3814,23 +3853,9 @@ void Game::getWorldLightInfo(LightInfo& lightInfo) const
lightInfo.color = 0xD7;
}
void Game::addCommandTag(char tag)
{
for (char commandTag : commandTags) {
if (commandTag == tag) {
return;
}
}
commandTags.push_back(tag);
}
void Game::resetCommandTag()
{
commandTags.clear();
}
void Game::shutdown()
{
saveGameState();
std::cout << "Shutting down..." << std::flush;
g_scheduler.shutdown();
@@ -4324,22 +4349,8 @@ void Game::playerReportBug(uint32_t playerId, const std::string& message)
return;
}
if (player->getAccountType() == ACCOUNT_TYPE_NORMAL) {
return;
}
std::string fileName = "data/reports/" + player->getName() + " report.txt";
FILE* file = fopen(fileName.c_str(), "a");
if (!file) {
player->sendTextMessage(MESSAGE_EVENT_DEFAULT, "There was an error when processing your report, please contact a gamemaster.");
return;
}
const Position& playerPosition = player->getPosition();
fprintf(file, "------------------------------\nName: %s [Player Position: %u, %u, %u]\nComment: %s\n", player->getName().c_str(), playerPosition.x, playerPosition.y, playerPosition.z, message.c_str());
fclose(file);
player->sendTextMessage(MESSAGE_EVENT_DEFAULT, "Your report has been sent to " + g_config.getString(ConfigManager::SERVER_NAME) + ".");
const Position& position = player->getPosition();
g_events->eventPlayerOnReportBug(player, message, position);
}
void Game::playerDebugAssert(uint32_t playerId, const std::string& assertLine, const std::string& date, const std::string& description, const std::string& comment)
@@ -4534,3 +4545,64 @@ void Game::removeBedSleeper(uint32_t guid)
bedSleepersMap.erase(it);
}
}
bool Game::reload(ReloadTypes_t reloadType)
{
switch (reloadType) {
case RELOAD_TYPE_ACTIONS: return g_actions->reload();
case RELOAD_TYPE_CHAT: return g_chat->load();
case RELOAD_TYPE_CONFIG: return g_config.reload();
case RELOAD_TYPE_CREATURESCRIPTS: return g_creatureEvents->reload();
case RELOAD_TYPE_EVENTS: return g_events->load();
case RELOAD_TYPE_GLOBALEVENTS: return g_globalEvents->reload();
case RELOAD_TYPE_ITEMS: return Item::items.reload();
case RELOAD_TYPE_MONSTERS: return g_monsters.reload();
case RELOAD_TYPE_MOVEMENTS: return g_moveEvents->reload();
case RELOAD_TYPE_NPCS: {
Npcs::reload();
return true;
}
case RELOAD_TYPE_RAIDS: return raids.reload() && raids.startup();
case RELOAD_TYPE_SPELLS: {
if (!g_spells->reload()) {
std::cout << "[Error - Game::reload] Failed to reload spells." << std::endl;
std::terminate();
}
else if (!g_monsters.reload()) {
std::cout << "[Error - Game::reload] Failed to reload monsters." << std::endl;
std::terminate();
}
return true;
}
case RELOAD_TYPE_TALKACTIONS: return g_talkActions->reload();
default: {
if (!g_spells->reload()) {
std::cout << "[Error - Game::reload] Failed to reload spells." << std::endl;
std::terminate();
return false;
}
else if (!g_monsters.reload()) {
std::cout << "[Error - Game::reload] Failed to reload monsters." << std::endl;
std::terminate();
return false;
}
g_actions->reload();
g_config.reload();
g_creatureEvents->reload();
g_monsters.reload();
g_moveEvents->reload();
Npcs::reload();
raids.reload() && raids.startup();
g_talkActions->reload();
Item::items.reload();
g_globalEvents->reload();
g_events->load();
g_chat->load();
return true;
}
}
}