mirror of
https://github.com/ErikasKontenis/SabrehavenServer.git
synced 2025-12-17 23:27:11 +01:00
introduce changes from streamside fork
This commit is contained in:
396
src/game.cpp
396
src/game.cpp
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user