ReturnValue Combat::canDoCombat(const CreatureP& caster, Tile* tile, bool isAggressive) { if(tile->hasProperty(BLOCKPROJECTILE) || tile->floorChange() || tile->getTeleporter()) return RET_NOTENOUGHROOM; if(caster) { bool success = true; CreatureEventList combatAreaEvents = caster->getCreatureEvents(CREATURE_EVENT_COMBAT_AREA); for(CreatureEventList::iterator it = combatAreaEvents.begin(); it != combatAreaEvents.end(); ++it) { if(!(*it)->executeCombatArea(caster, tile, isAggressive) && success) success = false; } if(!success) return RET_NOTPOSSIBLE; if(caster->getPosition().z < tile->getPosition().z) return RET_FIRSTGODOWNSTAIRS; if(caster->getPosition().z > tile->getPosition().z) return RET_FIRSTGOUPSTAIRS; if(!isAggressive) return RET_NOERROR; const Player* player = caster->getPlayer(); if(player && player->hasFlag(PlayerFlag_IgnoreProtectionZone)) return RET_NOERROR; } return isAggressive && tile->hasFlag(TILESTATE_PROTECTIONZONE) ? RET_ACTIONNOTPERMITTEDINPROTECTIONZONE : RET_NOERROR; }
bool ChatChannel::addUser(Player* player) { if(m_users.find(player->getID()) != m_users.end()) return false; ChatChannel* channel = g_chat.getChannel(player, m_id); if(!channel) { #ifdef __DEBUG_CHAT__ std::clog << "ChatChannel::addUser - failed retrieving channel." << std::endl; #endif return false; } if(m_id == CHANNEL_PARTY || m_id == CHANNEL_GUILD || m_id == CHANNEL_PRIVATE) { Player* tmpPlayer = NULL; for(UsersMap::iterator cit = m_users.begin(); cit != m_users.end(); ++cit) { if((tmpPlayer = cit->second->getPlayer())) tmpPlayer->sendChannelEvent(m_id, player->getName(), CHANNELEVENT_JOIN); } } m_users[player->getID()] = player; CreatureEventList joinEvents = player->getCreatureEvents(CREATURE_EVENT_CHANNEL_JOIN); for(CreatureEventList::iterator it = joinEvents.begin(); it != joinEvents.end(); ++it) (*it)->executeChannelJoin(player, m_id, m_users); Manager::getInstance()->addUser(player->getID(), m_id); return true; }
bool ChatChannel::removeUser(Player* player) { if(!player || player->isRemoved()) return false; UsersMap::iterator it = m_users.find(player->getID()); if(it == m_users.end()) return false; m_users.erase(it); CreatureEventList leaveEvents = player->getCreatureEvents(CREATURE_EVENT_CHANNEL_LEAVE); for(CreatureEventList::iterator it = leaveEvents.begin(); it != leaveEvents.end(); ++it) (*it)->executeChannelLeave(player, m_id, m_users); if(m_id == CHANNEL_PARTY || m_id == CHANNEL_GUILD || m_id == CHANNEL_PRIVATE) { Player* tmpPlayer = NULL; for(UsersMap::iterator cit = m_users.begin(); cit != m_users.end(); ++cit) { if((tmpPlayer = cit->second->getPlayer())) tmpPlayer->sendChannelEvent(m_id, player->getName(), CHANNELEVENT_LEAVE); } } Manager::getInstance()->removeUser(player->getID(), m_id); return true; }
void Creature::dropCorpse(DeathList deathList) { if(master && !g_config.getBool(ConfigManager::SUMMONS_DROP_CORPSE)) { g_game.addMagicEffect(getPosition(), MAGIC_EFFECT_POFF); return; } Item* corpse = createCorpse(deathList); if(corpse) corpse->setParent(VirtualCylinder::virtualCylinder); bool deny = false; CreatureEventList deathEvents = getCreatureEvents(CREATURE_EVENT_DEATH); for(CreatureEventList::iterator it = deathEvents.begin(); it != deathEvents.end(); ++it) { if(!(*it)->executeDeath(this, corpse, deathList) && !deny) deny = true; } if(!corpse) return; corpse->setParent(NULL); if(deny) return; Tile* tile = getTile(); if(!tile) return; Item* splash = NULL; switch(getRace()) { case RACE_VENOM: splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_GREEN); break; case RACE_BLOOD: splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_BLOOD); break; default: break; } if(splash) { g_game.internalAddItem(NULL, tile, splash, INDEX_WHEREEVER, FLAG_NOLIMIT); g_game.startDecay(splash); } g_game.internalAddItem(NULL, tile, corpse, INDEX_WHEREEVER, FLAG_NOLIMIT); dropLoot(corpse->getContainer()); g_game.startDecay(corpse); }
CreatureEventList Creature::getCreatureEvents(CreatureEventType_t type) { CreatureEventList list; for(CreatureEventList::iterator it = eventsList.begin(); it != eventsList.end(); ++it) { if((*it)->getEventType() == type && (*it)->isLoaded()) list.push_back(*it); } return list; }
void Creature::onCreatureDisappear(const Creature* creature, bool isLogout) { internalCreatureDisappear(creature, true); if(creature != this && isMapLoaded && creature->getPosition().z == getPosition().z) { updateTileCache(creature->getTile(), creature->getPosition()); CreatureEventList disappearEvents = getCreatureEvents(CREATURE_EVENT_DISAPPEAR); for(CreatureEventList::iterator it = disappearEvents.begin(); it != disappearEvents.end(); ++it) (*it)->executeDisappear(this, creature); } }
ReturnValue Combat::canTargetCreature(const Player* player, const Creature* target) { if(player == target) return RET_YOUMAYNOTATTACKTHISPLAYER; Player* tmpPlayer = const_cast<Player*>(player); bool deny = false; CreatureEventList targetEvents = tmpPlayer->getCreatureEvents(CREATURE_EVENT_TARGET); for(CreatureEventList::iterator it = targetEvents.begin(); it != targetEvents.end(); ++it) { if(!(*it)->executeAction(tmpPlayer, const_cast<Creature*>(target)) && !deny) deny = true; } if(deny) return RET_NEEDEXCHANGE; if(!player->hasFlag(PlayerFlag_IgnoreProtectionZone)) { if(player->getZone() == ZONE_PROTECTION) return RET_YOUMAYNOTATTACKAPERSONWHILEINPROTECTIONZONE; if(target->getZone() == ZONE_PROTECTION) return RET_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE; if(target->getPlayer() || target->isPlayerSummon()) { if(player->getZone() == ZONE_OPTIONAL) return RET_ACTIONNOTPERMITTEDINANOPVPZONE; if(target->getZone() == ZONE_OPTIONAL) return RET_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE; } } if(player->hasFlag(PlayerFlag_CannotUseCombat)) return target->getPlayer() ? RET_YOUMAYNOTATTACKTHISPLAYER : RET_YOUMAYNOTATTACKTHISCREATURE; if(target->getPlayer() && !Combat::isInPvpZone(player, target) && player->getSkullType(target->getPlayer()) == SKULL_NONE) { if(player->getSecureMode() == SECUREMODE_ON) return RET_TURNSECUREMODETOATTACKUNMARKEDPLAYERS; } if(player->checkLoginDelay()) return RET_YOUMAYNOTATTACKIMMEDIATELYAFTERLOGGINGIN; return Combat::canDoCombat(player, target, true); }
CreatureEventList Creature::getCreatureEvents(CreatureEventType_t type) { CreatureEventList retList; if(!hasEventRegistered(type)) return retList; for(CreatureEventList::iterator it = eventsList.begin(); it != eventsList.end(); ++it) { if((*it)->getEventType() == type) retList.push_back(*it); } return retList; }
ReturnValue Combat::canTargetCreature(const PlayerP& player, const CreatureP& target) { if(player == target) return RET_YOUMAYNOTATTACKTHISPLAYER; CreatureEventList targetEvents = player->getCreatureEvents(CREATURE_EVENT_TARGET); bool deny = false; for(CreatureEventList::iterator it = targetEvents.begin(); it != targetEvents.end(); ++it) { if(!(*it)->executeTarget(player, target)) deny = true; } if(deny) return RET_DONTSHOWMESSAGE; if(!player->hasFlag(PlayerFlag_IgnoreProtectionZone)) { if(player->getZone() == ZONE_PROTECTION) return RET_YOUMAYNOTATTACKAPERSONWHILEINPROTECTIONZONE; if(target->getZone() == ZONE_PROTECTION) return RET_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE; const Monster* targetMonster = target->getMonster(); if(target->getPlayer() || (targetMonster != nullptr && targetMonster->getMaster() && targetMonster->getMaster()->getPlayer())) { if(player->getZone() == ZONE_NOPVP) return RET_ACTIONNOTPERMITTEDINANOPVPZONE; if(target->getZone() == ZONE_NOPVP) return RET_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE; } } if(player->hasFlag(PlayerFlag_CannotUseCombat) || !target->isAttackable()) return target->getPlayer() ? RET_YOUMAYNOTATTACKTHISPLAYER : RET_YOUMAYNOTATTACKTHISCREATURE; if(target->getPlayer() && !Combat::isInPvpZone(*player, *target) && player->getSkullClient(target->getPlayer()) == SKULL_NONE) { if(player->getSecureMode() == SECUREMODE_ON) return RET_TURNSECUREMODETOATTACKUNMARKEDPLAYERS; if(player->getSkull() == SKULL_BLACK) return RET_YOUMAYNOTATTACKTHISPLAYER; } return canDoCombat(player, target); }
void Creature::onThink(uint32_t interval) { if(!isMapLoaded && useCacheMap()) { isMapLoaded = true; updateMapCache(); } if(followCreature && master != followCreature && !canSeeCreature(followCreature)) internalCreatureDisappear(followCreature, false); if(attackedCreature && master != attackedCreature && !canSeeCreature(attackedCreature)) internalCreatureDisappear(attackedCreature, false); blockTicks += interval; if(blockTicks >= 1000) { blockCount = std::min((uint32_t)blockCount + 1, (uint32_t)2); blockTicks = 0; } if(followCreature) { walkUpdateTicks += interval; if(forceUpdateFollowPath || walkUpdateTicks >= 2000) { walkUpdateTicks = 0; forceUpdateFollowPath = false; isUpdatingPath = true; } } if(isUpdatingPath) { isUpdatingPath = false; goToFollowCreature(); } #ifndef __GROUPED_ATTACKS__ onAttacking(interval / EVENT_CREATURECOUNT); #else onAttacking(interval); #endif executeConditions(interval); CreatureEventList thinkEvents = getCreatureEvents(CREATURE_EVENT_THINK); for(CreatureEventList::iterator it = thinkEvents.begin(); it != thinkEvents.end(); ++it) (*it)->executeThink(this, interval); }
bool Creature::onKilledCreature(Creature* target, bool lastHit/* = true*/) { if (getMaster()) { getMaster()->onKilledCreature(target); } //scripting event - onKill CreatureEventList killEvents = getCreatureEvents(CREATURE_EVENT_KILL); for (CreatureEventList::const_iterator it = killEvents.begin(), end = killEvents.end(); it != end; ++it) { (*it)->executeOnKill(this, target); } return false; }
CreatureEventList Creature::getCreatureEvents(CreatureEventType_t type) { CreatureEventList tmpEventList; if (!hasEventRegistered(type)) { return tmpEventList; } for (CreatureEventList::const_iterator it = eventsList.begin(), end = eventsList.end(); it != end; ++it) { if ((*it)->getEventType() == type) { tmpEventList.push_back(*it); } } return tmpEventList; }
CreatureEventList Creature::getCreatureEvents(CreatureEventType_t type) { CreatureEventList tmpEventList; if (!hasEventRegistered(type)) { return tmpEventList; } for (CreatureEvent* creatureEvent : eventsList) { if (creatureEvent->getEventType() == type) { tmpEventList.push_back(creatureEvent); } } return tmpEventList; }
void Creature::onCreatureAppear(const Creature* creature) { if(creature == this) { if(useCacheMap()) { isMapLoaded = true; updateMapCache(); } } else if(isMapLoaded && creature->getPosition().z == getPosition().z) { updateTileCache(creature->getTile(), creature->getPosition()); CreatureEventList disappearEvents = getCreatureEvents(CREATURE_EVENT_APPEAR); for(CreatureEventList::iterator it = disappearEvents.begin(); it != disappearEvents.end(); ++it) (*it)->executeDisappear(this, creature); } }
void Creature::onThink(uint32_t interval) { if (!isMapLoaded && useCacheMap()) { isMapLoaded = true; updateMapCache(); } if (followCreature && getMaster() != followCreature && !canSeeCreature(followCreature)) { onCreatureDisappear(followCreature, false); } if (attackedCreature && getMaster() != attackedCreature && !canSeeCreature(attackedCreature)) { onCreatureDisappear(attackedCreature, false); } blockTicks += interval; if (blockTicks >= 1000) { blockCount = std::min<uint32_t>(blockCount + 1, 2); blockTicks = 0; } if (followCreature) { walkUpdateTicks += interval; if (forceUpdateFollowPath || walkUpdateTicks >= 2000) { walkUpdateTicks = 0; forceUpdateFollowPath = false; isUpdatingPath = true; } } if (isUpdatingPath) { isUpdatingPath = false; goToFollowCreature(); } //scripting event - onThink CreatureEventList thinkEvents = getCreatureEvents(CREATURE_EVENT_THINK); for (CreatureEventList::const_iterator it = thinkEvents.begin(), end = thinkEvents.end(); it != end; ++it) { (*it)->executeOnThink(this, interval); } }
bool Creature::onKilledCreature(Creature* target, DeathEntry& entry) { bool ret = true; if(master) ret = master->onKilledCreature(target, entry); CreatureEventList killEvents = getCreatureEvents(CREATURE_EVENT_KILL); if(!entry.isLast()) { for(CreatureEventList::iterator it = killEvents.begin(); it != killEvents.end(); ++it) (*it)->executeKill(this, target, entry); return true; } for(CreatureEventList::iterator it = killEvents.begin(); it != killEvents.end(); ++it) { if(!(*it)->executeKill(this, target, entry) && ret) ret = false; } return ret; }
bool Creature::onKilledCreature(Creature* target, uint32_t& flags, DeathEntry& entry) { bool ret = true; if(master) ret = master->onKilledCreature(target, flags, entry); CreatureEventList killEvents = getCreatureEvents(CREATURE_EVENT_KILL); if(!hasBitSet((uint32_t)KILLFLAG_LASTHIT, flags)) { for(CreatureEventList::iterator it = killEvents.begin(); it != killEvents.end(); ++it) (*it)->executeKill(this, target, false); return true; } for(CreatureEventList::iterator it = killEvents.begin(); it != killEvents.end(); ++it) { if(!(*it)->executeKill(this, target, true) && ret) ret = false; } return ret; }
void Monster::onCreatureAppear(const Creature* creature) { Creature::onCreatureAppear(creature); if(creature == this) { //We just spawned lets look around to see who is there. if(isSummon()) isMasterInRange = canSee(getMaster()->getPosition()); setStorage(510, mType->realName); // sistema de shiny nomes 2.0 CreatureEventList spawn = getCreatureEvents(CREATURE_EVENT_SPAWN); for(CreatureEventList::iterator it = spawn.begin(); it != spawn.end(); ++it) (*it)->executeOnSpawn(this); updateTargetList(); updateIdleStatus(); } else onCreatureEnter(const_cast<Creature*>(creature)); }
bool Creature::dropCorpse() { if (!lootDrop && getMonster() && !(master && master->getPlayer())) { if (master) { //scripting event - onDeath CreatureEventList deathEvents = getCreatureEvents(CREATURE_EVENT_DEATH); for (CreatureEventList::const_iterator it = deathEvents.begin(); it != deathEvents.end(); ++it) { (*it)->executeOnDeath(this, NULL, _lastHitCreature, _mostDamageCreature, lastHitUnjustified, mostDamageUnjustified); } } g_game.addMagicEffect(getPosition(), NM_ME_POFF); } else { Item* splash = NULL; switch (getRace()) { case RACE_VENOM: splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_GREEN); break; case RACE_BLOOD: splash = Item::CreateItem(ITEM_FULLSPLASH, FLUID_BLOOD); break; default: break; } Tile* tile = getTile(); if (splash) { g_game.internalAddItem(tile, splash, INDEX_WHEREEVER, FLAG_NOLIMIT); g_game.startDecay(splash); } Item* corpse = getCorpse(); if (corpse) { g_game.internalAddItem(tile, corpse, INDEX_WHEREEVER, FLAG_NOLIMIT); g_game.startDecay(corpse); } //scripting event - onDeath CreatureEventList deathEvents = getCreatureEvents(CREATURE_EVENT_DEATH); for (CreatureEventList::const_iterator it = deathEvents.begin(); it != deathEvents.end(); ++it) { (*it)->executeOnDeath(this, corpse, _lastHitCreature, _mostDamageCreature, lastHitUnjustified, mostDamageUnjustified); } if (corpse) { dropLoot(corpse->getContainer()); } } return true; }
void Creature::onAttacking(uint32_t interval) { if(!attackedCreature || attackedCreature->getHealth() < 1 || interval < 100) return; bool deny = false; CreatureEventList attackEvents = getCreatureEvents(CREATURE_EVENT_ATTACK); for(CreatureEventList::iterator it = attackEvents.begin(); it != attackEvents.end(); ++it) { if(!(*it)->executeAction(this, attackedCreature) && !deny) deny = true; } if(deny) setAttackedCreature(NULL); if(!attackedCreature) return; onAttacked(); attackedCreature->onAttacked(); if(g_game.isSightClear(getPosition(), attackedCreature->getPosition(), true)) doAttacking(interval); }
Cylinder* Tile::__queryDestination(int32_t& index, const Thing* thing, Item** destItem, uint32_t& flags) { Tile* destTile = NULL; *destItem = NULL; Position _pos = pos; if(floorChange(CHANGE_DOWN)) { _pos.z++; if(Creature* creature = (Creature*) thing->getCreature()){ CreatureEventList moveEvents = creature->getCreatureEvents(CREATURE_EVENT_MOVE); for(CreatureEventList::iterator it = moveEvents.begin(); it != moveEvents.end(); ++it) (*it)->executeMove(creature, creature->getPosition(), _pos); } for(int32_t i = CHANGE_FIRST_EX; i < CHANGE_LAST; ++i) { Position __pos = _pos; Tile* tmpTile = NULL; switch(i) { case CHANGE_NORTH_EX: __pos.y++; if((tmpTile = g_game.getTile(__pos))) __pos.y++; break; case CHANGE_SOUTH_EX: __pos.y--; if((tmpTile = g_game.getTile(__pos))) __pos.y--; break; case CHANGE_EAST_EX: __pos.x--; if((tmpTile = g_game.getTile(__pos))) __pos.x--; break; case CHANGE_WEST_EX: __pos.x++; if((tmpTile = g_game.getTile(__pos))) __pos.x++; break; default: break; } if(!tmpTile || !tmpTile->floorChange((FloorChange_t)i)) continue; destTile = g_game.getTile(__pos); break; } if(!destTile) { if(Tile* downTile = g_game.getTile(_pos)) { if(downTile->floorChange(CHANGE_NORTH) || downTile->floorChange(CHANGE_NORTH_EX)) _pos.y++; if(downTile->floorChange(CHANGE_SOUTH) || downTile->floorChange(CHANGE_SOUTH_EX)) _pos.y--; if(downTile->floorChange(CHANGE_EAST) || downTile->floorChange(CHANGE_EAST_EX)) _pos.x--; if(downTile->floorChange(CHANGE_WEST) || downTile->floorChange(CHANGE_WEST_EX)) _pos.x++; destTile = g_game.getTile(_pos); } } } else if(floorChange()) { _pos.z--; if(floorChange(CHANGE_NORTH)) _pos.y--; if(floorChange(CHANGE_SOUTH)) _pos.y++; if(floorChange(CHANGE_EAST)) _pos.x++; if(floorChange(CHANGE_WEST)) _pos.x--; if(floorChange(CHANGE_NORTH_EX)) _pos.y -= 2; if(floorChange(CHANGE_SOUTH_EX)) _pos.y += 2; if(floorChange(CHANGE_EAST_EX)) _pos.x += 2; if(floorChange(CHANGE_WEST_EX)) _pos.x -= 2; destTile = g_game.getTile(_pos); if(Creature* creature = (Creature*) thing->getCreature()){ CreatureEventList moveEvents = creature->getCreatureEvents(CREATURE_EVENT_MOVE); for(CreatureEventList::iterator it = moveEvents.begin(); it != moveEvents.end(); ++it) (*it)->executeMove(creature, creature->getPosition(), _pos); } } if(!destTile) destTile = this; else flags |= FLAG_NOLIMIT; //will ignore that there is blocking items/creatures if(destTile) { Thing* destThing = destTile->getTopDownItem(); if(destThing && !destThing->isRemoved()) *destItem = destThing->getItem(); } return destTile; }
ReturnValue Combat::canDoCombat(const CreatureP& attacker, const CreatureP& target) { if(!attacker) return RET_NOERROR; if (!attacker->isAlive() || !target->isAlive()) { return RET_NOTPOSSIBLE; } bool success = true; CreatureEventList combatEvents = attacker->getCreatureEvents(CREATURE_EVENT_COMBAT); for(CreatureEventList::iterator it = combatEvents.begin(); it != combatEvents.end(); ++it) { if(!(*it)->executeCombat(attacker, target) && success) success = false; } if(!success) return RET_NOTPOSSIBLE; if (!attacker->isAlive() || !target->isAlive()) { return RET_NOTPOSSIBLE; } const Monster* attackerMonster = attacker->getMonster(); bool checkZones = false; if(const Player* targetPlayer = target->getPlayer()) { if(!targetPlayer->isAttackable()) return RET_YOUMAYNOTATTACKTHISPLAYER; const Player* attackerPlayer = nullptr; if((attackerPlayer = attacker->getPlayer()) || (attackerMonster != nullptr && attackerMonster->getMaster() && (attackerPlayer = attackerMonster->getMaster()->getPlayer()))) { checkZones = true; if((server.game().getWorldType() == WORLD_TYPE_NO_PVP && !Combat::isInPvpZone(*attacker, *target)) || isProtected(const_cast<Player*>(attackerPlayer), const_cast<Player*>(targetPlayer)) || (server.configManager().getBool(ConfigManager::CANNOT_ATTACK_SAME_LOOKFEET) && attackerPlayer->getDefaultOutfit().lookFeet == targetPlayer->getDefaultOutfit().lookFeet) || !attackerPlayer->canSeeCreature(*targetPlayer)) return RET_YOUMAYNOTATTACKTHISPLAYER; } } else if(const Monster* targetMonster = target->getMonster()) { if(!target->isAttackable()) return RET_YOUMAYNOTATTACKTHISCREATURE; if (attackerMonster != nullptr && !attackerMonster->hasController() && !targetMonster->hasController()) { return RET_YOUMAYNOTATTACKTHISCREATURE; } const Player* attackerPlayer = nullptr; if((attackerPlayer = attacker->getPlayer()) || (attackerMonster != nullptr && attackerMonster->getMaster() && (attackerPlayer = attackerMonster->getMaster()->getPlayer()))) { if(attackerPlayer->hasFlag(PlayerFlag_CannotAttackMonster)) return RET_YOUMAYNOTATTACKTHISCREATURE; const Monster* targetMonster = target->getMonster(); if(targetMonster != nullptr && targetMonster->getMaster() && targetMonster->getMaster()->getPlayer()) { checkZones = true; if(server.game().getWorldType() == WORLD_TYPE_NO_PVP && !Combat::isInPvpZone(*attacker, *target)) return RET_YOUMAYNOTATTACKTHISCREATURE; } } } return checkZones && (target->getTile()->hasFlag(TILESTATE_NOPVPZONE) || (attacker->getTile()->hasFlag(TILESTATE_NOPVPZONE) && !target->getTile()->hasFlag(TILESTATE_NOPVPZONE) && !target->getTile()->hasFlag(TILESTATE_PROTECTIONZONE))) ? RET_ACTIONNOTPERMITTEDINANOPVPZONE : RET_NOERROR; }
bool Creature::onDeath() { DeathList deathList = getKillers(); bool deny = false; CreatureEventList prepareDeathEvents = getCreatureEvents(CREATURE_EVENT_PREPAREDEATH); for(CreatureEventList::iterator it = prepareDeathEvents.begin(); it != prepareDeathEvents.end(); ++it) { if(!(*it)->executePrepareDeath(this, deathList) && !deny) deny = true; } if(deny) return false; int32_t i = 0, size = deathList.size(), limit = g_config.getNumber(ConfigManager::DEATH_ASSISTS) + 1; if(limit > 0 && size > limit) size = limit; Creature* tmp = NULL; CreatureVector justifyVec; for(DeathList::iterator it = deathList.begin(); it != deathList.end(); ++it, ++i) { if(it->isNameKill()) continue; if(it == deathList.begin()) it->setLast(); if(i < size) { if(it->getKillerCreature()->getPlayer()) tmp = it->getKillerCreature(); else if(it->getKillerCreature()->getPlayerMaster()) tmp = it->getKillerCreature()->getMaster(); } if(tmp) { if(std::find(justifyVec.begin(), justifyVec.end(), tmp) == justifyVec.end()) { it->setJustify(); justifyVec.push_back(tmp); } tmp = NULL; } if(!it->getKillerCreature()->onKilledCreature(this, (*it)) && it->isLast()) return false; } for(CountMap::iterator it = damageMap.begin(); it != damageMap.end(); ++it) { if((tmp = g_game.getCreatureByID(it->first))) tmp->onTargetKilled(this); } dropCorpse(deathList); if(master) master->removeSummon(this); return true; }
ReturnValue Combat::canDoCombat(const Creature* attacker, const Creature* target, bool isAggressive) { if(!attacker) return RET_NOERROR; bool success = true; CreatureEventList combatEvents = const_cast<Creature*>(attacker)->getCreatureEvents(CREATURE_EVENT_COMBAT); for(CreatureEventList::iterator it = combatEvents.begin(); it != combatEvents.end(); ++it) { if(!(*it)->executeCombat(const_cast<Creature*>(attacker), const_cast<Creature*>(target), isAggressive) && success) success = false; } if(!success) return RET_NOTPOSSIBLE; bool checkZones = false; if(const Player* targetPlayer = target->getPlayer()) { if(!targetPlayer->isAttackable()) return RET_YOUMAYNOTATTACKTHISPLAYER; const Player* attackerPlayer = NULL; if((attackerPlayer = attacker->getPlayer()) || (attackerPlayer = attacker->getPlayerMaster())) { checkZones = true; if((g_game.getWorldType() == WORLDTYPE_OPTIONAL && !Combat::isInPvpZone(attacker, target) && !attackerPlayer->isEnemy(targetPlayer)) || isProtected(const_cast<Player*>(attackerPlayer), const_cast<Player*>(targetPlayer)) || (g_config.getBool(ConfigManager::CANNOT_ATTACK_SAME_LOOKFEET) && attackerPlayer->getDefaultOutfit().lookFeet == targetPlayer->getDefaultOutfit().lookFeet) || !attackerPlayer->canSeeCreature(targetPlayer)) return RET_YOUMAYNOTATTACKTHISPLAYER; } } else if(target->getMonster()) { if(!target->isAttackable()) return RET_YOUMAYNOTATTACKTHISCREATURE; const Player* attackerPlayer = NULL; if((attackerPlayer = attacker->getPlayer()) || (attackerPlayer = attacker->getPlayerMaster())) { if(attackerPlayer->hasFlag(PlayerFlag_CannotAttackMonster)) return RET_YOUMAYNOTATTACKTHISCREATURE; if(target->isPlayerSummon()) { checkZones = true; if(g_game.getWorldType() == WORLDTYPE_OPTIONAL && !Combat::isInPvpZone(attacker, target) && !attackerPlayer->isEnemy(target->getPlayerMaster())) return RET_YOUMAYNOTATTACKTHISCREATURE; } } } else if(target->getNpc() && !target->isAttackable()) return RET_YOUMAYNOTATTACKTHISCREATURE; return checkZones && (target->getTile()->hasFlag(TILESTATE_OPTIONALZONE) || (attacker->getTile()->hasFlag(TILESTATE_OPTIONALZONE) && !target->getTile()->hasFlag(TILESTATE_OPTIONALZONE) && !target->getTile()->hasFlag(TILESTATE_PROTECTIONZONE))) ? RET_ACTIONNOTPERMITTEDINANOPVPZONE : RET_NOERROR; }