diff --git a/.gitattributes b/.gitattributes index 0966454ca4..cd05f7536c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,6 @@ * text=auto -*.c diff=cpp +*.cpp diff=cpp +*.yml diff *.sln merge=union *.vcproj merge=union *.vcxproj merge=union diff --git a/conf/battle/feature.conf b/conf/battle/feature.conf index c1917fe092..2747fe5380 100644 --- a/conf/battle/feature.conf +++ b/conf/battle/feature.conf @@ -71,6 +71,18 @@ feature.achievement: on // Requires: 2017-02-08bRagexeRE or later feature.equipswitch: on +// Pet evolution (Note 1) +// Requires: 2014-10-08aRagexe or later +feature.petevolution: on + +// Automatic Pet Feeding (Note 1) +// Requires: 2014-10-08aRagexe or later +feature.petautofeed: on + +// At which hunger rate should pet autofeeding trigger? (Note 2) +// Default: 89 +feature.pet_autofeed_rate: 89 + // Homunculues Autofeeding (Note 1) // Requires: 2017-09-20bRagexeRE or later feature.homunculus_autofeed: on diff --git a/conf/battle/pet.conf b/conf/battle/pet.conf index d61e56496b..4b048163b3 100644 --- a/conf/battle/pet.conf +++ b/conf/battle/pet.conf @@ -21,10 +21,6 @@ pet_friendly_rate: 100 // The rate at which a pet will become hungry. (Note 2) pet_hungry_delay_rate: 100 -// If your pet is hungry by how much will the friendlyness decrease by. (Default is 5) -// Note: The friendlyness is 0-1000 total, at 0 the pet runs away. -pet_hungry_friendly_decrease: 5 - // Does the pet need its equipment before it does its skill? (Note 1) pet_equip_required: yes @@ -39,9 +35,6 @@ pet_damage_support: no // At max (1000) support rate is 150%. pet_support_min_friendly: 900 -// Same as above, but this is to use the pet_script field with official pet abilities. -pet_equip_min_friendly: 900 - // Whether or not the pet's will use skills. (Note 1) // Note: Offensive pet skills need at least pet_attack_support or // pet_damage_support to work (they trigger while the pet is attacking). @@ -81,3 +74,7 @@ pet_ignore_infinite_def: yes // Whether or not the pet will continue to attack when the master is dead. (Note 1) pet_master_dead: no + +// Send auto-feed notice even if the client setting is OFF (Note 1) +// Official: yes +pet_autofeed_always: yes diff --git a/conf/msg_conf/map_msg.conf b/conf/msg_conf/map_msg.conf index e6b5386769..61958cca28 100644 --- a/conf/msg_conf/map_msg.conf +++ b/conf/msg_conf/map_msg.conf @@ -458,8 +458,7 @@ // Homunculus messages 450: You already have a homunculus -// Return pet to egg message -451: You can't return your pet because your inventory is full. +//451 free // Message System 460: Please enter a valid language (usage: @langtype ). diff --git a/conf/msg_conf/map_msg_chn.conf b/conf/msg_conf/map_msg_chn.conf index ccb19d70d2..d164f75c7a 100644 --- a/conf/msg_conf/map_msg_chn.conf +++ b/conf/msg_conf/map_msg_chn.conf @@ -441,8 +441,7 @@ // Homunculus messages 450: 你已經擁有一個人工生命體了 -// Return pet to egg message -451: 你無法收回寵物,因為你身上沒有空間了 +//451 free // Message System 460: 請輸入合法的語言 (usage: @langtype ). diff --git a/conf/msg_conf/map_msg_frn.conf b/conf/msg_conf/map_msg_frn.conf index 12db0e2471..7cdf3ba158 100644 --- a/conf/msg_conf/map_msg_frn.conf +++ b/conf/msg_conf/map_msg_frn.conf @@ -449,8 +449,7 @@ // Homunculus messages 450: Vous possdez dj un homunculus -// Return pet to egg message -451: Vous ne pouvez pas remettre votre pet dans son oeuf car votre inventaire est plein. +//451 free // Message System 460: Entrez une langue (usage: @langtype ). diff --git a/conf/msg_conf/map_msg_idn.conf b/conf/msg_conf/map_msg_idn.conf index 0aa4da523b..28d0418233 100644 --- a/conf/msg_conf/map_msg_idn.conf +++ b/conf/msg_conf/map_msg_idn.conf @@ -459,8 +459,7 @@ // Pesan-pesan untuk Homunculus 450: Kamu sudah memiliki homunculus -// Pesan tentang mengembalikan peliharaan ke telur -451: Kamu tidak dapat mengembalikan peliharaan kamu karena inventory penuh. +//451 free // Sistem Pesan 460: Harap masukkan tipe bahasa yang valid. (Penggunaan: @langtype ). diff --git a/conf/msg_conf/map_msg_por.conf b/conf/msg_conf/map_msg_por.conf index c1f1cb5af8..35e1e3bda0 100644 --- a/conf/msg_conf/map_msg_por.conf +++ b/conf/msg_conf/map_msg_por.conf @@ -468,8 +468,7 @@ // Mensagens de homunculus 450: Você já possui um homunculus -// Mensagem de retorno do pet ao ovo -451: Você não pode retornar o seu bichinho de estimação para o ovo pois o seu inventário está lotado. +//451 free // Sistema de Mensagens 460: Digite um idioma válido (uso: @langtype ). diff --git a/conf/msg_conf/map_msg_rus.conf b/conf/msg_conf/map_msg_rus.conf index dfec048f6b..30d434bf5c 100644 --- a/conf/msg_conf/map_msg_rus.conf +++ b/conf/msg_conf/map_msg_rus.conf @@ -449,8 +449,7 @@ // @makehomun 450: -// -451: , . +//451 free // @langtype 460: (: @langtype <>). diff --git a/conf/msg_conf/map_msg_spn.conf b/conf/msg_conf/map_msg_spn.conf index 5c293fd624..e1438bf668 100644 --- a/conf/msg_conf/map_msg_spn.conf +++ b/conf/msg_conf/map_msg_spn.conf @@ -458,8 +458,7 @@ // Mensajes de homnculos 450: Ya tienes un homnculo. -// Mensaje al devolver la mascota al huevo -451: No puedes devolver tu mascota al huevo porque tu inventario est lleno. +//451 free // Sistema de mensajera 460: Introduce un idioma vlido (instrucciones: @langtype ) diff --git a/conf/msg_conf/map_msg_tha.conf b/conf/msg_conf/map_msg_tha.conf index 81add8329d..8f8959d96f 100644 --- a/conf/msg_conf/map_msg_tha.conf +++ b/conf/msg_conf/map_msg_tha.conf @@ -447,8 +447,7 @@ // Homunculus messages 450: س Homunculus . -// Return pet to egg message -451: سöѵ§Ъͧ红ͧ㹵Ф. +//451 free // Message System 460: ô͡ҷͧ (Ը: @langtype <>). diff --git a/db/import-tmpl/pet_db.txt b/db/import-tmpl/pet_db.txt deleted file mode 100644 index cf39171e8c..0000000000 --- a/db/import-tmpl/pet_db.txt +++ /dev/null @@ -1,60 +0,0 @@ -// Pet Additional Database -// -// Structure of Database: -// MobID,Name,JName,LureID,EggID,EquipID,FoodID,Fullness,HungryDelay,R_Hungry,R_Full,Intimate,Die,Capture,Speed,S_Performance,talk_convert_class,attack_rate,defence_attack_rate,change_target_rate,pet_script,loyal_script -// -// 01. MobID Monster ID of the pet. -// 02. Name Name of the monster as defined in the database. -// 03. JName The display name of the monster when hatched. -// 04. LureID Pet Tame Item ID. -// 05. EggID Pet Egg ID. -// 06. EquipID Pet Accessory ID. -// 07. FoodID Pet Food ID. -// 08. Fullness The amount Hunger is decreased every [HungryDelay] seconds. -// 09. HungryDelay The amount of time it takes for hunger to decrease after feeding. (Default: 60 seconds) -// 10. R_Hungry Amount of Intimacy that is increased when fed. -// 11. R_Full Amount of Intimacy that is decreased when over-fed. -// 12. Intimate Amount of Intimacy the pet starts with. -// 13. Die Amount of Intimacy that is decreased when the pet owner dies. -// 14. Capture Capture succes rate (10000 = 100%) -// 15. Speed Pet's walk speed. (Defaul: 150) -// 16. S_Performance Special Performance. (Yes = 1, No = 0) -// 17. talk_convert_class Disables pet talk (instead of talking they emote with /!.) -// 18. attack_rate Rate of which the pet will attack (requires at least pet_support_min_friendly intimacy). -// 19. defence_attack_rate Rate of which the pet will retaliate when master is being attacked (requires at least pet_support_min_friendly intimacy). -// 20. change_target_rate Rate of which the pet will change its attack target. -// 21. pet_script Script to execute when the pet is hatched. -// 22. loyal_script Script to execute when the pet is hatched (requires at least pet_equip_min_friendly intimacy, independent of pet_script). -//NOTE: The max value (100%) of attack_rate, defense_rate & change_target_rate is 10000. - -//In theory you can use any valid script, but it is run only once upon pet -//loading, so it is recommended you use the specific pet scripts: - -//petskillattack skillid, skilllv, rate, bonusrate -//Skill attack that triggers while the pet is attacking. Rate is the base -//chance of execution per attack. Bonusrate is an additional success rate when -//intimacy reaches max. - -//petskillattack2 skillid, damage, hits, rate, bonusrate -//Same as petskillattack, but the damage and number of hits is fixed -//the damage specified is total, not per hit. - -//petskillsupport skillid, skilllv, delay, hp%, sp% -//Casts a support skill when the health levels are below the specified hp% and -//sp%. Delay is the minimum time in seconds before the skill can be cast again - -//petheal amount, delay, hp%, sp% -//Similar to petskillsupport, but the skill is fixed to heal (28) and the -//heal-amount is fixed to the value given. - -//petrecovery type, delay: Cures the "type" status effect after "delay" seconds - -//petskillbonus type, value, duration, delay -//Gives bonus stats. Type is the stat to increase (bStr, bLuk), value is the -//amount by which it is increased, duration signals how long the bonus lasts -//delay is the time elapsed after the bonus ends and before it starts again. - -//A single pet can have petloot, petskillbonus, petskillattack (or -//petskillattack2) and petskillsupport (or petheal) at the same time, -//but only one of each. - diff --git a/db/import-tmpl/pet_db.yml b/db/import-tmpl/pet_db.yml new file mode 100644 index 0000000000..cb433628e5 --- /dev/null +++ b/db/import-tmpl/pet_db.yml @@ -0,0 +1,486 @@ +# This file is a part of rAthena. +# Copyright(C) 2019 rAthena Development Team +# https://rathena.org - https://github.com/rathena +# +# 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 3 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, see . +# +########################################################################### +# Custom Pet Database +########################################################################### +# +# Pet Settings +# +########################################################################### +# - Mob Monster that can be used as pet +# TameItem Pet Tame Item. +# EggItem Pet Egg Item. +# EquipItem Pet Accessory Item. (Default: 0) +# FoodItem Pet Food Item. (Default: 0) +# Fullness The amount of hunger is decreased every [HungryDelay] seconds. +# HungryDelay The amount of time in seconds it takes for hunger to decrease after feeding. (Default: 60) +# HungerIncrease The amount of hunger that is increased every time the pet is fed (Default: 20) +# IntimacyStart Amount of Intimacy the pet starts with. (Default: 250) +# IntimacyFed Amount of Intimacy that is increased when fed. (Default: 50) +# IntimacyOverfed Amount of Intimacy that is increased when over-fed. (Default: -100) +# IntimacyHungry Amount of Intimacy that is increased when the pet is hungry. (Default: -5) +# IntimacyOwnerDie Amount of Intimacy that is increased when the pet owner dies. (Default: -20) +# CaptureRate Capture success rate. (10000 = 100%) +# SpecialPerformance If a pet has a Special Performance. (Default: true) +# AttackRate Rate of which the pet will attack [requires at least pet_support_min_friendly intimacy]. (10000 = 100%) +# RetaliateRate Rate of which the pet will retaliate when master is being attacked [requires at least pet_support_min_friendly intimacy]. (10000 = 100%) +# ChangeTargetRate Rate of which the pet will change its attack target. (10000 = 100%) +# AllowAutoFeed Allows turning automatic pet feeding on. (Default: false) +# Script Bonus script to execute when the pet is alive. (Default: null) +# SupportScript Bonus script to execute when pet_status_support is enabled. (Default: null) +# Evolution: Pet evolution settings. (Optional) (Default: null) +# - Target Mob this pet can evolve to. +# ItemRequirements: Item requirements for evolving this pet. +# - Item Self-explanatory +# Amount +########################################################################### + +Header: + Type: PET_DB + Version: 1 + +#Body: +# - Mob: PORING +# AttackRate: 350 +# RetaliateRate: 400 +# ChangeTargetRate: 800 +# SupportScript: > +# petloot 10; +# - Mob: DROPS +# AttackRate: 300 +# RetaliateRate: 400 +# ChangeTargetRate: 500 +# SupportScript: > +# petloot 10; +# - Mob: POPORING +# AttackRate: 300 +# RetaliateRate: 500 +# ChangeTargetRate: 400 +# SupportScript: > +# petloot 15; +# - Mob: LUNATIC +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 1000 +# SupportScript: > +# petskillbonus bLuk,3,10,50; +# - Mob: PICKY +# AttackRate: 500 +# RetaliateRate: 600 +# ChangeTargetRate: 50 +# SupportScript: > +# petskillbonus bStr,3,10,50; +# - Mob: CHONCHON +# AttackRate: 500 +# RetaliateRate: 500 +# ChangeTargetRate: 250 +# SupportScript: > +# petskillbonus bAgi,4,10,50; +# - Mob: STEEL_CHONCHON +# AttackRate: 500 +# RetaliateRate: 500 +# ChangeTargetRate: 200 +# SupportScript: > +# petskillbonus bAgiVit,4,20,40; +# - Mob: HUNTER_FLY +# AttackRate: 500 +# RetaliateRate: 500 +# ChangeTargetRate: 200 +# SupportScript: > +# petskillattack2 "NPC_WINDATTACK",888,2,0,10; +# - Mob: SAVAGE_BABE +# AttackRate: 500 +# RetaliateRate: 500 +# ChangeTargetRate: 200 +# SupportScript: > +# petskillbonus bVit,4,10,50; +# - Mob: DESERT_WOLF_B +# AttackRate: 400 +# RetaliateRate: 400 +# ChangeTargetRate: 400 +# SupportScript: > +# petskillattack "SM_PROVOKE",1,0,5; +# - Mob: ROCKER +# AttackRate: 350 +# RetaliateRate: 350 +# ChangeTargetRate: 600 +# SupportScript: > +# petskillbonus bAllStats,1,10,50; +# - Mob: SPORE +# AttackRate: 350 +# RetaliateRate: 500 +# ChangeTargetRate: 500 +# SupportScript: > +# petrecovery SC_POISON,60; +# - Mob: POISON_SPORE +# AttackRate: 600 +# RetaliateRate: 200 +# ChangeTargetRate: 400 +# SupportScript: > +# petskillattack "NPC_POISON",20,0,10; +# - Mob: PECOPECO +# AttackRate: 400 +# RetaliateRate: 500 +# ChangeTargetRate: 800 +# SupportScript: > +# petskillbonus bSpeedRate,25,20,20; +# - Mob: SMOKIE +# AttackRate: 600 +# RetaliateRate: 600 +# ChangeTargetRate: 100 +# SupportScript: > +# petskillbonus bPerfectHide,1,3600,0; +# - Mob: YOYO +# AttackRate: 300 +# RetaliateRate: 800 +# ChangeTargetRate: 400 +# SupportScript: > +# petloot 20; +# - Mob: ORK_WARRIOR +# AttackRate: 600 +# RetaliateRate: 200 +# ChangeTargetRate: 300 +# SupportScript: > +# petskillattack2 "NPC_PIERCINGATT",100,1,0,10; +# - Mob: MUNAK +# AttackRate: 300 +# RetaliateRate: 750 +# ChangeTargetRate: 300 +# SupportScript: > +# petskillattack2 "NPC_DARKNESSATTACK",444,1,0,10; +# - Mob: DOKEBI +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# SupportScript: > +# petskillattack "BS_HAMMERFALL",1,0,10; +# - Mob: SOHEE +# AttackRate: 100 +# RetaliateRate: 1000 +# ChangeTargetRate: 200 +# SupportScript: > +# petskillsupport "AL_HEAL",5,60,33,100; +# - Mob: ISIS +# AttackRate: 650 +# RetaliateRate: 450 +# ChangeTargetRate: 150 +# SupportScript: > +# petskillsupport "PR_MAGNIFICAT",2,60,50,50; +# - Mob: PETIT +# AttackRate: 800 +# RetaliateRate: 400 +# ChangeTargetRate: 100 +# SupportScript: > +# petskillattack2 "WZ_HEAVENDRIVE",500,1,0,10; +# - Mob: DEVIRUCHI +# AttackRate: 800 +# RetaliateRate: 200 +# ChangeTargetRate: 100 +# SupportScript: > +# petskillbonus bAgiDexStr,6,20,40; +# - Mob: BAPHOMET_ +# AttackRate: 1000 +# RetaliateRate: 100 +# ChangeTargetRate: 200 +# SupportScript: > +# petskillattack2 "NPC_DARKNESSATTACK",1776,4,0,5; +# - Mob: BON_GUN +# AttackRate: 600 +# RetaliateRate: 200 +# ChangeTargetRate: 400 +# SupportScript: > +# petskillattack2 "NPC_DARKNESSATTACK",555,1,1,1; +# - Mob: ZHERLTHSH +# AttackRate: 1000 +# RetaliateRate: 100 +# ChangeTargetRate: 500 +# SupportScript: > +# petskillattack "AS_SONICBLOW",1,0,3; +# - Mob: ALICE +# AttackRate: 100 +# RetaliateRate: 1000 +# ChangeTargetRate: 200 +# SupportScript: > +# petskillsupport "AL_HEAL",5,60,25,100; +# - Mob: EVENT_RICECAKE +# AttackRate: 500 +# RetaliateRate: 500 +# ChangeTargetRate: 200 +# SupportScript: > +# petskillsupport "CR_DEFENDER",3,240,50,100; +# - Mob: GOBLINE_XMAS +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# SupportScript: > +# petskillattack "MG_SIGHT",5,5,5; +# - Mob: CHUNG_E +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# SupportScript: > +# petskillattack "CR_SHIELDCHARGE",5,5,5; +# - Mob: ECLIPSE_P +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# SupportScript: > +# petskillattack "TF_THROWSTONE",1,5,5; +# - Mob: GOBLIN_1 +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# SupportScript: > +# petskillattack "NPC_WINDATTACK",5,5,5; +# - Mob: GOBLIN_2 +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# SupportScript: > +# petskillattack "NPC_FIREATTACK",5,5,5; +# - Mob: GOBLIN_4 +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# SupportScript: > +# petskillattack "NPC_GROUNDATTACK",5,5,5; +# - Mob: DELETER_ +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# SupportScript: > +# petskillattack "SM_MAGNUM",5,5,5; +# - Mob: DIABOLIC +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# SupportScript: > +# petskillattack "WZ_METEOR",2,5,5; +# - Mob: WANDER_MAN +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# SupportScript: > +# petskillattack "NPC_UNDEADATTACK",5,5,5; +# - Mob: P_CHUNG_E +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# SupportScript: > +# petskillattack "CR_SHIELDCHARGE",5,5,5; +# - Mob: GOLEM +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: MARIONETTE +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: MEDUSA +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: WHISPER +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: GOBLIN_LEADER +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: SUCCUBUS +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# SupportScript: > +# bonus2 bHPDrainRate,10,5; +# - Mob: INCUBUS +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# SupportScript: > +# bonus bMaxSPRate,3; +# bonus2 bSPDrainRate,10,1; +# - Mob: NIGHTMARE_TERROR +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: SHINOBI +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: MIYABI_NINGYO +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: WICKED_NYMPH +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: STONE_SHOOTER +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: DULLAHAN +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: LOLI_RURI +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: CIVIL_SERVANT +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: LEAF_CAT +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: BACSOJIN_ +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: IMP +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: E_CRAMP +# AttackRate: 350 +# RetaliateRate: 400 +# ChangeTargetRate: 800 +# - Mob: E_HYDRA +# AttackRate: 350 +# RetaliateRate: 400 +# ChangeTargetRate: 800 +# - Mob: J_TAINI +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: XMAS_LUNATIC +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: TIKBALANG +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: MARIN +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: LITTLE_PORING +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: NINE_TAIL +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: GREMLIN +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: MUMMY +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: TEDDY_BEAR +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: MASTERING +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: METALLER +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: ANGELING +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: MOONLIGHT +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: SAVAGE +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: HIGH_ORC +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: CHOCO +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: ANCIENT_MUMMY +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: AM_MUT +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: CAT_O_NINE_TAIL +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: GRAND_PECO +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: HYEGUN +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: HODREMLIN +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: XM_TEDDY_BEAR +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: DR_EGGRING +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: DR_LUNATIC +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: LITTLE_ISIS +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: DIABOLIC2 +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: DELETER_2 +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 +# - Mob: SWEETS_DROPS +# AttackRate: 300 +# RetaliateRate: 300 +# ChangeTargetRate: 800 diff --git a/db/pet_db.yml b/db/pet_db.yml new file mode 100644 index 0000000000..e9bd33fe0e --- /dev/null +++ b/db/pet_db.yml @@ -0,0 +1,63 @@ +# This file is a part of rAthena. +# Copyright(C) 2019 rAthena Development Team +# https://rathena.org - https://github.com/rathena +# +# 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 3 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, see . +# +########################################################################### +# Pet Database +########################################################################### +# +# Pet Settings +# +########################################################################### +# - Mob Monster that can be used as pet +# TameItem Pet Tame Item. +# EggItem Pet Egg Item. +# EquipItem Pet Accessory Item. (Default: 0) +# FoodItem Pet Food Item. (Default: 0) +# Fullness The amount of hunger is decreased every [HungryDelay] seconds. +# HungryDelay The amount of time in seconds it takes for hunger to decrease after feeding. (Default: 60) +# HungerIncrease The amount of hunger that is increased every time the pet is fed (Default: 20) +# IntimacyStart Amount of Intimacy the pet starts with. (Default: 250) +# IntimacyFed Amount of Intimacy that is increased when fed. (Default: 50) +# IntimacyOverfed Amount of Intimacy that is increased when over-fed. (Default: -100) +# IntimacyHungry Amount of Intimacy that is increased when the pet is hungry. (Default: -5) +# IntimacyOwnerDie Amount of Intimacy that is increased when the pet owner dies. (Default: -20) +# CaptureRate Capture success rate. (10000 = 100%) +# SpecialPerformance If a pet has a Special Performance. (Default: true) +# AttackRate Rate of which the pet will attack [requires at least pet_support_min_friendly intimacy]. (10000 = 100%) +# RetaliateRate Rate of which the pet will retaliate when master is being attacked [requires at least pet_support_min_friendly intimacy]. (10000 = 100%) +# ChangeTargetRate Rate of which the pet will change its attack target. (10000 = 100%) +# AllowAutoFeed Allows turning automatic pet feeding on. (Default: false) +# Script Bonus script to execute when the pet is alive. (Default: null) +# SupportScript Bonus script to execute when pet_status_support is enabled. (Default: null) +# Evolution: Pet evolution settings. (Optional) (Default: null) +# - Target Mob this pet can evolve to. +# ItemRequirements: Item requirements for evolving this pet. +# - Item Self-explanatory +# Amount +########################################################################### + +Header: + Type: PET_DB + Version: 1 + +Footer: + Imports: + - Path: db/pre-re/pet_db.yml + Mode: Prerenewal + - Path: db/re/pet_db.yml + Mode: Renewal + - Path: db/import/pet_db.yml diff --git a/db/pre-re/pet_db.txt b/db/pre-re/pet_db.txt deleted file mode 100644 index 5427676068..0000000000 --- a/db/pre-re/pet_db.txt +++ /dev/null @@ -1,104 +0,0 @@ -// Pet Database -// -// Structure of Database: -// MobID,Name,JName,LureID,EggID,EquipID,FoodID,Fullness,HungryDelay,R_Hungry,R_Full,Intimate,Die,Capture,Speed,S_Performance,talk_convert_class,attack_rate,defence_attack_rate,change_target_rate,pet_script,loyal_script -// -// 01. MobID Monster ID of the pet. -// 02. Name Name of the monster as defined in the database. -// 03. JName The display name of the monster when hatched. -// 04. LureID Pet Tame Item ID. -// 05. EggID Pet Egg ID. -// 06. EquipID Pet Accessory ID. -// 07. FoodID Pet Food ID. -// 08. Fullness The amount Hunger is decreased every [HungryDelay] seconds. -// 09. HungryDelay The amount of time it takes for hunger to decrease after feeding. (Default: 60 seconds) -// 10. R_Hungry Amount of Intimacy that is increased when fed. -// 11. R_Full Amount of Intimacy that is decreased when over-fed. -// 12. Intimate Amount of Intimacy the pet starts with. -// 13. Die Amount of Intimacy that is decreased when the pet owner dies. -// 14. Capture Capture succes rate (10000 = 100%) -// 15. Speed Pet's walk speed. (Defaul: 150) -// 16. S_Performance Special Performance. (Yes = 1, No = 0) -// 17. talk_convert_class Disables pet talk (instead of talking they emote with /!.) -// 18. attack_rate Rate of which the pet will attack (requires at least pet_support_min_friendly intimacy). -// 19. defence_attack_rate Rate of which the pet will retaliate when master is being attacked (requires at least pet_support_min_friendly intimacy). -// 20. change_target_rate Rate of which the pet will change its attack target. -// 21. pet_script Script to execute when the pet is hatched. -// 22. loyal_script Script to execute when the pet is hatched (requires at least pet_equip_min_friendly intimacy, independent of pet_script). -//NOTE: The max value (100%) of attack_rate, defense_rate & change_target_rate is 10000. - -//In theory you can use any valid script, but it is run only once upon pet -//loading, so it is recommended you use the specific pet scripts. -//Please see "The Pet AI commands" in 'doc/script_commands.txt'. - -1002,PORING,Poring,619,9001,10013,531,80,60,50,100,250,20,2000,150,1,0,350,400,800,{ petloot 10; },{ bonus bLuk,2; bonus bCritical,1; } -1113,DROPS,Drops,620,9002,10013,508,80,60,40,100,250,20,1500,150,1,0,300,400,500,{ petloot 10; },{ bonus bHit,3; bonus bAtk,3; } -1031,POPORING,Poporing,621,9003,10013,511,80,60,30,100,250,20,1000,150,1,0,300,500,400,{ petloot 15; },{ bonus bLuk,2; bonus2 bSubEle,Ele_Poison,10; } -1063,LUNATIC,Lunatic,622,9004,10007,534,80,60,40,100,250,20,1500,150,0,0,300,300,1000,{ petskillbonus bLuk,3,10,50; },{ bonus bCritical,2; bonus bAtk,2; } -1049,PICKY,Picky,623,9005,10012,507,80,60,40,100,250,20,2000,150,1,0,500,600,50,{ petskillbonus bStr,3,10,50;},{ bonus bStr,1; bonus bAtk,5; } -1011,CHONCHON,ChonChon,624,9006,10002,537,80,60,30,100,250,20,1500,150,1,0,500,500,250,{ petskillbonus bAgi,4,10,50; },{ bonus bAgi,1; bonus bFlee,2; } -1042,STEEL_CHONCHON,Steel ChonChon,625,9007,10002,1002,80,60,20,100,250,20,1000,150,1,0,500,500,200,{ petskillbonus bAgiVit,4,20,40; },{ bonus bFlee,6; bonus bAgi,-1; } -1035,HUNTER_FLY,Hunter Fly,626,9008,10002,716,80,60,10,100,250,20,500,150,1,0,500,500,200,{ petskillattack2 "NPC_WINDATTACK",888,2,0,10; },{ bonus bFlee,-5; bonus bFlee2,2; } -1167,SAVAGE_BABE,Savage Babe,627,9009,10015,537,80,60,40,100,250,20,1500,150,0,0,500,500,200,{ petskillbonus bVit,4,10,50; },{ bonus bVit,1; bonus bMaxHP,50; } -1107,DESERT_WOLF_B,Baby Desert Wolf,628,9010,10003,537,80,60,40,100,250,20,1000,150,0,0,400,400,400,{ petskillattack "SM_PROVOKE",1,0,5;},{ bonus bInt,1; bonus bMaxSP,50; } -1052,ROCKER,Rocker,629,9011,10014,537,80,60,30,100,250,20,1500,150,0,0,350,350,600,{ petskillbonus bAllStats,1,10,50; },{ bonus bHPrecovRate,5; bonus bMaxHP,25; } -1014,SPORE,Spore,630,9012,10017,537,80,60,30,100,250,20,1500,150,0,0,350,500,500,{ petrecovery SC_POISON,60; },{ bonus bHit,5; bonus bAtk,-2; } -1077,POISON_SPORE,Poison Spore,631,9013,10017,537,80,60,20,100,250,20,1000,150,0,0,600,200,400,{ petskillattack "NPC_POISON",20,0,10; },{ bonus bStr,1; bonus bInt,1; } -1019,PECOPECO,PecoPeco,632,9014,10010,537,80,60,30,100,250,20,1000,150,1,0,400,500,800,{ petskillbonus bSpeedRate,25,20,20; },{ bonus bMaxHP,150; bonus bMaxSP,-10; } -1056,SMOKIE,Smokie,633,9015,10019,537,80,60,30,100,250,20,1000,150,1,0,600,600,100,{ petskillbonus bPerfectHide,1,3600,0; },{ bonus bAgi,1; bonus bFlee2,1; } -1057,YOYO,Yoyo,634,9016,10018,532,80,60,20,100,250,20,1000,150,1,0,300,800,400,{ petloot 20; },{ bonus bCritical,3; bonus bLuk,-1; } -1023,ORK_WARRIOR,Orc Warrior,635,9017,10009,537,80,60,20,100,250,20,500,150,1,0,600,200,300,{ petskillattack2 "NPC_PIERCINGATT",100,1,0,10; },{ bonus bAtk,10; bonus bDef,-3; } -1026,MUNAK,Munak,636,9018,10008,537,80,60,20,100,250,20,500,150,0,0,300,750,300,{ petskillattack2 "NPC_DARKNESSATTACK",444,1,0,10; },{ bonus bInt,1; bonus bDef,1; } -1110,DOKEBI,Dokebi,637,9019,10005,537,80,60,20,100,250,20,500,150,0,0,300,300,800,{ petskillattack "BS_HAMMERFALL",1,0,10; },{ bonus bMatkRate,1; bonus bAtkRate,-1; } -1170,SOHEE,Sohee,638,9020,10016,537,80,60,10,100,250,20,500,150,0,0,100,1000,200,{ petskillsupport "AL_HEAL",5,60,33,100; },{ bonus bStr,1; bonus bDex,1; } -1029,ISIS,Isis,639,9021,10006,537,80,60,10,100,250,20,500,150,0,0,650,450,150,{ petskillsupport "PR_MAGNIFICAT",2,60,50,50; },{ bonus bMatkRate,-1; bonus bAtkRate,1; } -1155,PETIT,Petite,640,9022,10011,537,80,60,20,100,250,20,500,150,0,0,800,400,100,{ petskillattack2 "WZ_HEAVENDRIVE",500,1,0,10; },{ bonus bDef,-2; bonus bMdef,-2; bonus bAspdRate,1; } -1109,DEVIRUCHI,Deviruchi,641,9023,10004,711,80,60,10,100,250,20,500,150,0,0,800,200,100,{ petskillbonus bAgiDexStr,6,20,40; },{ bonus bMatkRate,1; bonus bAtkRate,1; bonus bMaxHPrate,-3; bonus bMaxSPrate,-3; } -1101,BAPHOMET_,Baphomet Jr.,642,9024,10001,518,80,60,10,100,250,20,200,150,0,0,1000,100,200,{ petskillattack2 "NPC_DARKNESSATTACK",1776,4,0,5; },{ bonus bDef,1; bonus bMdef,1; bonus2 bResEff,Eff_Stun,-100; } -1188,BON_GUN,Bon Gun,659,9025,10020,537,80,60,30,100,250,20,500,150,1,0,600,200,400,{ petskillattack2 "NPC_DARKNESSATTACK",555,1,1,1; },{ bonus bVit,1; bonus2 bResEff,Eff_Stun,100; } -1200,ZHERLTHSH,Zealotus,660,9026,0,929,80,60,10,100,250,20,300,150,0,0,1000,100,500,{ petskillattack "AS_SONICBLOW",1,0,3; },{ bonus2 bAddRace,RC_Demihuman,2; bonus2 bAddRace,RC_Player,2; bonus2 bMagicAddRace,RC_DemiHuman,2; bonus2 bMagicAddRace,RC_Player,2; } -1275,ALICE,Alice,661,9027,0,504,80,60,20,100,250,20,800,150,0,0,100,1000,200,{ petskillsupport "AL_HEAL",5,60,25,100; },{ bonus bMdef,1; bonus2 bSubRace,RC_DemiHuman,1; bonus2 bSubRace,RC_Player,1; } -1815,EVENT_RICECAKE,Rice Cake,0,9028,0,511,80,60,50,100,250,20,2000,150,1,0,500,500,200,{ petskillsupport "CR_DEFENDER",3,240,50,100; },{ bonus2 bSubEle,Ele_Neutral,1; bonus bMaxHPrate,-1; } -1245,GOBLINE_XMAS,Christmas Goblin,12225,9029,0,911,80,60,50,100,250,20,2000,150,0,0,300,300,800,{ petskillattack "MG_SIGHT",5,5,5; },{ bonus bMaxHP,30; bonus2 bSubEle,Ele_Water,1; } - -1519,CHUNG_E,Green Maiden,12395,9030,0,6115,80,60,50,100,250,20,2000,150,0,0,300,300,800,{ petskillattack "CR_SHIELDCHARGE",5,5,5; },{ bonus bDef,1; bonus2 bSubRace,RC_DemiHuman,1; bonus2 bSubRace,RC_Player,1; } -1879,ECLIPSE_P,Spring Rabbit,0,9031,0,7766,80,60,50,100,250,20,2000,150,0,0,300,300,800,{ petskillattack "TF_THROWSTONE",1,5,5; },{} -1122,GOBLIN_1,Goblin,14569,9032,0,7821,80,60,50,100,250,20,800,150,0,0,300,300,800,{ petskillattack "NPC_WINDATTACK",5,5,5; },{} -1123,GOBLIN_2,Goblin,14570,9033,0,7821,80,60,50,100,250,20,800,150,0,0,300,300,800,{ petskillattack "NPC_FIREATTACK",5,5,5; },{} -1125,GOBLIN_4,Goblin,14571,9034,0,7821,80,60,50,100,250,20,800,150,0,0,300,300,800,{ petskillattack "NPC_GROUNDATTACK",5,5,5; },{} -1385,DELETER_,Deleter,14572,9035,0,7822,80,60,20,100,250,20,800,150,0,0,300,300,800,{ petskillattack "SM_MAGNUM",5,5,5; },{} -1382,DIABOLIC,Diabolic,14573,9036,0,7823,80,60,10,100,250,20,800,150,0,0,300,300,800,{ petskillattack "WZ_METEOR",2,5,5; },{} -1208,WANDER_MAN,Wanderer,14574,9037,0,7824,80,60,20,100,250,20,800,150,0,0,300,300,800,{ petskillattack "NPC_UNDEADATTACK",5,5,5; },{ bonus bAgi,3; bonus bDex,1; } - -1963,P_CHUNG_E,New Year Doll,0,9038,0,554,80,60,30,100,250,20,800,150,0,0,300,300,800,{ petskillattack "CR_SHIELDCHARGE",5,5,5; },{} - -// New pets JapanRO Mobile -1040,GOLEM,Golem,12371,9053,10035,6111,80,60,20,100,250,20,500,150,0,0,300,300,800,{},{ bonus bMaxHP,100; bonus bFlee,-5; } -1143,MARIONETTE,Marionette,12361,9043,10025,6098,80,60,10,100,250,20,500,150,0,0,300,300,800,{},{ bonus bSPrecovRate,3; } -1148,MEDUSA,Medusa,12368,9050,10032,6108,80,60,10,100,250,20,200,150,0,0,300,300,800,{},{ bonus bVit,1; bonus2 bResEff,Eff_Stone,500; } -1179,WHISPER,Whisper,12363,9045,10027,6100,80,60,20,100,250,20,500,150,0,0,300,300,800,{},{ bonus bFlee,7; bonus bDef,-3; } -1299,GOBLIN_LEADER,Goblin Leader,12364,9046,10028,6104,80,60,10,100,250,20,50,150,0,0,300,300,800,{},{ bonus2 bAddRace,RC_DemiHuman,3; bonus2 bAddRace,RC_Player,3; } -1370,SUCCUBUS,Succubus,12373,9055,10037,6113,80,60,10,100,250,20,200,150,0,0,300,300,800,{},{ bonus2 bHpDrainRate,50,5; } -1374,INCUBUS,Incubus,12370,9052,10034,6110,80,60,10,100,250,20,50,150,0,0,300,300,800,{},{ bonus bMaxSPRate,3; } -1379,NIGHTMARE_TERROR,Nightmare Terror,12372,9054,10036,6112,80,60,10,100,250,20,200,150,0,0,300,300,800,{},{ bonus2 bResEff,Eff_Sleep,10000; } -1401,SHINOBI,Shinobi,12362,9044,10026,6099,80,60,20,100,250,20,500,150,0,0,300,300,800,{},{ bonus bAgi,2; } -1404,MIYABI_NINGYO,Miyabi Doll,12366,9048,10030,6106,80,60,15,100,250,20,200,150,0,0,300,300,800,{},{ bonus bInt,1; bonus bCastrate,-3; } -1416,WICKED_NYMPH,Evil Nymph,12365,9047,10029,6105,80,60,15,100,250,20,500,150,0,0,300,300,800,{},{ bonus bMaxSP,30; bonus bSPrecovRate,5; } -1495,STONE_SHOOTER,Stone Shooter,12369,9051,10033,6109,80,60,20,100,250,20,500,150,0,0,300,300,800,{},{ bonus2 bSubEle,Ele_Fire,3; } -1504,DULLAHAN,Dullahan,12367,9049,10031,6107,80,60,10,100,250,20,200,150,0,0,300,300,800,{},{ bonus bCritAtkRate,5; } -1505,LOLI_RURI,Loli Ruri,12360,9042,10024,6097,80,60,15,100,250,20,200,150,0,0,300,300,800,{},{ bonus bMaxHPRate,3; bonus3 bAutoSpellWhenHit,"AL_HEAL",1,10; } -1513,CIVIL_SERVANT,Mao Guai,12358,9040,10022,6095,80,60,10,100,250,20,500,150,0,0,300,300,800,{},{ bonus bMaxSP,10; } -1586,LEAF_CAT,Leaf Cat,12359,9041,10023,6096,80,60,20,100,250,20,200,150,0,0,300,300,800,{},{ bonus2 bSubRace,RC_Brute,3; } -1630,BACSOJIN_,White Lady,12357,9039,10021,6094,80,60,10,100,250,20,2000,150,0,0,300,300,800,{},{} -1837,IMP,Fire Imp,12374,9056,10038,6114,80,60,10,100,250,20,200,150,0,0,300,300,800,{},{ bonus2 bSubEle,Ele_Fire,2; bonus2 bAddEle,Ele_Fire,2; } - -// Brasilis Quest - Suspicious Beach [UNHATCHABLE] -2057,E_CRAMP,Strange Cramp,12408,6221,0,0,0,0,0,0,0,0,50,0,0,0,350,400,800,{},{} // kRO version -2081,E_HYDRA,Strange Hydra,12408,6221,0,0,0,0,0,0,0,0,50,0,0,0,350,400,800,{},{} // iRO/cRO version - -// New pets (FIX ME: pet bonuses for 2210 and 2313 do not require loyalty) -//2200,J_TAINI,Tiny,0,9057,0,512,80,60,10,100,250,20,0,150,1,0,300,300,800,{},{} -//2210,XMAS_LUNATIC,Christmas Snow Rabbit,0,9058,0,529,80,60,10,100,250,20,0,150,1,0,300,300,800,{},{ bonus2 bExpAddRace,RC_All,5; } -//2313,TIKBALANG,Tikbalang,12699,9059,0,528,80,60,10,100,250,20,1000,150,1,0,300,300,800,{},{ bonus2 bAddDamageClass,2320,10; bonus2 bAddDamageClass,2321,10; bonus2 bAddDamageClass,2322,10; bonus2 bAddDamageClass,2317,10; bonus2 bAddDamageClass,2318,10; bonus2 bAddDamageClass,2327,10; bonus2 bAddDamageClass,2319,10; bonus2 bAddDamageClass,2333,10; bonus2 bAddDamageClass,2332,10; } -1242,MARIN,Marin,12789,9061,10039,6534,80,60,50,100,250,20,2000,150,1,0,300,300,800,{},{} -//2398,LITTLE_PORING,Novice Poring,12846,9062,0,531,80,60,1000,0,250,0,5000,150,0,0,300,300,800,{},{ bonus bHPrecovRate,50; } diff --git a/db/pre-re/pet_db.yml b/db/pre-re/pet_db.yml new file mode 100644 index 0000000000..ef08838691 --- /dev/null +++ b/db/pre-re/pet_db.yml @@ -0,0 +1,867 @@ +# This file is a part of rAthena. +# Copyright(C) 2019 rAthena Development Team +# https://rathena.org - https://github.com/rathena +# +# 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 3 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, see . +# +########################################################################### +# Pre-Renewal Pet Database +########################################################################### +# +# Pet Settings +# +########################################################################### +# - Mob Monster that can be used as pet +# TameItem Pet Tame Item. +# EggItem Pet Egg Item. +# EquipItem Pet Accessory Item. (Default: 0) +# FoodItem Pet Food Item. (Default: 0) +# Fullness The amount of hunger is decreased every [HungryDelay] seconds. +# HungryDelay The amount of time in seconds it takes for hunger to decrease after feeding. (Default: 60) +# HungerIncrease The amount of hunger that is increased every time the pet is fed (Default: 20) +# IntimacyStart Amount of Intimacy the pet starts with. (Default: 250) +# IntimacyFed Amount of Intimacy that is increased when fed. (Default: 50) +# IntimacyOverfed Amount of Intimacy that is increased when over-fed. (Default: -100) +# IntimacyHungry Amount of Intimacy that is increased when the pet is hungry. (Default: -5) +# IntimacyOwnerDie Amount of Intimacy that is increased when the pet owner dies. (Default: -20) +# CaptureRate Capture success rate. (10000 = 100%) +# SpecialPerformance If a pet has a Special Performance. (Default: true) +# AttackRate Rate of which the pet will attack [requires at least pet_support_min_friendly intimacy]. (10000 = 100%) +# RetaliateRate Rate of which the pet will retaliate when master is being attacked [requires at least pet_support_min_friendly intimacy]. (10000 = 100%) +# ChangeTargetRate Rate of which the pet will change its attack target. (10000 = 100%) +# AllowAutoFeed Allows turning automatic pet feeding on. (Default: false) +# Script Bonus script to execute when the pet is alive. (Default: null) +# SupportScript Bonus script to execute when pet_status_support is enabled. (Default: null) +# Evolution: Pet evolution settings. (Optional) (Default: null) +# - Target Mob this pet can evolve to. +# ItemRequirements: Item requirements for evolving this pet. +# - Item Self-explanatory +# Amount +########################################################################### + +Header: + Type: PET_DB + Version: 1 + +Body: + - Mob: PORING + TameItem: Unripe_Apple + EggItem: Poring_Egg + EquipItem: Backpack + FoodItem: Apple_Juice + Fullness: 80 + IntimacyFed: 50 + CaptureRate: 2000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bLuk,2; + bonus bCritical,1; + } + - Mob: DROPS + TameItem: Orange_Juice + EggItem: Drops_Egg + EquipItem: Backpack + FoodItem: Yellow_Herb + Fullness: 80 + IntimacyFed: 40 + CaptureRate: 1500 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bHit,3; + bonus bAtk,3; + } + - Mob: POPORING + TameItem: Bitter_Herb + EggItem: Poporing_Egg + EquipItem: Backpack + FoodItem: Green_Herb + Fullness: 80 + IntimacyFed: 30 + CaptureRate: 1000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bLuk,2; + bonus2 bSubEle,Ele_Poison,10; + } + - Mob: LUNATIC + TameItem: Rainbow_Carrot + EggItem: Lunatic_Egg + EquipItem: Silk_Ribbon + FoodItem: Carrot_Juice + Fullness: 80 + IntimacyFed: 40 + CaptureRate: 1500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bCritical,2; + bonus bAtk,2; + } + - Mob: PICKY + TameItem: Earthworm_The_Dude + EggItem: Picky_Egg + EquipItem: Tiny_Egg_Shell + FoodItem: Red_Herb + Fullness: 80 + IntimacyFed: 40 + CaptureRate: 2000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bStr,1; + bonus bAtk,5; + } + - Mob: CHONCHON + TameItem: Rotten_Fish + EggItem: Chonchon_Egg + EquipItem: Monster_Oxygen_Mask + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 30 + CaptureRate: 1500 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bAgi,1; + bonus bFlee,2; + } + - Mob: STEEL_CHONCHON + TameItem: Lusty_Iron + EggItem: Steel_Chonchon_Egg + EquipItem: Monster_Oxygen_Mask + FoodItem: Iron_Ore + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 1000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bFlee,6; + bonus bAgi,-1; + } + - Mob: HUNTER_FLY + TameItem: Monster_Juice + EggItem: Hunter_Fly_Egg + EquipItem: Monster_Oxygen_Mask + FoodItem: Red_Gemstone + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 500 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bFlee,-5; + bonus bFlee2,2; + } + - Mob: SAVAGE_BABE + TameItem: Sweet_Milk + EggItem: Savage_Bebe_Egg + EquipItem: Green_Lace + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 40 + CaptureRate: 1500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bVit,1; + bonus bMaxHP,50; + } + - Mob: DESERT_WOLF_B + TameItem: Well_Dried_Bone + EggItem: Baby_Desert_Wolf_Egg + EquipItem: Transparent_Headgear + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 40 + CaptureRate: 1000 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bInt,1; + bonus bMaxSP,50; + } + - Mob: ROCKER + TameItem: Singing_Flower + EggItem: Rocker_Egg + EquipItem: Rocker_Glasses + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 30 + CaptureRate: 1500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bHPrecovRate,5; + bonus bMaxHP,25; + } + - Mob: SPORE + TameItem: Dew_Laden_Moss + EggItem: Spore_Egg + EquipItem: Bark_Shorts + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 30 + CaptureRate: 1500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bHit,5; + bonus bAtk,-2; + } + - Mob: POISON_SPORE + TameItem: Deadly_Noxious_Herb + EggItem: Poison_Spore_Egg + EquipItem: Bark_Shorts + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 1000 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bStr,1; + bonus bInt,1; + } + - Mob: PECOPECO + TameItem: Fatty_Chubby_Earthworm + EggItem: PecoPeco_Egg + EquipItem: Battered_Pot + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 30 + CaptureRate: 1000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxHP,150; + bonus bMaxSP,-10; + } + - Mob: SMOKIE + TameItem: Baked_Yam + EggItem: Smokie_Egg + EquipItem: Red_Muffler + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 30 + CaptureRate: 1000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bAgi,1; + bonus bFlee2,1; + } + - Mob: YOYO + TameItem: Tropical_Banana + EggItem: Yoyo_Egg + EquipItem: Monkey_Circlet + FoodItem: Banana_Juice + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 1000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bCritical,3; + bonus bLuk,-1; + } + - Mob: ORK_WARRIOR + TameItem: Horror_Of_Tribe + EggItem: Orc_Warrior_Egg + EquipItem: Wild_Flower + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 500 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bAtk,10; + bonus bDef,-3; + } + - Mob: MUNAK + TameItem: No_Recipient + EggItem: Munak_Egg + EquipItem: Punisher + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bInt,1; + bonus bDef,1; + } + - Mob: DOKEBI + TameItem: Old_Broom + EggItem: Dokkaebi_Egg + EquipItem: Wig + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMatkRate,1; + bonus bAtkRate,-1; + } + - Mob: SOHEE + TameItem: Silver_Knife_Of_Chaste + EggItem: Sohee_Egg + EquipItem: Golden_Bell + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bStr,1; + bonus bDex,1; + } + - Mob: ISIS + TameItem: Armlet_Of_Obedience + EggItem: Isis_Egg + EquipItem: Queen's_Hair_Ornament + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMatkRate,-1; + bonus bAtkRate,1; + } + - Mob: PETIT + TameItem: Shining_Stone + EggItem: Green_Petite_Egg + EquipItem: Stellar_Hairpin + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bDef,-2; + bonus bMdef,-2; + bonus bAspdRate,1; + } + - Mob: DEVIRUCHI + TameItem: Contracts_In_Shadow + EggItem: Deviruchi_Egg + EquipItem: Pacifier + FoodItem: Shoot + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMatkRate,1; + bonus bAtkRate,1; + bonus bMaxHPrate,-3; + bonus bMaxSPrate,-3; + } + - Mob: BAPHOMET_ + TameItem: Book_Of_Devil + EggItem: Bapho_Jr._Egg + EquipItem: Skull_Helm + FoodItem: Honey + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bDef,1; + bonus bMdef,1; + bonus2 bResEff,Eff_Stun,-100; + } + - Mob: BON_GUN + TameItem: Heart_Of_Her + EggItem: Bongun_Egg + EquipItem: Sword_Of_Grave_Keeper + FoodItem: Pet_Food + Fullness: 80 + IntimacyFed: 30 + CaptureRate: 500 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bVit,1; + bonus2 bResEff,Eff_Stun,100; + } + - Mob: ZHERLTHSH + TameItem: Prohibition_Red_Candle + EggItem: Zherlthsh_Egg + FoodItem: Immortal_Heart + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 300 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bAddRace,RC_Demihuman,2; + bonus2 bMagicAddRace,RC_DemiHuman,2; + bonus2 bAddRace,RC_Player,2; + bonus2 bMagicAddRace,RC_Player,2; + } + - Mob: ALICE + TameItem: Sway_Apron + EggItem: Alice_Egg + FoodItem: White_Potion + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 800 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMdef,1; + bonus2 bSubRace,RC_DemiHuman,1; + bonus2 bSubRace,RC_Player,1; + } + - Mob: EVENT_RICECAKE + EggItem: Rice_Cake_Egg + FoodItem: Green_Herb + Fullness: 80 + IntimacyFed: 50 + CaptureRate: 2000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bSubEle,Ele_Neutral,1; + bonus bMaxHPrate,-1; + } + - Mob: GOBLINE_XMAS + TameItem: Sweet_Candy_Striper + EggItem: Santa_Goblin_Egg + FoodItem: Scell + Fullness: 80 + IntimacyFed: 50 + CaptureRate: 2000 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxHP,30; + bonus2 bSubEle,Ele_Water,1; + } + - Mob: CHUNG_E + TameItem: Tantanmen + EggItem: Chung_E_Egg + FoodItem: Bun_ + Fullness: 80 + IntimacyFed: 50 + CaptureRate: 2000 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bDef,1; + bonus2 bSubRace,RC_DemiHuman,1; + bonus2 bSubRace,RC_Player,1; + } + - Mob: ECLIPSE_P + EggItem: Spring_Rabbit_Egg + FoodItem: Bok_Choy + Fullness: 80 + IntimacyFed: 50 + CaptureRate: 2000 + SpecialPerformance: false + - Mob: GOBLIN_1 + TameItem: Knife_Goblin_Ring + EggItem: Knife_Goblin_Egg + FoodItem: Green_Apple + Fullness: 80 + IntimacyFed: 50 + CaptureRate: 800 + SpecialPerformance: false + - Mob: GOBLIN_2 + TameItem: Flail_Goblin_Ring + EggItem: Flail_Goblin_Egg + FoodItem: Green_Apple + Fullness: 80 + IntimacyFed: 50 + CaptureRate: 800 + SpecialPerformance: false + - Mob: GOBLIN_4 + TameItem: Hammer_Goblin_Ring + EggItem: Hammer_Goblin_Egg + FoodItem: Green_Apple + Fullness: 80 + IntimacyFed: 50 + CaptureRate: 800 + SpecialPerformance: false + - Mob: DELETER_ + TameItem: Holy_Marble + EggItem: Red_Deleter_Egg + FoodItem: Whole_Barbecue + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 800 + SpecialPerformance: false + - Mob: DIABOLIC + TameItem: Red_Burning_Stone + EggItem: Diabolic_Egg + FoodItem: Meat_Veg_Skewer + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 800 + SpecialPerformance: false + - Mob: WANDER_MAN + TameItem: Skull_Of_Vagabond + EggItem: Wanderer_Egg + FoodItem: Spirit_Liquor + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 800 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bAgi,3; + bonus bDex,1; + } + - Mob: P_CHUNG_E + EggItem: New_Year_Doll_Egg + FoodItem: Mojji + Fullness: 80 + IntimacyFed: 30 + CaptureRate: 800 + SpecialPerformance: false + - Mob: GOLEM + TameItem: Magical_Lithography + EggItem: Golem_Egg + EquipItem: Windup_Spring + FoodItem: Mystic_Stone + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxHP,100; + bonus bFlee,-5; + } + - Mob: MARIONETTE + TameItem: Delicious_Shaved_Ice + EggItem: Marionette_Egg + EquipItem: Star_Hairband + FoodItem: Small_Snow_Flower + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bSPrecovRate,3; + } + - Mob: MEDUSA + TameItem: Splendid_Mirror + EggItem: Medusa_Egg + EquipItem: Queen's_Coronet + FoodItem: Apple_Pudding + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bVit,1; + bonus2 bResEff,Eff_Stone,500; + } + - Mob: WHISPER + TameItem: Fit_Pipe + EggItem: Whisper_Egg + EquipItem: Spirit_Chain_ + FoodItem: Damp_Darkness + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bFlee,7; + bonus bDef,-3; + } + - Mob: GOBLIN_LEADER + TameItem: Staff_Of_Leader + EggItem: Goblin_Leader_Egg + EquipItem: Nice_Badge + FoodItem: Big_Cell + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 50 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bAddRace,RC_DemiHuman,3; + bonus2 bAddRace,RC_Player,3; + } + - Mob: SUCCUBUS + TameItem: Boy's_Naivety + EggItem: Succubus_Egg + EquipItem: Black_Butterfly_Mask + FoodItem: Vital_Flower_ + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bHpDrainRate,50,5; + } + - Mob: INCUBUS + TameItem: Gril's_Naivety + EggItem: Incubus_Egg + EquipItem: Ball_Mask + FoodItem: Vital_Flower + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 50 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxSPRate,3; + } + - Mob: NIGHTMARE_TERROR + TameItem: Hell_Contract + EggItem: Nightmare_Terror_Egg + EquipItem: Hell_Horn + FoodItem: Fresh_Plant + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bResEff,Eff_Sleep,10000; + } + - Mob: SHINOBI + TameItem: Kuloren + EggItem: Shinobi_Egg + EquipItem: Wine_On_Sleeve + FoodItem: Grilled_Rice_Cake + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bAgi,2; + } + - Mob: MIYABI_NINGYO + TameItem: Gril_Doll + EggItem: Miyabi_Ningyo_Egg + EquipItem: Summer_Fan + FoodItem: Well_Ripened_Berry + Fullness: 80 + IntimacyFed: 15 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bInt,1; + bonus bCastrate,-3; + } + - Mob: WICKED_NYMPH + TameItem: Charming_Lotus + EggItem: Wicked_Nymph_Egg + EquipItem: Jade_Trinket + FoodItem: Morning_Dew + Fullness: 80 + IntimacyFed: 15 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxSP,30; + bonus bSPrecovRate,5; + } + - Mob: STONE_SHOOTER + TameItem: Oilpalm_Coconut + EggItem: Stone_Shooter_Egg + EquipItem: Apro_Hair + FoodItem: Plant_Neutrient + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bSubEle,Ele_Fire,3; + } + - Mob: DULLAHAN + TameItem: Luxury_Whisky_Bottle + EggItem: Dullahan_Egg + EquipItem: Death_Coil + FoodItem: Sunset_On_The_Rock + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bCritAtkRate,5; + } + - Mob: LOLI_RURI + TameItem: Very_Red_Juice + EggItem: Loli_Ruri_Egg + EquipItem: Fashionable_Glasses + FoodItem: Pumpkin_Pie_ + Fullness: 80 + IntimacyFed: 15 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxHPRate,3; + bonus3 bAutoSpellWhenHit,"AL_HEAL",1,10; + } + - Mob: CIVIL_SERVANT + TameItem: Fan_Of_Wind + EggItem: Civil_Servant_Egg + EquipItem: Golden_Earing + FoodItem: Flavored_Alcohol + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxSP,10; + } + - Mob: LEAF_CAT + TameItem: Very_Soft_Plant + EggItem: Leaf_Cat_Egg + EquipItem: Green_Lucky_Bag + FoodItem: Fish_With_Blue_Back + Fullness: 80 + IntimacyFed: 20 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bSubRace,RC_Brute,3; + } + - Mob: BACSOJIN_ + TameItem: Shiny_Wing_Gown + EggItem: Bacsojin_Egg + EquipItem: Round_Hair_Ornament + FoodItem: Traditional_Cookie + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 2000 + SpecialPerformance: false + - Mob: IMP + TameItem: Flaming_Ice + EggItem: Imp_Egg + EquipItem: Horn_Protector + FoodItem: Flame_Gemstone + Fullness: 80 + IntimacyFed: 10 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bSubEle,Ele_Fire,2; + bonus2 bAddEle,Ele_Fire,2; + } diff --git a/db/re/item_db.txt b/db/re/item_db.txt index 3f2be5605d..d8686730e3 100644 --- a/db/re/item_db.txt +++ b/db/re/item_db.txt @@ -5999,11 +5999,54 @@ 9060,Brownie_Egg,Brownie Egg,7,20,,0,,,,,,,,,,,,,{},{},{} 9061,Marin_Egg,Marin Egg,7,20,,0,,,,,,,,,,,,,{},{},{} 9062,Novice_Poring_Egg,Novice Poring Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9063,Woodie_Egg,Woodie Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9064,Elephant_Egg,Elephant Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9065,Gorilla_Egg,Gorilla Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9066,Lion_Egg,Lion Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9067,Rhino_Egg,Rhino Egg,7,20,,0,,,,,,,,,,,,,{},{},{} 9068,Blue_Unicorn_Egg,Blue Unicorn Egg,7,20,,0,,,,,,,,,,,,,{},{},{} 9069,Mastering_Egg,Mastering Egg,7,20,,0,,,,,,,,,,,,,{},{},{} 9070,Savage_Egg,Savage Egg,7,20,,0,,,,,,,,,,,,,{},{},{} 9071,Grand_Peco_Peco_Egg,Grand Peco Peco Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9072,Orc_Hero_Egg,Orc Hero Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9073,Orc_Lord_Egg,Orc Lord Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9074,Rubylit_Egg,Rubylit Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9075,Sapphilit_Egg,Sapphilit Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9076,Emelit_Egg,Emelit Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9077,Topalit_Egg,Topalit Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9078,Amelit_Egg,Amelit Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9079,Mythlit_Egg,Mythlit Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9080,Tamadora_Egg,Tamadora Egg,7,20,,0,,,,,,,,,,,,,{},{},{} + 9087,High_Orc_Egg,High Orc Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9088,Angeling_Egg,Angeling Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9089,Am_Mut_Egg,Am Mut Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9090,Little_Isis_Egg,Little Isis Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9091,Choco_Egg,Choco Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9092,Eggring_Egg,Eggring Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9093,Hyegun_Egg,Hyegun Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9094,Dr_Lunatic_Egg,Leaf Lunatic Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9095,Nine_Tail_Egg,Nine Tail Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9096,Cat_o_Nine_Tail_Egg,Cat o Nine Tail Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9097,Diabolic_2_Egg,Diabolic Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9098,Fire_Deleter_Egg,Fire Deleter Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9099,Teddy_Bear_Egg,Teddy Bear Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9100,Gremlin_Egg,Gremlin Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9101,Scatleton_Egg,Scatleton Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9102,Mummy_Egg,Mummy Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9103,Willow_Egg,Willow Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9104,Roween_Egg,Roween Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9105,Hodremlin_Egg,Hodremlin Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9106,Metaller_Egg,Metaller Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9107,Ancient_Mummy_Egg,Ancient Mummy Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9108,Xm_Teddy_Bear_Egg,Xmas Teddy Bear Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9109,Sweet_Drops_Egg,Sweet Drops Egg,7,20,,0,,,,,,,,,,,,,{},{},{} + +9111,Phreeoni_Egg,Phreeoni Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9112,Moonlight_Egg,Moonlight Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9113,Skelion_Egg,Skelion Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9114,Pouring_Egg,Pouring Egg,7,20,,0,,,,,,,,,,,,,{},{},{} +9115,Bacsojin2_Egg_,Bacsojin Egg,7,20,,0,,,,,,,,,,,,,{},{},{} //=================================================================== // Pet Accessories //=================================================================== @@ -6046,6 +6089,9 @@ 10037,Black_Butterfly_Mask,Black Butterfly Mask,8,20,,0,,,,,,,,,,,,,{},{},{} 10038,Horn_Protector,Horn Barrier,8,20,,0,,,,,,,,,,,,,{},{},{} 10039,Tw_Backpack,Tw Backpack,8,20,,0,,,,,,,,,,,,,{},{},{} +10040,Red_Bell_Necklace,Red Bell Necklace,8,20,,0,,,,,,,,,,,,,{},{},{} +10041,Shiny_Star_Button,Shiny Star Button,8,20,,0,,,,,,,,,,,,,{},{},{} +10042,Dark_Mane,Dark Mane,8,20,,0,,,,,,,,,,,,,{},{},{} //=================================================================== // Misc "Etc" Books //=================================================================== @@ -11335,6 +11381,9 @@ 23126,Bullet_Case_Poison,Poison Bullet Cartridge,2,10,,250,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 13231,500; },{},{} 23127,Bullet_Case_Blind,Blind Bullet Cartridge,2,10,,250,,,,,0xFFFFFFFF,63,2,,,,,,{ getitem 13232,500; },{},{} 23177,Kafra_Card_,Kafra Card,2,2,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ callfunc "F_CashStore"; },{},{} +23188,Unprocessed_Parts,Unprocessed Parts,2,10,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ pet 1632; },{},{} +23189,Small_Needle_Kit,Small Needle Kit,2,10,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ pet 1622; },{},{} +23187,Sap_Liquid,Sap Liquid,2,10,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ pet 1180; },{},{} 23191,Varetyr_Spear_Scroll_1_5,Level 5 Varetyr Spear,11,10,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill "SO_VARETYR_SPEAR",5; },{},{} 23192,Diamond_Dust_Scroll_1_5,Level 5 Diamond Dust,11,10,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill "SO_DIAMONDDUST",5; },{},{} 23193,Crimson_Rock_Scroll_1_5,Level 5 Crimson Rock,11,10,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill "WL_CRIMSONROCK",5; },{},{} @@ -11343,6 +11392,7 @@ // 23228,Hazy_Mooncake,Hazy Mooncake,0,768,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ /* unknown */ },{},{} // +23256,Elixir_Bandages,Elixir Bandages,2,10,,0,,,,,0xFFFFFFFF,63,2,,,,,,{ pet 1041; },{},{} 23277,Mado_Box,Emergency Magic Gear,2,10000,,3000,,,,,0x00000400,56,2,,,100,,,{ setmadogear 1; },{},{} 23280,N_Fly_Wing_,Novice Fly Wing,11,10,,0,,,,,0xFFFFFFFF,63,2,,,1:98,,,{ itemskill "AL_TELEPORT",1; },{},{} 23288,Compressed_Wing_Of_Fly,Compressed Fly Wing,11,1000,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ itemskill "AL_TELEPORT",1; },{},{} @@ -11661,6 +11711,9 @@ 25185,Locket_Pendant,Locket Pendant,3,0,,0,,,,,,,,,,,,,{},{},{} 25187,Slug_Bullet,Slug Bullet,3,1200,,1200,,,,,,,,,,,,,{},{},{} 25223,Para_Team_Coin,Eden Group Coin,3,0,,0,,,,,,,,,,,,,{},{},{} +25231,Suspicious_Bottle,Suspicious Bottle,3,0,,10,,,,,,,,,,,,,{},{},{} +25232,Cheap_Lubricant,Cheap Lubricant,3,0,,10,,,,,,,,,,,,,{},{},{} +25233,Cotton_Tufts,Cotton Tufts,3,0,,10,,,,,,,,,,,,,{},{},{} 25238,New_Normal_Lubricant,New Normal Lubricant,3,0,,0,,,,,,,,,,,,,{},{},{} 25239,New_Advanced_Lubricant,New Advanced Lubricant,3,0,,0,,,,,,,,,,,,,{},{},{} 25246,Juice_Mix_Package,Juice Mix Package,3,0,,0,,,,,,,,,,,,,{},{},{} @@ -11684,6 +11737,9 @@ 25283,Brown_Muffler,Brown Muffler,3,420,,10,,,,,,,,,,,,,{},{},{} 25284,Swamp_Bug_Shell,Swamp Bug Shell,3,0,,10,,,,,,,,,,,,,{},{},{} 25285,Brown_Rat_Tail,Brown Rat Tail,3,0,,10,,,,,,,,,,,,,{},{},{} +25290,Sweets_Festival_Coin,Sweets Festival Coin,3,0,,0,,,,,,,,,,,,,{},{},{} +25375,Powerful_Soul_Essence,Powerful Soul Essence,3,0,,0,,,,,,,,,,,,,{},{},{} +25377,Luxurious_Pet_Food,Luxurious Pet Food,3,0,,10,,,,,,,,,,,,,{},{},{} // 25464,World_Moving_Rights,World Moving Rights,3,20,,0,,,,,,,,,,,,,{},{},{} // diff --git a/db/re/mob_db.txt b/db/re/mob_db.txt index 94ebc8c108..0fa74aff53 100644 --- a/db/re/mob_db.txt +++ b/db/re/mob_db.txt @@ -2796,7 +2796,7 @@ //3633,EP16_2_VENOM_KIMERA //3634,MYSTCASE_GIANT //3635,EVENT_KOBOLD -//3636,LITTLE_ISIS +3636,LITTLE_ISIS,Little Isis,Little Isis,59,2092,1,531,597,1,192,229,83,5,58,43,22,5,39,15,10,12,2,6,27,0x2003095,200,1384,768,336,0,0,0,0,0,0,0,936,5335,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //3637,MD_SKELETON_60 //3638,MD_SKELETON_80 //3639,MD_SKELETON_100 @@ -2829,8 +2829,8 @@ //3666,MD_DRAINLIAR_100 //3667,MD_DRAINLIAR_160 //3668,B_KIEL_ -//3669,DIABOLIC2 -//3670,DELETER_2 +3669,DIABOLIC2,Diabolic2,Diabolic2,104,10572,1,2172,1629,1,544,644,68,61,103,80,53,65,78,25,10,12,0,6,47,0x2003885,150,1080,780,180,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +3670,DELETER_2,Deleter 2,Deleter 2,105,10000,1,2099,1574,1,510,621,114,53,98,65,49,72,57,73,10,12,1,9,43,0x308D,175,1024,624,336,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //3671,JP_MAZEMOB_01 //3672,JP_MAZEMOB_02 //3673,JP_MAZEMOB_03 @@ -2950,7 +2950,7 @@ 3787,RR_ARCLOUSE,Rr Arclouse,Swamp Arclouze,106,1120,1,864,900,1,316,126,76,36,41,73,23,29,122,15,10,12,1,4,42,0x2003885,100,768,500,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27177,1 3788,RR_CRAMP,Rr Cramp,Brown Rat,101,988,1,681,720,1,185,74,68,42,38,43,17,15,97,30,10,12,0,2,45,0x3885,100,768,500,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27176,1 //3789,ESCAPED_LETTER -//3790,SWEETS_DROPS +3790,SWEETS_DROPS,Sweets Drops,Sweets Drops,2,45,1,27,20,1,12,13,16,0,8,1,1,0,6,2,10,12,1,3,23,0x83,400,1372,672,480,0,0,0,0,0,0,0,909,7500,1602,80,938,500,512,1100,713,1700,512,800,620,20,0,0,0,0,0,0 //3791,JP_E_MONSTER_73 //3792,ILL_GAZETI //3793,ILL_SNOWIER diff --git a/db/re/pet_db.txt b/db/re/pet_db.txt deleted file mode 100644 index be51f61a08..0000000000 --- a/db/re/pet_db.txt +++ /dev/null @@ -1,110 +0,0 @@ -// Pet Database -// -// Structure of Database: -// MobID,Name,JName,LureID,EggID,EquipID,FoodID,Fullness,HungryDelay,R_Hungry,R_Full,Intimate,Die,Capture,Speed,S_Performance,talk_convert_class,attack_rate,defence_attack_rate,change_target_rate,pet_script,loyal_script -// -// 01. MobID Monster ID of the pet. -// 02. Name Name of the monster as defined in the database. -// 03. JName The display name of the monster when hatched. -// 04. LureID Pet Tame Item ID. -// 05. EggID Pet Egg ID. -// 06. EquipID Pet Accessory ID. -// 07. FoodID Pet Food ID. -// 08. Fullness The amount Hunger is decreased every [HungryDelay] seconds. -// 09. HungryDelay The amount of time it takes for hunger to decrease after feeding. (Default: 60 seconds) -// 10. R_Hungry Amount of Intimacy that is increased when fed. -// 11. R_Full Amount of Intimacy that is decreased when over-fed. -// 12. Intimate Amount of Intimacy the pet starts with. -// 13. Die Amount of Intimacy that is decreased when the pet owner dies. -// 14. Capture Capture succes rate (10000 = 100%) -// 15. Speed Pet's walk speed. (Defaul: 150) -// 16. S_Performance Special Performance. (Yes = 1, No = 0) -// 17. talk_convert_class Disables pet talk (instead of talking they emote with /!.) -// 18. attack_rate Rate of which the pet will attack (requires at least pet_support_min_friendly intimacy). -// 19. defence_attack_rate Rate of which the pet will retaliate when master is being attacked (requires at least pet_support_min_friendly intimacy). -// 20. change_target_rate Rate of which the pet will change its attack target. -// 21. pet_script Script to execute when the pet is hatched. -// 22. loyal_script Script to execute when the pet is hatched (requires at least pet_equip_min_friendly intimacy, independent of pet_script). -//NOTE: The max value (100%) of attack_rate, defense_rate & change_target_rate is 10000. - -//In theory you can use any valid script, but it is run only once upon pet -//loading, so it is recommended you use the specific pet scripts. -//Please see "The Pet AI commands" in 'doc/script_commands.txt'. - -1002,PORING,Poring,619,9001,10013,531,80,60,50,100,250,20,2000,150,1,0,350,400,800,{ petloot 10; },{ bonus bLuk,2; bonus bCritical,1; } -1113,DROPS,Drops,620,9002,10013,508,80,60,40,100,250,20,1500,150,1,0,300,400,500,{ petloot 10; },{ bonus bHit,3; bonus bAtk,3; } -1031,POPORING,Poporing,621,9003,10013,511,80,60,30,100,250,20,1000,150,1,0,300,500,400,{ petloot 15; },{ bonus bLuk,2; bonus2 bSubEle,Ele_Poison,10; } -1063,LUNATIC,Lunatic,622,9004,10007,534,80,60,40,100,250,20,1500,150,0,0,300,300,1000,{ petskillbonus bLuk,3,10,50; },{ bonus bCritical,2; bonus bAtk,2; } -1049,PICKY,Picky,623,9005,10012,507,80,60,40,100,250,20,2000,150,1,0,500,600,50,{ petskillbonus bStr,3,10,50;},{ bonus bStr,1; bonus bAtk,5; } -1011,CHONCHON,ChonChon,624,9006,10002,537,80,60,30,100,250,20,1500,150,1,0,500,500,250,{ petskillbonus bAgi,4,10,50; },{ bonus bAgi,1; bonus bFlee,2; } -1042,STEEL_CHONCHON,Steel ChonChon,625,9007,10002,1002,80,60,20,100,250,20,1000,150,1,0,500,500,200,{ petskillbonus bAgiVit,4,20,40; },{ bonus bFlee,6; bonus bAgi,-1; } -1035,HUNTER_FLY,Hunter Fly,626,9008,10002,716,80,60,10,100,250,20,500,150,1,0,500,500,200,{ petskillattack2 "NPC_WINDATTACK",888,2,0,10; },{ bonus bFlee,-5; bonus bFlee2,2; } -1167,SAVAGE_BABE,Savage Babe,627,9009,10015,537,80,60,40,100,250,20,1500,150,0,0,500,500,200,{ petskillbonus bVit,4,10,50; },{ bonus bVit,1; bonus bMaxHP,50; } -1107,DESERT_WOLF_B,Baby Desert Wolf,628,9010,10003,537,80,60,40,100,250,20,1000,150,0,0,400,400,400,{ petskillattack "SM_PROVOKE",1,0,5;},{ bonus bInt,1; bonus bMaxSP,50; } -1052,ROCKER,Rocker,629,9011,10014,537,80,60,30,100,250,20,1500,150,0,0,350,350,600,{ petskillbonus bAllStats,1,10,50; },{ bonus bHPrecovRate,5; bonus bMaxHP,25; } -1014,SPORE,Spore,630,9012,10017,537,80,60,30,100,250,20,1500,150,0,0,350,500,500,{ petrecovery SC_POISON,60; },{ bonus bHit,5; bonus bAtk,-2; } -1077,POISON_SPORE,Poison Spore,631,9013,10017,537,80,60,20,100,250,20,1000,150,0,0,600,200,400,{ petskillattack "NPC_POISON",20,0,10; },{ bonus bStr,1; bonus bInt,1; } -1019,PECOPECO,PecoPeco,632,9014,10010,537,80,60,30,100,250,20,1000,150,1,0,400,500,800,{ petskillbonus bSpeedRate,25,20,20; },{ bonus bMaxHP,150; bonus bMaxSP,-10; } -1056,SMOKIE,Smokie,633,9015,10019,537,80,60,30,100,250,20,1000,150,1,0,600,600,100,{ petskillbonus bPerfectHide,1,3600,0; },{ bonus bAgi,1; bonus bFlee2,1; } -1057,YOYO,Yoyo,634,9016,10018,532,80,60,20,100,250,20,1000,150,1,0,300,800,400,{ petloot 20; },{ bonus bCritical,3; bonus bLuk,-1; } -1023,ORK_WARRIOR,Orc Warrior,635,9017,10009,537,80,60,20,100,250,20,500,150,1,0,600,200,300,{ petskillattack2 "NPC_PIERCINGATT",100,1,0,10; },{ bonus bAtk,10; bonus bDef,-3; } -1026,MUNAK,Munak,636,9018,10008,537,80,60,20,100,250,20,500,150,0,0,300,750,300,{ petskillattack2 "NPC_DARKNESSATTACK",444,1,0,10; },{ bonus bInt,1; bonus bDef,1; } -1110,DOKEBI,Dokebi,637,9019,10005,537,80,60,20,100,250,20,500,150,0,0,300,300,800,{ petskillattack "BS_HAMMERFALL",1,0,10; },{ bonus bMatkRate,1; bonus2 bAddClass,Class_All,-1; } -1170,SOHEE,Sohee,638,9020,10016,537,80,60,10,100,250,20,500,150,0,0,100,1000,200,{ petskillsupport "AL_HEAL",5,60,33,100; },{ bonus bStr,1; bonus bDex,1; } -1029,ISIS,Isis,639,9021,10006,537,80,60,10,100,250,20,500,150,0,0,650,450,150,{ petskillsupport "PR_MAGNIFICAT",2,60,50,50; },{ bonus bMatkRate,-1; bonus2 bAddClass,Class_All,1; } -1155,PETIT,Petite,640,9022,10011,537,80,60,20,100,250,20,500,150,0,0,800,400,100,{ petskillattack2 "WZ_HEAVENDRIVE",500,1,0,10; },{ bonus bDef,-2; bonus bMdef,-2; bonus bAspdRate,1; } -1109,DEVIRUCHI,Deviruchi,641,9023,10004,711,80,60,10,100,250,20,500,150,0,0,800,200,100,{ petskillbonus bAgiDexStr,6,20,40; },{ bonus bMatkRate,1; bonus2 bAddClass,Class_All,1; bonus bMaxHPrate,-3; bonus bMaxSPrate,-3; } -1101,BAPHOMET_,Baphomet Jr.,642,9024,10001,518,80,60,10,100,250,20,200,150,0,0,1000,100,200,{ petskillattack2 "NPC_DARKNESSATTACK",1776,4,0,5; },{ bonus bDef,1; bonus bMdef,1; bonus2 bResEff,Eff_Stun,-100; } -1188,BON_GUN,Bon Gun,659,9025,10020,537,80,60,30,100,250,20,500,150,1,0,600,200,400,{ petskillattack2 "NPC_DARKNESSATTACK",555,1,1,1; },{ bonus bVit,1; bonus2 bResEff,Eff_Stun,100; } -1200,ZHERLTHSH,Zealotus,660,9026,0,929,80,60,10,100,250,20,300,150,0,0,1000,100,500,{ petskillattack "AS_SONICBLOW",1,0,3; },{ bonus2 bAddRace,RC_Demihuman,2; bonus2 bAddRace,RC_Player,2; bonus2 bMagicAddRace,RC_DemiHuman,2; bonus2 bMagicAddRace, RC_Player,2; } -1275,ALICE,Alice,661,9027,0,504,80,60,20,100,250,20,800,150,0,0,100,1000,200,{ petskillsupport "AL_HEAL",5,60,25,100; },{ bonus bMdef,1; bonus2 bSubRace,RC_DemiHuman,1; bonus2 bSubRace,RC_Player,1; } -1815,EVENT_RICECAKE,Rice Cake,0,9028,0,511,80,60,50,100,250,20,2000,150,1,0,500,500,200,{ petskillsupport "CR_DEFENDER",3,240,50,100; },{ bonus2 bSubEle,Ele_Neutral,1; bonus bMaxHPrate,-1; } -1245,GOBLINE_XMAS,Christmas Goblin,12225,9029,0,911,80,60,50,100,250,20,2000,150,0,0,300,300,800,{ petskillattack "MG_SIGHT",5,5,5; },{ bonus bMaxHP,30; bonus2 bSubEle,Ele_Water,1; } - -1519,CHUNG_E,Green Maiden,12395,9030,0,6115,80,60,50,100,250,20,2000,150,0,0,300,300,800,{ petskillattack "CR_SHIELDCHARGE",5,5,5; },{ bonus bDef,1; bonus2 bSubRace,RC_DemiHuman,1; bonus2 bSubRace,RC_Player,1; } -1879,ECLIPSE_P,Spring Rabbit,0,9031,0,7766,80,60,50,100,250,20,2000,150,0,0,300,300,800,{ petskillattack "TF_THROWSTONE",1,5,5; },{} -1122,GOBLIN_1,Goblin,14569,9032,0,7821,80,60,50,100,250,20,800,150,0,0,300,300,800,{ petskillattack "NPC_WINDATTACK",5,5,5; },{} -1123,GOBLIN_2,Goblin,14570,9033,0,7821,80,60,50,100,250,20,800,150,0,0,300,300,800,{ petskillattack "NPC_FIREATTACK",5,5,5; },{} -1125,GOBLIN_4,Goblin,14571,9034,0,7821,80,60,50,100,250,20,800,150,0,0,300,300,800,{ petskillattack "NPC_GROUNDATTACK",5,5,5; },{} -1385,DELETER_,Deleter,14572,9035,0,7822,80,60,20,100,250,20,800,150,0,0,300,300,800,{ petskillattack "SM_MAGNUM",5,5,5; },{} -1382,DIABOLIC,Diabolic,14573,9036,0,7823,80,60,10,100,250,20,800,150,0,0,300,300,800,{ petskillattack "WZ_METEOR",2,5,5; },{} -1208,WANDER_MAN,Wanderer,14574,9037,0,7824,80,60,20,100,250,20,800,150,0,0,300,300,800,{ petskillattack "NPC_UNDEADATTACK",5,5,5; },{ bonus bAgi,3; bonus bDex,1; } - -1963,P_CHUNG_E,New Year Doll,0,9038,0,554,80,60,30,100,250,20,800,150,0,0,300,300,800,{ petskillattack "CR_SHIELDCHARGE",5,5,5; },{} - -// New pets JapanRO Mobile -1040,GOLEM,Golem,12371,9053,10035,6111,80,60,20,100,250,20,500,150,0,0,300,300,800,{},{ bonus bMaxHP,100; bonus bFlee,-5; } -1143,MARIONETTE,Marionette,12361,9043,10025,6098,80,60,10,100,250,20,500,150,0,0,300,300,800,{},{ bonus bSPrecovRate,3; } -1148,MEDUSA,Medusa,12368,9050,10032,6108,80,60,10,100,250,20,200,150,0,0,300,300,800,{},{ bonus bVit,1; bonus2 bResEff,Eff_Stone,500; } -1179,WHISPER,Whisper,12363,9045,10027,6100,80,60,20,100,250,20,500,150,0,0,300,300,800,{},{ bonus bFlee,7; bonus bDef,-3; } -1299,GOBLIN_LEADER,Goblin Leader,12364,9046,10028,6104,80,60,10,100,250,20,50,150,0,0,300,300,800,{},{ bonus2 bAddRace,RC_DemiHuman,3; bonus2 bAddRace,RC_Player,3; } -1370,SUCCUBUS,Succubus,12373,9055,10037,6113,80,60,10,100,250,20,200,150,0,0,300,300,800,{ bonus2 bHPDrainRate,10,5; },{ bonus2 bHPDrainRate,30,5; bonus bMaxHPrate,1; } -1374,INCUBUS,Incubus,12370,9052,10034,6110,80,60,10,100,250,20,50,150,0,0,300,300,800,{ bonus bMaxSPRate,3; bonus2 bSPDrainRate,10,1; },{ bonus bMaxSPRate,5; bonus2 bSPDrainRate,30,1; } -1379,NIGHTMARE_TERROR,Nightmare Terror,12372,9054,10036,6112,80,60,10,100,250,20,200,150,0,0,300,300,800,{},{ bonus2 bResEff,Eff_Sleep,10000; } -1401,SHINOBI,Shinobi,12362,9044,10026,6099,80,60,20,100,250,20,500,150,0,0,300,300,800,{},{ bonus bAgi,2; } -1404,MIYABI_NINGYO,Miyabi Doll,12366,9048,10030,6106,80,60,15,100,250,20,200,150,0,0,300,300,800,{},{ bonus bInt,1; bonus bCastrate,-3; } -1416,WICKED_NYMPH,Evil Nymph,12365,9047,10029,6105,80,60,15,100,250,20,500,150,0,0,300,300,800,{},{ bonus bMaxSP,30; bonus bSPrecovRate,5; } -1495,STONE_SHOOTER,Stone Shooter,12369,9051,10033,6109,80,60,20,100,250,20,500,150,0,0,300,300,800,{},{ bonus2 bSubEle,Ele_Fire,3; } -1504,DULLAHAN,Dullahan,12367,9049,10031,6107,80,60,10,100,250,20,200,150,0,0,300,300,800,{},{ bonus bCritAtkRate,5; } -1505,LOLI_RURI,Loli Ruri,12360,9042,10024,6097,80,60,15,100,250,20,200,150,0,0,300,300,800,{},{ bonus bMaxHPRate,3; bonus3 bAutoSpellWhenHit,"AL_HEAL",1,10; } -1513,CIVIL_SERVANT,Mao Guai,12358,9040,10022,6095,80,60,10,100,250,20,500,150,0,0,300,300,800,{},{ bonus bMaxSP,10; } -1586,LEAF_CAT,Leaf Cat,12359,9041,10023,6096,80,60,20,100,250,20,200,150,0,0,300,300,800,{},{ bonus2 bSubRace,RC_Brute,3; } -1630,BACSOJIN_,White Lady,12357,9039,10021,6094,80,60,10,100,250,20,2000,150,0,0,300,300,800,{},{} -1837,IMP,Fire Imp,12374,9056,10038,6114,80,60,10,100,250,20,200,150,0,0,300,300,800,{},{ bonus2 bSubEle,Ele_Fire,2; bonus2 bAddEle,Ele_Fire,2; } - -// Brasilis Quest - Suspicious Beach [UNHATCHABLE] -2057,E_CRAMP,Strange Cramp,12408,6221,0,0,0,0,0,0,0,0,50,0,0,0,350,400,800,{},{} // kRO version -2081,E_HYDRA,Strange Hydra,12408,6221,0,0,0,0,0,0,0,0,50,0,0,0,350,400,800,{},{} // iRO/cRO version - -// New pets (FIX ME: pet bonuses for 2210 and 2313 do not require loyalty) -2200,J_TAINI,Tiny,0,9057,0,512,80,60,10,100,250,20,0,150,1,0,300,300,800,{},{} -2210,XMAS_LUNATIC,Christmas Snow Rabbit,0,9058,0,529,80,60,10,100,250,20,0,150,1,0,300,300,800,{},{ bonus2 bExpAddRace,RC_All,5; } -2313,TIKBALANG,Tikbalang,12699,9059,0,528,80,60,10,100,250,20,1000,150,1,0,300,300,800,{},{ bonus2 bAddDamageClass,2320,10; bonus2 bAddDamageClass,2321,10; bonus2 bAddDamageClass,2322,10; bonus2 bAddDamageClass,2317,10; bonus2 bAddDamageClass,2318,10; bonus2 bAddDamageClass,2327,10; bonus2 bAddDamageClass,2319,10; bonus2 bAddDamageClass,2333,10; bonus2 bAddDamageClass,2332,10; } -1242,MARIN,Marin,12789,9061,10039,6534,80,60,50,100,250,20,2000,150,1,0,300,300,800,{},{} -2398,LITTLE_PORING,Novice Poring,12846,9062,0,531,80,60,1000,0,250,0,5000,150,0,0,300,300,800,{},{ bonus bHPrecovRate,50; } - -// New pets from kRO 2014-10-08 (Needs more info) -//1090,MASTERING,Mastering,,9069,,,,,,,,,,,,,,,,,{ set .@i,getpetinfo(3); /*Awkward=LUK + 2, CRI + 1; Neutral=LUK + 3, CRI + 1; Cordial=LUK + 3, CRI + 2; Best Friend=LUK + 3, CRI + 3;*/ } -//1166,SAVAGE,Savage,,9070,,,,,,,,,,,,,,,,,{ set .@i,getpetinfo(3); /*Awkward=VIT + 1, MHP + 50; Neutral=VIT + 2, MHP + 50; Cordial=VIT + 2, MHP + 100; Best Friend=VIT + 2, MHP + 200;*/ } -//1369,GRAND_PECO,Grand Peco,,9071,,,,,,,,,,,,,,,,,{ set .@i,getpetinfo(3); /*Awkward=MHP + 150; Neutral=MHP + 200; Cordial=MHP + 300; Best Friend=MHP + 400;*/ } -//1213,HIGH_ORC,High Orc,,9087,,,,,,,,,,,,,,,,,{ set .@i,getpetinfo(3); /*Awkward=ATK + 10; Neutral=ATK + 15; Cordial=ATK + 20; Best Friend=ATK + 25;*/ } diff --git a/db/re/pet_db.yml b/db/re/pet_db.yml new file mode 100644 index 0000000000..158ad5811b --- /dev/null +++ b/db/re/pet_db.yml @@ -0,0 +1,1733 @@ +# This file is a part of rAthena. +# Copyright(C) 2019 rAthena Development Team +# https://rathena.org - https://github.com/rathena +# +# 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 3 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, see . +# +########################################################################### +# Renewal Pet Database +########################################################################### +# +# Pet Settings +# +########################################################################### +# - Mob Monster that can be used as pet +# TameItem Pet Tame Item. +# EggItem Pet Egg Item. +# EquipItem Pet Accessory Item. (Default: 0) +# FoodItem Pet Food Item. (Default: 0) +# Fullness The amount of hunger is decreased every [HungryDelay] seconds. +# HungryDelay The amount of time in seconds it takes for hunger to decrease after feeding. (Default: 60) +# HungerIncrease The amount of hunger that is increased every time the pet is fed (Default: 20) +# IntimacyStart Amount of Intimacy the pet starts with. (Default: 250) +# IntimacyFed Amount of Intimacy that is increased when fed. (Default: 50) +# IntimacyOverfed Amount of Intimacy that is increased when over-fed. (Default: -100) +# IntimacyHungry Amount of Intimacy that is increased when the pet is hungry. (Default: -5) +# IntimacyOwnerDie Amount of Intimacy that is increased when the pet owner dies. (Default: -20) +# CaptureRate Capture success rate. (10000 = 100%) +# SpecialPerformance If a pet has a Special Performance. (Default: true) +# AttackRate Rate of which the pet will attack [requires at least pet_support_min_friendly intimacy]. (10000 = 100%) +# RetaliateRate Rate of which the pet will retaliate when master is being attacked [requires at least pet_support_min_friendly intimacy]. (10000 = 100%) +# ChangeTargetRate Rate of which the pet will change its attack target. (10000 = 100%) +# AllowAutoFeed Allows turning automatic pet feeding on. (Default: false) +# Script Bonus script to execute when the pet is alive. (Default: null) +# SupportScript Bonus script to execute when pet_status_support is enabled. (Default: null) +# Evolution: Pet evolution settings. (Optional) (Default: null) +# - Target Mob this pet can evolve to. +# ItemRequirements: Item requirements for evolving this pet. +# - Item Self-explanatory +# Amount +########################################################################### + +Header: + Type: PET_DB + Version: 1 + +Body: + - Mob: PORING + TameItem: Unripe_Apple + EggItem: Poring_Egg + EquipItem: Backpack + FoodItem: Apple_Juice + Fullness: 3 + IntimacyFed: 50 + CaptureRate: 2000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bLuk,2; + bonus bCritical,1; + } + Evolution: + - Target: MASTERING + ItemRequirements: + - Item: Leaf_Of_Yggdrasil + Amount: 10 + - Item: Unripe_Apple + Amount: 3 + + - Mob: DROPS + TameItem: Orange_Juice + EggItem: Drops_Egg + EquipItem: Backpack + FoodItem: Yellow_Herb + Fullness: 4 + IntimacyFed: 40 + CaptureRate: 1500 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bHit,3; + bonus bAtk,3; + } + Evolution: + - Target: DR_EGGRING + ItemRequirements: + - Item: Piece_Of_Egg_Shell + Amount: 20 + - Item: Old_Frying_Pan + Amount: 10 + - Item: Apple_Juice + Amount: 3 + - Item: Eggring_Card + Amount: 1 + - Target: SWEETS_DROPS + ItemRequirements: + - Item: Sweets_Festival_Coin + Amount: 500 + - Item: Candy + Amount: 50 + - Item: Candy_Striper + Amount: 50 + - Item: Drops_Card + Amount: 1 + - Mob: POPORING + TameItem: Bitter_Herb + EggItem: Poporing_Egg + EquipItem: Backpack + FoodItem: Green_Herb + Fullness: 5 + IntimacyFed: 30 + CaptureRate: 1000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bLuk,2; + bonus2 bSubEle,Ele_Poison,10; + } + - Mob: LUNATIC + TameItem: Rainbow_Carrot + EggItem: Lunatic_Egg + EquipItem: Silk_Ribbon + FoodItem: Carrot_Juice + Fullness: 4 + IntimacyFed: 40 + CaptureRate: 1500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bCritical,2; + bonus bAtk,2; + } + Evolution: + - Target: DR_LUNATIC + ItemRequirements: + - Item: Great_Leaf + Amount: 100 + - Item: Clover + Amount: 250 + - Item: Four_Leaf_Clover + Amount: 30 + - Item: Leaf_Lunatic_Card + Amount: 1 + + - Mob: PICKY + TameItem: Earthworm_The_Dude + EggItem: Picky_Egg + EquipItem: Tiny_Egg_Shell + FoodItem: Red_Herb + Fullness: 4 + IntimacyFed: 40 + CaptureRate: 2000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bStr,1; + bonus bAtk,5; + } + - Mob: CHONCHON + TameItem: Rotten_Fish + EggItem: Chonchon_Egg + EquipItem: Monster_Oxygen_Mask + FoodItem: Pet_Food + Fullness: 6 + IntimacyFed: 30 + CaptureRate: 1500 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bAgi,1; + bonus bFlee,2; + } + - Mob: STEEL_CHONCHON + TameItem: Lusty_Iron + EggItem: Steel_Chonchon_Egg + EquipItem: Monster_Oxygen_Mask + FoodItem: Iron_Ore + Fullness: 5 + IntimacyFed: 20 + CaptureRate: 1000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bFlee,6; + bonus bAgi,-1; + } + - Mob: HUNTER_FLY + TameItem: Monster_Juice + EggItem: Hunter_Fly_Egg + EquipItem: Monster_Oxygen_Mask + FoodItem: Red_Gemstone + Fullness: 5 + IntimacyFed: 10 + CaptureRate: 500 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bFlee,-5; + bonus bFlee2,2; + } + - Mob: SAVAGE_BABE + TameItem: Sweet_Milk + EggItem: Savage_Bebe_Egg + EquipItem: Green_Lace + FoodItem: Pet_Food + Fullness: 7 + IntimacyFed: 40 + CaptureRate: 1500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bVit,1; + bonus bMaxHP,50; + } + Evolution: + - Target: SAVAGE + ItemRequirements: + - Item: Pet_Food + Amount: 10 + - Item: Sweet_Milk + Amount: 3 + - Item: Meat + Amount: 100 + - Item: Feather + Amount: 50 + - Mob: DESERT_WOLF_B + TameItem: Well_Dried_Bone + EggItem: Baby_Desert_Wolf_Egg + EquipItem: Transparent_Headgear + FoodItem: Pet_Food + Fullness: 6 + IntimacyFed: 40 + CaptureRate: 1000 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bInt,1; + bonus bMaxSP,50; + } + - Mob: ROCKER + TameItem: Singing_Flower + EggItem: Rocker_Egg + EquipItem: Rocker_Glasses + FoodItem: Pet_Food + Fullness: 1 + IntimacyFed: 30 + CaptureRate: 1500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bHPrecovRate,5; + bonus bMaxHP,25; + } + Evolution: + - Target: METALLER + ItemRequirements: + - Item: Singing_Plant + Amount: 3 + - Item: Grasshopper's_Leg + Amount: 777 + - Item: Yellow_Herb + Amount: 200 + - Item: Metaller_Card + Amount: 1 + - Mob: SPORE + TameItem: Dew_Laden_Moss + EggItem: Spore_Egg + EquipItem: Bark_Shorts + FoodItem: Pet_Food + Fullness: 3 + IntimacyFed: 30 + CaptureRate: 1500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bHit,5; + bonus bAtk,-2; + } + - Mob: POISON_SPORE + TameItem: Deadly_Noxious_Herb + EggItem: Poison_Spore_Egg + EquipItem: Bark_Shorts + FoodItem: Pet_Food + Fullness: 3 + IntimacyFed: 20 + CaptureRate: 1000 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bStr,1; + bonus bInt,1; + } + - Mob: PECOPECO + TameItem: Fatty_Chubby_Earthworm + EggItem: PecoPeco_Egg + EquipItem: Battered_Pot + FoodItem: Pet_Food + Fullness: 4 + IntimacyFed: 30 + CaptureRate: 1000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxHP,150; + bonus bMaxSP,-10; + } + Evolution: + - Target: GRAND_PECO + ItemRequirements: + - Item: Pet_Food + Amount: 10 + - Item: Fatty_Chubby_Earthworm + Amount: 3 + - Item: Peco_Wing_Feather + Amount: 300 + - Item: Pecopeco_Card + Amount: 1 + - Item: Fruit_Of_Mastela + Amount: 10 + - Mob: SMOKIE + TameItem: Baked_Yam + EggItem: Smokie_Egg + EquipItem: Red_Muffler + FoodItem: Pet_Food + Fullness: 4 + IntimacyFed: 30 + CaptureRate: 1000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bAgi,1; + bonus bFlee2,1; + } + - Mob: YOYO + TameItem: Tropical_Banana + EggItem: Yoyo_Egg + EquipItem: Monkey_Circlet + FoodItem: Banana_Juice + Fullness: 5 + IntimacyFed: 20 + CaptureRate: 1000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bCritical,3; + bonus bLuk,-1; + } + Evolution: + - Target: CHOCO + ItemRequirements: + - Item: Tropical_Banana + Amount: 3 + - Item: Monkey_Doll + Amount: 2 + - Item: Cacao + Amount: 300 + - Item: Yoyo_Card + Amount: 1 + - Mob: ORK_WARRIOR + TameItem: Horror_Of_Tribe + EggItem: Orc_Warrior_Egg + EquipItem: Wild_Flower + FoodItem: Pet_Food + Fullness: 5 + IntimacyFed: 20 + CaptureRate: 500 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bAtk,10; + bonus bDef,-3; + } + Evolution: + - Target: HIGH_ORC + ItemRequirements: + - Item: Horror_Of_Tribe + Amount: 3 + - Item: Orcish_Sword + Amount: 1 + - Item: Orcish_Voucher + Amount: 500 + - Item: Cigar + Amount: 1 + - Item: Orc_Warrior_Card + Amount: 1 + - Mob: MUNAK + TameItem: No_Recipient + EggItem: Munak_Egg + EquipItem: Punisher + FoodItem: Pet_Food + Fullness: 3 + IntimacyFed: 20 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bInt,1; + bonus bDef,1; + } + - Mob: DOKEBI + TameItem: Old_Broom + EggItem: Dokkaebi_Egg + EquipItem: Wig + FoodItem: Pet_Food + Fullness: 4 + IntimacyFed: 20 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMatkRate,1; + bonus bAtkRate,-1; + } + Evolution: + - Target: AM_MUT + ItemRequirements: + - Item: Old_Broom + Amount: 3 + - Item: Violet_Dyestuffs + Amount: 3 + - Item: Dokkaebi_Horn + Amount: 300 + - Item: Gold + Amount: 3 + - Mob: SOHEE + TameItem: Silver_Knife_Of_Chaste + EggItem: Sohee_Egg + EquipItem: Golden_Bell + FoodItem: Pet_Food + Fullness: 3 + IntimacyFed: 10 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bStr,1; + bonus bDex,1; + } + - Mob: ISIS + TameItem: Armlet_Of_Obedience + EggItem: Isis_Egg + EquipItem: Queen's_Hair_Ornament + FoodItem: Pet_Food + Fullness: 3 + IntimacyFed: 10 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMatkRate,-1; + bonus bAtkRate,1; + } + Evolution: + - Target: LITTLE_ISIS + ItemRequirements: + - Item: Armlet_Of_Obedience + Amount: 3 + - Item: Crystal_Jewel__ + Amount: 6 + - Item: Queen's_Hair_Ornament + Amount: 1 + - Item: Shining_Scales + Amount: 300 + - Mob: PETIT + TameItem: Shining_Stone + EggItem: Green_Petite_Egg + EquipItem: Stellar_Hairpin + FoodItem: Pet_Food + Fullness: 4 + IntimacyFed: 20 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bDef,-2; + bonus bMdef,-2; + bonus bAspdRate,1; + } + Evolution: + - Target: DELETER_2 + ItemRequirements: + - Item: Shining_Stone + Amount: 3 + - Item: Petti_Tail + Amount: 100 + - Item: Aloebera + Amount: 150 + - Item: Deleter_Card + Amount: 1 + - Mob: DEVIRUCHI + TameItem: Contracts_In_Shadow + EggItem: Deviruchi_Egg + EquipItem: Pacifier + FoodItem: Shoot + Fullness: 2 + IntimacyFed: 10 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMatkRate,1; + bonus bAtkRate,1; + bonus bMaxHPrate,-3; + bonus bMaxSPrate,-3; + } + Evolution: + - Target: DIABOLIC2 + ItemRequirements: + - Item: Contracts_In_Shadow + Amount: 3 + - Item: Petite_DiablOfs_Wing + Amount: 250 + - Item: Sacred_Marks + Amount: 30 + - Item: Deviruchi_Card + Amount: 1 + - Mob: BAPHOMET_ + TameItem: Book_Of_Devil + EggItem: Bapho_Jr._Egg + EquipItem: Skull_Helm + FoodItem: Honey + Fullness: 2 + IntimacyFed: 10 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bDef,1; + bonus bMdef,1; + bonus2 bResEff,Eff_Stun,-100; + } + - Mob: BON_GUN + TameItem: Heart_Of_Her + EggItem: Bongun_Egg + EquipItem: Sword_Of_Grave_Keeper + FoodItem: Pet_Food + Fullness: 4 + IntimacyFed: 30 + CaptureRate: 500 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bVit,1; + bonus2 bResEff,Eff_Stun,100; + } + Evolution: + - Target: HYEGUN + ItemRequirements: + - Item: Hyegun_Hat + Amount: 1 + - Item: Munak_Doll + Amount: 100 + - Item: Old_Portrait + Amount: 50 + - Item: Hyegun_Card + Amount: 1 + - Mob: ZHERLTHSH + TameItem: Prohibition_Red_Candle + EggItem: Zherlthsh_Egg + FoodItem: Immortal_Heart + Fullness: 7 + IntimacyFed: 10 + CaptureRate: 300 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bAddRace,RC_Demihuman,2; + bonus2 bMagicAddRace,RC_DemiHuman,2; + bonus2 bAddRace,RC_Player,2; + bonus2 bMagicAddRace,RC_Player,2; + } + - Mob: ALICE + TameItem: Sway_Apron + EggItem: Alice_Egg + FoodItem: White_Potion + Fullness: 2 + IntimacyFed: 20 + CaptureRate: 800 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMdef,1; + bonus2 bSubRace,RC_DemiHuman,1; + bonus2 bSubRace,RC_Player,1; + } + - Mob: EVENT_RICECAKE + EggItem: Rice_Cake_Egg + FoodItem: Green_Herb + Fullness: 3 + IntimacyFed: 50 + CaptureRate: 2000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bSubEle,Ele_Neutral,1; + bonus bMaxHPrate,-1; + } + - Mob: GOBLINE_XMAS + TameItem: Sweet_Candy_Striper + EggItem: Santa_Goblin_Egg + FoodItem: Scell + Fullness: 3 + IntimacyFed: 50 + CaptureRate: 2000 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxHP,30; + bonus2 bSubEle,Ele_Water,1; + } + - Mob: CHUNG_E + TameItem: Tantanmen + EggItem: Chung_E_Egg + FoodItem: Bun_ + Fullness: 3 + IntimacyFed: 50 + CaptureRate: 2000 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bDef,1; + bonus2 bSubRace,RC_DemiHuman,1; + bonus2 bSubRace,RC_Player,1; + } + - Mob: ECLIPSE_P + EggItem: Spring_Rabbit_Egg + FoodItem: Bok_Choy + Fullness: 3 + IntimacyFed: 50 + CaptureRate: 2000 + SpecialPerformance: false + - Mob: GOBLIN_1 + TameItem: Knife_Goblin_Ring + EggItem: Knife_Goblin_Egg + FoodItem: Green_Apple + Fullness: 3 + IntimacyFed: 50 + CaptureRate: 800 + SpecialPerformance: false + - Mob: GOBLIN_2 + TameItem: Flail_Goblin_Ring + EggItem: Flail_Goblin_Egg + FoodItem: Green_Apple + Fullness: 3 + IntimacyFed: 50 + CaptureRate: 800 + SpecialPerformance: false + - Mob: GOBLIN_4 + TameItem: Hammer_Goblin_Ring + EggItem: Hammer_Goblin_Egg + FoodItem: Green_Apple + Fullness: 3 + IntimacyFed: 50 + CaptureRate: 800 + SpecialPerformance: false + - Mob: DELETER_ + TameItem: Holy_Marble + EggItem: Red_Deleter_Egg + FoodItem: Whole_Barbecue + Fullness: 4 + IntimacyFed: 20 + CaptureRate: 800 + SpecialPerformance: false + - Mob: DIABOLIC + TameItem: Red_Burning_Stone + EggItem: Diabolic_Egg + FoodItem: Meat_Veg_Skewer + Fullness: 2 + IntimacyFed: 10 + CaptureRate: 800 + SpecialPerformance: false + - Mob: WANDER_MAN + TameItem: Skull_Of_Vagabond + EggItem: Wanderer_Egg + FoodItem: Spirit_Liquor + Fullness: 2 + IntimacyFed: 20 + CaptureRate: 800 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bAgi,3; + bonus bDex,1; + } + - Mob: P_CHUNG_E + EggItem: New_Year_Doll_Egg + FoodItem: Mojji + Fullness: 3 + IntimacyFed: 30 + CaptureRate: 800 + SpecialPerformance: false + - Mob: GOLEM + TameItem: Magical_Lithography + EggItem: Golem_Egg + EquipItem: Windup_Spring + FoodItem: Mystic_Stone + Fullness: 7 + IntimacyFed: 20 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxHP,100; + bonus bFlee,-5; + } + - Mob: MARIONETTE + TameItem: Delicious_Shaved_Ice + EggItem: Marionette_Egg + EquipItem: Star_Hairband + FoodItem: Small_Snow_Flower + Fullness: 3 + IntimacyFed: 10 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bSPrecovRate,3; + } + - Mob: MEDUSA + TameItem: Splendid_Mirror + EggItem: Medusa_Egg + EquipItem: Queen's_Coronet + FoodItem: Apple_Pudding + Fullness: 3 + IntimacyFed: 10 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bVit,1; + bonus2 bResEff,Eff_Stone,500; + } + - Mob: WHISPER + TameItem: Fit_Pipe + EggItem: Whisper_Egg + EquipItem: Spirit_Chain_ + FoodItem: Damp_Darkness + Fullness: 7 + IntimacyFed: 20 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bFlee,7; + bonus bDef,-3; + } + - Mob: GOBLIN_LEADER + TameItem: Staff_Of_Leader + EggItem: Goblin_Leader_Egg + EquipItem: Nice_Badge + FoodItem: Big_Cell + Fullness: 7 + IntimacyFed: 10 + CaptureRate: 50 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bAddRace,RC_DemiHuman,3; + bonus2 bAddRace,RC_Player,3; + } + - Mob: SUCCUBUS + TameItem: Boy's_Naivety + EggItem: Succubus_Egg + EquipItem: Black_Butterfly_Mask + FoodItem: Vital_Flower_ + Fullness: 3 + IntimacyFed: 10 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bHPDrainRate,30,5; + bonus bMaxHPrate,1; + } + - Mob: INCUBUS + TameItem: Gril's_Naivety + EggItem: Incubus_Egg + EquipItem: Ball_Mask + FoodItem: Vital_Flower + Fullness: 3 + IntimacyFed: 10 + CaptureRate: 50 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxSPRate,5; + bonus2 bSPDrainRate,30,1; + } + - Mob: NIGHTMARE_TERROR + TameItem: Hell_Contract + EggItem: Nightmare_Terror_Egg + EquipItem: Hell_Horn + FoodItem: Fresh_Plant + Fullness: 3 + IntimacyFed: 10 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bResEff,Eff_Sleep,10000; + } + - Mob: SHINOBI + TameItem: Kuloren + EggItem: Shinobi_Egg + EquipItem: Wine_On_Sleeve + FoodItem: Grilled_Rice_Cake + Fullness: 7 + IntimacyFed: 20 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bAgi,2; + } + - Mob: MIYABI_NINGYO + TameItem: Gril_Doll + EggItem: Miyabi_Ningyo_Egg + EquipItem: Summer_Fan + FoodItem: Well_Ripened_Berry + Fullness: 3 + IntimacyFed: 15 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bInt,1; + bonus bCastrate,-3; + } + - Mob: WICKED_NYMPH + TameItem: Charming_Lotus + EggItem: Wicked_Nymph_Egg + EquipItem: Jade_Trinket + FoodItem: Morning_Dew + Fullness: 3 + IntimacyFed: 15 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxSP,30; + bonus bSPrecovRate,5; + } + - Mob: STONE_SHOOTER + TameItem: Oilpalm_Coconut + EggItem: Stone_Shooter_Egg + EquipItem: Apro_Hair + FoodItem: Plant_Neutrient + Fullness: 7 + IntimacyFed: 20 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bSubEle,Ele_Fire,3; + } + - Mob: DULLAHAN + TameItem: Luxury_Whisky_Bottle + EggItem: Dullahan_Egg + EquipItem: Death_Coil + FoodItem: Sunset_On_The_Rock + Fullness: 3 + IntimacyFed: 10 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bCritAtkRate,5; + } + - Mob: LOLI_RURI + TameItem: Very_Red_Juice + EggItem: Loli_Ruri_Egg + EquipItem: Fashionable_Glasses + FoodItem: Pumpkin_Pie_ + Fullness: 3 + IntimacyFed: 15 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxHPRate,3; + bonus3 bAutoSpellWhenHit,"AL_HEAL",1,10; + } + - Mob: CIVIL_SERVANT + TameItem: Fan_Of_Wind + EggItem: Civil_Servant_Egg + EquipItem: Golden_Earing + FoodItem: Flavored_Alcohol + Fullness: 3 + IntimacyFed: 10 + CaptureRate: 500 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxSP,10; + } + - Mob: LEAF_CAT + TameItem: Very_Soft_Plant + EggItem: Leaf_Cat_Egg + EquipItem: Green_Lucky_Bag + FoodItem: Fish_With_Blue_Back + Fullness: 7 + IntimacyFed: 20 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bSubRace,RC_Brute,3; + } + - Mob: BACSOJIN_ + TameItem: Shiny_Wing_Gown + EggItem: Bacsojin_Egg + EquipItem: Round_Hair_Ornament + FoodItem: Traditional_Cookie + Fullness: 7 + IntimacyFed: 10 + CaptureRate: 2000 + SpecialPerformance: false + - Mob: IMP + TameItem: Flaming_Ice + EggItem: Imp_Egg + EquipItem: Horn_Protector + FoodItem: Flame_Gemstone + Fullness: 3 + IntimacyFed: 10 + CaptureRate: 200 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bSubEle,Ele_Fire,2; + bonus2 bAddEle,Ele_Fire,2; + } + - Mob: E_CRAMP + TameItem: Leaf_Cat_Ball + EggItem: Mystic_Leaf_Cat_Ball + Fullness: 0 + HungryDelay: 0 + IntimacyStart: 0 + IntimacyFed: 0 + IntimacyOverfed: 0 + IntimacyOwnerDie: 0 + CaptureRate: 50 + SpecialPerformance: false + - Mob: E_HYDRA + TameItem: Leaf_Cat_Ball + EggItem: Mystic_Leaf_Cat_Ball + Fullness: 0 + HungryDelay: 0 + IntimacyStart: 0 + IntimacyFed: 0 + IntimacyOverfed: 0 + IntimacyOwnerDie: 0 + CaptureRate: 50 + SpecialPerformance: false + - Mob: J_TAINI + EggItem: Egg_Of_Tiny + FoodItem: Apple + Fullness: 3 + IntimacyFed: 10 + CaptureRate: 0 + - Mob: XMAS_LUNATIC + EggItem: Snow_Rabbit_Egg + FoodItem: Candy + Fullness: 3 + IntimacyFed: 10 + CaptureRate: 0 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bExpAddRace,RC_All,5; + } + - Mob: TIKBALANG + TameItem: Tikbalang_Belt + EggItem: Tikbalang_Pet + FoodItem: Monster's_Feed + Fullness: 8 + IntimacyFed: 10 + CaptureRate: 1000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus2 bAddDamageClass,2317,10; + bonus2 bAddDamageClass,2318,10; + bonus2 bAddDamageClass,2319,10; + bonus2 bAddDamageClass,2320,10; + bonus2 bAddDamageClass,2321,10; + bonus2 bAddDamageClass,2322,10; + bonus2 bAddDamageClass,2327,10; + bonus2 bAddDamageClass,2332,10; + bonus2 bAddDamageClass,2333,10; + } + - Mob: MARIN + TameItem: Juicy_Fruit + EggItem: Marin_Egg + EquipItem: Tw_Backpack + FoodItem: Fruit_Sundae + Fullness: 3 + IntimacyFed: 50 + CaptureRate: 2000 + - Mob: LITTLE_PORING + TameItem: Unripe_Apple2 + EggItem: Novice_Poring_Egg + FoodItem: Apple_Juice + Fullness: 3 + IntimacyFed: 1000 + IntimacyOverfed: 0 + IntimacyOwnerDie: 0 + CaptureRate: 5000 + SpecialPerformance: false + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bHPrecovRate,50; + } + - Mob: NINE_TAIL + TameItem: Sap_Liquid + EggItem: Nine_Tail_Egg + FoodItem: Suspicious_Bottle + Fullness: 4 + IntimacyFed: 50 + CaptureRate: 2000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bCritical,3; + bonus bHit,2; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bCritical,2; + bonus bHit,2; + } + Evolution: + - Target: CAT_O_NINE_TAIL + ItemRequirements: + - Item: Sap_Liquid + Amount: 3 + - Item: Fox_Tail + Amount: 999 + - Item: Punisher + Amount: 1 + - Item: Nine_Tail_Card + Amount: 1 + - Mob: GREMLIN + TameItem: Unprocessed_Parts + EggItem: Gremlin_Egg + FoodItem: Cheap_Lubricant + Fullness: 4 + IntimacyFed: 50 + CaptureRate: 2000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus Dex,2; + bonus bHit,1; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bDex,1; + bonus bHit,1; + } + Evolution: + - Target: HODREMLIN + ItemRequirements: + - Item: Unprocessed_Parts + Amount: 3 + - Item: Damp_Darkness + Amount: 50 + - Item: Will_Of_Darkness + Amount: 200 + - Item: Hodremlin_Card + Amount: 1 + - Mob: MUMMY + TameItem: Elixir_Bandages + EggItem: Mummy_Egg + FoodItem: Mementos + Fullness: 7 + IntimacyFed: 50 + CaptureRate: 2000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bHit,5; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bHit,4; + } + Evolution: + - Target: ANCIENT_MUMMY + ItemRequirements: + - Item: Elixir_Bandages + Amount: 3 + - Item: Rune_Of_Darkness + Amount: 200 + - Item: Gold + Amount: 30 + - Item: Ancient_Mummy_Card + Amount: 1 + - Mob: TEDDY_BEAR + TameItem: Small_Needle_Kit + EggItem: Teddy_Bear_Egg + FoodItem: Cotton_Tufts + Fullness: 3 + IntimacyFed: 50 + CaptureRate: 2000 + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bMaxSP,150; + } + Evolution: + - Target: XM_TEDDY_BEAR + ItemRequirements: + - Item: Small_Needle_Kit + Amount: 3 + - Item: Cursed_Seal + Amount: 300 + - Item: Cardinal_Jewel_ + Amount: 50 + - Item: Teddy_Bear_Card + Amount: 1 + + # Pet Evolution, most are dummy values + - Mob: MASTERING + EggItem: Mastering_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bLuk,3; + bonus bCritical,3; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bLuk,3; + bonus bCritical,2; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bLuk,3; + bonus bCritical,1; + }else{ + bonus bLuk,2; + bonus bCritical,1; + } + Evolution: + - Target: ANGELING + ItemRequirements: + - Item: Yellow_Potion + Amount: 20 + - Item: Spirit_Chain + Amount: 1 + - Item: White_Herb + Amount: 50 + - Item: Jellopy + Amount: 200 + - Mob: METALLER + EggItem: Metaller_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bHPrecovRate,20; + bonus bMaxHP,70; + bonus2 bAddRace,RC_Plant,6; + bonus2 bMagicAddRace,RC_Plant,6; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bHPrecovRate,15; + bonus bMaxHP,55; + bonus2 bAddRace,RC_Plant,3; + bonus2 bMagicAddRace,RC_Plant,3; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bHPrecovRate,10; + bonus bMaxHP,38; + }else{ + bonus bHPrecovRate,5; + bonus bMaxHP,25; + } + - Mob: ANGELING + EggItem: Angeling_Egg + FoodItem: Pet_Food + Fullness: 1 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxHPrate,2; + bonus bHealPower,8; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bMaxHPrate,2; + bonus bHealPower,6; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bMaxHPrate,1; + bonus bHealPower,4; + }else{ + bonus bMaxHPrate,1; + bonus bHealPower,2; + } + - Mob: MOONLIGHT + EggItem: Moonlight_Egg + FoodItem: Luxurious_Pet_Food + Fullness: 1 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bCritical,6; + bonus bHit,6; + autobonus "{ bonus bHPRegenRate,500,1000; bonus bSPRegenRate,20,1000; }",30,5000,BF_WEAPON|BF_SHORT; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bCritical,5; + bonus bHit,5; + autobonus "{ bonus bHPRegenRate,400,1000; bonus bSPRegenRate,10,1000; }",30,5000,BF_WEAPON|BF_SHORT; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bCritical,4; + bonus bHit,4; + autobonus "{ bonus bHPRegenRate,300,1000; }",20,5000,BF_WEAPON|BF_SHORT; + }else{ + bonus bCritical,3; + bonus bHit,3; + } + - Mob: SAVAGE + EggItem: Savage_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxHP,200; + bonus bVit,2; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bMaxHP,100; + bonus bVit,2; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bMaxHP,50; + bonus bVit,2; + }else{ + bonus bMaxHP,50; + bonus bVit,1; + } + - Mob: HIGH_ORC + EggItem: High_Orc_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxHP,200; + bonus bVit,2; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bMaxHP,100; + bonus bVit,2; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bMaxHP,50; + bonus bVit,2; + }else{ + bonus bMaxHP,50; + bonus bVit,1; + } + - Mob: CHOCO + EggItem: Choco_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bCritical,9; + bonus bLongAtkRate,3; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bCritical,7; + bonus bLongAtkRate,2; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bCritical,5; + bonus bLongAtkRate,1; + }else{ + bonus bCritical,3; + } + - Mob: ANCIENT_MUMMY + EggItem: Ancient_Mummy_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bHit,6; + bonus2 bAddClass,Class_All,6; + bonus2 bMagicAddClass,Class_All,6; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bHit,6; + bonus2 bAddClass,Class_All,3; + bonus2 bMagicAddClass,Class_All,3; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bHit,5; + }else{ + bonus bHit,4; + } + - Mob: AM_MUT + EggItem: Am_Mut_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMatkRate,4; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bMatkRate,3; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bMatkRate,2; + }else{ + bonus bMatkRate,1; + } + - Mob: CAT_O_NINE_TAIL + EggItem: Cat_o_Nine_Tail_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bCritical,5; + bonus bHit,5; + autobonus "{ bonus bHPRegenRate,400,1000; }",20,5000,BF_WEAPON|BF_SHORT; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bCritical,4; + bonus bHit,4; + autobonus "{ bonus bHPRegenRate,300,1000; }",20,5000,BF_WEAPON|BF_SHORT; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bCritical,3; + bonus bHit,3; + }else{ + bonus bCritical,2; + bonus bHit,2; + } + Evolution: + - Target: MOONLIGHT + ItemRequirements: + - Item: Powerful_Soul_Essence + Amount: 30 + - Item: Nine_Tail_Card + Amount: 10 + - Item: Sohee_Card + Amount: 10 + - Item: Munak_Card + Amount: 10 + - Mob: GRAND_PECO + EggItem: Grand_Peco_Peco_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxHP,400; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bMaxHP,300; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bMaxHP,200; + }else{ + bonus bMaxHP,150; + } + - Mob: HYEGUN + EggItem: Hyegun_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bVit,4; + bonus2 bResEff,Eff_Stun,400; + bonus2 bSPDrainRate,20,1; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bVit,3; + bonus2 bResEff,Eff_Stun,300; + bonus2 bSPDrainRate,10,1; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bVit,2; + bonus2 bResEff,Eff_Stun,200; + }else{ + bonus bVit,1; + bonus2 bResEff,Eff_Stun,100; + } + - Mob: HODREMLIN + EggItem: Hodremlin_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bDex,2; + bonus bHit,2; + bonus bCritAtkRate,9; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bDex,2; + bonus bHit,2; + bonus bCritAtkRate,7; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bDex,2; + bonus bHit,1; + }else{ + bonus bDex,1; + bonus bHit,1; + } + - Mob: XM_TEDDY_BEAR + EggItem: Xm_Teddy_Bear_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bMaxSP,150; + autobonus "{ bonus bSPRegenRate,40,1000; }",30,5000,BF_MAGIC; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bMaxSP,150; + autobonus "{ bonus bSPRegenRate,30,1000; }",30,5000,BF_MAGIC; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bMaxSP,100; + }else{ + bonus bMaxSP,50; + } + - Mob: DR_EGGRING + EggItem: Eggring_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bHit,9; + bonus bAtk,9; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bHit,7; + bonus bAtk,7; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bHit,5; + bonus bAtk,5; + }else{ + bonus bHit,3; + bonus bAtk,3; + } + - Mob: DR_LUNATIC + EggItem: Dr_Lunatic_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bCritical,5; + bonus bAtk,5; + bonus2 bAddRace,RC_Formless,6; + bonus2 bMagicAddRace,RC_Formless,6; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bCritical,4; + bonus bAtk,4; + bonus2 bAddRace,RC_Formless,3; + bonus2 bMagicAddRace,RC_Formless,3; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bCritical,3; + bonus bAtk,3; + }else{ + bonus bCritical,2; + bonus bAtk,2; + } + - Mob: LITTLE_ISIS + EggItem: Little_Isis_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bAtkRate,4; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bAtkRate,3; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bAtkRate,2; + }else{ + bonus bAtkRate,1; + } + - Mob: DIABOLIC2 + EggItem: Diabolic_2_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bAtkRate,2; + bonus bMatkRate,2; + bonus bMaxHPrate,1; + bonus bMaxSPrate,1; + bonus5 bAutoSpell,"MG_FIREBOLT",3,50,BF_WEAPON|BF_SHORT,1; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bAtkRate,1; + bonus bMatkRate,1; + bonus bMaxHPrate,1; + bonus bMaxSPrate,1; + }else{ + bonus bAtkRate,1; + bonus bMatkRate,1; + } + - Mob: DELETER_2 + EggItem: Fire_Deleter_Egg + FoodItem: Pet_Food + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_LOYAL ){ + bonus bAspdRate,3; + bonus bAgi,3; + }else if( .@i >= PET_INTIMATE_CORDIAL ){ + bonus bAspdRate,2; + bonus bAgi,2; + }else if( .@i >= PET_INTIMATE_NEUTRAL ){ + bonus bAspdRate,2; + bonus bAgi,1; + }else{ + bonus bAspdRate,1; + } + - Mob: SWEETS_DROPS + EggItem: Sweet_Drops_Egg + FoodItem: Candy + Fullness: 2 + HungryDelay: 120 + IntimacyFed: 15 + CaptureRate: 0 + SpecialPerformance: false + AllowAutoFeed: true + Script: > + .@i = getpetinfo(PETINFO_INTIMATE); + + if( .@i >= PET_INTIMATE_CORDIAL ){ + /* bonus2 bExpAddClass,Class_All,3; */ + bonus2 bExpAddClass,Class_All,1; + } diff --git a/doc/atcommands.txt b/doc/atcommands.txt index e546720e2f..bed1b55805 100644 --- a/doc/atcommands.txt +++ b/doc/atcommands.txt @@ -1361,7 +1361,7 @@ Affected files: -- battleconf: battle_athena.conf, battle_conf.txt -- instancedb: instance_db.txt -- itemdb: item_db.txt, item_group_db.txt, item_trade.txt, item_noequip.txt, item_nouse.txt, item_combo_db.txt, item_avail.txt, item_stack.txt, item_delay.txt, item_buyingstore.txt, item_flag.txt --- mobdb: mob_db.txt, mob_item_ratio.txt, mob_chat_db.txt, mob_avail.txt, mob_race2_db.txt, mob_branch.txt, mob_poring.txt, mob_boss.txt, mob_pouch.txt, mob_classchange.txt, pet_db.txt, homunculus_db.txt, homun_skill_tree.txt, exp_homun.txt, mercenary_db.txt, mercenary_skill_db.txt, elemental_db.txt, elemental_skill_db.txt +-- mobdb: mob_db.txt, mob_item_ratio.txt, mob_chat_db.txt, mob_avail.txt, mob_race2_db.txt, mob_branch.txt, mob_poring.txt, mob_boss.txt, mob_pouch.txt, mob_classchange.txt, pet_db.yml, homunculus_db.txt, homun_skill_tree.txt, exp_homun.txt, mercenary_db.txt, mercenary_skill_db.txt, elemental_db.txt, elemental_skill_db.txt -- motd: motd.txt -- msgconf: atcommand_athena.conf -- pcdb: statpoint.txt, job_exp.txt, skill_tree.txt, attr_fix.txt, job_db1.txt, job_db2.txt, job_basehpsp_db.txt, job_maxhpsp_db.txt, job_param_db.txt, level_penalty.txt diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 0d9c427887..8b2e30c14e 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -9380,7 +9380,7 @@ monster as long as it is in the pet database and the targeted monster requires t item used. See 'doc/mob_db_mode_list.txt' for more information about monster modes. -A full list of pet IDs can be found inside 'db/(pre-)re/pet_db.txt'. +A full list of pet IDs can be found inside 'db/(pre-)re/pet_db.yml'. --------------------------------------- @@ -9388,7 +9388,7 @@ A full list of pet IDs can be found inside 'db/(pre-)re/pet_db.txt'. This command will create a pet egg and put it in the invoking character's inventory. The kind of pet is specified by pet ID numbers listed in -'db/(pre-)re/pet_db.txt'. The egg is created exactly as if the character just successfully +'db/(pre-)re/pet_db.yml'. The egg is created exactly as if the character just successfully caught a pet in the normal way. // This will make you a poring: @@ -9406,16 +9406,40 @@ This function will return pet information for the pet the invoking character currently has active. Valid types are: PETINFO_ID - Pet ID - PETINFO_CLASS - Pet class number as per 'db/(pre-)re/pet_db.txt' - will tell you what kind of a pet it - is. + PETINFO_CLASS - Pet class number as per 'db/(pre-)re/pet_db.yml' - will tell you what kind of a pet it is. PETINFO_NAME - Pet name. Will return "null" if there's no pet. PETINFO_INTIMATE - Pet friendly level (intimacy score). 1000 is full loyalty. - PETINFO_HUNGRY - Pet hungry level. 100 is completely full. + PETINFO_HUNGRY - Pet hungry level. 100 is full hunger. PETINFO_RENAMED - Pet rename flag. 0 means this pet has not been named yet. PETINFO_LEVEL - Pet level PETINFO_BLOCKID - Pet Game ID - PETINFO_EGGID - Pet egg item id - PETINFO_FOODID - Pet food item id + PETINFO_EGGID - Pet egg item ID + PETINFO_FOODID - Pet food item ID + +PETINFO_INTIMATE can be used with the following constants for checking values: + PET_INTIMATE_NONE = 0 + PET_INTIMATE_AWKWARD = 1 ~ 99 + PET_INTIMATE_SHY = 100 ~ 249 + PET_INTIMATE_NEUTRAL = 250 ~ 749 + PET_INTIMATE_CORDIAL = 750 ~ 909 + PET_INTIMATE_LOYAL = 910 ~ 1000 + +PETINFO_HUNGRY can be used with the following constants for checking values: + PET_HUNGRY_NONE = 0 + PET_HUNGRY_VERY_HUNGRY = 1 ~ 10 + PET_HUNGRY_HUNGRY = 11 ~ 25 + PET_HUNGRY_NEUTRAL = 26 ~ 75 + PET_HUNGRY_SATISFIED = 76 ~ 90 + PET_HUNGRY_STUFFED = 91 ~ 100 + +Example: + mes "[Vet]"; + mes "Your pet + " getpetinfo(PETINFO_NAME); + if (getpetinfo(PETINFO_INTIMATE) < PET_INTIMATE_LOYAL) + mes "has some growing to do on you!"; + else + mes "seems to love you very much!"; + close; --------------------------------------- diff --git a/sql-files/main.sql b/sql-files/main.sql index 7eff1f523d..fbbff0cf99 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -967,6 +967,7 @@ CREATE TABLE IF NOT EXISTS `pet` ( `hungry` smallint(9) unsigned NOT NULL default '0', `rename_flag` tinyint(4) unsigned NOT NULL default '0', `incubate` int(11) unsigned NOT NULL default '0', + `autofeed` tinyint(2) NOT NULL default '0', PRIMARY KEY (`pet_id`) ) ENGINE=MyISAM; diff --git a/sql-files/upgrades/upgrade_20190309.sql b/sql-files/upgrades/upgrade_20190309.sql new file mode 100644 index 0000000000..0fb99fae48 --- /dev/null +++ b/sql-files/upgrades/upgrade_20190309.sql @@ -0,0 +1,2 @@ +ALTER TABLE `pet` + ADD COLUMN `autofeed` tinyint(2) NOT NULL default '0' AFTER `incubate`; diff --git a/src/char/int_pet.cpp b/src/char/int_pet.cpp index 9f9ba0a54f..1111defff8 100644 --- a/src/char/int_pet.cpp +++ b/src/char/int_pet.cpp @@ -23,7 +23,7 @@ int mapif_load_pet(int fd, uint32 account_id, uint32 char_id, int pet_id); //--------------------------------------------------------- int inter_pet_tosql(int pet_id, struct s_pet* p) { - //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate`) + //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate`,`autofeed`) char esc_name[NAME_LENGTH*2+1];// escaped pet name Sql_EscapeStringLen(sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH)); @@ -33,10 +33,10 @@ int inter_pet_tosql(int pet_id, struct s_pet* p) if( pet_id == -1 ) {// New pet. if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` " - "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate`) " - "VALUES ('%d', '%s', '%d', '%d', '%d', '%hu', '%hu', '%d', '%d', '%d', '%d')", + "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate`,`autofeed`) " + "VALUES ('%d', '%s', '%d', '%d', '%d', '%hu', '%hu', '%d', '%d', '%d', '%d', '%d')", schema_config.pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, - p->equip, p->intimate, p->hungry, p->rename_flag, p->incubate) ) + p->equip, p->intimate, p->hungry, p->rename_flag, p->incubate, p->autofeed) ) { Sql_ShowDebug(sql_handle); return 0; @@ -45,9 +45,9 @@ int inter_pet_tosql(int pet_id, struct s_pet* p) } else {// Update pet. - if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%hu',`equip`='%hu',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incubate`='%d' WHERE `pet_id`='%d'", + if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%hu',`equip`='%hu',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incubate`='%d',`autofeed`='%d' WHERE `pet_id`='%d'", schema_config.pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id, - p->equip, p->intimate, p->hungry, p->rename_flag, p->incubate, p->pet_id) ) + p->equip, p->intimate, p->hungry, p->rename_flag, p->incubate, p->autofeed, p->pet_id) ) { Sql_ShowDebug(sql_handle); return 0; @@ -69,9 +69,9 @@ int inter_pet_fromsql(int pet_id, struct s_pet* p) #endif memset(p, 0, sizeof(struct s_pet)); - //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate`) + //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate`,`autofeed`) - if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate` FROM `%s` WHERE `pet_id`='%d'", schema_config.pet_db, pet_id) ) + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate`,`autofeed` FROM `%s` WHERE `pet_id`='%d'", schema_config.pet_db, pet_id) ) { Sql_ShowDebug(sql_handle); return 0; @@ -91,6 +91,7 @@ int inter_pet_fromsql(int pet_id, struct s_pet* p) Sql_GetData(sql_handle, 9, &data, NULL); p->hungry = atoi(data); Sql_GetData(sql_handle, 10, &data, NULL); p->rename_flag = atoi(data); Sql_GetData(sql_handle, 11, &data, NULL); p->incubate = atoi(data); + Sql_GetData(sql_handle, 12, &data, NULL); p->autofeed = atoi(data) != 0; Sql_FreeResult(sql_handle); @@ -201,6 +202,7 @@ int mapif_create_pet(int fd, uint32 account_id, uint32 char_id, short pet_class, pet_pt->hungry = hungry; pet_pt->rename_flag = rename_flag; pet_pt->incubate = incubate; + pet_pt->autofeed = 0; if(pet_pt->hungry < 0) pet_pt->hungry = 0; diff --git a/src/common/database.cpp b/src/common/database.cpp index 65f7fabb39..33cf6920c1 100644 --- a/src/common/database.cpp +++ b/src/common/database.cpp @@ -20,6 +20,24 @@ bool YamlDatabase::nodeExists( const YAML::Node& node, const std::string& name ) } } +bool YamlDatabase::nodesExist( const YAML::Node& node, std::initializer_list names ){ + bool missing = false; + + for( const std::string& name : names ){ + if( !this->nodeExists( node, name ) ){ + ShowError( "Missing mandatory node \"%s\".\n", name.c_str() ); + missing = true; + } + } + + if( missing ){ + this->invalidWarning( node, "At least one mandatory node did not exist.\n" ); + return false; + } + + return true; +} + bool YamlDatabase::verifyCompatibility( const YAML::Node& rootNode ){ if( !this->nodeExists( rootNode, "Header" ) ){ ShowError( "No database \"Header\" was found.\n" ); @@ -67,6 +85,12 @@ bool YamlDatabase::load(){ return this->load( this->getDefaultLocation() ); } +bool YamlDatabase::reload(){ + this->clear(); + + return this->load(); +} + bool YamlDatabase::load(const std::string& path) { YAML::Node rootNode; diff --git a/src/common/database.hpp b/src/common/database.hpp index 47393f72a9..76a402609d 100644 --- a/src/common/database.hpp +++ b/src/common/database.hpp @@ -31,6 +31,7 @@ private: protected: // Helper functions bool nodeExists( const YAML::Node& node, const std::string& name ); + bool nodesExist( const YAML::Node& node, std::initializer_list names ); void invalidWarning( const YAML::Node &node, const char* fmt, ... ); std::string getCurrentFile(); @@ -58,6 +59,7 @@ public: } bool load(); + bool reload(); // Functions that need to be implemented for each type virtual void clear() = 0; diff --git a/src/common/mmo.hpp b/src/common/mmo.hpp index 3c3cd3d517..a8fac05bf2 100644 --- a/src/common/mmo.hpp +++ b/src/common/mmo.hpp @@ -407,6 +407,7 @@ struct s_pet { char name[NAME_LENGTH]; char rename_flag; char incubate; + bool autofeed; }; struct s_homunculus { //[orn] diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index 8bed1a91c2..2b163d7cce 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -2742,7 +2742,6 @@ ACMD_FUNC(guildlevelup) { ACMD_FUNC(makeegg) { struct item_data *item_data; int id; - struct s_pet_db* pet; nullpo_retr(-1, sd); @@ -2759,12 +2758,18 @@ ACMD_FUNC(makeegg) { else id = atoi(message); - pet = pet_db(id); - if (!pet) + std::shared_ptr pet = pet_db.find(id); + + if( pet == nullptr ){ pet = pet_db_search(id, PET_EGG); + } + if (pet != nullptr) { sd->catch_target_class = pet->class_; - intif_create_pet(sd->status.account_id, sd->status.char_id, pet->class_, mob_db(pet->class_)->lv, pet->EggID, 0, pet->intimate, 100, 0, 1, pet->jname); + + struct mob_db* mdb = mob_db(pet->class_); + + intif_create_pet(sd->status.account_id, sd->status.char_id, pet->class_, mdb->lv, pet->EggID, 0, pet->intimate, 100, 0, 1, mdb->jname); } else { clif_displaymessage(fd, msg_txt(sd,180)); // The monster/egg name/id doesn't exist. return -1; @@ -3819,7 +3824,7 @@ ACMD_FUNC(reload) { clif_displaymessage(fd, msg_txt(sd,97)); // Item database has been reloaded. } else if (strstr(command, "mobdb") || strncmp(message, "mobdb", 3) == 0) { mob_reload(); - read_petdb(); + pet_db.reload(); hom_reload(); mercenary_readdb(); mercenary_read_skilldb(); @@ -4488,7 +4493,7 @@ ACMD_FUNC(repairall) count = 0; for (i = 0; i < MAX_INVENTORY; i++) { - if (sd->inventory.u.items_inventory[i].nameid && sd->inventory.u.items_inventory[i].attribute == 1) { + if (sd->inventory.u.items_inventory[i].nameid && sd->inventory.u.items_inventory[i].card[0] != CARD0_PET && sd->inventory.u.items_inventory[i].attribute == 1) { sd->inventory.u.items_inventory[i].attribute = 0; clif_produceeffect(sd, 0, sd->inventory.u.items_inventory[i].nameid); count++; diff --git a/src/map/battle.cpp b/src/map/battle.cpp index 472dece863..fc07187a86 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -8506,6 +8506,10 @@ static const struct _battle_data { { "allow_bound_sell", &battle_config.allow_bound_sell, 0, 0, 0xF, }, { "event_refine_chance", &battle_config.event_refine_chance, 0, 0, 1, }, { "autoloot_adjust", &battle_config.autoloot_adjust, 0, 0, 1, }, + { "feature.petevolution", &battle_config.feature_petevolution, 1, 0, 1, }, + { "feature.petautofeed", &battle_config.feature_pet_autofeed, 1, 0, 1, }, + { "feature.pet_autofeed_rate", &battle_config.feature_pet_autofeed_rate, 89, 0, 100, }, + { "pet_autofeed_always", &battle_config.pet_autofeed_always, 1, 0, 1, }, { "broadcast_hide_name", &battle_config.broadcast_hide_name, 2, 0, NAME_LENGTH, }, { "skill_drop_items_full", &battle_config.skill_drop_items_full, 0, 0, 1, }, { "switch_remove_edp", &battle_config.switch_remove_edp, 2, 0, 3, }, @@ -8649,6 +8653,17 @@ void battle_adjust_conf() } #endif +#if PACKETVER < 20141008 + if (battle_config.feature_petevolution) { + ShowWarning("conf/battle/feature.conf petevolution is enabled but it requires PACKETVER 2014-10-08 or newer, disabling...\n"); + battle_config.feature_petevolution = 0; + } + if (battle_config.feature_pet_auto_feed) { + ShowWarning("conf/battle/feature.conf pet auto feed is enabled but it requires PACKETVER 2014-10-08 or newer, disabling...\n"); + battle_config.feature_pet_auto_feed = 0; + } +#endif + #if PACKETVER < 20170208 if (battle_config.feature_equipswitch) { ShowWarning("conf/battle/feature.conf equip switch is enabled but it requires PACKETVER 2017-02-08 or newer, disabling...\n"); diff --git a/src/map/battle.hpp b/src/map/battle.hpp index 86449450bb..87995481ea 100644 --- a/src/map/battle.hpp +++ b/src/map/battle.hpp @@ -641,6 +641,10 @@ struct Battle_Config int allow_bound_sell; int event_refine_chance; int autoloot_adjust; + int feature_petevolution; + int feature_pet_autofeed; + int feature_pet_autofeed_rate; + int pet_autofeed_always; int broadcast_hide_name; int skill_drop_items_full; int switch_remove_edp; diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 64b74c77c7..8be4bc2af0 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -7970,25 +7970,13 @@ void clif_send_petstatus(struct map_session_data *sd) void clif_pet_emotion(struct pet_data *pd,int param) { unsigned char buf[16]; - s_pet_db *pet_db_ptr; nullpo_retv(pd); - pet_db_ptr = pd->get_pet_db(); - memset(buf,0,packet_len(0x1aa)); WBUFW(buf,0)=0x1aa; WBUFL(buf,2)=pd->bl.id; - if(param >= 100 && pet_db_ptr->talk_convert_class) { - if(pet_db_ptr->talk_convert_class < 0) - return; - else if(pet_db_ptr->talk_convert_class > 0) { - // replace mob_id component of talk/act data - param -= (pd->pet.class_ - 100)*100; - param += (pet_db_ptr->talk_convert_class - 100)*100; - } - } WBUFL(buf,6)=param; clif_send(buf,packet_len(0x1aa),&pd->bl,AREA); @@ -10408,7 +10396,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) if( sd->pd ) { if( battle_config.pet_no_gvg && mapdata_flag_gvg(mapdata) ) { //Return the pet to egg. [Skotlex] clif_displaymessage(sd->fd, msg_txt(sd,666)); - pet_menu(sd, 3); //Option 3 is return to egg. + pet_return_egg( sd, sd->pd ); } else { if(map_addblock(&sd->pd->bl)) return; @@ -10527,6 +10515,21 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) clif_partyinvitationstate(sd); clif_equipcheckbox(sd); #endif +#if PACKETVER >= 20141008 + if( battle_config.pet_autofeed_always ){ + // Always send ON or OFF + if( sd->pd && battle_config.feature_pet_autofeed ){ + clif_configuration( sd, CONFIG_PET_AUTOFEED, sd->pd->pet.autofeed ); + }else{ + clif_configuration( sd, CONFIG_PET_AUTOFEED, false ); + } + }else{ + // Only send when enabled + if( sd->pd && battle_config.feature_pet_autofeed && sd->pd->pet.autofeed ){ + clif_configuration( sd, CONFIG_PET_AUTOFEED, true ); + } + } +#endif #if PACKETVER >= 20170920 if( battle_config.homunculus_autofeed_always ){ // Always send ON or OFF @@ -16687,7 +16690,12 @@ void clif_parse_configuration( int fd, struct map_session_data* sd ){ sd->status.show_equip = flag; break; case CONFIG_PET_AUTOFEED: - // TODO: Implement with pet evolution system + // Player can not click this if he does not have a pet + if( sd->pd == nullptr || !battle_config.feature_pet_autofeed || !sd->pd->get_pet_db()->allow_autofeed ){ + return; + } + + sd->pd->pet.autofeed = flag; break; case CONFIG_HOMUNCULUS_AUTOFEED: // Player can not click this if he does not have a homunculus or it is vaporized @@ -20369,6 +20377,34 @@ void clif_achievement_reward_ack(int fd, unsigned char result, int achievement_i WFIFOSET(fd, packet_len(0xa26)); } +/// Process the pet evolution request +/// 09fb .W .W .W (CZ_PET_EVOLUTION) +void clif_parse_pet_evolution( int fd, struct map_session_data *sd ){ +#if PACKETVER >= 20141008 + auto pet = pet_db_search(RFIFOW(fd, 4), PET_EGG); + + if (!pet) { + clif_pet_evolution_result(sd, e_pet_evolution_result::FAIL_NOT_PETEGG); + return; + } + + pet_evolution(sd, pet->class_); +#endif +} + +/// Sends the result of the evolution to the client. +/// 09fc .L (ZC_PET_EVOLUTION_RESULT) +void clif_pet_evolution_result( struct map_session_data* sd, e_pet_evolution_result result ){ +#if PACKETVER >= 20141008 + int fd = sd->fd; + + WFIFOHEAD(fd, packet_len(0x9fc)); + WFIFOW(fd, 0) = 0x9fc; + WFIFOL(fd, 2) = static_cast(result); + WFIFOSET(fd, packet_len(0x9fc)); +#endif +} + /* * This packet is sent by /changedress or /nocosplay * diff --git a/src/map/clif.hpp b/src/map/clif.hpp index 949920edbd..82240fe1c9 100644 --- a/src/map/clif.hpp +++ b/src/map/clif.hpp @@ -549,6 +549,16 @@ enum e_damage_type : uint8_t { DMG_TOUCH, /// (touch skill?) }; +enum class e_pet_evolution_result : uint32 { + FAIL_UNKNOWN = 0x0, + FAIL_NOTEXIST_CALLPET = 0x1, + FAIL_NOT_PETEGG = 0x2, + FAIL_RECIPE = 0x3, + FAIL_MATERIAL = 0x4, + FAIL_RG_FAMILIAR = 0x5, + SUCCESS = 0x6 +}; + enum e_config_type : uint32 { CONFIG_OPEN_EQUIPMENT_WINDOW = 0, // Unknown @@ -1113,4 +1123,7 @@ void clif_equipswitch_add( struct map_session_data* sd,uint16 index, uint32 pos, void clif_equipswitch_remove( struct map_session_data* sd, uint16 index, uint32 pos, bool failed ); void clif_equipswitch_reply( struct map_session_data* sd, bool failed ); +/// Pet evolution +void clif_pet_evolution_result( struct map_session_data* sd, e_pet_evolution_result result ); + #endif /* CLIF_HPP */ diff --git a/src/map/clif_packetdb.hpp b/src/map/clif_packetdb.hpp index f5149bdc8f..17d0bdd8db 100644 --- a/src/map/clif_packetdb.hpp +++ b/src/map/clif_packetdb.hpp @@ -2193,6 +2193,12 @@ packet(0x09DA,-1); #endif +// 2014-10-08Ragexe +#if PACKETVER >= 20141008 + parseable_packet(0x9FB, -1, clif_parse_pet_evolution, 2, 4); // CZ_PET_EVOLUTION + packet(0x09FC, 6); // ZC_PET_EVOLUTION_RESULT +#endif + // 2014-10-16Ragexe #if PACKETVER >= 20141016 packet(0x09DF,7); @@ -2284,9 +2290,6 @@ parseable_packet(0x0A2E,6,clif_parse_change_title,0); // CZ_REQ_CHANGE_TITLE packet(0x0A2F,7); // ZC_ACK_CHANGE_TITLE packet(0x0A30,106); // ZC_ACK_REQNAMEALL2 - // Pet Evolution System - parseable_packet(0x09FB,-1,clif_parse_dull,0); // CZ_PET_EVOLUTION - packet(0x09FC,6); // ZC_PET_EVOLUTION_RESULT // Quest UI packet(0x08FE,-1); // ZC_HUNTING_QUEST_INFO diff --git a/src/map/itemdb.cpp b/src/map/itemdb.cpp index d3e6f94c43..d9a2671a11 100644 --- a/src/map/itemdb.cpp +++ b/src/map/itemdb.cpp @@ -116,6 +116,10 @@ struct item_data* itemdb_searchname(const char *str) return itemdb_searchname1(str, false); } +struct item_data* itemdb_search_aegisname( const char *str ){ + return itemdb_searchname1( str, true ); +} + /** * @see DBMatcher */ diff --git a/src/map/itemdb.hpp b/src/map/itemdb.hpp index 2400fb2a8e..5cf2f140c9 100644 --- a/src/map/itemdb.hpp +++ b/src/map/itemdb.hpp @@ -889,6 +889,7 @@ struct s_random_opt_group { }; struct item_data* itemdb_searchname(const char *name); +struct item_data* itemdb_search_aegisname( const char *str ); int itemdb_searchname_array(struct item_data** data, int size, const char *str); struct item_data* itemdb_search(unsigned short nameid); struct item_data* itemdb_exists(unsigned short nameid); diff --git a/src/map/map-server.vcxproj b/src/map/map-server.vcxproj index 6cd326dcce..dd1c315170 100644 --- a/src/map/map-server.vcxproj +++ b/src/map/map-server.vcxproj @@ -351,7 +351,7 @@ - + diff --git a/src/map/mob.cpp b/src/map/mob.cpp index 157634ad01..9ce390b033 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -333,6 +333,17 @@ uint16 mobdb_searchname(const char * const str) { return mobdb_searchname_(str, true); } + +struct mob_db* mobdb_search_aegisname( const char* str ){ + for( auto &mobdb_pair : mob_db_data ){ + if( strcmpi( str, mobdb_pair.second.sprite ) == 0 ){ + return &mobdb_pair.second; + } + } + + return nullptr; +} + /*========================================== * Founds up to N matches. Returns number of matches [Skotlex] *------------------------------------------*/ diff --git a/src/map/mob.hpp b/src/map/mob.hpp index 52a1aebba0..54b886f8a3 100644 --- a/src/map/mob.hpp +++ b/src/map/mob.hpp @@ -301,6 +301,7 @@ struct item_drop_list { struct mob_db *mob_db(int mob_id); uint16 mobdb_searchname(const char * const str); +struct mob_db* mobdb_search_aegisname( const char* str ); int mobdb_searchname_array(const char *str, uint16 * out, int size); int mobdb_checkid(const int id); struct view_data* mob_get_viewdata(int mob_id); diff --git a/src/map/pc.cpp b/src/map/pc.cpp index c217692521..d80c384763 100755 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -7944,7 +7944,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) if(sd->status.pet_id > 0 && sd->pd) { struct pet_data *pd = sd->pd; if( !mapdata->flag[MF_NOEXPPENALTY] ) { - pet_set_intimate(pd, pd->pet.intimate - pd->get_pet_db()->die); + pet_set_intimate(pd, pd->pet.intimate + pd->get_pet_db()->die); if( pd->pet.intimate < 0 ) pd->pet.intimate = 0; clif_send_petdata(sd,sd->pd,1,pd->pet.intimate); diff --git a/src/map/pet.cpp b/src/map/pet.cpp index 0b8a0f5081..328c3edd25 100644 --- a/src/map/pet.cpp +++ b/src/map/pet.cpp @@ -4,8 +4,12 @@ #include "pet.hpp" #include +#include + #include +#include + #include "../common/db.hpp" #include "../common/ers.hpp" #include "../common/malloc.hpp" @@ -31,12 +35,540 @@ using namespace rathena; const t_tick MIN_PETTHINKTIME = 100; -//Dynamic pet database -std::map pet_db_data; -struct s_pet_db *pet_db( uint16 pet_id ){ - return util::map_find( pet_db_data, pet_id ); +const std::string PetDatabase::getDefaultLocation(){ + return std::string(db_path) + "/pet_db.yml"; } +uint64 PetDatabase::parseBodyNode( const YAML::Node &node ){ + std::string mob_name; + + if( !this->asString( node, "Mob", mob_name ) ){ + return 0; + } + + struct mob_db* mob = mobdb_search_aegisname( mob_name.c_str() ); + + if( mob == nullptr ){ + this->invalidWarning( node["Target"], "Mob %s does not exist and cannot be used as a pet.\n", mob_name.c_str() ); + return 0; + } + + uint16 mob_id = mob->vd.class_; + + std::shared_ptr pet = this->find( mob_id ); + bool exists = pet != nullptr; + + if( !exists ){ + // Check mandatory nodes + if( !this->nodesExist( node, { "EggItem", "Fullness", "CaptureRate" } ) ){ + return 0; + } + + pet = std::make_shared(); + pet->class_ = mob_id; + } + + if( this->nodeExists( node, "TameItem" ) ){ + std::string item_name; + + if( !this->asString( node, "TameItem", item_name ) ){ + return 0; + } + + struct item_data* item = itemdb_search_aegisname( item_name.c_str() ); + + if( item == nullptr ){ + this->invalidWarning( node["TameItem"], "Taming item %s does not exist.\n", item_name.c_str() ); + return 0; + } + + pet->itemID = item->nameid; + }else{ + if( !exists ){ + pet->itemID = 0; + } + } + + if( this->nodeExists( node, "EggItem" ) ){ + std::string item_name; + + if( !this->asString( node, "EggItem", item_name ) ){ + return 0; + } + + struct item_data* item = itemdb_search_aegisname( item_name.c_str() ); + + if( item == nullptr ){ + this->invalidWarning( node["EggItem"], "Egg item %s does not exist.\n", item_name.c_str() ); + return 0; + } + + pet->EggID = item->nameid; + } + + if( this->nodeExists( node, "EquipItem" ) ){ + std::string item_name; + + if( !this->asString( node, "EquipItem", item_name ) ){ + return 0; + } + + struct item_data* item = itemdb_search_aegisname( item_name.c_str() ); + + if( item == nullptr ){ + this->invalidWarning( node["EquipItem"], "Equip item %s does not exist.\n", item_name.c_str() ); + return 0; + } + + pet->AcceID = item->nameid; + }else{ + if( !exists ){ + pet->AcceID = 0; + } + } + + if( this->nodeExists( node, "FoodItem" ) ){ + std::string item_name; + + if( !this->asString( node, "FoodItem", item_name ) ){ + return 0; + } + + struct item_data* item = itemdb_search_aegisname( item_name.c_str() ); + + if( item == nullptr ){ + this->invalidWarning( node["FoodItem"], "Food item %s does not exist.\n", item_name.c_str() ); + return 0; + } + + pet->FoodID = item->nameid; + }else{ + if( !exists ){ + pet->FoodID = 0; + } + } + + if( this->nodeExists( node, "Fullness" ) ){ + uint16 fullness; + + if( !this->asUInt16( node, "Fullness", fullness ) ){ + return 0; + } + + if( fullness > 100 ){ + this->invalidWarning( node["Fullness"], "Fullness %hu exceeds maximum of 100. Capping...\n", fullness ); + fullness = 100; + } + + pet->fullness = fullness; + } + + if( this->nodeExists( node, "HungryDelay" ) ){ + uint32 delay; + + if( !this->asUInt32( node, "HungryDelay", delay ) ){ + return 0; + } + + pet->hungry_delay = delay * 1000; + }else{ + if( !exists ){ + pet->hungry_delay = 60000; + } + } + + if( this->nodeExists( node, "HungerIncrease" ) ){ + int32 increase; + + if( !this->asInt32( node, "HungerIncrease", increase ) ){ + return 0; + } + + pet->hunger_increase = increase; + }else{ + if( !exists ){ + pet->hunger_increase = 20; + } + } + + if( this->nodeExists( node, "IntimacyStart" ) ){ + uint32 start; + + if( !this->asUInt32( node, "IntimacyStart", start ) ){ + return 0; + } + + if( start > 10000 ){ + this->invalidWarning( node["IntimacyStart"], "IntimacyStart %hu exceeds maximum of 10000. Capping...\n", start ); + start = 10000; + } + + pet->intimate = start; + }else{ + if( !exists ){ + pet->intimate = 250; + } + } + + if( this->nodeExists( node, "IntimacyFed" ) ){ + int32 fed; + + if( !this->asInt32( node, "IntimacyFed", fed ) ){ + return 0; + } + + pet->r_hungry = fed; + }else{ + if( !exists ){ + pet->r_hungry = 50; + } + } + + if( this->nodeExists( node, "IntimacyOverfed" ) ){ + int32 overfed; + + if( !this->asInt32( node, "IntimacyOverfed", overfed ) ){ + return 0; + } + + pet->r_full = overfed; + }else{ + if( !exists ){ + pet->r_full = -100; + } + } + + if( this->nodeExists( node, "IntimacyHungry" ) ){ + int32 hungry; + + if( !this->asInt32( node, "IntimacyHungry", hungry ) ){ + return 0; + } + + pet->hungry_intimacy_dec = hungry; + }else{ + if( !exists ){ + pet->hungry_intimacy_dec = -5; + } + } + + if( this->nodeExists( node, "IntimacyOwnerDie" ) ){ + int32 die; + + if( !this->asInt32( node, "IntimacyOwnerDie", die ) ){ + return 0; + } + + pet->die = die; + }else{ + if( !exists ){ + pet->die = -20; + } + } + + if( this->nodeExists( node, "CaptureRate" ) ){ + uint16 rate; + + if( !this->asUInt16( node, "CaptureRate", rate ) ){ + return 0; + } + + if( rate > 10000 ){ + this->invalidWarning( node["CaptureRate"], "CaptureRate %hu exceeds maximum of 10000. Capping...\n", rate ); + rate = 10000; + } + + pet->capture = rate; + } + + if( this->nodeExists( node, "SpecialPerformance" ) ){ + bool performance; + + if( !this->asBool( node, "SpecialPerformance", performance ) ){ + return 0; + } + + pet->s_perfor = performance; + }else{ + if( !exists ){ + pet->s_perfor = true; + } + } + + if( this->nodeExists( node, "AttackRate" ) ){ + uint16 rate; + + if( !this->asUInt16( node, "AttackRate", rate ) ){ + return 0; + } + + if( rate > 10000 ){ + this->invalidWarning( node["AttackRate"], "AttackRate %hu exceeds maximum of 10000. Capping...\n", rate ); + rate = 10000; + } + + pet->attack_rate = rate; + }else{ + if( !exists ){ + pet->attack_rate = 10001; // unreachable + } + } + + if( this->nodeExists( node, "RetaliateRate" ) ){ + uint16 rate; + + if( !this->asUInt16( node, "RetaliateRate", rate ) ){ + return 0; + } + + if( rate > 10000 ){ + this->invalidWarning( node["RetaliateRate"], "RetaliateRate %hu exceeds maximum of 10000. Capping...\n", rate ); + rate = 10000; + } + + pet->defence_attack_rate = rate; + }else{ + if( !exists ){ + pet->defence_attack_rate = 10001; // unreachable + } + } + + if( this->nodeExists( node, "ChangeTargetRate" ) ){ + uint16 rate; + + if( !this->asUInt16( node, "ChangeTargetRate", rate ) ){ + return 0; + } + + if( rate > 10000 ){ + this->invalidWarning( node["ChangeTargetRate"], "ChangeTargetRate %hu exceeds maximum of 10000. Capping...\n", rate ); + rate = 10000; + } + + pet->change_target_rate = rate; + }else{ + if( !exists ){ + pet->change_target_rate = 10001; // unreachable + } + } + + if( this->nodeExists( node, "AllowAutoFeed" ) ){ + bool allow; + + if( !this->asBool( node, "AllowAutoFeed", allow ) ){ + return 0; + } + + pet->allow_autofeed = allow; + }else{ + if( !exists ){ + pet->allow_autofeed = false; + } + } + + if( this->nodeExists( node, "Script" ) ){ + std::string script; + + if( !this->asString( node, "Script", script ) ){ + return 0; + } + + pet->pet_bonus_script = parse_script( script.c_str(), this->getCurrentFile().c_str(), node["Script"].Mark().line + 1, SCRIPT_IGNORE_EXTERNAL_BRACKETS ); + }else{ + if( !exists ){ + pet->pet_bonus_script = nullptr; + } + } + + if( this->nodeExists( node, "SupportScript" ) ){ + std::string script; + + if( !this->asString( node, "SupportScript", script ) ){ + return 0; + } + + pet->pet_support_script = parse_script( script.c_str(), this->getCurrentFile().c_str(), node["SupportScript"].Mark().line + 1, SCRIPT_IGNORE_EXTERNAL_BRACKETS ); + }else{ + if( !exists ){ + pet->pet_support_script = nullptr; + } + } + + if( this->nodeExists( node, "Evolution" ) ){ + for( const YAML::Node& evolutionNode : node["Evolution"] ){ + std::string target_name; + + if( !this->asString( evolutionNode, "Target", target_name ) ){ + return 0; + } + + struct mob_db* mob = mobdb_search_aegisname( target_name.c_str() ); + + if( mob == nullptr ){ + this->invalidWarning( evolutionNode["Target"], "Evolution target %s does not exist.\n", target_name.c_str() ); + return 0; + } + + uint16 targetId = mob->vd.class_; + + if( !this->nodeExists( evolutionNode, "ItemRequirements" ) ){ + this->invalidWarning( evolutionNode, "Missing required node \"ItemRequirements\".\n" ); + return 0; + } + + std::shared_ptr evolution = util::umap_find( pet->evolution_data, targetId ); + bool evolution_exists = evolution != nullptr; + + if( !evolution_exists ){ + evolution = std::make_shared(); + evolution->target_mob_id = targetId; + } + + for( const YAML::Node& requirementNode : evolutionNode["ItemRequirements"] ){ + std::string item_name; + + if( !this->asString( requirementNode, "Item", item_name ) ){ + return 0; + } + + struct item_data* item = itemdb_search_aegisname( item_name.c_str() ); + + if( item == nullptr ){ + this->invalidWarning( requirementNode["Item"], "Evolution requirement item %s does not exist.\n", item_name.c_str() ); + return 0; + } + + uint32 amount; + + if( !this->asUInt32( requirementNode, "Amount", amount ) ){ + return 0; + } + + if( amount > MAX_AMOUNT ){ + this->invalidWarning( requirementNode["Amount"], "Amount %u exceeds the maximum of %d.\n", amount, MAX_AMOUNT ); + return 0; + } + + evolution->requirements[item->nameid] = amount; + } + + if( !evolution_exists ){ + pet->evolution_data[targetId] = evolution; + } + } + } + + if( !exists ){ + this->put( mob_id, pet ); + } + + return 1; +} + +/** + * Clear pet support bonuses from memory + * @param sd: Pet owner + */ +void pet_clear_support_bonuses(struct map_session_data *sd) { + nullpo_retv(sd); + + if (!sd->pd) + return; + + struct pet_data *pd = sd->pd; + + if (pd->a_skill) { + aFree(pd->a_skill); + pd->a_skill = NULL; + } + + if (pd->s_skill) { + if (pd->s_skill->timer != INVALID_TIMER) { + if (pd->s_skill->id) + delete_timer(pd->s_skill->timer, pet_skill_support_timer); + else + delete_timer(pd->s_skill->timer, pet_heal_timer); + } + + aFree(pd->s_skill); + pd->s_skill = NULL; + } + + if (pd->recovery) { + if (pd->recovery->timer != INVALID_TIMER) + delete_timer(pd->recovery->timer, pet_recovery_timer); + + aFree(pd->recovery); + pd->recovery = NULL; + } + + if (pd->bonus) { + if (pd->bonus->timer != INVALID_TIMER) + delete_timer(pd->bonus->timer, pet_skill_bonus_timer); + + aFree(pd->bonus); + pd->bonus = NULL; + } + + if (pd->loot) { + pet_lootitem_drop(pd, sd); + + if (pd->loot->item) + aFree(pd->loot->item); + + aFree(pd->loot); + pd->loot = NULL; + } +} + +/** + * Apply the proper data on pet owners and pets during pet_db reload. + * @param sd: Pet owner + * @param args: va_list of arguments + * @return 0 + */ +static int pet_reload_sub( struct map_session_data *sd, va_list args ){ + if( sd->pd == nullptr ){ + return 0; + } + + struct pet_data *pd = sd->pd; + std::shared_ptr pet_db_ptr = pd->get_pet_db(); + + if( pet_db_ptr == nullptr ){ + return 0; + } + + // Clear pet bonuses + pet_clear_support_bonuses(sd); + + // Relink the pet to the new database entry + pd->db = mob_db( pet_db_ptr->class_ ); + + if( battle_config.pet_status_support ){ + run_script( pet_db_ptr->pet_support_script, 0, sd->bl.id, 0 ); + } + + // Recalculate the player status based on the new data + status_calc_pc( sd, SCO_NONE ); + + // Recalculate the pet status based on the new data + status_calc_pet( pd, SCO_NONE ); + + return 0; +} + +bool PetDatabase::reload(){ + if( !TypesafeYamlDatabase::reload() ){ + return false; + } + + map_foreachpc( pet_reload_sub ); + return true; +} + +PetDatabase pet_db; + static struct eri *item_drop_ers; //For loot drops delay structures. static struct eri *item_drop_list_ers; @@ -49,13 +581,13 @@ int pet_hungry_val(struct pet_data *pd) { nullpo_ret(pd); - if(pd->pet.hungry > 90) + if(pd->pet.hungry > PET_HUNGRY_SATISFIED) return 4; - else if(pd->pet.hungry > 75) + else if(pd->pet.hungry > PET_HUNGRY_NEUTRAL) return 3; - else if(pd->pet.hungry > 25) + else if(pd->pet.hungry > PET_HUNGRY_HUNGRY) return 2; - else if(pd->pet.hungry > 10) + else if(pd->pet.hungry > PET_HUNGRY_VERY_HUNGRY) return 1; else return 0; @@ -76,7 +608,7 @@ void pet_set_intimate(struct pet_data *pd, int value) intimate = pd->pet.intimate; sd = pd->master; - pd->pet.intimate = value; + pd->pet.intimate = min(value, PET_INTIMATE_MAX); if( sd && ((intimate >= battle_config.pet_equip_min_friendly && pd->pet.intimate < battle_config.pet_equip_min_friendly) || (intimate < battle_config.pet_equip_min_friendly && pd->pet.intimate >= battle_config.pet_equip_min_friendly)) ) status_calc_pc(sd,SCO_NONE); @@ -90,16 +622,22 @@ void pet_set_intimate(struct pet_data *pd, int value) */ bool pet_create_egg(struct map_session_data *sd, unsigned short item_id) { - struct s_pet_db* pet = pet_db_search(item_id, PET_EGG); + std::shared_ptr pet = pet_db_search(item_id, PET_EGG); if (!pet) return false; //No pet egg here. + struct mob_db* mdb = mob_db(pet->class_); + + if( mdb == nullptr ){ + return false; + } + if (!pc_inventoryblank(sd)) return false; // Inventory full sd->catch_target_class = pet->class_; - intif_create_pet(sd->status.account_id, sd->status.char_id, pet->class_, mob_db(pet->class_)->lv, pet->EggID, 0, pet->intimate, 100, 0, 1, pet->jname); + intif_create_pet(sd->status.account_id, sd->status.char_id, pet->class_, mdb->lv, pet->EggID, 0, pet->intimate, 100, 0, 1, mdb->jname); return true; } @@ -164,18 +702,14 @@ int pet_attackskill(struct pet_data *pd, int target_id) */ int pet_target_check(struct pet_data *pd,struct block_list *bl,int type) { - int rate; - s_pet_db* pet_db_ptr; - nullpo_ret(pd); Assert((pd->master == 0) || (pd->master->pd == pd)); - pet_db_ptr = pd->get_pet_db(); if(bl == NULL || bl->type != BL_MOB || bl->prev == NULL || pd->pet.intimate < battle_config.pet_support_min_friendly || - pd->pet.hungry < 1 || + pd->pet.hungry <= PET_HUNGRY_NONE || pd->pet.class_ == status_get_class(bl)) return 0; @@ -191,6 +725,9 @@ int pet_target_check(struct pet_data *pd,struct block_list *bl,int type) if (!status_check_skilluse(&pd->bl, bl, 0, 0)) return 0; + std::shared_ptr pet_db_ptr = pd->get_pet_db(); + int rate; + if(!type) { rate = pet_db_ptr->attack_rate; rate = rate * pd->rate_fix / 1000; @@ -249,7 +786,6 @@ int pet_sc_check(struct map_session_data *sd, int type) static TIMER_FUNC(pet_hungry){ struct map_session_data *sd; struct pet_data *pd; - s_pet_db *pet_db_ptr; int interval; sd = map_id2sd(id); @@ -261,7 +797,6 @@ static TIMER_FUNC(pet_hungry){ return 1; pd = sd->pd; - pet_db_ptr = pd->get_pet_db(); if(pd->pet_hungry_timer != tid) { ShowError("pet_hungry_timer %d != %d\n",pd->pet_hungry_timer,tid); @@ -270,35 +805,40 @@ static TIMER_FUNC(pet_hungry){ pd->pet_hungry_timer = INVALID_TIMER; - if (pd->pet.intimate <= 0) + if (pd->pet.intimate <= PET_INTIMATE_NONE) return 1; //You lost the pet already, the rest is irrelevant. - pd->pet.hungry--; + std::shared_ptr pet_db_ptr = pd->get_pet_db(); - if( pd->pet.hungry < 0 ) { + if (battle_config.pet_hungry_delay_rate != 100) + interval = (pet_db_ptr->hungry_delay*battle_config.pet_hungry_delay_rate) / 100; + else + interval = pet_db_ptr->hungry_delay; + + pd->pet.hungry -= pet_db_ptr->fullness; + + if( pd->pet.hungry < PET_HUNGRY_NONE ) { pet_stop_attack(pd); - pd->pet.hungry = 0; - pet_set_intimate(pd, pd->pet.intimate - battle_config.pet_hungry_friendly_decrease); + pd->pet.hungry = PET_HUNGRY_NONE; + pet_set_intimate(pd, pd->pet.intimate + pet_db_ptr->hungry_intimacy_dec); - if( pd->pet.intimate <= 0 ) { - pd->pet.intimate = 0; + if( pd->pet.intimate <= PET_INTIMATE_NONE ) { + pd->pet.intimate = PET_INTIMATE_NONE; pd->status.speed = pd->db->status.speed; } status_calc_pet(pd,SCO_NONE); clif_send_petdata(sd,pd,1,pd->pet.intimate); + interval = 20000; // While starving, it's every 20 seconds } clif_send_petdata(sd,pd,2,pd->pet.hungry); - if(battle_config.pet_hungry_delay_rate != 100) - interval = (pet_db_ptr->hungry_delay*battle_config.pet_hungry_delay_rate)/100; - else - interval = pet_db_ptr->hungry_delay; - - if(interval <= 0) - interval = 1; + if( battle_config.feature_pet_autofeed && pd->pet.autofeed && pd->pet.hungry <= battle_config.feature_pet_autofeed_rate ){ + pet_food( sd, pd ); + } + interval = max(interval, 1); pd->pet_hungry_timer = add_timer(tick+interval,pet_hungry,sd->bl.id,0); return 0; @@ -310,9 +850,9 @@ static TIMER_FUNC(pet_hungry){ * @param type : pet type to search for (Catch, Egg, Equip, Food) * @return Pet DB pointer on success, NULL on failure */ -struct s_pet_db* pet_db_search( int key, enum e_pet_itemtype type ){ - for( auto &pair : pet_db_data ){ - struct s_pet_db* pet = &pair.second; +std::shared_ptr pet_db_search( int key, enum e_pet_itemtype type ){ + for( auto &pair : pet_db ){ + std::shared_ptr pet = pair.second; switch(type) { case PET_CATCH: if(pet->itemID == key) return pet; break; @@ -355,9 +895,9 @@ static int pet_performance(struct map_session_data *sd, struct pet_data *pd) { int val; - if (pd->pet.intimate > 900) - val = (pd->get_pet_db()->s_perfor > 0) ? 4 : 3; - else if(pd->pet.intimate > 750) //TODO: this is way too high + if (pd->pet.intimate > PET_INTIMATE_LOYAL) + val = pd->get_pet_db()->s_perfor ? 4 : 3; + else if(pd->pet.intimate > PET_INTIMATE_CORDIAL) //TODO: this is way too high val = 2; else val = 1; @@ -373,34 +913,26 @@ static int pet_performance(struct map_session_data *sd, struct pet_data *pd) * Return a pet to it's egg. * @param sd : player requesting * @param pd : pet requesting - * @return 1 + * @return true if everything went well, false if the egg is not found in the inventory. */ -static int pet_return_egg(struct map_session_data *sd, struct pet_data *pd) -{ - struct item tmp_item; - unsigned char flag = 0; - +bool pet_return_egg( struct map_session_data *sd, struct pet_data *pd ){ pet_lootitem_drop(pd,sd); - memset(&tmp_item,0,sizeof(tmp_item)); - tmp_item.nameid = pd->get_pet_db()->EggID; - tmp_item.identify = 1; - tmp_item.card[0] = CARD0_PET; - tmp_item.card[1] = GetWord(pd->pet.pet_id,0); - tmp_item.card[2] = GetWord(pd->pet.pet_id,1); - tmp_item.card[3] = pd->pet.rename_flag; - if((flag = pc_additem(sd,&tmp_item,1,LOG_TYPE_OTHER))) { - clif_additem(sd,0,0,flag); - map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0,0); - } + int i = pet_egg_search( sd, pd->pet.pet_id ); + if( i == -1 ){ + return false; + } + + sd->inventory.u.items_inventory[i].attribute = 0; + sd->inventory.dirty = true; pd->pet.incubate = 1; unit_free(&pd->bl,CLR_OUTSIGHT); status_calc_pc(sd,SCO_NONE); sd->status.pet_id = 0; - return 1; + return true; } /** @@ -412,7 +944,6 @@ static int pet_return_egg(struct map_session_data *sd, struct pet_data *pd) bool pet_data_init(struct map_session_data *sd, struct s_pet *pet) { struct pet_data *pd; - struct s_pet_db *pet_db_ptr; int interval = 0; nullpo_retr(false, sd); @@ -439,9 +970,9 @@ bool pet_data_init(struct map_session_data *sd, struct s_pet *pet) sd->status.pet_id = pet->pet_id; } - pet_db_ptr = pet_db(pet->class_); + std::shared_ptr pet_db_ptr = pet_db.find(pet->class_); - if( !pet_db_ptr ){ + if( pet_db_ptr == nullptr ){ sd->status.pet_id = 0; return false; @@ -471,25 +1002,30 @@ bool pet_data_init(struct map_session_data *sd, struct s_pet *pet) pd->last_thinktime = gettick(); pd->state.skillbonus = 0; - if( battle_config.pet_status_support ) - run_script(pet_db_ptr->pet_script,0,sd->bl.id,0); + if( pet_db_ptr != nullptr ) { + if( battle_config.pet_status_support ) + run_script(pet_db_ptr->pet_support_script,0,sd->bl.id,0); - if( pd->get_pet_db() ) { - if( pet_db_ptr->pet_loyal_script ) + if( pet_db_ptr->pet_bonus_script ) status_calc_pc(sd,SCO_NONE); if( battle_config.pet_hungry_delay_rate != 100 ) interval = pet_db_ptr->hungry_delay * battle_config.pet_hungry_delay_rate / 100; else interval = pet_db_ptr->hungry_delay; + if (pd->pet.hungry <= PET_HUNGRY_NONE) + interval = 20000; // While starving, it's every 20 seconds } - if( interval <= 0 ) - interval = 1; + interval = max(interval, 1); pd->pet_hungry_timer = add_timer(gettick() + interval, pet_hungry, sd->bl.id, 0); pd->masterteleport_timer = INVALID_TIMER; + if( !pet->rename_flag ){ + safestrncpy( sd->pd->pet.name, pd->db->jname, NAME_LENGTH ); + } + return true; } @@ -563,24 +1099,21 @@ int pet_recv_petdata(uint32 account_id,struct s_pet *p,int flag) } if(p->incubate == 1) { - int i; + int i = pet_egg_search(sd, p->pet_id); - //Delete egg from inventory. [Skotlex] - for (i = 0; i < MAX_INVENTORY; i++) { - if(sd->inventory.u.items_inventory[i].card[0] == CARD0_PET && - p->pet_id == MakeDWord(sd->inventory.u.items_inventory[i].card[1], sd->inventory.u.items_inventory[i].card[2])) - break; - } - - if(i >= MAX_INVENTORY) { - ShowError("pet_recv_petdata: Hatching pet (%d:%s) aborted, couldn't find egg in inventory for removal!\n",p->pet_id, p->name); + if(i == -1) { + ShowError("pet_recv_petdata: Hatching pet (%d:%s) aborted, couldn't find egg in inventory!\n",p->pet_id, p->name); sd->status.pet_id = 0; return 1; } - if (!pet_birth_process(sd,p)) //Pet hatched. Delete egg. - pc_delitem(sd,i,1,0,0,LOG_TYPE_OTHER); + // Hide egg from inventory. + // Set pet egg to broken, before the inventory gets saved + sd->inventory.u.items_inventory[i].attribute = 1; + + // Hatch the pet + pet_birth_process( sd, p ); } else { pet_data_init(sd,p); @@ -646,7 +1179,6 @@ int pet_catch_process2(struct map_session_data* sd, int target_id) { struct mob_data* md; int pet_catch_rate = 0; - struct s_pet_db* pet; nullpo_retr(1, sd); @@ -661,7 +1193,7 @@ int pet_catch_process2(struct map_session_data* sd, int target_id) //FIXME: delete taming item here, if this was an item-invoked capture and the item was flagged as delay-consume [ultramage] - pet = pet_db(md->mob_id); + std::shared_ptr pet = pet_db.find(md->mob_id); // If the target is a valid pet, we have a few exceptions if( pet ){ @@ -695,7 +1227,10 @@ int pet_catch_process2(struct map_session_data* sd, int target_id) unit_remove_map(&md->bl,CLR_OUTSIGHT); status_kill(&md->bl); clif_pet_roulette(sd,1); - intif_create_pet(sd->status.account_id, sd->status.char_id, pet->class_, mob_db(pet->class_)->lv, pet->EggID, 0, pet->intimate, 100, 0, 1, pet->jname); + + struct mob_db *mdb = mob_db(pet->class_); + + intif_create_pet(sd->status.account_id, sd->status.char_id, pet->class_, mdb->lv, pet->EggID, 0, pet->intimate, 100, 0, 1, mdb->jname); } else { clif_pet_roulette(sd,0); sd->catch_target_class = PET_CATCH_FAIL; @@ -717,7 +1252,6 @@ bool pet_get_egg(uint32 account_id, short pet_class, int pet_id ) { struct map_session_data *sd; struct item tmp_item; int ret = 0; - struct s_pet_db* pet; if( pet_id == 0 || pet_class == 0 ) return false; @@ -732,7 +1266,7 @@ bool pet_get_egg(uint32 account_id, short pet_class, int pet_id ) { // Before this change in cases where more than one pet egg were requested in a short // period of time it wasn't possible to know which kind of egg was being requested after // the first request. [Panikon] - pet = pet_db(pet_class); + std::shared_ptr pet = pet_db.find(pet_class); sd->catch_target_class = PET_CATCH_FAIL; if(!pet) { @@ -758,7 +1292,6 @@ bool pet_get_egg(uint32 account_id, short pet_class, int pet_id ) { } static int pet_unequipitem(struct map_session_data *sd, struct pet_data *pd); -static int pet_food(struct map_session_data *sd, struct pet_data *pd); static int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap); /** @@ -769,25 +1302,15 @@ static int pet_ai_sub_hard_lootsearch(struct block_list *bl,va_list ap); */ int pet_menu(struct map_session_data *sd,int menunum) { - struct item_data *egg_id; nullpo_ret(sd); if (sd->pd == NULL) return 1; //You lost the pet already. - if(!sd->status.pet_id || sd->pd->pet.intimate <= 0 || sd->pd->pet.incubate) + if(!sd->status.pet_id || sd->pd->pet.intimate <= PET_INTIMATE_NONE || sd->pd->pet.incubate) return 1; - egg_id = itemdb_exists(sd->pd->get_pet_db()->EggID); - - if (egg_id) { - if ((egg_id->flag.trade_restriction&0x01) && !pc_inventoryblank(sd)) { - clif_displaymessage(sd->fd, msg_txt(sd, 451)); // You can't return your pet because your inventory is full. - return 1; - } - } - switch(menunum) { case 0: clif_send_petstatus(sd); @@ -875,7 +1398,6 @@ int pet_change_name_ack(struct map_session_data *sd, char* name, int flag) int pet_equipitem(struct map_session_data *sd,int index) { struct pet_data *pd; - s_pet_db *pet_db_ptr; unsigned short nameid; nullpo_retr(1, sd); @@ -884,9 +1406,12 @@ int pet_equipitem(struct map_session_data *sd,int index) if (!pd) return 1; - - if((pet_db_ptr = pd->get_pet_db()) == nullptr) + + std::shared_ptr pet_db_ptr = pd->get_pet_db(); + + if( pet_db_ptr == nullptr ){ return 1; + } nameid = sd->inventory.u.items_inventory[index].nameid; @@ -974,12 +1499,12 @@ static int pet_unequipitem(struct map_session_data *sd, struct pet_data *pd) * @param pd : pet requesting * @return 0:success, 1:failure */ -static int pet_food(struct map_session_data *sd, struct pet_data *pd) +int pet_food(struct map_session_data *sd, struct pet_data *pd) { nullpo_retr(1, sd); nullpo_retr(1, pd); - s_pet_db *pet_db_ptr = pd->get_pet_db(); + std::shared_ptr pet_db_ptr = pd->get_pet_db(); int i,k; k = pet_db_ptr->FoodID; @@ -993,32 +1518,30 @@ static int pet_food(struct map_session_data *sd, struct pet_data *pd) pc_delitem(sd,i,1,0,0,LOG_TYPE_CONSUME); - if( pd->pet.hungry > 90 ) - pet_set_intimate(pd, pd->pet.intimate - pet_db_ptr->r_full); + if (pd->pet.hungry > PET_HUNGRY_SATISFIED) { + pet_set_intimate(pd, pd->pet.intimate + pet_db_ptr->r_full); + if (pd->pet.intimate <= PET_INTIMATE_NONE) { + pd->pet.intimate = PET_INTIMATE_NONE; + pet_stop_attack(pd); + pd->status.speed = pd->db->status.speed; + } + } else { if( battle_config.pet_friendly_rate != 100 ) k = (pet_db_ptr->r_hungry * battle_config.pet_friendly_rate) / 100; else k = pet_db_ptr->r_hungry; - if( pd->pet.hungry > 75 ) { - k = k >> 1; - if( k <= 0 ) - k = 1; + if( pd->pet.hungry > PET_HUNGRY_NEUTRAL) { + k >>= 1; + k = max(k, 1); } pet_set_intimate(pd, pd->pet.intimate + k); } - if( pd->pet.intimate <= 0 ) { - pd->pet.intimate = 0; - pet_stop_attack(pd); - pd->status.speed = pd->db->status.speed; - } else if( pd->pet.intimate > 1000 ) - pd->pet.intimate = 1000; - status_calc_pet(pd,SCO_NONE); - pd->pet.hungry += pet_db_ptr->fullness; + pd->pet.hungry = min(pd->pet.hungry + pet_db_ptr->hunger_increase, PET_HUNGRY_STUFFED); if( pd->pet.hungry > 100 ) pd->pet.hungry = 100; @@ -1115,7 +1638,7 @@ static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, t_t if(pd->ud.walktimer != INVALID_TIMER && pd->ud.walkpath.path_pos <= 2) return 0; // No thinking when you just started to walk. - if(pd->pet.intimate <= 0) { + if(pd->pet.intimate <= PET_INTIMATE_NONE) { // Pet should just... well, random walk. pet_randomwalk(pd,tick); @@ -1145,11 +1668,11 @@ static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, t_t } // Return speed to normal. - if (pd->status.speed != pd->get_pet_db()->speed) { + if (pd->status.speed != pd->db->status.speed) { if (pd->ud.walktimer != INVALID_TIMER) return 0; // Wait until the pet finishes walking back to master. - pd->status.speed = pd->get_pet_db()->speed; + pd->status.speed = pd->db->status.speed; pd->ud.state.change_walk_target = pd->ud.state.speed_changed = 1; } @@ -1552,149 +2075,173 @@ TIMER_FUNC(pet_skill_support_timer){ } /** - * Read pet databases. (pet_db.txt and pet_db2.txt) + * Search for the egg of pet pointed by pd from the player's inventory + * @param sd : player + * @param pet_id : pet ID of the pet + * @return index of egg in player's inventory or -1 if the egg is not found. */ -void read_petdb() -{ - const char* filename[] = { - DBPATH"pet_db.txt", - DBIMPORT"/pet_db.txt" - }; - unsigned short nameid; - int i; - - // clear database - pet_db_data.clear(); - - for( i = 0; i < ARRAYLENGTH(filename); i++ ) { - char line[1024]; - int lines, entries; - FILE *fp; - - sprintf(line, "%s/%s", db_path, filename[i]); - fp = fopen(line,"r"); - - if( fp == NULL ) { - if( i == 0 ) - ShowError("can't read %s\n",line); - continue; - } - - lines = entries = 0; - - while( fgets(line, sizeof(line), fp) ) { - char *str[22], *p; - unsigned k; - lines++; - - if(line[0] == '/' && line[1] == '/') - continue; - - memset(str, 0, sizeof(str)); - p = line; - - while( ISSPACE(*p) ) - ++p; - - if( *p == '\0' ) - continue; // empty line - - for( k = 0; k < 20; ++k ) { - str[k] = p; - p = strchr(p,','); - - if( p == NULL ) - break; // comma not found - - *p = '\0'; - ++p; - } - - if( p == NULL ) { - ShowError("read_petdb: Insufficient columns in line %d, skipping.\n", lines); - continue; - } - - // Pet Script - if( *p != '{' ) { - ShowError("read_petdb: Invalid format (Pet Script column) in line %d, skipping.\n", lines); - continue; - } - - str[20] = p; - p = strstr(p+1,"},"); - - if( p == NULL ) { - ShowError("read_petdb: Invalid format (Pet Script column) in line %d, skipping.\n", lines); - continue; - } - - p[1] = '\0'; - p += 2; - - // Equip Script - if( *p != '{' ) { - ShowError("read_petdb: Invalid format (Equip Script column) in line %d, skipping.\n", lines); - continue; - } - - str[21] = p; - - if( (nameid = atoi(str[0])) <= 0 ) - continue; - - if( !mobdb_checkid(nameid) ) { - ShowWarning("pet_db reading: Invalid mob-class %hu, pet not read.\n", nameid); - continue; - } - - struct s_pet_db* pet = &pet_db_data[nameid]; - - pet->class_ = nameid; - safestrncpy(pet->name,str[1],NAME_LENGTH); - safestrncpy(pet->jname,str[2],NAME_LENGTH); - pet->itemID=atoi(str[3]); - pet->EggID=atoi(str[4]); - pet->AcceID=atoi(str[5]); - pet->FoodID=atoi(str[6]); - pet->fullness=atoi(str[7]); - pet->hungry_delay=atoi(str[8])*1000; - pet->r_hungry=atoi(str[9]); - if( pet->r_hungry <= 0 ) - pet->r_hungry=1; - pet->r_full=atoi(str[10]); - pet->intimate=atoi(str[11]); - pet->die=atoi(str[12]); - pet->capture=atoi(str[13]); - pet->speed=atoi(str[14]); - pet->s_perfor=(char)atoi(str[15]); - pet->talk_convert_class=atoi(str[16]); - pet->attack_rate=atoi(str[17]); - pet->defence_attack_rate=atoi(str[18]); - pet->change_target_rate=atoi(str[19]); - pet->pet_script = nullptr; - pet->pet_loyal_script = nullptr; - - if( *str[20] ) - pet->pet_script = parse_script(str[20], filename[i], lines, 0); - - if( *str[21] ) - pet->pet_loyal_script = parse_script(str[21], filename[i], lines, 0); - - entries++; - } - - fclose(fp); - ShowStatus("Done reading '" CL_WHITE "%d" CL_RESET "' pets in '" CL_WHITE "%s/%s" CL_RESET "'.\n", entries, db_path, filename[i]); +int pet_egg_search(struct map_session_data* sd, int pet_id) { + for (int i = 0; i < MAX_INVENTORY; i++) { + if (sd->inventory.u.items_inventory[i].card[0] == CARD0_PET && + pet_id == MakeDWord(sd->inventory.u.items_inventory[i].card[1], sd->inventory.u.items_inventory[i].card[2])) + return i; } + return -1; } /** - * Initialization process of skill relationship. + * Check if the pet owner has the required evolution items + * @param sd: Player requesting the evolution item check + * @param pet_id: Pet's database ID + * @return True on success or false otherwise + */ +bool pet_evolution_requirements_check(struct map_session_data *sd, short pet_id) { + nullpo_retr(false, sd); + + if (sd->pd == nullptr) + return false; + + auto pet_db_ptr = sd->pd->get_pet_db(); + auto evo_data = pet_db_ptr->evolution_data.find(pet_id); + + if (evo_data == pet_db_ptr->evolution_data.end()) { + return false; + } + + for (const auto &requirement : evo_data->second->requirements) { + int count = 0; + for (int i = 0; i < MAX_INVENTORY; i++) { + if (sd->inventory.u.items_inventory[i].nameid == requirement.first) { + count += sd->inventory.u.items_inventory[i].amount; + } + } + if (count < requirement.second) + return false; + } + + return true; +} + +/** + * Process a pet evolution request + * @param sd: Player requesting the evolution + * @param pet_id: Pet's database ID + */ +void pet_evolution(struct map_session_data *sd, int16 pet_id) { + nullpo_retv(sd); + + if (sd->pd == nullptr) { + clif_pet_evolution_result(sd, e_pet_evolution_result::FAIL_UNKNOWN); + return; + } + + if (!battle_config.feature_petevolution) { + clif_pet_evolution_result(sd, e_pet_evolution_result::FAIL_UNKNOWN); + return; + } + + if (sd->pd->pet.intimate < PET_INTIMATE_LOYAL) { + clif_pet_evolution_result(sd, e_pet_evolution_result::FAIL_RG_FAMILIAR); + return; + } + + if (sd->pd->pet.equip) { + clif_pet_evolution_result(sd, e_pet_evolution_result::FAIL_RG_FAMILIAR); + return; + } + + auto pet_db_ptr = sd->pd->get_pet_db(); + + if (pet_db_ptr->evolution_data.find(pet_id) == pet_db_ptr->evolution_data.end()) { + clif_pet_evolution_result(sd, e_pet_evolution_result::FAIL_NOTEXIST_CALLPET); + return; + } + + if (!pet_evolution_requirements_check(sd, pet_id)) { + clif_pet_evolution_result(sd, e_pet_evolution_result::FAIL_MATERIAL); + return; + } + + for (const auto &requirement : pet_db_ptr->evolution_data[pet_id]->requirements) { + int count = requirement.second; + for (int i = 0; i < MAX_INVENTORY; i++) { + item *slot = &sd->inventory.u.items_inventory[i]; + int deduction = min(requirement.second, slot->amount); + if (slot->nameid == requirement.first) { + pc_delitem(sd, i, deduction, 0, 0, LOG_TYPE_OTHER); + count -= deduction; + if (count == 0) + break; + } + } + } + + std::shared_ptr new_data = pet_db.find(pet_id); + + if( new_data == nullptr ){ + return; + } + + int idx = pet_egg_search(sd, sd->pd->pet.pet_id); + + if( idx == -1 ){ + clif_pet_evolution_result(sd, e_pet_evolution_result::FAIL_NOTEXIST_CALLPET); + return; + } + + // Virtually delete the old egg + log_pick_pc(sd, LOG_TYPE_OTHER, -1, &sd->inventory.u.items_inventory[idx]); + clif_delitem(sd, idx, 1, 0); + + // Change the old egg to the new one + sd->inventory.u.items_inventory[idx].nameid = new_data->EggID; + sd->inventory_data[idx] = itemdb_search(new_data->EggID); + + // Virtually add it to the inventory + log_pick_pc(sd, LOG_TYPE_OTHER, 1, &sd->inventory.u.items_inventory[idx]); + clif_additem(sd, idx, 1, 0); + + // Remove the old pet from sight + unit_remove_map(&sd->pd->bl, CLR_OUTSIGHT); + + // Prepare the new pet + sd->pd->pet.class_ = pet_id; + sd->pd->pet.egg_id = new_data->EggID; + sd->pd->pet.intimate = new_data->intimate; + if( !sd->pd->pet.rename_flag ){ + struct mob_db* mdb = mob_db( pet_id ); + + safestrncpy(sd->pd->pet.name, mdb->jname, NAME_LENGTH); + } + status_set_viewdata(&sd->pd->bl, pet_id); + + // Save the pet and inventory data + intif_save_petdata(sd->status.account_id, &sd->pd->pet); + if (save_settings&CHARSAVE_PET) + chrif_save(sd, CSAVE_INVENTORY); + + // Spawn it + if (map_addblock(&sd->pd->bl)) + return; + + clif_spawn(&sd->pd->bl); + clif_send_petdata(sd, sd->pd, 0, 0); + clif_send_petdata(sd, sd->pd, 5, battle_config.pet_hair_style); + clif_pet_equip_area(sd->pd); + clif_send_petstatus(sd); + clif_emotion(&sd->bl, ET_BEST); + clif_specialeffect(&sd->pd->bl, EF_HO_UP, AREA); + + clif_pet_evolution_result(sd, e_pet_evolution_result::SUCCESS); + clif_inventorylist(sd); +} + +/** + * Initialize pet data. */ void do_init_pet(void) { - read_petdb(); + pet_db.load(); item_drop_ers = ers_new(sizeof(struct item_drop),"pet.cpp::item_drop_ers",ERS_OPT_NONE); item_drop_list_ers = ers_new(sizeof(struct item_drop_list),"pet.cpp::item_drop_list_ers",ERS_OPT_NONE); @@ -1710,12 +2257,12 @@ void do_init_pet(void) } /** - * Pet destructor. + * Destroy pet data. */ void do_final_pet(void) { - pet_db_data.clear(); - ers_destroy(item_drop_ers); ers_destroy(item_drop_list_ers); + + pet_db.clear(); } diff --git a/src/map/pet.hpp b/src/map/pet.hpp index a6b174d691..2b3732c4d7 100644 --- a/src/map/pet.hpp +++ b/src/map/pet.hpp @@ -5,6 +5,7 @@ #define PET_HPP #include "../common/cbasetypes.hpp" +#include "../common/database.hpp" #include "../common/mmo.hpp" #include "../common/timer.hpp" @@ -12,42 +13,49 @@ #include "status.hpp" #include "unit.hpp" +#include + #define MAX_PETLOOT_SIZE 30 +struct s_pet_evo_data { + uint16 target_mob_id; + std::unordered_map requirements; +}; + /// Pet DB struct s_pet_db { - short class_; ///< Monster ID - char name[NAME_LENGTH], ///< AEGIS name - jname[NAME_LENGTH]; ///< English name - unsigned short itemID; ///< Lure ID - unsigned short EggID; ///< Egg ID - unsigned short AcceID; ///< Accessory ID - unsigned short FoodID; ///< Food ID - int fullness; ///< Amount of hunger decresed each hungry_delay interval - int hungry_delay; ///< Hunger value decrease each x seconds - int r_hungry; ///< Intimacy increased after feeding - int r_full; ///< Intimacy reduced when over-fed - int intimate; ///< Initial intimacy value - int die; ///< Intimacy decreased when die - int capture; ///< Capture success rate 1000 = 100% - int speed; ///< Walk speed - char s_perfor; ///< Special performance - int talk_convert_class; ///< Disables pet talk (instead of talking they emote with /!.) (?) - int attack_rate; ///< Rate of which the pet will attack (requires at least pet_support_min_friendly intimacy). - int defence_attack_rate; ///< Rate of which the pet will retaliate when master is being attacked (requires at least pet_support_min_friendly intimacy). - int change_target_rate; ///< Rate of which the pet will change its attack target. + uint16 class_; ///< Monster ID + uint16 itemID; ///< Lure ID + uint16 EggID; ///< Egg ID + uint16 AcceID; ///< Accessory ID + uint16 FoodID; ///< Food ID + uint16 fullness; ///< Amount of hunger decresed each hungry_delay interval + uint32 hungry_delay; ///< Hunger value decrease each x seconds + int32 hunger_increase; ///< Hunger increased every time the pet is fed. + int32 r_hungry; ///< Intimacy increased after feeding + int32 r_full; ///< Intimacy increased when over-fed + uint32 intimate; ///< Initial intimacy value + int32 die; ///< Intimacy increased when die + int32 hungry_intimacy_dec; ///< Intimacy increased when hungry + uint16 capture; ///< Capture success rate 10000 = 100% + bool s_perfor; ///< Special performance + uint16 attack_rate; ///< Rate of which the pet will attack (requires at least pet_support_min_friendly intimacy). + uint16 defence_attack_rate; ///< Rate of which the pet will retaliate when master is being attacked (requires at least pet_support_min_friendly intimacy). + uint16 change_target_rate; ///< Rate of which the pet will change its attack target. + bool allow_autofeed; ///< Can this pet use auto feeding mechanic. + std::unordered_map> evolution_data; ///< Data for evolving the pet. struct script_code - *pet_script, ///< Script since pet hatched - *pet_loyal_script; ///< Script when pet is loyal + *pet_support_script, ///< Script since pet hatched. For pet* script commands only. + *pet_bonus_script; ///< Bonus script for this pet. ~s_pet_db() { - if( this->pet_script ){ - script_free_code(this->pet_script); + if( this->pet_support_script ){ + script_free_code(this->pet_support_script); } - if( this->pet_loyal_script ){ - script_free_code(this->pet_loyal_script); + if( this->pet_bonus_script ){ + script_free_code(this->pet_bonus_script); } } }; @@ -60,6 +68,25 @@ enum e_pet_catch : uint16 { PET_CATCH_UNIVERSAL_ITEM = 2, }; +enum e_pet_intimate_level : uint16 { + PET_INTIMATE_NONE = 0, + PET_INTIMATE_AWKWARD = 1, + PET_INTIMATE_SHY = 100, + PET_INTIMATE_NEUTRAL = 250, + PET_INTIMATE_CORDIAL = 750, + PET_INTIMATE_LOYAL = 910, + PET_INTIMATE_MAX = 1000 +}; + +enum e_pet_hungry : uint16 { + PET_HUNGRY_NONE = 0, + PET_HUNGRY_VERY_HUNGRY = 10, + PET_HUNGRY_HUNGRY = 25, + PET_HUNGRY_NEUTRAL = 75, + PET_HUNGRY_SATISFIED = 90, + PET_HUNGRY_STUFFED = 100 +}; + struct pet_recovery { //Stat recovery enum sc_type type; //Status Change id unsigned short delay; //How long before curing (secs). @@ -99,7 +126,18 @@ struct pet_loot { unsigned short max; }; -struct s_pet_db *pet_db(uint16 pet_id); +class PetDatabase : public TypesafeYamlDatabase{ +public: + PetDatabase() : TypesafeYamlDatabase( "PET_DB", 1 ){ + + } + + const std::string getDefaultLocation(); + uint64 parseBodyNode( const YAML::Node& node ); + bool reload(); +}; + +extern PetDatabase pet_db; struct pet_data { struct block_list bl; @@ -126,8 +164,8 @@ struct pet_data { int masterteleport_timer; struct map_session_data *master; - s_pet_db* get_pet_db() { - return pet_db(this->pet.class_); + std::shared_ptr get_pet_db() { + return pet_db.find(this->pet.class_); } }; @@ -137,9 +175,10 @@ void pet_set_intimate(struct pet_data *pd, int value); int pet_target_check(struct pet_data *pd,struct block_list *bl,int type); void pet_unlocktarget(struct pet_data *pd); int pet_sc_check(struct map_session_data *sd, int type); //Skotlex -struct s_pet_db* pet_db_search(int key, enum e_pet_itemtype type); +std::shared_ptr pet_db_search(int key, enum e_pet_itemtype type); int pet_hungry_timer_delete(struct pet_data *pd); bool pet_data_init(struct map_session_data *sd, struct s_pet *pet); +bool pet_return_egg( struct map_session_data *sd, struct pet_data *pd ); int pet_birth_process(struct map_session_data *sd, struct s_pet *pet); int pet_recv_petdata(uint32 account_id,struct s_pet *p,int flag); int pet_select_egg(struct map_session_data *sd,short egg_index); @@ -156,11 +195,14 @@ TIMER_FUNC(pet_skill_support_timer); // [Skotlex] TIMER_FUNC(pet_skill_bonus_timer); // [Valaris] TIMER_FUNC(pet_recovery_timer); // [Valaris] TIMER_FUNC(pet_heal_timer); // [Valaris] +int pet_egg_search(struct map_session_data *sd, int pet_id); +void pet_evolution(struct map_session_data *sd, int16 pet_id); +int pet_food(struct map_session_data *sd, struct pet_data *pd); +void pet_clear_support_bonuses(struct map_session_data *sd); #define pet_stop_walking(pd, type) unit_stop_walking(&(pd)->bl, type) #define pet_stop_attack(pd) unit_stop_attack(&(pd)->bl) -void read_petdb(void); void do_init_pet(void); void do_final_pet(void); diff --git a/src/map/script.cpp b/src/map/script.cpp index be5bebe74c..0eed657684 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -8638,7 +8638,7 @@ BUILDIN_FUNC(getbrokenid) num = script_getnum(st,2); for(i = 0; i < MAX_INVENTORY; i++) { - if(sd->inventory.u.items_inventory[i].attribute) { + if( sd->inventory.u.items_inventory[i].card[0] != CARD0_PET && sd->inventory.u.items_inventory[i].attribute ){ brokencounter++; if(num == brokencounter){ id = sd->inventory.u.items_inventory[i].nameid; @@ -8667,7 +8667,7 @@ BUILDIN_FUNC(repair) num = script_getnum(st,2); for(i = 0; i < MAX_INVENTORY; i++) { - if(sd->inventory.u.items_inventory[i].attribute) { + if( sd->inventory.u.items_inventory[i].card[0] != CARD0_PET && sd->inventory.u.items_inventory[i].attribute ){ repaircounter++; if(num == repaircounter) { sd->inventory.u.items_inventory[i].attribute = 0; @@ -8695,8 +8695,7 @@ BUILDIN_FUNC(repairall) for(i = 0; i < MAX_INVENTORY; i++) { - if(sd->inventory.u.items_inventory[i].nameid && sd->inventory.u.items_inventory[i].attribute) - { + if( sd->inventory.u.items_inventory[i].nameid && sd->inventory.u.items_inventory[i].card[0] != CARD0_PET && sd->inventory.u.items_inventory[i].attribute ){ sd->inventory.u.items_inventory[i].attribute = 0; clif_produceeffect(sd,0,sd->inventory.u.items_inventory[i].nameid); repaircounter++; @@ -10110,13 +10109,12 @@ BUILDIN_FUNC(makepet) { struct map_session_data* sd; uint16 mob_id; - struct s_pet_db* pet; if( !script_rid2sd(sd) ) return SCRIPT_CMD_FAILURE; mob_id = script_getnum(st,2); - pet = pet_db(mob_id); + std::shared_ptr pet = pet_db.find(mob_id); if( !pet ){ ShowError( "buildin_makepet: failed to create a pet with mob id %hu\n", mob_id); @@ -10124,7 +10122,10 @@ BUILDIN_FUNC(makepet) } sd->catch_target_class = mob_id; - intif_create_pet( sd->status.account_id, sd->status.char_id, pet->class_, mob_db(pet->class_)->lv, pet->EggID, 0, pet->intimate, 100, 0, 1, pet->jname ); + + struct mob_db* mdb = mob_db(pet->class_); + + intif_create_pet( sd->status.account_id, sd->status.char_id, pet->class_, mdb->lv, pet->EggID, 0, pet->intimate, 100, 0, 1, mdb->jname ); return SCRIPT_CMD_SUCCESS; } diff --git a/src/map/script_constants.hpp b/src/map/script_constants.hpp index 2da78757a6..89d4205e01 100644 --- a/src/map/script_constants.hpp +++ b/src/map/script_constants.hpp @@ -7105,6 +7105,23 @@ export_constant(PET_CATCH_UNIVERSAL); export_constant(PET_CATCH_UNIVERSAL_ITEM); + /* pet intimacy levels */ + export_constant(PET_INTIMATE_NONE); + export_constant(PET_INTIMATE_AWKWARD); + export_constant(PET_INTIMATE_SHY); + export_constant(PET_INTIMATE_NEUTRAL); + export_constant(PET_INTIMATE_CORDIAL); + export_constant(PET_INTIMATE_LOYAL); + export_constant(PET_INTIMATE_MAX); + + /* pet hunger levels */ + export_constant(PET_HUNGRY_NONE); + export_constant(PET_HUNGRY_VERY_HUNGRY); + export_constant(PET_HUNGRY_HUNGRY); + export_constant(PET_HUNGRY_NEUTRAL); + export_constant(PET_HUNGRY_SATISFIED); + export_constant(PET_HUNGRY_STUFFED); + /* monster modes */ export_constant(MD_NONE); export_constant(MD_CANMOVE); diff --git a/src/map/skill.cpp b/src/map/skill.cpp index b3ceb80424..ea9b9ec0e3 100755 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -6514,7 +6514,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui break; case SA_TAMINGMONSTER: clif_skill_nodamage(src,bl,skill_id,skill_lv,1); - if (sd && dstmd && pet_db(dstmd->mob_id)) { + if (sd && dstmd && pet_db.find(dstmd->mob_id)) { pet_catch_process1(sd, dstmd->mob_id); } break; diff --git a/src/map/status.cpp b/src/map/status.cpp index 497ba5e5e8..de66bc3d0e 100644 --- a/src/map/status.cpp +++ b/src/map/status.cpp @@ -2969,7 +2969,7 @@ void status_calc_pet_(struct pet_data *pd, enum e_status_calc_opt opt) memcpy(&pd->status, &pd->db->status, sizeof(struct status_data)); pd->status.mode = MD_CANMOVE; // Pets discard all modes, except walking pd->status.class_ = CLASS_NORMAL; - pd->status.speed = pd->get_pet_db()->speed; + pd->status.speed = pd->db->status.speed; if(battle_config.pet_attack_support || battle_config.pet_damage_support) { // Attack support requires the pet to be able to attack @@ -3823,11 +3823,10 @@ int status_calc_pc_sub(struct map_session_data* sd, enum e_status_calc_opt opt) if( sd->pd ) { // Pet Bonus struct pet_data *pd = sd->pd; - s_pet_db *pet_db_ptr = pd->get_pet_db(); - - if( pet_db_ptr != nullptr && pet_db_ptr->pet_loyal_script && pd->pet.intimate >= battle_config.pet_equip_min_friendly ) - run_script(pd->get_pet_db()->pet_loyal_script,0,sd->bl.id,0); - if( pd->pet.intimate > 0 && (!battle_config.pet_equip_required || pd->pet.equip > 0) && pd->state.skillbonus == 1 && pd->bonus ) + std::shared_ptr pet_db_ptr = pd->get_pet_db(); + if( pet_db_ptr != nullptr && pet_db_ptr->pet_bonus_script && pd->pet.intimate >= battle_config.pet_equip_min_friendly ) + run_script(pet_db_ptr->pet_bonus_script,0,sd->bl.id,0); + if( pet_db_ptr != nullptr && pd->pet.intimate > 0 && (!battle_config.pet_equip_required || pd->pet.equip > 0) && pd->state.skillbonus == 1 && pd->bonus ) pc_bonus(sd,pd->bonus->type, pd->bonus->val); } @@ -10568,7 +10567,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty if( pc_iswug(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_WUG); if( pc_isridingwug(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_WUGRIDER); if( pc_isfalcon(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_FALCON); - if( sd->status.pet_id > 0 ) pet_menu(sd, 3); + if( sd->status.pet_id > 0 ) pet_return_egg(sd, sd->pd); if( hom_is_active(sd->hd) ) hom_vaporize(sd, HOM_ST_ACTIVE); //if( sd->md ) mercenary_delete(sd->md,3); // Are Mercenaries removed? [aleos] } diff --git a/src/map/unit.cpp b/src/map/unit.cpp index 3305283d91..e7acd3f5a7 100644 --- a/src/map/unit.cpp +++ b/src/map/unit.cpp @@ -982,7 +982,7 @@ bool unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, boo } else sd->areanpc_id=0; - if( sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > 0 ) { + if( sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > PET_INTIMATE_NONE ) { // Check if pet needs to be teleported. [Skotlex] int flag = 0; struct block_list* pbl = &sd->pd->bl; @@ -3033,7 +3033,7 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, case BL_PET: { struct pet_data *pd = (struct pet_data*)bl; - if( pd->pet.intimate <= 0 && !(pd->master && !pd->master->state.active) ) { + if( pd->pet.intimate <= PET_INTIMATE_NONE && !(pd->master && !pd->master->state.active) ) { // If logging out, this is deleted on unit_free clif_clearunit_area(bl,clrtype); map_delblock(bl); @@ -3265,51 +3265,9 @@ int unit_free(struct block_list *bl, clr_type clrtype) struct map_session_data *sd = pd->master; pet_hungry_timer_delete(pd); + pet_clear_support_bonuses(sd); - if( pd->a_skill ) { - aFree(pd->a_skill); - pd->a_skill = NULL; - } - - if( pd->s_skill ) { - if (pd->s_skill->timer != INVALID_TIMER) { - if (pd->s_skill->id) - delete_timer(pd->s_skill->timer, pet_skill_support_timer); - else - delete_timer(pd->s_skill->timer, pet_heal_timer); - } - - aFree(pd->s_skill); - pd->s_skill = NULL; - } - - if( pd->recovery ) { - if(pd->recovery->timer != INVALID_TIMER) - delete_timer(pd->recovery->timer, pet_recovery_timer); - - aFree(pd->recovery); - pd->recovery = NULL; - } - - if( pd->bonus ) { - if (pd->bonus->timer != INVALID_TIMER) - delete_timer(pd->bonus->timer, pet_skill_bonus_timer); - - aFree(pd->bonus); - pd->bonus = NULL; - } - - if( pd->loot ) { - pet_lootitem_drop(pd,sd); - - if (pd->loot->item) - aFree(pd->loot->item); - - aFree (pd->loot); - pd->loot = NULL; - } - - if( pd->pet.intimate > 0 ) + if( pd->pet.intimate > PET_INTIMATE_NONE ) intif_save_petdata(pd->pet.account_id,&pd->pet); else { // Remove pet. intif_delete_petdata(pd->pet.pet_id); diff --git a/src/tool/csv2yaml.cpp b/src/tool/csv2yaml.cpp index 42257af372..1e7147b5bb 100644 --- a/src/tool/csv2yaml.cpp +++ b/src/tool/csv2yaml.cpp @@ -24,6 +24,9 @@ #include "../common/strlib.hpp" #include "../common/utilities.hpp" +// Only for constants - do not use functions of it or linking will fail +#include "../map/mob.hpp" // MAX_MVP_DROP and MAX_MOB_DROP + using namespace rathena; #ifndef WIN32 @@ -45,11 +48,16 @@ int getch( void ){ // Forward declaration of conversion functions static bool guild_read_guildskill_tree_db( char* split[], int columns, int current ); +static size_t pet_read_db( const char* file ); // Constants for conversion +std::unordered_map aegis_itemnames; +std::unordered_map aegis_mobnames; std::unordered_map aegis_skillnames; // Forward declaration of constant loading functions +static bool parse_item_constants( const char* path ); +static bool parse_mob_constants( char* split[], int columns, int current ); static bool parse_skill_constants( char* split[], int columns, int current ); bool fileExists( const std::string& path ); @@ -109,6 +117,10 @@ int do_init( int argc, char** argv ){ const std::string path_db_import = path_db + "/" + DBIMPORT; // Loads required conversion constants + parse_item_constants( ( path_db_mode + "/item_db.txt" ).c_str() ); + parse_item_constants( ( path_db_import + "/item_db.txt" ).c_str() ); + sv_readdb( path_db_mode.c_str(), "mob_db.txt", ',', 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, -1, &parse_mob_constants, false ); + sv_readdb( path_db_import.c_str(), "mob_db.txt", ',', 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, 31 + 2 * MAX_MVP_DROP + 2 * MAX_MOB_DROP, -1, &parse_mob_constants, false ); sv_readdb( path_db_mode.c_str(), "skill_db.txt", ',', 18, 18, -1, parse_skill_constants, false ); sv_readdb( path_db_import.c_str(), "skill_db.txt", ',', 18, 18, -1, parse_skill_constants, false ); @@ -117,12 +129,23 @@ int do_init( int argc, char** argv ){ path_db_import }; - if( process( "GUILD_SKILL_TREE_DB", 1, guild_skill_tree_paths, "guild_skill_tree", []( const std::string& path, const std::string& name_ext ) -> bool { + if( !process( "GUILD_SKILL_TREE_DB", 1, guild_skill_tree_paths, "guild_skill_tree", []( const std::string& path, const std::string& name_ext ) -> bool { return sv_readdb( path.c_str(), name_ext.c_str(), ',', 2 + MAX_GUILD_SKILL_REQUIRE * 2, 2 + MAX_GUILD_SKILL_REQUIRE * 2, -1, &guild_read_guildskill_tree_db, false ); } ) ){ return 0; } + std::vector pet_paths = { + path_db_mode, + path_db_import + }; + + if( !process( "PET_DB", 1, pet_paths, "pet_db", []( const std::string& path, const std::string& name_ext ) -> bool { + return pet_read_db( ( path + name_ext ).c_str() ); + } ) ){ + return 0; + } + // TODO: add implementations ;-) return 0; @@ -197,6 +220,141 @@ bool askConfirmation( const char* fmt, ... ){ } // Constant loading functions +static bool parse_item_constants( const char* path ){ + uint32 lines = 0, count = 0; + char line[1024]; + + FILE* fp; + + fp = fopen(path, "r"); + if (fp == NULL) { + ShowWarning("itemdb_readdb: File not found \"%s\", skipping.\n", path); + return false; + } + + // process rows one by one + while (fgets(line, sizeof(line), fp)) + { + char *str[32], *p; + int i; + lines++; + if (line[0] == '/' && line[1] == '/') + continue; + memset(str, 0, sizeof(str)); + + p = strstr(line, "//"); + + if (p != nullptr) { + *p = '\0'; + } + + p = line; + while (ISSPACE(*p)) + ++p; + if (*p == '\0') + continue;// empty line + for (i = 0; i < 19; ++i) + { + str[i] = p; + p = strchr(p, ','); + if (p == NULL) + break;// comma not found + *p = '\0'; + ++p; + } + + if (p == NULL) + { + ShowError("itemdb_readdb: Insufficient columns in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); + continue; + } + + // Script + if (*p != '{') + { + ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); + continue; + } + str[19] = p + 1; + p = strstr(p + 1, "},"); + if (p == NULL) + { + ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); + continue; + } + *p = '\0'; + p += 2; + + // OnEquip_Script + if (*p != '{') + { + ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); + continue; + } + str[20] = p + 1; + p = strstr(p + 1, "},"); + if (p == NULL) + { + ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); + continue; + } + *p = '\0'; + p += 2; + + // OnUnequip_Script (last column) + if (*p != '{') + { + ShowError("itemdb_readdb: Invalid format (OnUnequip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); + continue; + } + str[21] = p; + p = &str[21][strlen(str[21]) - 2]; + + if (*p != '}') { + /* lets count to ensure it's not something silly e.g. a extra space at line ending */ + int lcurly = 0, rcurly = 0; + + for (size_t v = 0; v < strlen(str[21]); v++) { + if (str[21][v] == '{') + lcurly++; + else if (str[21][v] == '}') { + rcurly++; + p = &str[21][v]; + } + } + + if (lcurly != rcurly) { + ShowError("itemdb_readdb: Mismatching curly braces in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0])); + continue; + } + } + str[21] = str[21] + 1; //skip the first left curly + *p = '\0'; //null the last right curly + + uint16 item_id = atoi( str[0] ); + char* name = trim( str[1] ); + + aegis_itemnames[item_id] = std::string(name); + + count++; + } + + fclose(fp); + + ShowStatus("Done reading '" CL_WHITE "%u" CL_RESET "' entries in '" CL_WHITE "%s" CL_RESET "'.\n", count, path); + + return true; +} + +static bool parse_mob_constants( char* split[], int columns, int current ){ + uint16 mob_id = atoi( split[0] ); + char* name = trim( split[1] ); + + aegis_mobnames[mob_id] = std::string( name ); + + return true; +} + static bool parse_skill_constants( char* split[], int columns, int current ){ uint16 skill_id = atoi( split[0] ); char* name = trim( split[16] ); @@ -252,3 +410,184 @@ static bool guild_read_guildskill_tree_db( char* split[], int columns, int curre return true; } + +// Copied and adjusted from pet.cpp +static size_t pet_read_db( const char* file ){ + FILE* fp = fopen( file, "r" ); + + if( fp == nullptr ){ + ShowError( "can't read %s\n", file ); + return 0; + } + + int lines = 0; + size_t entries = 0; + char line[1024]; + + while( fgets( line, sizeof(line), fp ) ) { + char *str[22], *p; + unsigned k; + lines++; + + if(line[0] == '/' && line[1] == '/') + continue; + + memset(str, 0, sizeof(str)); + p = line; + + while( ISSPACE(*p) ) + ++p; + + if( *p == '\0' ) + continue; // empty line + + for( k = 0; k < 20; ++k ) { + str[k] = p; + p = strchr(p,','); + + if( p == NULL ) + break; // comma not found + + *p = '\0'; + ++p; + } + + if( p == NULL ) { + ShowError("read_petdb: Insufficient columns in line %d, skipping.\n", lines); + continue; + } + + // Pet Script + if( *p != '{' ) { + ShowError("read_petdb: Invalid format (Pet Script column) in line %d, skipping.\n", lines); + continue; + } + + str[20] = p; + p = strstr(p+1,"},"); + + if( p == NULL ) { + ShowError("read_petdb: Invalid format (Pet Script column) in line %d, skipping.\n", lines); + continue; + } + + p[1] = '\0'; + p += 2; + + // Equip Script + if( *p != '{' ) { + ShowError("read_petdb: Invalid format (Equip Script column) in line %d, skipping.\n", lines); + continue; + } + + str[21] = p; + + uint16 mob_id = atoi( str[0] ); + std::string* mob_name = util::umap_find( aegis_mobnames, mob_id ); + + if( mob_name == nullptr ){ + ShowWarning( "pet_db reading: Invalid mob-class %hu, pet not read.\n", mob_id ); + continue; + } + + YAML::Node node; + + node["Mob"] = *mob_name; + + uint16 tame_item_id = (uint16)atoi( str[3] ); + + if( tame_item_id > 0 ){ + std::string* tame_item_name = util::umap_find( aegis_itemnames, tame_item_id ); + + if( tame_item_name == nullptr ){ + ShowError( "Item name for item id %hu is not known.\n", tame_item_id ); + return false; + } + + node["TameItem"] = *tame_item_name; + } + + uint16 egg_item_id = (uint16)atoi( str[4] ); + + std::string* egg_item_name = util::umap_find( aegis_itemnames, egg_item_id ); + + if( egg_item_name == nullptr ){ + ShowError( "Item name for item id %hu is not known.\n", egg_item_id ); + return false; + } + + node["EggItem"] = *egg_item_name; + + uint16 equip_item_id = (uint16)atoi( str[5] ); + + if( equip_item_id > 0 ){ + std::string* equip_item_name = util::umap_find( aegis_itemnames, equip_item_id ); + + if( equip_item_name == nullptr ){ + ShowError( "Item name for item id %hu is not known.\n", equip_item_id ); + return false; + } + + node["EquipItem"] = *equip_item_name; + } + + uint16 food_item_id = (uint16)atoi( str[6] ); + + if( food_item_id > 0 ){ + std::string* food_item_name = util::umap_find( aegis_itemnames, food_item_id ); + + if( food_item_name == nullptr ){ + ShowError( "Item name for item id %hu is not known.\n", food_item_id ); + return false; + } + + node["FoodItem"] = *food_item_name; + } + + node["Fullness"] = atoi( str[7] ); + // Default: 60 + if( atoi( str[8] ) != 60 ){ + node["HungryDelay"] = atoi( str[8] ); + } + // Default: 250 + if( atoi( str[11] ) != 250 ){ + node["IntimacyStart"] = atoi( str[11] ); + } + node["IntimacyFed"] = atoi( str[9] ); + // Default: -100 + if( atoi( str[10] ) != 100 ){ + node["IntimacyOverfed"] = -atoi( str[10] ); + } + // pet_hungry_friendly_decrease battle_conf + //node["IntimacyHungry"] = -5; + // Default: -20 + if( atoi( str[12] ) != 20 ){ + node["IntimacyOwnerDie"] = -atoi( str[12] ); + } + node["CaptureRate"] = atoi( str[13] ); + // Default: true + if( atoi( str[15] ) == 0 ){ + node["SpecialPerformance"] = false; + } + node["AttackRate"] = atoi( str[17] ); + node["RetaliateRate"] = atoi( str[18] ); + node["ChangeTargetRate"] = atoi( str[19] ); + + if( *str[21] ){ + node["Script"] = str[21]; + } + + if( *str[20] ){ + node["SupportScript"] = str[20]; + } + + body[counter++] = node; + + entries++; + } + + fclose(fp); + ShowStatus("Done reading '" CL_WHITE "%d" CL_RESET "' pets in '" CL_WHITE "%s" CL_RESET "'.\n", entries, file ); + + return entries; +}