void Commands::newItem(Player* player, const std::string& cmd, const std::string& param) { int32_t itemId = atoi(param.c_str()); for (uint32_t i = 0; i < param.length(); i++) { if (!isNumber(param[i])) { itemId = Item::items.getItemIdByName(param); break; } } if (itemId <= 0) { return; } const ItemType& it = Item::items[itemId]; if (it.id == 0) { return; } Outfit_t outfit; outfit.lookTypeEx = itemId; ConditionOutfit* outfitCondition = new ConditionOutfit(CONDITIONID_COMBAT, CONDITION_OUTFIT, -1); outfitCondition->addOutfit(outfit); player->addCondition(outfitCondition); }
bool Monsters::deserializeSpell(const pugi::xml_node& node, spellBlock_t& sb, const std::string& description) { std::string name; std::string scriptName; bool isScripted; pugi::xml_attribute attr; if ((attr = node.attribute("script"))) { scriptName = attr.as_string(); isScripted = true; } else if ((attr = node.attribute("name"))) { name = attr.as_string(); isScripted = false; } else { return false; } if ((attr = node.attribute("speed")) || (attr = node.attribute("interval"))) { sb.speed = std::max<int32_t>(1, pugi::cast<int32_t>(attr.value())); } if ((attr = node.attribute("chance"))) { uint32_t chance = pugi::cast<uint32_t>(attr.value()); if (chance > 100) { chance = 100; } sb.chance = chance; } if ((attr = node.attribute("range"))) { uint32_t range = pugi::cast<uint32_t>(attr.value()); if (range > (Map::maxViewportX * 2)) { range = Map::maxViewportX * 2; } sb.range = range; } if ((attr = node.attribute("min"))) { sb.minCombatValue = pugi::cast<int32_t>(attr.value()); } if ((attr = node.attribute("max"))) { sb.maxCombatValue = pugi::cast<int32_t>(attr.value()); //normalize values if (std::abs(sb.minCombatValue) > std::abs(sb.maxCombatValue)) { int32_t value = sb.maxCombatValue; sb.maxCombatValue = sb.minCombatValue; sb.minCombatValue = value; } } if (auto spell = g_spells->getSpellByName(name)) { sb.spell = spell; return true; } CombatSpell* combatSpell = nullptr; bool needTarget = false; bool needDirection = false; if (isScripted) { if ((attr = node.attribute("direction"))) { needDirection = attr.as_bool(); } if ((attr = node.attribute("target"))) { needTarget = attr.as_bool(); } std::unique_ptr<CombatSpell> combatSpellPtr(new CombatSpell(nullptr, needTarget, needDirection)); if (!combatSpellPtr->loadScript("data/" + g_spells->getScriptBaseName() + "/scripts/" + scriptName)) { return false; } if (!combatSpellPtr->loadScriptCombat()) { return false; } combatSpell = combatSpellPtr.release(); combatSpell->getCombat()->setPlayerCombatValues(COMBAT_FORMULA_DAMAGE, sb.minCombatValue, 0, sb.maxCombatValue, 0); } else { Combat* combat = new Combat; if ((attr = node.attribute("length"))) { int32_t length = pugi::cast<int32_t>(attr.value()); if (length > 0) { int32_t spread = 3; //need direction spell if ((attr = node.attribute("spread"))) { spread = std::max<int32_t>(0, pugi::cast<int32_t>(attr.value())); } AreaCombat* area = new AreaCombat(); area->setupArea(length, spread); combat->setArea(area); needDirection = true; } } if ((attr = node.attribute("radius"))) { int32_t radius = pugi::cast<int32_t>(attr.value()); //target spell if ((attr = node.attribute("target"))) { needTarget = attr.as_bool(); } AreaCombat* area = new AreaCombat(); area->setupArea(radius); combat->setArea(area); } std::string tmpName = asLowerCaseString(name); if (tmpName == "melee") { sb.isMelee = true; pugi::xml_attribute attackAttribute, skillAttribute; if ((attackAttribute = node.attribute("attack")) && (skillAttribute = node.attribute("skill"))) { sb.minCombatValue = 0; sb.maxCombatValue = -Weapons::getMaxMeleeDamage(pugi::cast<int32_t>(skillAttribute.value()), pugi::cast<int32_t>(attackAttribute.value())); } ConditionType_t conditionType = CONDITION_NONE; int32_t minDamage = 0; int32_t maxDamage = 0; uint32_t tickInterval = 2000; if ((attr = node.attribute("fire"))) { conditionType = CONDITION_FIRE; minDamage = pugi::cast<int32_t>(attr.value()); maxDamage = minDamage; tickInterval = 9000; } else if ((attr = node.attribute("poison"))) { conditionType = CONDITION_POISON; minDamage = pugi::cast<int32_t>(attr.value()); maxDamage = minDamage; tickInterval = 5000; } else if ((attr = node.attribute("energy"))) { conditionType = CONDITION_ENERGY; minDamage = pugi::cast<int32_t>(attr.value()); maxDamage = minDamage; tickInterval = 10000; } else if ((attr = node.attribute("drown"))) { conditionType = CONDITION_DROWN; minDamage = pugi::cast<int32_t>(attr.value()); maxDamage = minDamage; tickInterval = 5000; } else if ((attr = node.attribute("freeze"))) { conditionType = CONDITION_FREEZING; minDamage = pugi::cast<int32_t>(attr.value()); maxDamage = minDamage; tickInterval = 8000; } else if ((attr = node.attribute("dazzle"))) { conditionType = CONDITION_DAZZLED; minDamage = pugi::cast<int32_t>(attr.value()); maxDamage = minDamage; tickInterval = 10000; } else if ((attr = node.attribute("curse"))) { conditionType = CONDITION_CURSED; minDamage = pugi::cast<int32_t>(attr.value()); maxDamage = minDamage; tickInterval = 4000; } else if ((attr = node.attribute("bleed")) || (attr = node.attribute("physical"))) { conditionType = CONDITION_BLEEDING; tickInterval = 5000; } if ((attr = node.attribute("tick"))) { int32_t value = pugi::cast<int32_t>(attr.value()); if (value > 0) { tickInterval = value; } } if (conditionType != CONDITION_NONE) { Condition* condition = getDamageCondition(conditionType, maxDamage, minDamage, 0, tickInterval); combat->setCondition(condition); } sb.range = 1; combat->setParam(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE); combat->setParam(COMBAT_PARAM_BLOCKARMOR, 1); combat->setParam(COMBAT_PARAM_BLOCKSHIELD, 1); combat->setOrigin(ORIGIN_MELEE); } else if (tmpName == "physical") { combat->setParam(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE); combat->setParam(COMBAT_PARAM_BLOCKARMOR, 1); combat->setOrigin(ORIGIN_RANGED); } else if (tmpName == "bleed") { combat->setParam(COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE); } else if (tmpName == "poison" || tmpName == "earth") { combat->setParam(COMBAT_PARAM_TYPE, COMBAT_EARTHDAMAGE); } else if (tmpName == "fire") { combat->setParam(COMBAT_PARAM_TYPE, COMBAT_FIREDAMAGE); } else if (tmpName == "energy") { combat->setParam(COMBAT_PARAM_TYPE, COMBAT_ENERGYDAMAGE); } else if (tmpName == "drown") { combat->setParam(COMBAT_PARAM_TYPE, COMBAT_DROWNDAMAGE); } else if (tmpName == "ice") { combat->setParam(COMBAT_PARAM_TYPE, COMBAT_ICEDAMAGE); } else if (tmpName == "holy") { combat->setParam(COMBAT_PARAM_TYPE, COMBAT_HOLYDAMAGE); } else if (tmpName == "death") { combat->setParam(COMBAT_PARAM_TYPE, COMBAT_DEATHDAMAGE); } else if (tmpName == "lifedrain") { combat->setParam(COMBAT_PARAM_TYPE, COMBAT_LIFEDRAIN); } else if (tmpName == "manadrain") { combat->setParam(COMBAT_PARAM_TYPE, COMBAT_MANADRAIN); } else if (tmpName == "healing") { combat->setParam(COMBAT_PARAM_TYPE, COMBAT_HEALING); combat->setParam(COMBAT_PARAM_AGGRESSIVE, 0); } else if (tmpName == "speed") { int32_t speedChange = 0; int32_t duration = 10000; if ((attr = node.attribute("duration"))) { duration = pugi::cast<int32_t>(attr.value()); } if ((attr = node.attribute("speedchange"))) { speedChange = pugi::cast<int32_t>(attr.value()); if (speedChange < -1000) { //cant be slower than 100% speedChange = -1000; } } ConditionType_t conditionType; if (speedChange > 0) { conditionType = CONDITION_HASTE; combat->setParam(COMBAT_PARAM_AGGRESSIVE, 0); } else { conditionType = CONDITION_PARALYZE; } ConditionSpeed* condition = static_cast<ConditionSpeed*>(Condition::createCondition(CONDITIONID_COMBAT, conditionType, duration, 0)); condition->setFormulaVars(speedChange / 1000.0, 0, speedChange / 1000.0, 0); combat->setCondition(condition); } else if (tmpName == "outfit") { int32_t duration = 10000; if ((attr = node.attribute("duration"))) { duration = pugi::cast<int32_t>(attr.value()); } if ((attr = node.attribute("monster"))) { MonsterType* mType = g_monsters.getMonsterType(attr.as_string()); if (mType) { ConditionOutfit* condition = static_cast<ConditionOutfit*>(Condition::createCondition(CONDITIONID_COMBAT, CONDITION_OUTFIT, duration, 0)); condition->setOutfit(mType->outfit); combat->setParam(COMBAT_PARAM_AGGRESSIVE, 0); combat->setCondition(condition); } } else if ((attr = node.attribute("item"))) { Outfit_t outfit; outfit.lookTypeEx = pugi::cast<uint16_t>(attr.value()); ConditionOutfit* condition = static_cast<ConditionOutfit*>(Condition::createCondition(CONDITIONID_COMBAT, CONDITION_OUTFIT, duration, 0)); condition->setOutfit(outfit); combat->setParam(COMBAT_PARAM_AGGRESSIVE, 0); combat->setCondition(condition); } } else if (tmpName == "invisible") { int32_t duration = 10000; if ((attr = node.attribute("duration"))) { duration = pugi::cast<int32_t>(attr.value()); } Condition* condition = Condition::createCondition(CONDITIONID_COMBAT, CONDITION_INVISIBLE, duration, 0); combat->setParam(COMBAT_PARAM_AGGRESSIVE, 0); combat->setCondition(condition); } else if (tmpName == "drunk") { int32_t duration = 10000; if ((attr = node.attribute("duration"))) { duration = pugi::cast<int32_t>(attr.value()); } Condition* condition = Condition::createCondition(CONDITIONID_COMBAT, CONDITION_DRUNK, duration, 0); combat->setCondition(condition); } else if (tmpName == "firefield") { combat->setParam(COMBAT_PARAM_CREATEITEM, ITEM_FIREFIELD_PVP_FULL); } else if (tmpName == "poisonfield") { combat->setParam(COMBAT_PARAM_CREATEITEM, ITEM_POISONFIELD_PVP); } else if (tmpName == "energyfield") { combat->setParam(COMBAT_PARAM_CREATEITEM, ITEM_ENERGYFIELD_PVP); } else if (tmpName == "firecondition" || tmpName == "energycondition" || tmpName == "earthcondition" || tmpName == "poisoncondition" || tmpName == "icecondition" || tmpName == "freezecondition" || tmpName == "deathcondition" || tmpName == "cursecondition" || tmpName == "holycondition" || tmpName == "dazzlecondition" || tmpName == "drowncondition" || tmpName == "bleedcondition" || tmpName == "physicalcondition") { ConditionType_t conditionType = CONDITION_NONE; uint32_t tickInterval = 2000; if (tmpName == "firecondition") { conditionType = CONDITION_FIRE; tickInterval = 10000; } else if (tmpName == "poisoncondition" || tmpName == "earthcondition") { conditionType = CONDITION_POISON; tickInterval = 5000; } else if (tmpName == "energycondition") { conditionType = CONDITION_ENERGY; tickInterval = 10000; } else if (tmpName == "drowncondition") { conditionType = CONDITION_DROWN; tickInterval = 5000; } else if (tmpName == "freezecondition" || tmpName == "icecondition") { conditionType = CONDITION_FREEZING; tickInterval = 10000; } else if (tmpName == "cursecondition" || tmpName == "deathcondition") { conditionType = CONDITION_CURSED; tickInterval = 4000; } else if (tmpName == "dazzlecondition" || tmpName == "holycondition") { conditionType = CONDITION_DAZZLED; tickInterval = 10000; } else if (tmpName == "physicalcondition" || tmpName == "bleedcondition") { conditionType = CONDITION_BLEEDING; tickInterval = 5000; } if ((attr = node.attribute("tick"))) { int32_t value = pugi::cast<int32_t>(attr.value()); if (value > 0) { tickInterval = value; } } int32_t minDamage = std::abs(sb.minCombatValue); int32_t maxDamage = std::abs(sb.maxCombatValue); int32_t startDamage = 0; if ((attr = node.attribute("start"))) { int32_t value = std::abs(pugi::cast<int32_t>(attr.value())); if (value <= minDamage) { startDamage = value; } } Condition* condition = getDamageCondition(conditionType, maxDamage, minDamage, startDamage, tickInterval); combat->setCondition(condition); } else if (tmpName == "strength") { // } else if (tmpName == "effect") { // } else { std::cout << "[Error - Monsters::deserializeSpell] - " << description << " - Unknown spell name: " << name << std::endl; delete combat; return false; } combat->setPlayerCombatValues(COMBAT_FORMULA_DAMAGE, sb.minCombatValue, 0, sb.maxCombatValue, 0); combatSpell = new CombatSpell(combat, needTarget, needDirection); for (auto attributeNode : node.children()) { if ((attr = attributeNode.attribute("key"))) { const char* value = attr.value(); if (strcasecmp(value, "shooteffect") == 0) { if ((attr = attributeNode.attribute("value"))) { ShootType_t shoot = getShootType(attr.as_string()); if (shoot != CONST_ANI_NONE) { combat->setParam(COMBAT_PARAM_DISTANCEEFFECT, shoot); } else { std::cout << "[Warning - Monsters::deserializeSpell] " << description << " - Unknown shootEffect: " << attr.as_string() << std::endl; } } } else if (strcasecmp(value, "areaeffect") == 0) { if ((attr = attributeNode.attribute("value"))) { MagicEffectClasses effect = getMagicEffect(attr.as_string()); if (effect != CONST_ME_NONE) { combat->setParam(COMBAT_PARAM_EFFECT, effect); } else { std::cout << "[Warning - Monsters::deserializeSpell] " << description << " - Unknown areaEffect: " << attr.as_string() << std::endl; } } } else { std::cout << "[Warning - Monsters::deserializeSpells] Effect type \"" << attr.as_string() << "\" does not exist." << std::endl; } } } } sb.spell = combatSpell; if (combatSpell) { sb.combatSpell = true; } return true; }