summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2020-04-05 23:10:48 +0200
committerGitHub <noreply@github.com>2020-04-05 23:10:48 +0200
commitc7ad2580c502dfed6d4fe34907758cd93ddfded3 (patch)
tree6fe8bab9014587acbc09bf0750afabee840c6199
parentb996ad73974b282a15db217fcbac5f284be3fdd5 (diff)
parentfb0e6a0172124df95ce32d6ad0b3b4cb85747f6d (diff)
downloadhercules-c7ad2580c502dfed6d4fe34907758cd93ddfded3.tar.gz
hercules-c7ad2580c502dfed6d4fe34907758cd93ddfded3.tar.bz2
hercules-c7ad2580c502dfed6d4fe34907758cd93ddfded3.tar.xz
hercules-c7ad2580c502dfed6d4fe34907758cd93ddfded3.zip
Merge pull request #2600 from Kenpachi2k13/issue#2434
Preparation for upcoming pet DB update.
-rw-r--r--conf/map/battle/pet.conf15
-rw-r--r--db/pre-re/pet_db.conf915
-rw-r--r--db/re/pet_db.conf1014
-rw-r--r--doc/pet_db.txt196
-rw-r--r--src/char/int_pet.c231
-rw-r--r--src/common/mmo.h21
-rw-r--r--src/map/atcommand.c143
-rw-r--r--src/map/battle.c3
-rw-r--r--src/map/battle.h3
-rw-r--r--src/map/clif.c453
-rw-r--r--src/map/mob.h2
-rw-r--r--src/map/pc.c694
-rw-r--r--src/map/pet.c934
-rw-r--r--src/map/pet.h4
-rw-r--r--src/map/script.c648
-rw-r--r--src/map/status.c14
-rw-r--r--src/map/unit.c6
17 files changed, 2474 insertions, 2822 deletions
diff --git a/conf/map/battle/pet.conf b/conf/map/battle/pet.conf
index fa0057564..5797bb2a5 100644
--- a/conf/map/battle/pet.conf
+++ b/conf/map/battle/pet.conf
@@ -32,6 +32,14 @@
// assume unit types (1: Pc, 2: Mob, 4: Pet, 8: Homun, 16: Mercenary)
//=========================================================================
+// Use the offical formula to calculate the pet catch rate? (Note 1)
+// Official formula:
+// CatchRate = CaptureRate * (100 - 100 * MonsterHP / MonsterMaxHP) / 100 + CaptureRate
+// Custum *Athena formula:
+// CatchRate = (CaptureRate + (CharacterBaseLevel - MonsterLevel) * 30 + CharacterLuk * 20) * (200 - 100 * MonsterHP / MonsterMaxHP) / 100
+// (CaptureRate is defined in db/(pre-)re/pet_db.conf.)
+pet_catch_rate_official_formula: true
+
// Rate for catching pets (Note 2)
pet_catch_rate: 100
@@ -44,10 +52,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: true
@@ -62,9 +66,6 @@ pet_damage_support: false
// 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).
diff --git a/db/pre-re/pet_db.conf b/db/pre-re/pet_db.conf
index 112ce54eb..5c3949572 100644
--- a/db/pre-re/pet_db.conf
+++ b/db/pre-re/pet_db.conf
@@ -34,1518 +34,1037 @@ pet_db:(
{
// ================ Mandatory fields ==============================
Id: ID (int)
- SpriteName: "Sprite_Name" (string)
Name: "Pet Name" (string)
+ EggItem: "Egg Item Constant" (string)
// ================ Optional fields ===============================
- TamingItem: Taming Item (string, defaults to 0)
- EggItem: Egg Id (string, defaults to 0)
- AccessoryItem: Equipment Id (string, defaults to 0)
- FoodItem: Food Id (string, defaults to 0)
- FoodEffectiveness: hunger points (int, defaults to 0)
- HungerDelay: hunger time (int, defaults to 0)
+ TamingItem: "Taming Item Constant" (string, defaults to 0)
+ FoodItem: "Food Item Constant" (string, defaults to "Pet_Food" (ID=537))
+ AccessoryItem: "Equipment Item Constant" (string, defaults to 0)
+ FoodEffectiveness: hunger points (int, defaults to 80)
+ HungerDelay: hunger time (int, defaults to 60)
+ HungerDecrement: hunger points (int, defaults to 1)
Intimacy: {
- Initial: start intimacy (int, defaults to 0)
- FeedIncrement: feeding intimacy (int, defaults to 0)
- OverFeedDecrement: overfeeding intimacy (int, defaults to 0)
- OwnerDeathDecrement: owner die intimacy (int, defaults to 0)
+ Initial: start intimacy (int, defaults to 250)
+ FeedIncrement: feeding intimacy (int, defaults to 10)
+ OverFeedDecrement: overfeeding intimacy (int, defaults to 100)
+ OwnerDeathDecrement: owner die intimacy (int, defaults to 20)
+ StarvingDelay: starving time (int, defaults to 20)
+ StarvingDecrement: starving intimacy (int, defaults to 20)
}
- CaptureRate: capture rate (int, defaults to 0)
- Speed: speed (int, defaults to 0)
+ CaptureRate: capture rate (int, defaults to 1000)
+ Speed: speed (int, defaults to 150)
SpecialPerformance: true/false (boolean, defaults to false)
TalkWithEmotes: convert talk (boolean, defaults to false)
- AttackRate: attack rate (int, defaults to 0)
- DefendRate: Defence attack (int, defaults to 0)
- ChangeTargetRate: change target (int, defaults to 0)
+ AttackRate: attack rate (int, defaults to 300)
+ DefendRate: Defence attack (int, defaults to 300)
+ ChangeTargetRate: change target (int, defaults to 800)
+ AutoFeed: true/false (boolean, defaults to false)
+ PetScript: <" Pet Script (can also be multi-line) ">
+ EquipScript: <" Equip Script (can also be multi-line) ">
Evolve: {
- EggID: { (string, Evolved Pet EggID)
- Name: Amount (items required to perform evolution)
+ EggID: { (string, Evolved Pet EggID)
+ Name: Amount (items required to perform evolution)
...
}
}
- AutoFeed: true/false (boolean, defaults to false)
- PetScript: <" Pet Script (can also be multi-line) ">
- EquipScript: <" Equip Script (can also be multi-line) ">
},
**************************************************************************/
{
Id: 1002
- SpriteName: "PORING"
Name: "Poring"
TamingItem: "Unripe_Apple"
EggItem: "Poring_Egg"
AccessoryItem: "Backpack"
FoodItem: "Apple_Juice"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 2000
- Speed: 150
SpecialPerformance: true
AttackRate: 350
DefendRate: 400
- ChangeTargetRate: 800
PetScript: <" petloot(10); ">
EquipScript: <"
- bonus(bLuk, 2);
- bonus(bCritical, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bLuk, 2);
+ bonus(bCritical, 1);
+ }
">
},
{
Id: 1011
- SpriteName: "CHONCHON"
Name: "ChonChon"
TamingItem: "Rotten_Fish"
EggItem: "Chonchon_Egg"
AccessoryItem: "Monster_Oxygen_Mask"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 1500
- Speed: 150
SpecialPerformance: true
AttackRate: 500
DefendRate: 500
ChangeTargetRate: 250
PetScript: <" petskillbonus(bAgi, 4, 10, 50); ">
EquipScript: <"
- bonus(bAgi, 1);
- bonus(bFlee, 2);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bAgi, 1);
+ bonus(bFlee, 2);
+ }
">
},
{
Id: 1014
- SpriteName: "SPORE"
Name: "Spore"
TamingItem: "Dew_Laden_Moss"
EggItem: "Spore_Egg"
AccessoryItem: "Bark_Shorts"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 1500
- Speed: 150
AttackRate: 350
DefendRate: 500
ChangeTargetRate: 500
PetScript: <" petrecovery(SC_POISON, 60); ">
EquipScript: <"
- bonus(bHit, 5);
- bonus(bAtk, -2);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bHit, 5);
+ bonus(bAtk, -2);
+ }
">
},
{
Id: 1019
- SpriteName: "PECOPECO"
Name: "PecoPeco"
TamingItem: "Fatty_Chubby_Earthworm"
EggItem: "PecoPeco_Egg"
AccessoryItem: "Battered_Pot"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 1000
- Speed: 150
SpecialPerformance: true
AttackRate: 400
DefendRate: 500
- ChangeTargetRate: 800
PetScript: <" petskillbonus(bSpeedRate, 25, 20, 20); ">
EquipScript: <"
- bonus(bMaxHP, 150);
- bonus(bMaxSP, -10);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMaxHP, 150);
+ bonus(bMaxSP, -10);
+ }
">
},
{
Id: 1023
- SpriteName: "ORK_WARRIOR"
Name: "Orc Warrior"
TamingItem: "Horror_Of_Tribe"
EggItem: "Orc_Warrior_Egg"
AccessoryItem: "Wild_Flower"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
SpecialPerformance: true
AttackRate: 600
DefendRate: 200
ChangeTargetRate: 300
PetScript: <" petskillattack("NPC_PIERCINGATT", 100, 1, 0, 10); ">
EquipScript: <"
- bonus(bAtk, 10);
- bonus(bDef, -3);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bAtk, 10);
+ bonus(bDef, -3);
+ }
">
},
{
Id: 1026
- SpriteName: "MUNAK"
Name: "Munak"
TamingItem: "No_Recipient"
EggItem: "Munak_Egg"
AccessoryItem: "Punisher"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 300
DefendRate: 750
ChangeTargetRate: 300
PetScript: <" petskillattack("NPC_DARKNESSATTACK", 444, 1, 0, 10); ">
EquipScript: <"
- bonus(bInt, 1);
- bonus(bDef, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bInt, 1);
+ bonus(bDef, 1);
+ }
">
},
{
Id: 1029
- SpriteName: "ISIS"
Name: "Isis"
TamingItem: "Armlet_Of_Obedience"
EggItem: "Isis_Egg"
AccessoryItem: "Queens_Hair_Ornament"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 500
- Speed: 150
AttackRate: 650
DefendRate: 450
ChangeTargetRate: 150
PetScript: <" petskillsupport("PR_MAGNIFICAT", 2, 60, 50, 50); ">
EquipScript: <"
- bonus(bMatkRate, -1);
- bonus(bAtkRate, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMatkRate, -1);
+ bonus(bAtkRate, 1);
+ }
">
},
{
Id: 1031
- SpriteName: "POPORING"
Name: "Poporing"
TamingItem: "Bitter_Herb"
EggItem: "Poporing_Egg"
AccessoryItem: "Backpack"
FoodItem: "Green_Herb"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 1000
- Speed: 150
SpecialPerformance: true
- AttackRate: 300
DefendRate: 500
ChangeTargetRate: 400
PetScript: <" petloot(15); ">
EquipScript: <"
- bonus(bLuk, 2);
- bonus2(bSubEle, Ele_Poison, 10);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bLuk, 2);
+ bonus2(bSubEle, Ele_Poison, 10);
+ }
">
},
{
Id: 1035
- SpriteName: "HUNTER_FLY"
Name: "Hunter Fly"
TamingItem: "Monster_Juice"
EggItem: "Hunter_Fly_Egg"
AccessoryItem: "Monster_Oxygen_Mask"
FoodItem: "Red_Gemstone"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 500
- Speed: 150
SpecialPerformance: true
AttackRate: 500
DefendRate: 500
ChangeTargetRate: 200
PetScript: <" petskillattack("NPC_WINDATTACK", 888, 2, 0, 10); ">
EquipScript: <"
- bonus(bFlee, -5);
- bonus(bFlee2, 2);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bFlee, -5);
+ bonus(bFlee2, 2);
+ }
">
},
{
Id: 1042
- SpriteName: "STEEL_CHONCHON"
Name: "Steel ChonChon"
TamingItem: "Lusty_Iron"
EggItem: "Steel_Chonchon_Egg"
AccessoryItem: "Monster_Oxygen_Mask"
FoodItem: "Iron_Ore"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 1000
- Speed: 150
SpecialPerformance: true
AttackRate: 500
DefendRate: 500
ChangeTargetRate: 200
PetScript: <" petskillbonus(bAgiVit, 4, 20, 40); ">
EquipScript: <"
- bonus(bFlee, 6);
- bonus(bAgi, -1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bFlee, 6);
+ bonus(bAgi, -1);
+ }
">
},
{
Id: 1049
- SpriteName: "PICKY"
Name: "Picky"
TamingItem: "Earthworm_The_Dude"
EggItem: "Picky_Egg"
AccessoryItem: "Tiny_Egg_Shell"
FoodItem: "Red_Herb"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 40
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 2000
- Speed: 150
SpecialPerformance: true
AttackRate: 500
DefendRate: 600
ChangeTargetRate: 50
PetScript: <" petskillbonus(bStr, 3, 10, 50); ">
EquipScript: <"
- bonus(bStr, 1);
- bonus(bAtk, 5);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bStr, 1);
+ bonus(bAtk, 5);
+ }
">
},
{
Id: 1052
- SpriteName: "ROCKER"
Name: "Rocker"
TamingItem: "Singing_Flower"
EggItem: "Rocker_Egg"
AccessoryItem: "Rocker_Glasses"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 1500
- Speed: 150
AttackRate: 350
DefendRate: 350
ChangeTargetRate: 600
PetScript: <" petskillbonus(bAllStats, 1, 10, 50); ">
EquipScript: <"
- bonus(bHPrecovRate, 5);
- bonus(bMaxHP, 25);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bHPrecovRate, 5);
+ bonus(bMaxHP, 25);
+ }
">
},
{
Id: 1056
- SpriteName: "SMOKIE"
Name: "Smokie"
TamingItem: "Baked_Yam"
EggItem: "Smokie_Egg"
AccessoryItem: "Red_Muffler"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 1000
- Speed: 150
SpecialPerformance: true
AttackRate: 600
DefendRate: 600
ChangeTargetRate: 100
PetScript: <" petskillbonus(bPerfectHide, 1, 3600, 0); ">
EquipScript: <"
- bonus(bAgi, 1);
- bonus(bFlee2, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bAgi, 1);
+ bonus(bFlee2, 1);
+ }
">
},
{
Id: 1057
- SpriteName: "YOYO"
Name: "Yoyo"
TamingItem: "Tropical_Banana"
EggItem: "Yoyo_Egg"
AccessoryItem: "Monkey_Circlet"
FoodItem: "Banana_Juice"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 1000
- Speed: 150
SpecialPerformance: true
- AttackRate: 300
- DefendRate: 800
ChangeTargetRate: 400
PetScript: <" petloot(20); ">
EquipScript: <"
- bonus(bCritical, 3);
- bonus(bLuk, -1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bCritical, 3);
+ bonus(bLuk, -1);
+ }
">
},
{
Id: 1063
- SpriteName: "LUNATIC"
Name: "Lunatic"
TamingItem: "Rainbow_Carrot"
EggItem: "Lunatic_Egg"
AccessoryItem: "Silk_Ribbon"
FoodItem: "Carrot_Juice"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 40
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 1500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
ChangeTargetRate: 1000
PetScript: <" petskillbonus(bLuk, 3, 10, 50); ">
EquipScript: <"
- bonus(bCritical, 2);
- bonus(bAtk, 2);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bCritical, 2);
+ bonus(bAtk, 2);
+ }
">
},
{
Id: 1077
- SpriteName: "POISON_SPORE"
Name: "Poison Spore"
TamingItem: "Deadly_Noxious_Herb"
EggItem: "Poison_Spore_Egg"
AccessoryItem: "Bark_Shorts"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 1000
- Speed: 150
AttackRate: 600
DefendRate: 200
ChangeTargetRate: 400
PetScript: <" petskillattack("NPC_POISON", 20, 0, 0, 10); ">
EquipScript: <"
- bonus(bStr, 1);
- bonus(bInt, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bStr, 1);
+ bonus(bInt, 1);
+ }
">
},
{
Id: 1101
- SpriteName: "BAPHOMET_"
Name: "Baphomet Jr."
TamingItem: "Book_Of_Devil"
EggItem: "Bapho_Jr_Egg"
AccessoryItem: "Skull_Helm"
FoodItem: "Honey"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 200
- Speed: 150
AttackRate: 1000
DefendRate: 100
ChangeTargetRate: 200
PetScript: <" petskillattack("NPC_DARKNESSATTACK", 1776, 4, 0, 5); ">
EquipScript: <"
- bonus(bDef, 1);
- bonus(bMdef, 1);
- bonus2(bResEff, Eff_Stun, -100);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bDef, 1);
+ bonus(bMdef, 1);
+ bonus2(bResEff, Eff_Stun, -100);
+ }
">
},
{
Id: 1107
- SpriteName: "DESERT_WOLF_B"
Name: "Baby Desert Wolf"
TamingItem: "Well_Dried_Bone"
EggItem: "Baby_Desert_Wolf_Egg"
AccessoryItem: "Transparent_Headgear"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 40
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 1000
- Speed: 150
AttackRate: 400
DefendRate: 400
ChangeTargetRate: 400
PetScript: <" petskillattack("SM_PROVOKE", 1, 0, 0, 5);">
EquipScript: <"
- bonus(bInt, 1);
- bonus(bMaxSP, 50);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bInt, 1);
+ bonus(bMaxSP, 50);
+ }
">
},
{
Id: 1109
- SpriteName: "DEVIRUCHI"
Name: "Deviruchi"
TamingItem: "Contracts_In_Shadow"
EggItem: "Deviruchi_Egg"
AccessoryItem: "Pacifier"
FoodItem: "Shoot"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 500
- Speed: 150
- AttackRate: 800
DefendRate: 200
ChangeTargetRate: 100
PetScript: <" petskillbonus(bAgiDexStr, 6, 20, 40); ">
EquipScript: <"
- bonus(bMatkRate, 1);
- bonus(bAtkRate, 1);
- bonus(bMaxHPrate, -3);
- bonus(bMaxSPrate, -3);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMatkRate, 1);
+ bonus(bAtkRate, 1);
+ bonus(bMaxHPrate, -3);
+ bonus(bMaxSPrate, -3);
+ }
">
},
{
Id: 1110
- SpriteName: "DOKEBI"
Name: "Dokebi"
TamingItem: "Old_Broom"
EggItem: "Dokkaebi_Egg"
AccessoryItem: "Wig"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("BS_HAMMERFALL", 1, 0, 0, 10); ">
EquipScript: <"
- bonus(bMatkRate, 1);
- bonus(bAtkRate, -1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMatkRate, 1);
+ bonus(bAtkRate, -1);
+ }
">
},
{
Id: 1113
- SpriteName: "DROPS"
Name: "Drops"
TamingItem: "Orange_Juice"
EggItem: "Drops_Egg"
AccessoryItem: "Backpack"
FoodItem: "Yellow_Herb"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 40
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 1500
- Speed: 150
SpecialPerformance: true
- AttackRate: 300
DefendRate: 400
ChangeTargetRate: 500
PetScript: <" petloot(10); ">
EquipScript: <"
- bonus(bHit, 3);
- bonus(bAtk, 3);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bHit, 3);
+ bonus(bAtk, 3);
+ }
">
},
{
Id: 1155
- SpriteName: "PETIT"
Name: "Petite"
TamingItem: "Shining_Stone"
EggItem: "Green_Petite_Egg"
AccessoryItem: "Stellar_Hairpin"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 800
DefendRate: 400
ChangeTargetRate: 100
PetScript: <" petskillattack("WZ_HEAVENDRIVE", 500, 1, 0, 10); ">
EquipScript: <"
- bonus(bDef, -2);
- bonus(bMdef, -2);
- bonus(bAspdRate, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bDef, -2);
+ bonus(bMdef, -2);
+ bonus(bAspdRate, 1);
+ }
">
},
{
Id: 1167
- SpriteName: "SAVAGE_BABE"
Name: "Savage Babe"
TamingItem: "Sweet_Milk"
EggItem: "Savage_Bebe_Egg"
AccessoryItem: "Green_Lace"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 40
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 1500
- Speed: 150
AttackRate: 500
DefendRate: 500
ChangeTargetRate: 200
PetScript: <" petskillbonus(bVit, 4, 10, 50); ">
EquipScript: <"
- bonus(bVit, 1);
- bonus(bMaxHP, 50);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bVit, 1);
+ bonus(bMaxHP, 50);
+ }
">
},
{
Id: 1170
- SpriteName: "SOHEE"
Name: "Sohee"
TamingItem: "Silver_Knife_Of_Chaste"
EggItem: "Sohee_Egg"
AccessoryItem: "Golden_Bell"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 500
- Speed: 150
AttackRate: 100
DefendRate: 1000
ChangeTargetRate: 200
PetScript: <" petskillsupport(AL_HEAL, 10, 60, 33, 100); ">
EquipScript: <"
- bonus(bStr, 1);
- bonus(bDex, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bStr, 1);
+ bonus(bDex, 1);
+ }
">
},
{
Id: 1188
- SpriteName: "BON_GUN"
Name: "Bon Gun"
TamingItem: "Heart_Of_Her"
EggItem: "Bongun_Egg"
AccessoryItem: "Sword_Of_Grave_Keeper"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
SpecialPerformance: true
AttackRate: 600
DefendRate: 200
ChangeTargetRate: 400
PetScript: <" petskillattack("NPC_DARKNESSATTACK", 555, 1, 1, 1); ">
EquipScript: <"
- bonus(bVit, 1);
- bonus2(bResEff, Eff_Stun, 100);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bVit, 1);
+ bonus2(bResEff, Eff_Stun, 100);
+ }
">
},
{
Id: 1200
- SpriteName: "ZHERLTHSH"
Name: "Zealotus"
TamingItem: "Prohibition_Red_Candle"
EggItem: "Zherlthsh_Egg"
FoodItem: "Immortal_Heart"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 300
- Speed: 150
AttackRate: 1000
DefendRate: 100
ChangeTargetRate: 500
PetScript: <" petskillattack("AS_SONICBLOW", 1, 0, 0, 3); ">
EquipScript: <"
- bonus2(bAddRace, RC_DemiPlayer, 2);
- bonus2(bMagicAddRace, RC_DemiPlayer, 2);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus2(bAddRace, RC_DemiPlayer, 2);
+ bonus2(bMagicAddRace, RC_DemiPlayer, 2);
+ }
">
},
{
Id: 1245
- SpriteName: "GOBLINE_XMAS"
Name: "Christmas Goblin"
TamingItem: "Sweet_Candy_Striper"
EggItem: "Santa_Goblin_Egg"
FoodItem: "Scell"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 2000
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("MG_SIGHT", 5, 0, 5, 5); ">
EquipScript: <"
- bonus(bMaxHP, 30);
- bonus2(bSubEle, Ele_Water, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMaxHP, 30);
+ bonus2(bSubEle, Ele_Water, 1);
+ }
">
},
{
Id: 1275
- SpriteName: "ALICE"
Name: "Alice"
TamingItem: "Sway_Apron"
EggItem: "Alice_Egg"
FoodItem: "White_Potion"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 800
- Speed: 150
AttackRate: 100
DefendRate: 1000
ChangeTargetRate: 200
PetScript: <" petskillsupport("AL_HEAL", 5, 60, 25, 100); ">
EquipScript: <"
- bonus(bMdef, 1);
- bonus2(bSubRace, RC_DemiPlayer, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMdef, 1);
+ bonus2(bSubRace, RC_DemiPlayer, 1);
+ }
">
},
// New Pets
{
Id: 1122
- SpriteName: "GOBLIN_1"
Name: "Goblin"
TamingItem: "Knife_Goblin_Ring"
EggItem: "Knife_Goblin_Egg"
FoodItem: "Green_Apple"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 800
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("NPC_WINDATTACK", 5, 0, 5, 5); ">
},
{
Id: 1123
- SpriteName: "GOBLIN_2"
Name: "Goblin"
TamingItem: "Flail_Goblin_Ring"
EggItem: "Flail_Goblin_Egg"
FoodItem: "Green_Apple"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 800
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("NPC_FIREATTACK", 5, 0, 5, 5); ">
},
{
Id: 1125
- SpriteName: "GOBLIN_4"
Name: "Goblin"
TamingItem: "Hammer_Goblin_Ring"
EggItem: "Hammer_Goblin_Egg"
FoodItem: "Green_Apple"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 800
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("NPC_GROUNDATTACK", 5, 0, 5, 5); ">
},
{
Id: 1208
- SpriteName: "WANDER_MAN"
Name: "Wanderer"
TamingItem: "Skull_Of_Vagabond"
EggItem: "Wanderer_Egg"
FoodItem: "Spirit_Liquor"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 800
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("NPC_UNDEADATTACK", 5, 0, 5, 5); ">
},
{
Id: 1382
- SpriteName: "DIABOLIC"
Name: "Diabolic"
TamingItem: "Red_Burning_Stone"
EggItem: "Diabolic_Egg"
FoodItem: "Meat_Veg_Skewer"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
- CaptureRate: 800
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("WZ_METEOR", 2, 0, 5, 5); ">
},
{
Id: 1385
- SpriteName: "DELETER_"
Name: "Deleter"
TamingItem: "Holy_Marble"
EggItem: "Red_Deleter_Egg"
FoodItem: "Whole_Barbecue"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 800
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("SM_MAGNUM", 5, 0, 5, 5); ">
},
{
Id: 1879
- SpriteName: "ECLIPSE_P"
Name: "Spring Rabbit"
EggItem: "Spring_Rabbit_Egg"
FoodItem: "Bok_Choy"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 2000
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("TF_THROWSTONE", 1, 0, 5, 5); ">
},
// Episode 12
{
Id: 1963
- SpriteName: "P_CHUNG_E"
Name: "New Year Doll"
EggItem: "New_Year_Doll_Egg"
FoodItem: "Mojji"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 800
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("CR_SHIELDCHARGE", 5, 0, 5, 5); ">
},
// Episode 13
{
Id: 1815
- SpriteName: "EVENT_RICECAKE"
Name: "Rice Cake"
EggItem: "Rice_Cake_Egg"
FoodItem: "Green_Herb"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 2000
- Speed: 150
SpecialPerformance: true
AttackRate: 500
DefendRate: 500
ChangeTargetRate: 200
PetScript: <" petskillsupport("CR_DEFENDER", 3, 240, 50, 100); ">
EquipScript: <"
- bonus2(bSubEle, Ele_Neutral, 1);
- bonus(bMaxHPrate, -1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus2(bSubEle, Ele_Neutral, 1);
+ bonus(bMaxHPrate, -1);
+ }
">
},
{
Id: 2210
- SpriteName: "XMAS_LUNATIC"
Name: "Christmas Snow Rabbit"
EggItem: "Snow_Rabbit_Egg"
FoodItem: "Candy"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
- Speed: 150
SpecialPerformance: true
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus2(bExpAddRace, RC_All, 5); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus2(bExpAddRace, RC_All, 5);
+ ">
},
// Episode 13.2
{
Id: 1040
- SpriteName: "GOLEM"
Name: "Golem"
TamingItem: "Magical_Lithography"
EggItem: "Golem_Egg"
AccessoryItem: "Windup_Spring"
FoodItem: "Mystic_Stone"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus(bMaxHP, 100);
- bonus(bFlee, -5);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMaxHP, 100);
+ bonus(bFlee, -5);
+ }
">
},
{
Id: 1143
- SpriteName: "MARIONETTE"
Name: "Marionette"
TamingItem: "Delicious_Shaved_Ice"
EggItem: "Marionette_Egg"
AccessoryItem: "Star_Hairband"
FoodItem: "Small_Snow_Flower"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus(bSPrecovRate, 3); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus(bSPrecovRate, 3);
+ ">
},
{
Id: 1148
- SpriteName: "MEDUSA"
Name: "Medusa"
TamingItem: "Splendid_Mirror"
EggItem: "Medusa_Egg"
AccessoryItem: "Queens_Coronet"
FoodItem: "Apple_Pudding"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus(bVit, 1);
- bonus2(bResEff, Eff_Stone, 500);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bVit, 1);
+ bonus2(bResEff, Eff_Stone, 500);
+ }
">
},
{
Id: 1179
- SpriteName: "WHISPER"
Name: "Whisper"
TamingItem: "Fit_Pipe"
EggItem: "Whisper_Egg"
AccessoryItem: "Spirit_Chain_"
FoodItem: "Damp_Darkness"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus(bFlee, 7);
- bonus(bDef, -3);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bFlee, 7);
+ bonus(bDef, -3);
+ }
">
},
{
Id: 1299
- SpriteName: "GOBLIN_LEADER"
Name: "Goblin Leader"
TamingItem: "Staff_Of_Leader"
EggItem: "Goblin_Leader_Egg"
AccessoryItem: "Nice_Badge"
FoodItem: "Big_Cell"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 50
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus2(bAddRace, RC_DemiPlayer, 3); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus2(bAddRace, RC_DemiPlayer, 3);
+ ">
},
{
Id: 1370
- SpriteName: "SUCCUBUS"
Name: "Succubus"
TamingItem: "Boys_Naivety"
EggItem: "Succubus_Egg"
AccessoryItem: "Black_Butterfly_Mask"
FoodItem: "Vital_Flower_"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus2(bHPDrainRate, 50, 5); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus2(bHPDrainRate, 50, 5);
+ ">
},
{
Id: 1374
- SpriteName: "INCUBUS"
Name: "Incubus"
TamingItem: "Grils_Naivety"
EggItem: "Incubus_Egg"
AccessoryItem: "Ball_Mask"
FoodItem: "Vital_Flower"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 50
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus(bMaxSPrate, 3); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus(bMaxSPrate, 3);
+ ">
},
{
Id: 1379
- SpriteName: "NIGHTMARE_TERROR"
Name: "Nightmare Terror"
TamingItem: "Hell_Contract"
EggItem: "Nightmare_Terror_Egg"
AccessoryItem: "Hell_Horn"
FoodItem: "Fresh_Plant"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus2(bResEff, Eff_Sleep, 10000); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus2(bResEff, Eff_Sleep, 10000);
+ ">
},
{
Id: 1401
- SpriteName: "SHINOBI"
Name: "Shinobi"
TamingItem: "Kuloren"
EggItem: "Shinobi_Egg"
AccessoryItem: "Wine_On_Sleeve"
FoodItem: "Grilled_Rice_Cake"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus(bAgi, 2); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus(bAgi, 2);
+ ">
},
{
Id: 1404
- SpriteName: "MIYABI_NINGYO"
Name: "Miyabi Doll"
TamingItem: "Gril_Doll"
EggItem: "Miyabi_Ningyo_Egg"
AccessoryItem: "Summer_Fan"
FoodItem: "Well_Ripened_Berry"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 15
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus(bInt, 1);
- bonus(bCastrate, -3);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bInt, 1);
+ bonus(bCastrate, -3);
+ }
">
},
{
Id: 1416
- SpriteName: "WICKED_NYMPH"
Name: "Evil Nymph"
TamingItem: "Charming_Lotus"
EggItem: "Wicked_Nymph_Egg"
AccessoryItem: "Jade_Trinket"
FoodItem: "Morning_Dew"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 15
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus(bMaxSP, 30);
- bonus(bSPrecovRate, 5);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMaxSP, 30);
+ bonus(bSPrecovRate, 5);
+ }
">
},
{
Id: 1495
- SpriteName: "STONE_SHOOTER"
Name: "Stone Shooter"
TamingItem: "Oilpalm_Coconut"
EggItem: "Stone_Shooter_Egg"
AccessoryItem: "Apro_Hair"
FoodItem: "Plant_Neutrient"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus2(bSubEle, Ele_Fire, 3); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus2(bSubEle, Ele_Fire, 3);
+ ">
},
{
Id: 1504
- SpriteName: "DULLAHAN"
Name: "Dullahan"
TamingItem: "Luxury_Whisky_Bottle"
EggItem: "Dullahan_Egg"
AccessoryItem: "Death_Coil"
FoodItem: "Sunset_On_The_Rock"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus(bCritAtkRate, 5); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus(bCritAtkRate, 5);
+ ">
},
{
Id: 1505
- SpriteName: "LOLI_RURI"
Name: "Loli Ruri"
TamingItem: "Very_Red_Juice"
EggItem: "Loli_Ruri_Egg"
AccessoryItem: "Fashionable_Glasses"
FoodItem: "Pumpkin_Pie_"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 15
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus(bMaxHPrate, 3);
- bonus3(bAutoSpellWhenHit, "AL_HEAL", 1, 50);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMaxHPrate, 3);
+ bonus3(bAutoSpellWhenHit, "AL_HEAL", 1, 50);
+ }
">
},
{
Id: 1513
- SpriteName: "CIVIL_SERVANT"
Name: "Mao Guai"
TamingItem: "Fan_Of_Wind"
EggItem: "Civil_Servant_Egg"
AccessoryItem: "Golden_Earing"
FoodItem: "Flavored_Alcohol"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus(bMaxSP, 10); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus(bMaxSP, 10);
+ ">
},
{
Id: 1519
- SpriteName: "CHUNG_E"
Name: "Green Maiden"
TamingItem: "Tantanmen"
EggItem: "Chung_E_Egg"
FoodItem: "Bun_"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 2000
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("CR_SHIELDCHARGE", 5, 0, 5, 5); ">
EquipScript: <"
- bonus(bDef, 1);
- bonus2(bSubRace, RC_DemiPlayer, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bDef, 1);
+ bonus2(bSubRace, RC_DemiPlayer, 1);
+ }
">
},
{
Id: 1586
- SpriteName: "LEAF_CAT"
Name: "Leaf Cat"
TamingItem: "Very_Soft_Plant"
EggItem: "Leaf_Cat_Egg"
AccessoryItem: "Green_Lucky_Bag"
FoodItem: "Fish_With_Blue_Back"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus2(bSubRace, RC_Brute, 3);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus2(bSubRace, RC_Brute, 3);
">
},
{
Id: 1630
- SpriteName: "BACSOJIN_"
Name: "White Lady"
TamingItem: "Shiny_Wing_Gown"
EggItem: "Bacsojin_Egg"
AccessoryItem: "Round_Hair_Ornament"
FoodItem: "Traditional_Cookie"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 2000
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
},
{
Id: 1837
- SpriteName: "IMP"
Name: "Fire Imp"
TamingItem: "Flaming_Ice"
EggItem: "Imp_Egg"
AccessoryItem: "Horn_Protector"
FoodItem: "Flame_Gemstone"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus2(bSubEle, Ele_Fire, 2);
- bonus2(bAddEle, Ele_Fire, 2);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus2(bSubEle, Ele_Fire, 2);
+ bonus2(bAddEle, Ele_Fire, 2);
+ }
">
},
// Episode 13.2 Brasilis
{
Id: 2057
- SpriteName: "E_CRAMP"
Name: "Strange Cramp"
TamingItem: "Leaf_Cat_Ball"
EggItem: "Mystic_Leaf_Cat_Ball"
CaptureRate: 50
AttackRate: 350
DefendRate: 400
- ChangeTargetRate: 800
},
{
Id: 2081
- SpriteName: "E_HYDRA"
Name: "Strange Hydra"
TamingItem: "Leaf_Cat_Ball"
EggItem: "Mystic_Leaf_Cat_Ball"
CaptureRate: 50
AttackRate: 350
DefendRate: 400
- ChangeTargetRate: 800
},
)
diff --git a/db/re/pet_db.conf b/db/re/pet_db.conf
index fc4496125..3392a8191 100644
--- a/db/re/pet_db.conf
+++ b/db/re/pet_db.conf
@@ -34,65 +34,61 @@ pet_db:(
{
// ================ Mandatory fields ==============================
Id: ID (int)
- SpriteName: "Sprite_Name" (string)
Name: "Pet Name" (string)
+ EggItem: "Egg Item Constant" (string)
// ================ Optional fields ===============================
- TamingItem: Taming Item (string, defaults to 0)
- EggItem: Egg Id (string, defaults to 0)
- AccessoryItem: Equipment Id (string, defaults to 0)
- FoodItem: Food Id (string, defaults to 0)
- FoodEffectiveness: hunger points (int, defaults to 0)
- HungerDelay: hunger time (int, defaults to 0)
+ TamingItem: "Taming Item Constant" (string, defaults to 0)
+ FoodItem: "Food Item Constant" (string, defaults to "Pet_Food" (ID=537))
+ AccessoryItem: "Equipment Item Constant" (string, defaults to 0)
+ FoodEffectiveness: hunger points (int, defaults to 80)
+ HungerDelay: hunger time (int, defaults to 60)
+ HungerDecrement: hunger points (int, defaults to 1)
Intimacy: {
- Initial: start intimacy (int, defaults to 0)
- FeedIncrement: feeding intimacy (int, defaults to 0)
- OverFeedDecrement: overfeeding intimacy (int, defaults to 0)
- OwnerDeathDecrement: owner die intimacy (int, defaults to 0)
- }
- CaptureRate: capture rate (int, defaults to 0)
- Speed: speed (int, defaults to 0)
+ Initial: start intimacy (int, defaults to 250)
+ FeedIncrement: feeding intimacy (int, defaults to 10)
+ OverFeedDecrement: overfeeding intimacy (int, defaults to 100)
+ OwnerDeathDecrement: owner die intimacy (int, defaults to 20)
+ StarvingDelay: starving time (int, defaults to 20)
+ StarvingDecrement: starving intimacy (int, defaults to 20)
+ }
+ CaptureRate: capture rate (int, defaults to 1000)
+ Speed: speed (int, defaults to 150)
SpecialPerformance: true/false (boolean, defaults to false)
TalkWithEmotes: convert talk (boolean, defaults to false)
- AttackRate: attack rate (int, defaults to 0)
- DefendRate: Defence attack (int, defaults to 0)
- ChangeTargetRate: change target (int, defaults to 0)
+ AttackRate: attack rate (int, defaults to 300)
+ DefendRate: Defence attack (int, defaults to 300)
+ ChangeTargetRate: change target (int, defaults to 800)
+ AutoFeed: true/false (boolean, defaults to false)
+ PetScript: <" Pet Script (can also be multi-line) ">
+ EquipScript: <" Equip Script (can also be multi-line) ">
Evolve: {
- EggID: { (string, Evolved Pet EggID)
- Name: Amount (items required to perform evolution)
+ EggID: { (string, Evolved Pet EggID)
+ Name: Amount (items required to perform evolution)
...
}
}
- AutoFeed: true/false (boolean, defaults to false)
- PetScript: <" Pet Script (can also be multi-line) ">
- EquipScript: <" Equip Script (can also be multi-line) ">
},
**************************************************************************/
{
Id: 1002
- SpriteName: "PORING"
Name: "Poring"
TamingItem: "Unripe_Apple"
EggItem: "Poring_Egg"
AccessoryItem: "Backpack"
FoodItem: "Apple_Juice"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 2000
- Speed: 150
SpecialPerformance: true
AttackRate: 350
DefendRate: 400
- ChangeTargetRate: 800
PetScript: <" petloot(10); ">
EquipScript: <"
- bonus(bLuk, 2);
- bonus(bCritical, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bLuk, 2);
+ bonus(bCritical, 1);
+ }
">
Evolve: {
Mastering_Egg: {
@@ -103,85 +99,65 @@ pet_db:(
},
{
Id: 1011
- SpriteName: "CHONCHON"
Name: "ChonChon"
TamingItem: "Rotten_Fish"
EggItem: "Chonchon_Egg"
AccessoryItem: "Monster_Oxygen_Mask"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 1500
- Speed: 150
SpecialPerformance: true
AttackRate: 500
DefendRate: 500
ChangeTargetRate: 250
PetScript: <" petskillbonus(bAgi, 4, 10, 50); ">
EquipScript: <"
- bonus(bAgi, 1);
- bonus(bFlee, 2);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bAgi, 1);
+ bonus(bFlee, 2);
+ }
">
},
{
Id: 1014
- SpriteName: "SPORE"
Name: "Spore"
TamingItem: "Dew_Laden_Moss"
EggItem: "Spore_Egg"
AccessoryItem: "Bark_Shorts"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 1500
- Speed: 150
AttackRate: 350
DefendRate: 500
ChangeTargetRate: 500
PetScript: <" petrecovery(SC_POISON, 60); ">
EquipScript: <"
- bonus(bHit, 5);
- bonus(bAtk, -2);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bHit, 5);
+ bonus(bAtk, -2);
+ }
">
},
{
Id: 1019
- SpriteName: "PECOPECO"
Name: "PecoPeco"
TamingItem: "Fatty_Chubby_Earthworm"
EggItem: "PecoPeco_Egg"
AccessoryItem: "Battered_Pot"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 1000
- Speed: 150
SpecialPerformance: true
AttackRate: 400
DefendRate: 500
- ChangeTargetRate: 800
PetScript: <" petskillbonus(bSpeedRate, 25, 20, 20); ">
EquipScript: <"
- bonus(bMaxHP, 150);
- bonus(bMaxSP, -10);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMaxHP, 150);
+ bonus(bMaxSP, -10);
+ }
">
Evolve: {
Grand_Peco_Peco_Egg: {
@@ -195,30 +171,24 @@ pet_db:(
},
{
Id: 1023
- SpriteName: "ORK_WARRIOR"
Name: "Orc Warrior"
TamingItem: "Horror_Of_Tribe"
EggItem: "Orc_Warrior_Egg"
AccessoryItem: "Wild_Flower"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
SpecialPerformance: true
AttackRate: 600
DefendRate: 200
ChangeTargetRate: 300
PetScript: <" petskillattack("NPC_PIERCINGATT", 100, 1, 0, 10); ">
EquipScript: <"
- bonus(bAtk, 10);
- bonus(bDef, -3);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bAtk, 10);
+ bonus(bDef, -3);
+ }
">
Evolve: {
High_Orc_Egg: {
@@ -232,56 +202,40 @@ pet_db:(
},
{
Id: 1026
- SpriteName: "MUNAK"
Name: "Munak"
TamingItem: "No_Recipient"
EggItem: "Munak_Egg"
AccessoryItem: "Punisher"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 300
DefendRate: 750
ChangeTargetRate: 300
PetScript: <" petskillattack("NPC_DARKNESSATTACK", 444, 1, 0, 10); ">
EquipScript: <"
- bonus(bInt, 1);
- bonus(bDef, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bInt, 1);
+ bonus(bDef, 1);
+ }
">
},
{
Id: 1029
- SpriteName: "ISIS"
Name: "Isis"
TamingItem: "Armlet_Of_Obedience"
EggItem: "Isis_Egg"
AccessoryItem: "Queens_Hair_Ornament"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 500
- Speed: 150
AttackRate: 650
DefendRate: 450
ChangeTargetRate: 150
PetScript: <" petskillsupport("PR_MAGNIFICAT", 2, 60, 50, 50); ">
EquipScript: <"
- bonus(bMatkRate, -1);
- bonus(bAtkRate, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMatkRate, -1);
+ bonus(bAtkRate, 1);
+ }
">
Evolve: {
Little_Isis_Egg: {
@@ -294,141 +248,109 @@ pet_db:(
},
{
Id: 1031
- SpriteName: "POPORING"
Name: "Poporing"
TamingItem: "Bitter_Herb"
EggItem: "Poporing_Egg"
AccessoryItem: "Backpack"
FoodItem: "Green_Herb"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 1000
- Speed: 150
SpecialPerformance: true
- AttackRate: 300
DefendRate: 500
ChangeTargetRate: 400
PetScript: <" petloot(15); ">
EquipScript: <"
- bonus(bLuk, 2);
- bonus2(bSubEle, Ele_Poison, 10);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bLuk, 2);
+ bonus2(bSubEle, Ele_Poison, 10);
+ }
">
},
{
Id: 1035
- SpriteName: "HUNTER_FLY"
Name: "Hunter Fly"
TamingItem: "Monster_Juice"
EggItem: "Hunter_Fly_Egg"
AccessoryItem: "Monster_Oxygen_Mask"
FoodItem: "Red_Gemstone"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 500
- Speed: 150
SpecialPerformance: true
AttackRate: 500
DefendRate: 500
ChangeTargetRate: 200
PetScript: <" petskillattack("NPC_WINDATTACK", 888, 2, 0, 10); ">
EquipScript: <"
- bonus(bFlee, -5);
- bonus(bFlee2, 2);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bFlee, -5);
+ bonus(bFlee2, 2);
+ }
">
},
{
Id: 1042
- SpriteName: "STEEL_CHONCHON"
Name: "Steel ChonChon"
TamingItem: "Lusty_Iron"
EggItem: "Steel_Chonchon_Egg"
AccessoryItem: "Monster_Oxygen_Mask"
FoodItem: "Iron_Ore"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 1000
- Speed: 150
SpecialPerformance: true
AttackRate: 500
DefendRate: 500
ChangeTargetRate: 200
PetScript: <" petskillbonus(bAgiVit, 4, 20, 40); ">
EquipScript: <"
- bonus(bFlee, 6);
- bonus(bAgi, -1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bFlee, 6);
+ bonus(bAgi, -1);
+ }
">
},
{
Id: 1049
- SpriteName: "PICKY"
Name: "Picky"
TamingItem: "Earthworm_The_Dude"
EggItem: "Picky_Egg"
AccessoryItem: "Tiny_Egg_Shell"
FoodItem: "Red_Herb"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 40
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 2000
- Speed: 150
SpecialPerformance: true
AttackRate: 500
DefendRate: 600
ChangeTargetRate: 50
PetScript: <" petskillbonus(bStr, 3, 10, 50); ">
EquipScript: <"
- bonus(bStr, 1);
- bonus(bAtk, 5);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bStr, 1);
+ bonus(bAtk, 5);
+ }
">
},
{
Id: 1052
- SpriteName: "ROCKER"
Name: "Rocker"
TamingItem: "Singing_Flower"
EggItem: "Rocker_Egg"
AccessoryItem: "Rocker_Glasses"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 1500
- Speed: 150
AttackRate: 350
DefendRate: 350
ChangeTargetRate: 600
PetScript: <" petskillbonus(bAllStats, 1, 10, 50); ">
EquipScript: <"
- bonus(bHPrecovRate, 5);
- bonus(bMaxHP, 25);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bHPrecovRate, 5);
+ bonus(bMaxHP, 25);
+ }
">
Evolve: {
Metaller_Egg: {
@@ -441,58 +363,43 @@ pet_db:(
},
{
Id: 1056
- SpriteName: "SMOKIE"
Name: "Smokie"
TamingItem: "Baked_Yam"
EggItem: "Smokie_Egg"
AccessoryItem: "Red_Muffler"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 1000
- Speed: 150
SpecialPerformance: true
AttackRate: 600
DefendRate: 600
ChangeTargetRate: 100
PetScript: <" petskillbonus(bPerfectHide, 1, 3600, 0); ">
EquipScript: <"
- bonus(bAgi, 1);
- bonus(bFlee2, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bAgi, 1);
+ bonus(bFlee2, 1);
+ }
">
},
{
Id: 1057
- SpriteName: "YOYO"
Name: "Yoyo"
TamingItem: "Tropical_Banana"
EggItem: "Yoyo_Egg"
AccessoryItem: "Monkey_Circlet"
FoodItem: "Banana_Juice"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 1000
- Speed: 150
SpecialPerformance: true
- AttackRate: 300
- DefendRate: 800
ChangeTargetRate: 400
PetScript: <" petloot(20); ">
EquipScript: <"
- bonus(bCritical, 3);
- bonus(bLuk, -1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bCritical, 3);
+ bonus(bLuk, -1);
+ }
">
Evolve: {
Choco_Egg: {
@@ -505,29 +412,22 @@ pet_db:(
},
{
Id: 1063
- SpriteName: "LUNATIC"
Name: "Lunatic"
TamingItem: "Rainbow_Carrot"
EggItem: "Lunatic_Egg"
AccessoryItem: "Silk_Ribbon"
FoodItem: "Carrot_Juice"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 40
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 1500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
ChangeTargetRate: 1000
PetScript: <" petskillbonus(bLuk, 3, 10, 50); ">
EquipScript: <"
- bonus(bCritical, 2);
- bonus(bAtk, 2);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bCritical, 2);
+ bonus(bAtk, 2);
+ }
">
Evolve: {
Leaf_Lunatic_Egg: {
@@ -540,113 +440,82 @@ pet_db:(
},
{
Id: 1077
- SpriteName: "POISON_SPORE"
Name: "Poison Spore"
TamingItem: "Deadly_Noxious_Herb"
EggItem: "Poison_Spore_Egg"
AccessoryItem: "Bark_Shorts"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 1000
- Speed: 150
AttackRate: 600
DefendRate: 200
ChangeTargetRate: 400
PetScript: <" petskillattack("NPC_POISON", 20, 0, 0, 10); ">
EquipScript: <"
- bonus(bStr, 1);
- bonus(bInt, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bStr, 1);
+ bonus(bInt, 1);
+ }
">
},
{
Id: 1101
- SpriteName: "BAPHOMET_"
Name: "Baphomet Jr."
TamingItem: "Book_Of_Devil"
EggItem: "Bapho_Jr_Egg"
AccessoryItem: "Skull_Helm"
FoodItem: "Honey"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 200
- Speed: 150
AttackRate: 1000
DefendRate: 100
ChangeTargetRate: 200
PetScript: <" petskillattack("NPC_DARKNESSATTACK", 1776, 4, 0, 5); ">
EquipScript: <"
- bonus(bDef, 1);
- bonus(bMdef, 1);
- bonus2(bResEff, Eff_Stun, -100);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bDef, 1);
+ bonus(bMdef, 1);
+ bonus2(bResEff, Eff_Stun, -100);
+ }
">
},
{
Id: 1107
- SpriteName: "DESERT_WOLF_B"
Name: "Baby Desert Wolf"
TamingItem: "Well_Dried_Bone"
EggItem: "Baby_Desert_Wolf_Egg"
AccessoryItem: "Transparent_Headgear"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 40
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 1000
- Speed: 150
AttackRate: 400
DefendRate: 400
ChangeTargetRate: 400
PetScript: <" petskillattack("SM_PROVOKE", 1, 0, 0, 5);">
EquipScript: <"
- bonus(bInt, 1);
- bonus(bMaxSP, 50);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bInt, 1);
+ bonus(bMaxSP, 50);
+ }
">
},
{
Id: 1109
- SpriteName: "DEVIRUCHI"
Name: "Deviruchi"
TamingItem: "Contracts_In_Shadow"
EggItem: "Deviruchi_Egg"
AccessoryItem: "Pacifier"
FoodItem: "Shoot"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 500
- Speed: 150
- AttackRate: 800
DefendRate: 200
ChangeTargetRate: 100
PetScript: <" petskillbonus(bAgiDexStr, 6, 20, 40); ">
EquipScript: <"
- bonus(bMatkRate, 1);
- bonus(bAtkRate, 1);
- bonus(bMaxHPrate, -3);
- bonus(bMaxSPrate, -3);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMatkRate, 1);
+ bonus(bAtkRate, 1);
+ bonus(bMaxHPrate, -3);
+ bonus(bMaxSPrate, -3);
+ }
">
Evolve: {
Diabolic_Egg_: {
@@ -659,29 +528,20 @@ pet_db:(
},
{
Id: 1110
- SpriteName: "DOKEBI"
Name: "Dokebi"
TamingItem: "Old_Broom"
EggItem: "Dokkaebi_Egg"
AccessoryItem: "Wig"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("BS_HAMMERFALL", 1, 0, 0, 10); ">
EquipScript: <"
- bonus(bMatkRate, 1);
- bonus(bAtkRate, -1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMatkRate, 1);
+ bonus(bAtkRate, -1);
+ }
">
Evolve: {
Am_Mut_Egg: {
@@ -694,30 +554,24 @@ pet_db:(
},
{
Id: 1113
- SpriteName: "DROPS"
Name: "Drops"
TamingItem: "Orange_Juice"
EggItem: "Drops_Egg"
AccessoryItem: "Backpack"
FoodItem: "Yellow_Herb"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 40
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 1500
- Speed: 150
SpecialPerformance: true
- AttackRate: 300
DefendRate: 400
ChangeTargetRate: 500
PetScript: <" petloot(10); ">
EquipScript: <"
- bonus(bHit, 3);
- bonus(bAtk, 3);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bHit, 3);
+ bonus(bAtk, 3);
+ }
">
Evolve: {
Eggring_Egg: {
@@ -738,30 +592,23 @@ pet_db:(
},
{
Id: 1155
- SpriteName: "PETIT"
Name: "Petite"
TamingItem: "Shining_Stone"
EggItem: "Green_Petite_Egg"
AccessoryItem: "Stellar_Hairpin"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 800
DefendRate: 400
ChangeTargetRate: 100
PetScript: <" petskillattack("WZ_HEAVENDRIVE", 500, 1, 0, 10); ">
EquipScript: <"
- bonus(bDef, -2);
- bonus(bMdef, -2);
- bonus(bAspdRate, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bDef, -2);
+ bonus(bMdef, -2);
+ bonus(bAspdRate, 1);
+ }
">
Evolve: {
Earth_Deleter_Egg: {
@@ -774,29 +621,23 @@ pet_db:(
},
{
Id: 1167
- SpriteName: "SAVAGE_BABE"
Name: "Savage Babe"
TamingItem: "Sweet_Milk"
EggItem: "Savage_Bebe_Egg"
AccessoryItem: "Green_Lace"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 40
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 1500
- Speed: 150
AttackRate: 500
DefendRate: 500
ChangeTargetRate: 200
PetScript: <" petskillbonus(bVit, 4, 10, 50); ">
EquipScript: <"
- bonus(bVit, 1);
- bonus(bMaxHP, 50);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bVit, 1);
+ bonus(bMaxHP, 50);
+ }
">
Evolve: {
Savage_Egg: {
@@ -809,57 +650,42 @@ pet_db:(
},
{
Id: 1170
- SpriteName: "SOHEE"
Name: "Sohee"
TamingItem: "Silver_Knife_Of_Chaste"
EggItem: "Sohee_Egg"
AccessoryItem: "Golden_Bell"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 500
- Speed: 150
AttackRate: 100
DefendRate: 1000
ChangeTargetRate: 200
PetScript: <" petskillsupport(AL_HEAL, 10, 60, 33, 100); ">
EquipScript: <"
- bonus(bStr, 1);
- bonus(bDex, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bStr, 1);
+ bonus(bDex, 1);
+ }
">
},
{
Id: 1188
- SpriteName: "BON_GUN"
Name: "Bon Gun"
TamingItem: "Heart_Of_Her"
EggItem: "Bongun_Egg"
AccessoryItem: "Sword_Of_Grave_Keeper"
- FoodItem: "Pet_Food"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
SpecialPerformance: true
AttackRate: 600
DefendRate: 200
ChangeTargetRate: 400
PetScript: <" petskillattack("NPC_DARKNESSATTACK", 555, 1, 1, 1); ">
EquipScript: <"
- bonus(bVit, 1);
- bonus2(bResEff, Eff_Stun, 100);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bVit, 1);
+ bonus2(bResEff, Eff_Stun, 100);
+ }
">
Evolve: {
Hyegun_Egg: {
@@ -872,903 +698,554 @@ pet_db:(
},
{
Id: 1200
- SpriteName: "ZHERLTHSH"
Name: "Zealotus"
TamingItem: "Prohibition_Red_Candle"
EggItem: "Zherlthsh_Egg"
FoodItem: "Immortal_Heart"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 300
- Speed: 150
AttackRate: 1000
DefendRate: 100
ChangeTargetRate: 500
PetScript: <" petskillattack("AS_SONICBLOW", 1, 0, 0, 3); ">
EquipScript: <"
- bonus2(bAddRace, RC_DemiPlayer, 2);
- bonus2(bMagicAddRace, RC_DemiPlayer, 2);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus2(bAddRace, RC_DemiPlayer, 2);
+ bonus2(bMagicAddRace, RC_DemiPlayer, 2);
+ }
">
},
{
Id: 1245
- SpriteName: "GOBLINE_XMAS"
Name: "Christmas Goblin"
TamingItem: "Sweet_Candy_Striper"
EggItem: "Santa_Goblin_Egg"
FoodItem: "Scell"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 2000
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("MG_SIGHT", 5, 0, 5, 5); ">
EquipScript: <"
- bonus(bMaxHP, 30);
- bonus2(bSubEle, Ele_Water, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMaxHP, 30);
+ bonus2(bSubEle, Ele_Water, 1);
+ }
">
},
{
Id: 1275
- SpriteName: "ALICE"
Name: "Alice"
TamingItem: "Sway_Apron"
EggItem: "Alice_Egg"
FoodItem: "White_Potion"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 800
- Speed: 150
AttackRate: 100
DefendRate: 1000
ChangeTargetRate: 200
PetScript: <" petskillsupport("AL_HEAL", 5, 60, 25, 100); ">
EquipScript: <"
- bonus(bMdef, 1);
- bonus2(bAddRaceTolerance, RC_DemiPlayer, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMdef, 1);
+ bonus2(bAddRaceTolerance, RC_DemiPlayer, 1);
+ }
">
},
// New Pets
{
Id: 1122
- SpriteName: "GOBLIN_1"
Name: "Goblin"
TamingItem: "Knife_Goblin_Ring"
EggItem: "Knife_Goblin_Egg"
FoodItem: "Green_Apple"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 800
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("NPC_WINDATTACK", 5, 0, 5, 5); ">
},
{
Id: 1123
- SpriteName: "GOBLIN_2"
Name: "Goblin"
TamingItem: "Flail_Goblin_Ring"
EggItem: "Flail_Goblin_Egg"
FoodItem: "Green_Apple"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 800
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("NPC_FIREATTACK", 5, 0, 5, 5); ">
},
{
Id: 1125
- SpriteName: "GOBLIN_4"
Name: "Goblin"
TamingItem: "Hammer_Goblin_Ring"
EggItem: "Hammer_Goblin_Egg"
FoodItem: "Green_Apple"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 800
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("NPC_GROUNDATTACK", 5, 0, 5, 5); ">
},
{
Id: 1208
- SpriteName: "WANDER_MAN"
Name: "Wanderer"
TamingItem: "Skull_Of_Vagabond"
EggItem: "Wanderer_Egg"
FoodItem: "Spirit_Liquor"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 800
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("NPC_UNDEADATTACK", 5, 0, 5, 5); ">
},
{
Id: 1382
- SpriteName: "DIABOLIC"
Name: "Diabolic"
TamingItem: "Red_Burning_Stone"
EggItem: "Diabolic_Egg"
FoodItem: "Meat_Veg_Skewer"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
- CaptureRate: 800
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("WZ_METEOR", 2, 0, 5, 5); ">
},
{
Id: 1385
- SpriteName: "DELETER_"
Name: "Deleter"
TamingItem: "Holy_Marble"
EggItem: "Red_Deleter_Egg"
FoodItem: "Whole_Barbecue"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 800
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("SM_MAGNUM", 5, 0, 5, 5); ">
},
{
Id: 1879
- SpriteName: "ECLIPSE_P"
Name: "Spring Rabbit"
EggItem: "Spring_Rabbit_Egg"
FoodItem: "Bok_Choy"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 2000
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("TF_THROWSTONE", 1, 0, 5, 5); ">
},
// Episode 12
{
Id: 1963
- SpriteName: "P_CHUNG_E"
Name: "New Year Doll"
EggItem: "New_Year_Doll_Egg"
FoodItem: "Mojji"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 30
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
- CaptureRate: 800
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("CR_SHIELDCHARGE", 5, 0, 5, 5); ">
},
// Episode 13
{
Id: 1815
- SpriteName: "EVENT_RICECAKE"
Name: "Rice Cake"
EggItem: "Rice_Cake_Egg"
FoodItem: "Green_Herb"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 2000
- Speed: 150
SpecialPerformance: true
AttackRate: 500
DefendRate: 500
ChangeTargetRate: 200
PetScript: <" petskillsupport("CR_DEFENDER", 3, 240, 50, 100); ">
EquipScript: <"
- bonus2(bSubEle, Ele_Neutral, 1);
- bonus(bMaxHPrate, -1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus2(bSubEle, Ele_Neutral, 1);
+ bonus(bMaxHPrate, -1);
+ }
">
},
{
Id: 2210
- SpriteName: "XMAS_LUNATIC"
Name: "Christmas Snow Rabbit"
EggItem: "Snow_Rabbit_Egg"
FoodItem: "Candy"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
- Speed: 150
SpecialPerformance: true
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus2(bExpAddRace, RC_All, 5); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus2(bExpAddRace, RC_All, 5);
+ ">
},
// Episode 13.2
{
Id: 1040
- SpriteName: "GOLEM"
Name: "Golem"
TamingItem: "Magical_Lithography"
EggItem: "Golem_Egg"
AccessoryItem: "Windup_Spring"
FoodItem: "Mystic_Stone"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus(bMaxHP, 100);
- bonus(bFlee, -5);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMaxHP, 100);
+ bonus(bFlee, -5);
+ }
">
},
{
Id: 1143
- SpriteName: "MARIONETTE"
Name: "Marionette"
TamingItem: "Delicious_Shaved_Ice"
EggItem: "Marionette_Egg"
AccessoryItem: "Star_Hairband"
FoodItem: "Small_Snow_Flower"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus(bSPrecovRate, 3); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus(bSPrecovRate, 3);
+ ">
},
{
Id: 1148
- SpriteName: "MEDUSA"
Name: "Medusa"
TamingItem: "Splendid_Mirror"
EggItem: "Medusa_Egg"
AccessoryItem: "Queens_Coronet"
FoodItem: "Apple_Pudding"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus(bVit, 1);
- bonus2(bResEff, Eff_Stone, 500);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bVit, 1);
+ bonus2(bResEff, Eff_Stone, 500);
+ }
">
},
{
Id: 1179
- SpriteName: "WHISPER"
Name: "Whisper"
TamingItem: "Fit_Pipe"
EggItem: "Whisper_Egg"
AccessoryItem: "Spirit_Chain_"
FoodItem: "Damp_Darkness"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus(bFlee, 7);
- bonus(bDef, -3);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bFlee, 7);
+ bonus(bDef, -3);
+ }
">
},
{
Id: 1299
- SpriteName: "GOBLIN_LEADER"
Name: "Goblin Leader"
TamingItem: "Staff_Of_Leader"
EggItem: "Goblin_Leader_Egg"
AccessoryItem: "Nice_Badge"
FoodItem: "Big_Cell"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 50
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus2(bAddRace, RC_DemiPlayer, 3); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus2(bAddRace, RC_DemiPlayer, 3);
+ ">
},
{
Id: 1370
- SpriteName: "SUCCUBUS"
Name: "Succubus"
TamingItem: "Boys_Naivety"
EggItem: "Succubus_Egg"
AccessoryItem: "Black_Butterfly_Mask"
FoodItem: "Vital_Flower_"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus2(bHPDrainRate, 50, 5); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus2(bHPDrainRate, 50, 5);
+ ">
},
{
Id: 1374
- SpriteName: "INCUBUS"
Name: "Incubus"
TamingItem: "Grils_Naivety"
EggItem: "Incubus_Egg"
AccessoryItem: "Ball_Mask"
FoodItem: "Vital_Flower"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 50
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus(bMaxSPrate, 3); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus(bMaxSPrate, 3);
+ ">
},
{
Id: 1379
- SpriteName: "NIGHTMARE_TERROR"
Name: "Nightmare Terror"
TamingItem: "Hell_Contract"
EggItem: "Nightmare_Terror_Egg"
AccessoryItem: "Hell_Horn"
FoodItem: "Fresh_Plant"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus2(bResEff, Eff_Sleep, 10000); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus2(bResEff, Eff_Sleep, 10000);
+ ">
},
{
Id: 1401
- SpriteName: "SHINOBI"
Name: "Shinobi"
TamingItem: "Kuloren"
EggItem: "Shinobi_Egg"
AccessoryItem: "Wine_On_Sleeve"
FoodItem: "Grilled_Rice_Cake"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus(bAgi, 2); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus(bAgi, 2);
+ ">
},
{
Id: 1404
- SpriteName: "MIYABI_NINGYO"
Name: "Miyabi Doll"
TamingItem: "Gril_Doll"
EggItem: "Miyabi_Ningyo_Egg"
AccessoryItem: "Summer_Fan"
FoodItem: "Well_Ripened_Berry"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 15
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus(bInt, 1);
- bonus(bCastrate, -3);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bInt, 1);
+ bonus(bCastrate, -3);
+ }
">
},
{
Id: 1416
- SpriteName: "WICKED_NYMPH"
Name: "Evil Nymph"
TamingItem: "Charming_Lotus"
EggItem: "Wicked_Nymph_Egg"
AccessoryItem: "Jade_Trinket"
FoodItem: "Morning_Dew"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 15
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus(bMaxSP, 30);
- bonus(bSPrecovRate, 5);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMaxSP, 30);
+ bonus(bSPrecovRate, 5);
+ }
">
},
{
Id: 1495
- SpriteName: "STONE_SHOOTER"
Name: "Stone Shooter"
TamingItem: "Oilpalm_Coconut"
EggItem: "Stone_Shooter_Egg"
AccessoryItem: "Apro_Hair"
FoodItem: "Plant_Neutrient"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus2(bSubEle, Ele_Fire, 3); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus2(bSubEle, Ele_Fire, 3);
+ ">
},
{
Id: 1504
- SpriteName: "DULLAHAN"
Name: "Dullahan"
TamingItem: "Luxury_Whisky_Bottle"
EggItem: "Dullahan_Egg"
AccessoryItem: "Death_Coil"
FoodItem: "Sunset_On_The_Rock"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus(bCritAtkRate, 5); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus(bCritAtkRate, 5);
+ ">
},
{
Id: 1505
- SpriteName: "LOLI_RURI"
Name: "Loli Ruri"
TamingItem: "Very_Red_Juice"
EggItem: "Loli_Ruri_Egg"
AccessoryItem: "Fashionable_Glasses"
FoodItem: "Pumpkin_Pie_"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 15
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus(bMaxHPrate, 3);
- bonus3(bAutoSpellWhenHit, "AL_HEAL", 1, 50);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bMaxHPrate, 3);
+ bonus3(bAutoSpellWhenHit, "AL_HEAL", 1, 50);
+ }
">
},
{
Id: 1513
- SpriteName: "CIVIL_SERVANT"
Name: "Mao Guai"
TamingItem: "Fan_Of_Wind"
EggItem: "Civil_Servant_Egg"
AccessoryItem: "Golden_Earing"
FoodItem: "Flavored_Alcohol"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 500
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
- EquipScript: <" bonus(bMaxSP, 10); ">
+ EquipScript: <"
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus(bMaxSP, 10);
+ ">
},
{
Id: 1519
- SpriteName: "CHUNG_E"
Name: "Green Maiden"
TamingItem: "Tantanmen"
EggItem: "Chung_E_Egg"
FoodItem: "Bun_"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 2000
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
PetScript: <" petskillattack("CR_SHIELDCHARGE", 5, 0, 5, 5); ">
EquipScript: <"
- bonus(bDef, 1);
- bonus2(bAddRaceTolerance, RC_DemiPlayer, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bDef, 1);
+ bonus2(bAddRaceTolerance, RC_DemiPlayer, 1);
+ }
">
},
{
Id: 1586
- SpriteName: "LEAF_CAT"
Name: "Leaf Cat"
TamingItem: "Very_Soft_Plant"
EggItem: "Leaf_Cat_Egg"
AccessoryItem: "Green_Lucky_Bag"
FoodItem: "Fish_With_Blue_Back"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 20
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus2(bAddRaceTolerance, RC_Brute, 3);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL)
+ bonus2(bAddRaceTolerance, RC_Brute, 3);
">
},
{
Id: 1630
- SpriteName: "BACSOJIN_"
Name: "White Lady"
TamingItem: "Shiny_Wing_Gown"
EggItem: "Bacsojin_Egg"
AccessoryItem: "Round_Hair_Ornament"
FoodItem: "Traditional_Cookie"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 2000
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
},
{
Id: 1837
- SpriteName: "IMP"
Name: "Fire Imp"
TamingItem: "Flaming_Ice"
EggItem: "Imp_Egg"
AccessoryItem: "Horn_Protector"
FoodItem: "Flame_Gemstone"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
CaptureRate: 200
- Speed: 150
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- bonus2(bSubEle, Ele_Fire, 2);
- bonus2(bAddEle, Ele_Fire, 2);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus2(bSubEle, Ele_Fire, 2);
+ bonus2(bAddEle, Ele_Fire, 2);
+ }
">
},
// Episode 13.2 Brasilis
{
Id: 2057
- SpriteName: "E_CRAMP"
Name: "Strange Cramp"
TamingItem: "Leaf_Cat_Ball"
EggItem: "Mystic_Leaf_Cat_Ball"
CaptureRate: 50
AttackRate: 350
DefendRate: 400
- ChangeTargetRate: 800
},
{
Id: 2081
- SpriteName: "E_HYDRA"
Name: "Strange Hydra"
TamingItem: "Leaf_Cat_Ball"
EggItem: "Mystic_Leaf_Cat_Ball"
CaptureRate: 50
AttackRate: 350
DefendRate: 400
- ChangeTargetRate: 800
},
// Episode 14.1
{
Id: 2313
- SpriteName: "TIKBALANG"
Name: "Tikbalang"
TamingItem: "Tikbalang_Belt"
EggItem: "Tikbalang_Pet"
FoodItem: "Monsters_Feed"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
- CaptureRate: 1000
- Speed: 150
SpecialPerformance: true
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
EquipScript: <"
- 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);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ 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);
+ }
">
},
// New Pets
{
Id: 1242
- SpriteName: "MARIN"
Name: "Marin"
TamingItem: "Juicy_Fruit"
EggItem: "Marin_Egg"
AccessoryItem: "Tw_Backpack"
FoodItem: "Fruit_Sundae"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 2000
- Speed: 150
SpecialPerformance: true
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
},
{
Id: 2200
- SpriteName: "J_TAINI"
Name: "Tiny"
EggItem: "Egg_Of_Tiny"
FoodItem: "Apple"
- FoodEffectiveness: 80
- HungerDelay: 60
- Intimacy: {
- Initial: 250
- FeedIncrement: 10
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
- }
- Speed: 150
SpecialPerformance: true
- AttackRate: 300
- DefendRate: 300
- ChangeTargetRate: 800
},
// Episode 14.2
{
Id: 2398
- SpriteName: "LITTLE_PORING"
Name: "Little Poring"
TamingItem: "Unripe_Apple2"
EggItem: "Novice_Poring_Egg"
AccessoryItem: "Backpack"
FoodItem: "Apple_Juice"
- FoodEffectiveness: 80
- HungerDelay: 60
Intimacy: {
- Initial: 250
FeedIncrement: 50
- OverFeedDecrement: 100
- OwnerDeathDecrement: 20
}
CaptureRate: 2000
- Speed: 150
SpecialPerformance: true
AttackRate: 350
DefendRate: 400
- ChangeTargetRate: 800
PetScript: <" petloot(10); ">
EquipScript: <"
- bonus(bLuk, 2);
- bonus(bCritical, 1);
+ if (getpetinfo(PETINFO_INTIMACY) >= PET_INTIMACY_LOYAL) {
+ bonus(bLuk, 2);
+ bonus(bCritical, 1);
+ }
">
},
// New Pets [Need Info]
{
Id: 1090
- SpriteName: "MASTERING"
Name: "Mastering"
EggItem: "Mastering_Egg"
AutoFeed: true
@@ -1783,14 +1260,12 @@ pet_db:(
},
{
Id: 1096
- SpriteName: "ANGELING"
Name: "Angeling"
EggItem: "Angeling_Egg"
AutoFeed: true
},
{
Id: 1301
- SpriteName: "AM_MUT"
Name: "Am Mut"
EggItem: "Am_Mut_Egg"
AutoFeed: true
@@ -1798,7 +1273,6 @@ pet_db:(
/*
{
Id: 3636
- SpriteName: "LITTLE_ISIS"
Name: "Little Isis"
EggItem: "Little_Isis_Egg"
AutoFeed: true
@@ -1806,7 +1280,6 @@ pet_db:(
*/
{
Id: 1214
- SpriteName: "CHOCO"
Name: "Choco"
EggItem: "Choco_Egg"
AutoFeed: true
@@ -1814,7 +1287,6 @@ pet_db:(
/*
{
Id: 3495
- SpriteName: "DR_EGGRING"
Name: "Eggring"
EggItem: "Eggring_Egg"
AutoFeed: true
@@ -1822,7 +1294,6 @@ pet_db:(
*/
{
Id: 1512
- SpriteName: "HYEGUN"
Name: "Hyegun"
EggItem: "Hyegun_Egg"
AutoFeed: true
@@ -1830,7 +1301,6 @@ pet_db:(
/*
{
Id: 3496
- SpriteName: "DR_LUNATIC"
Name: "Leaf Lunatic"
EggItem: "Leaf_Lunatic_Egg"
AutoFeed: true
@@ -1838,7 +1308,6 @@ pet_db:(
*/
{
Id: 1180
- SpriteName: "NINE_TAIL"
Name: "Nine Tails"
EggItem: "Nine_Tails_Egg"
AutoFeed: true
@@ -1855,7 +1324,6 @@ pet_db:(
},
{
Id: 1307
- SpriteName: "CAT_O_NINE_TAIL"
Name: "Cat o' Nine Tails"
EggItem: "Cat_o_Nine_Tails_Egg"
AutoFeed: true
@@ -1873,7 +1341,6 @@ pet_db:(
/*
{
Id: 3669
- SpriteName: "DIABOLIC2"
Name: "Diabolic"
EggItem: "Diabolic_Egg_"
AutoFeed: true
@@ -1882,7 +1349,6 @@ pet_db:(
/*
{
Id: 3670
- SpriteName: "DELETER_2"
Name: "Earth Deleter"
EggItem: "Earth_Deleter_Egg"
AutoFeed: true
@@ -1890,7 +1356,6 @@ pet_db:(
*/
{
Id: 1622
- SpriteName: "TEDDY_BEAR"
Name: "Teddy Bear"
EggItem: "Teddy_Bear_Egg"
AutoFeed: true
@@ -1907,7 +1372,6 @@ pet_db:(
},
{
Id: 1632
- SpriteName: "GREMLIN"
Name: "Gremlin"
EggItem: "Gremlin_Egg"
AutoFeed: true
@@ -1925,7 +1389,6 @@ pet_db:(
/*
{
Id: 3731
- SpriteName: "SCATLETON"
Name: "Scatleton Crate"
EggItem: "Scatleton_Crate"
AutoFeed: true
@@ -1933,7 +1396,6 @@ pet_db:(
*/
{
Id: 1041
- SpriteName: "MUMMY"
Name: "Mummy"
EggItem: "Mummy_Egg"
AutoFeed: true
@@ -1950,42 +1412,36 @@ pet_db:(
},
{
Id: 1010
- SpriteName: "WILOW"
Name: "Willow"
EggItem: "Willow_Egg"
AutoFeed: true
},
{
Id: 1782
- SpriteName: "ROWEEN"
Name: "Roween"
EggItem: "Roween_Egg"
AutoFeed: true
},
{
Id: 1773
- SpriteName: "HODREMLIN"
Name: "Hodremlin"
EggItem: "Hodremlin_Egg"
AutoFeed: true
},
{
Id: 1058
- SpriteName: "METALLER"
Name: "Metaller"
EggItem: "Metaller_Egg"
AutoFeed: true
},
{
Id: 1297
- SpriteName: "ANCIENT_MUMMY"
Name: "Ancient Mummy"
EggItem: "Ancient_Mummy_Egg"
AutoFeed: true
},
/*{
Id: 2995
- SpriteName: "XM_TEDDY_BEAR"
Name: "Abandoned Teddy Bear"
EggItem: "Abandoned_Teddy_Bear_Egg"
AutoFeed: true
@@ -1994,7 +1450,6 @@ pet_db:(
/* UNKNOWN MONSTER
{
Id: 0
- SpriteName: "X"
Name: "Sweet Drops"
EggItem: "Sweet_Drops_Egg"
AutoFeed: true
@@ -2002,14 +1457,12 @@ pet_db:(
*/
{
Id: 1159
- SpriteName: "PHREEONI"
Name: "Phreeoni"
EggItem: "Phreeoni_Egg"
AutoFeed: true
},
{
Id: 1150
- SpriteName: "MOONLIGHT"
Name: "Moonlight Flower"
EggItem: "Moonlight_Flower_Egg"
AutoFeed: true
@@ -2017,7 +1470,6 @@ pet_db:(
/*
{
Id: 3971
- SpriteName: "SKELION"
Name: "Skelion"
EggItem: "Skelion_Egg"
AutoFeed: true
diff --git a/doc/pet_db.txt b/doc/pet_db.txt
new file mode 100644
index 000000000..140a8309d
--- /dev/null
+++ b/doc/pet_db.txt
@@ -0,0 +1,196 @@
+//===== Hercules Documentation ===============================
+//= Pet Database
+//===== By: ==================================================
+//= Hercules Dev Team
+//===== Current Version: =====================================
+//= 20200102
+//===== Description: =========================================
+//= Explanation of the pet_db.conf file and structure.
+//============================================================
+
+pet_db: (
+{
+ // ================ Mandatory fields ==============================
+ Id: ID (int)
+ Name: "Pet Name" (string)
+ EggItem: "Egg Item Constant" (string)
+ // ================ Optional fields ===============================
+ TamingItem: "Taming Item Constant" (string, defaults to 0)
+ FoodItem: "Food Item Constant" (string, defaults to 537 ("Pet_Food"))
+ AccessoryItem: "Equipment Item Constant" (string, defaults to 0)
+ FoodEffectiveness: hunger points (int, defaults to 80)
+ HungerDelay: hunger time (int, defaults to 60)
+ HungerDecrement: hunger points (int, defaults to 1)
+ Intimacy: {
+ Initial: start intimacy (int, defaults to 250)
+ FeedIncrement: feeding intimacy (int, defaults to 10)
+ OverFeedDecrement: overfeeding intimacy (int, defaults to 100)
+ OwnerDeathDecrement: owner die intimacy (int, defaults to 20)
+ StarvingDelay: starving time (int, defaults to 20)
+ StarvingDecrement: starving intimacy (int, defaults to 20)
+ }
+ CaptureRate: capture rate (int, defaults to 1000)
+ Speed: speed (int, defaults to 150)
+ SpecialPerformance: true/false (boolean, defaults to false)
+ TalkWithEmotes: convert talk (boolean, defaults to false)
+ AttackRate: attack rate (int, defaults to 300)
+ DefendRate: Defence attack (int, defaults to 300)
+ ChangeTargetRate: change target (int, defaults to 800)
+ AutoFeed: true/false (boolean, defaults to false)
+ PetScript: <" Pet Script (can also be multi-line) ">
+ EquipScript: <" Equip Script (can also be multi-line) ">
+ Evolve: {
+ EggID: { (string, Evolved Pet EggID)
+ Name: Amount (items required to perform evolution)
+ ...
+ }
+ }
+},
+...
+)
+
+ * Id:
+ The ID of the monster that should be tamed. See mob_db.conf.
+ * Name:
+ The pet's default name.
+ * EggItem:
+ The name of the pet's egg item. See item_db.conf AegisName field.
+ * TamingItem:
+ The name of the item, which is used to tame the pet.
+ See item_db.conf AegisName field.
+ This field is optional and defaults to 0.
+ * FoodItem:
+ The name of the item, which is used to feed the pet.
+ See item_db.conf AegisName field.
+ This field is optional and defaults to Pet_Food (ID=537).
+ * AccessoryItem:
+ The name of the pet's accesssory item.
+ See item_db.conf AegisName field.
+ This field is optional and defaults to 0.
+ * FoodEffectiveness:
+ This field defines how many hunger points
+ are restored, when feeding the pet.
+ This field is optional and defaults to 80.
+ Minimum value is 1, maximum value is 100.
+ * HungerDelay:
+ This is the interval for consuming hunger points.
+ Every <HungerDelay> seconds, the pet will consume
+ <HungerDecrement> hunger points.
+ In official servers it's 60 seconds for every pet.
+ This field is optional and defaults to 60.
+ Minimum value is 0, maximum value is 2147483.
+ If set to 0, the pet won't consume hunger points.
+ * HungerDecrement:
+ How many hunger points will be consumed every <HungerDelay> seconds.
+ This field is optional and defaults to 1.
+ Minimum value is 0, maximum value is 99.
+ If set to 0, <HungerDelay> is automatically set to 0, too,
+ regardless of what value was defined.
+ * Intimacy: {
+ The <Intimacy> block contains all settings,
+ which affect the pet's intimacy value.
+ * Initial:
+ The amount of intimacy points, the pet will have when tamed.
+ This field is optional and defaults to 250.
+ Minimum value is 1, maximum value is 1000.
+ * FeedIncrement:
+ The amount of intimacy points, gained when feeding the pet.
+ Note: This value is used as base value.
+ The actual added amount depends on the pet's current hunger.
+ This field is optional and defaults to 10.
+ Minimum value is 1, maximum value is 1000.
+ * OverFeedDecrement:
+ The amount of intimacy points, lost when feeding the pet
+ if it isn't hungry.
+ Note: This value is used as base value.
+ The actual removed amount depends on the pet's current hunger.
+ This field is optional and defaults to 100.
+ Minimum value is 0, maximum value is 1000.
+ * OwnerDeathDecrement:
+ The amount of intimacy points, lost when its master dies.
+ This field is optional and defaults to 20.
+ Minimum value is 0, maximum value is 1000.
+ * StarvingDelay:
+ This is the interval for loosing intimacy points,
+ when the pet is starving.
+ The pet is starving, if it has no hunger points left.
+ Every <StarvingDelay> seconds, the pet will lose
+ <StarvingDecrement> intimacy points.
+ In official servers it's 20 seconds for all pets.
+ If <HungerDelay> is set to 0, <StarvingDelay> is set to 0, too,
+ regardless of what value was defined.
+ This field is optional and defaults to 20.
+ Minimum value is 0, maximum value is <HungerDelay>.
+ If set to 0, the pet won't lose intimacy points while starving.
+ * StarvingDecrement:
+ How many intimacy points will be lost every <StarvingDelay> seconds,
+ when the pet is starving.
+ This field is optional and defaults to 20.
+ Minimum value is 0, maximum value is 1000.
+ If set to 0, <StarvingDelay> is automatically set to 0, too,
+ regardless of what value was defined.
+ }
+ * CaptureRate:
+ The chance of success when taming the pet.
+ 10000 equals 100%.
+ This field is optional and defaults to 1000.
+ Minimum value is 1, maximum value is 10000.
+ * Speed:
+ The pet's moving speed.
+ Note: The lower the value, the higher the speed.
+ This field is optional and defaults to 150.
+ Minimum value is 20, maximum value is 1000.
+ * SpecialPerformance:
+ If 'true', the pet is allowed to do its special performance.
+ This field is optional and defaults to 'false'.
+ * TalkWithEmotes:
+ If 'true', the pet is allowed to talk by using emotes.
+ This field is optional and defaults to 'false'.
+ * AttackRate:
+ Chance for supporting when the master attacks a monster.
+ 10000 equals 100%.
+ This field is optional and defaults to 300.
+ Minimum value is 0, maximum value is 10000.
+ * DefendRate:
+ Chance for supporting when the master receives damage from a monster.
+ 10000 equals 100%.
+ This field is optional and defaults to 300.
+ Minimum value is 0, maximum value is 10000.
+ * ChangeTargetRate:
+ Chance for the pet changes its target when supporting.
+ 10000 equals 100%.
+ This field is optional and defaults to 800.
+ Minimum value is 0, maximum value is 10000.
+ * AutoFeed:
+ If 'true', the pet is fed automatically.
+ This field is optional and defaults to 'false'.
+ * PetScript: <"
+ This field is used for pet AI commands. See doc/script_commands.txt.
+ It will be executed every time, the pet's data gets initialized.
+ Everything you can do in a NPC script should work here, too,
+ but using the <EquipScript> field is recommended, when executing
+ other commands than the pet AI ones.
+ This field is optional and has no default value.
+ ">
+ * EquipScript: <"
+ This field is commonly used to apply bonuses to the the pet's master.
+ See doc/item_bonus.md.
+ It will be executed every time, the pet master's status is calculated.
+ Everything you can do in a NPC script should work here, too.
+ This field is optional and has no default value.
+ ">
+ * Evolve: {
+ The <Evolve> block is used to define which pet(s) can be eveolved
+ from the current pet.
+ This block is optional and has no default value.
+ * Evolved_Egg_Item_Name: {
+ The name of the egg item, which will be created when evolving.
+ You can add multiple <Evolved_Egg_Item_Name> blocks.
+ See item_db.conf AegisName field.
+ * Evolve_Item_Name: Amount
+ This is a pair of an item name and the corresponding amount which is
+ required to evolve the pet into <Evolved_Egg_Item_Name>.
+ You can add multiple <Evolve_Item_Name: Amount> pairs.
+ See item_db.conf AegisName field for item names.
+ }
+ }
diff --git a/src/char/int_pet.c b/src/char/int_pet.c
index 880de668d..176025f13 100644
--- a/src/char/int_pet.c
+++ b/src/char/int_pet.c
@@ -43,97 +43,161 @@ struct inter_pet_interface *inter_pet;
/**
* Saves a pet to the SQL database.
*
- * @remark
- * In case of newly created pet, the pet ID is not updated to reflect the
- * newly assigned ID. The caller must do so.
+ * Table structure:
+ * `pet` (`pet_id`, `class`, `name`, `account_id`, `char_id`, `level`, `egg_id`, `equip`, `intimate`, `hungry`, `rename_flag`, `incubate`, `autofeed`)
+ *
+ * @remark In case of newly created pet, the pet ID is not updated to reflect the newly assigned ID. The caller must do so.
*
* @param p The pet data to save.
- * @return The ID of the saved pet.
- * @retval 0 in case of errors.
- */
+ * @return The ID of the saved pet, or 0 in case of errors.
+ *
+ **/
static int inter_pet_tosql(const struct s_pet *p)
{
- //`pet` (`pet_id`, `class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate`)
- char esc_name[NAME_LENGTH*2+1];// escaped pet name
- int pet_id = 0, hungry = 0, intimate = 0;
-
nullpo_ret(p);
- SQL->EscapeStringLen(inter->sql_handle, esc_name, p->name, strnlen(p->name, NAME_LENGTH));
- hungry = cap_value(p->hungry, 0, 100);
- intimate = cap_value(p->intimate, 0, 1000);
-
- if (p->pet_id == 0) {
- // New pet.
- if (SQL_ERROR == SQL->Query(inter->sql_handle, "INSERT INTO `%s` "
- "(`class`,`name`,`account_id`,`char_id`,`level`,`egg_id`,`equip`,`intimate`,`hungry`,`rename_flag`,`incubate`, `autofeed`) "
- "VALUES ('%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')",
- pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id,
- p->equip, intimate, hungry, p->rename_flag, p->incubate, p->autofeed)) {
- Sql_ShowDebug(inter->sql_handle);
+ struct SqlStmt *stmt = SQL->StmtMalloc(inter->sql_handle);
+
+ if (stmt == NULL) {
+ SqlStmt_ShowDebug(stmt);
+ return 0;
+ }
+
+ int pet_id = 0;
+
+ if (p->pet_id == 0) { // New pet.
+ const char *query = "INSERT INTO `%s` "
+ "(`class`, `name`, `account_id`, `char_id`, `level`, `egg_id`, `equip`, "
+ "`intimate`, `hungry`, `rename_flag`, `incubate`, `autofeed`) "
+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+
+ if (SQL_ERROR == SQL->StmtPrepare(stmt, query, pet_db) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT32, &p->class_, sizeof(p->class_)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 1, SQLDT_STRING, &p->name, strnlen(p->name, sizeof(p->name))) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 2, SQLDT_INT32, &p->account_id, sizeof(p->account_id)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 3, SQLDT_INT32, &p->char_id, sizeof(p->char_id)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 4, SQLDT_INT16, &p->level, sizeof(p->level)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 5, SQLDT_INT32, &p->egg_id, sizeof(p->egg_id)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 6, SQLDT_INT32, &p->equip, sizeof(p->equip)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 7, SQLDT_INT16, &p->intimate, sizeof(p->intimate)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 8, SQLDT_INT16, &p->hungry, sizeof(p->hungry)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 9, SQLDT_INT8, &p->rename_flag, sizeof(p->rename_flag)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 10, SQLDT_INT8, &p->incubate, sizeof(p->incubate)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 11, SQLDT_INT32, &p->autofeed, sizeof(p->autofeed)) ||
+ SQL_ERROR == SQL->StmtExecute(stmt)) {
+ SqlStmt_ShowDebug(stmt);
+ SQL->StmtFree(stmt);
return 0;
}
+
pet_id = (int)SQL->LastInsertId(inter->sql_handle);
- } else {
- // Update pet.
- if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `class`='%d',`name`='%s',`account_id`='%d',`char_id`='%d',`level`='%d',`egg_id`='%d',`equip`='%d',`intimate`='%d',`hungry`='%d',`rename_flag`='%d',`incubate`='%d', `autofeed`='%d' WHERE `pet_id`='%d'",
- pet_db, p->class_, esc_name, p->account_id, p->char_id, p->level, p->egg_id,
- p->equip, intimate, hungry, p->rename_flag, p->incubate, p->autofeed, p->pet_id)) {
- Sql_ShowDebug(inter->sql_handle);
+ } else { // Update pet.
+ const char *query = "UPDATE `%s` SET "
+ "`class`=?, `name`=?, `account_id`=?, `char_id`=?, `level`=?, `egg_id`=?, `equip`=?, "
+ "`intimate`=?, `hungry`=?, `rename_flag`=?, `incubate`=?, `autofeed`=? "
+ "WHERE `pet_id`=?";
+
+ if (SQL_ERROR == SQL->StmtPrepare(stmt, query, pet_db) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT32, &p->class_, sizeof(p->class_)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 1, SQLDT_STRING, &p->name, strnlen(p->name, sizeof(p->name))) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 2, SQLDT_INT32, &p->account_id, sizeof(p->account_id)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 3, SQLDT_INT32, &p->char_id, sizeof(p->char_id)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 4, SQLDT_INT16, &p->level, sizeof(p->level)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 5, SQLDT_INT32, &p->egg_id, sizeof(p->egg_id)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 6, SQLDT_INT32, &p->equip, sizeof(p->equip)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 7, SQLDT_INT16, &p->intimate, sizeof(p->intimate)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 8, SQLDT_INT16, &p->hungry, sizeof(p->hungry)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 9, SQLDT_INT8, &p->rename_flag, sizeof(p->rename_flag)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 10, SQLDT_INT8, &p->incubate, sizeof(p->incubate)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 11, SQLDT_INT32, &p->autofeed, sizeof(p->autofeed)) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 12, SQLDT_INT32, &p->pet_id, sizeof(p->pet_id)) ||
+ SQL_ERROR == SQL->StmtExecute(stmt)) {
+ SqlStmt_ShowDebug(stmt);
+ SQL->StmtFree(stmt);
return 0;
}
+
pet_id = p->pet_id;
}
+ SQL->StmtFree(stmt);
+
if (chr->show_save_log)
ShowInfo("Pet saved %d - %s.\n", pet_id, p->name);
return pet_id;
}
+/**
+ * Loads a pet's data from the SQL database.
+ *
+ * Table structure:
+ * `pet` (`pet_id`, `class`, `name`, `account_id`, `char_id`, `level`, `egg_id`, `equip`, `intimate`, `hungry`, `rename_flag`, `incubate`, `autofeed`)
+ *
+ * @param pet_id The pet's ID.
+ * @param p The pet data to save the SQL data in.
+ * @return Always 0.
+ *
+ **/
static int inter_pet_fromsql(int pet_id, struct s_pet *p)
{
- char* data;
- size_t len;
+ nullpo_ret(p);
+
+ struct SqlStmt *stmt = SQL->StmtMalloc(inter->sql_handle);
+
+ if (stmt == NULL) {
+ SqlStmt_ShowDebug(stmt);
+ return 0;
+ }
#ifdef NOISY
ShowInfo("Loading pet (%d)...\n",pet_id);
#endif
- nullpo_ret(p);
+
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`, `autofeed`)
+ const char *query = "SELECT "
+ "`class`, `name`, `account_id`, `char_id`, `level`, `egg_id`, `equip`, "
+ "`intimate`, `hungry`, `rename_flag`, `incubate`, `autofeed` "
+ "FROM `%s` WHERE `pet_id`=?";
+
+ if (SQL_ERROR == SQL->StmtPrepare(stmt, query, pet_db) ||
+ SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT32, &pet_id, sizeof(pet_id)) ||
+ SQL_ERROR == SQL->StmtExecute(stmt) ||
+ SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT32, &p->class_, sizeof(p->class_), NULL, NULL) ||
+ SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_STRING, &p->name, sizeof(p->name), NULL, NULL) ||
+ SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_INT32, &p->account_id, sizeof(p->account_id), NULL, NULL) ||
+ SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_INT32, &p->char_id, sizeof(p->char_id), NULL, NULL) ||
+ SQL_ERROR == SQL->StmtBindColumn(stmt, 4, SQLDT_INT16, &p->level, sizeof(p->level), NULL, NULL) ||
+ SQL_ERROR == SQL->StmtBindColumn(stmt, 5, SQLDT_INT32, &p->egg_id, sizeof(p->egg_id), NULL, NULL) ||
+ SQL_ERROR == SQL->StmtBindColumn(stmt, 6, SQLDT_INT32, &p->equip, sizeof(p->equip), NULL, NULL) ||
+ SQL_ERROR == SQL->StmtBindColumn(stmt, 7, SQLDT_INT16, &p->intimate, sizeof(p->intimate), NULL, NULL) ||
+ SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_INT16, &p->hungry, sizeof(p->hungry), NULL, NULL) ||
+ SQL_ERROR == SQL->StmtBindColumn(stmt, 9, SQLDT_INT8, &p->rename_flag, sizeof(p->rename_flag), NULL, NULL) ||
+ SQL_ERROR == SQL->StmtBindColumn(stmt, 10, SQLDT_INT8, &p->incubate, sizeof(p->incubate), NULL, NULL) ||
+ SQL_ERROR == SQL->StmtBindColumn(stmt, 11, SQLDT_INT32, &p->autofeed, sizeof(p->autofeed), NULL, NULL)) {
+ SqlStmt_ShowDebug(stmt);
+ SQL->StmtFree(stmt);
+ return 0;
+ }
- if( SQL_ERROR == SQL->Query(inter->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'", pet_db, pet_id) )
- {
- Sql_ShowDebug(inter->sql_handle);
+ if (SQL->StmtNumRows(stmt) < 1) {
+ ShowError("inter_pet_fromsql: Requested non-existant pet ID: %d\n", pet_id);
+ SQL->StmtFree(stmt);
return 0;
}
- if( SQL_SUCCESS == SQL->NextRow(inter->sql_handle) )
- {
- p->pet_id = pet_id;
- SQL->GetData(inter->sql_handle, 1, &data, NULL); p->class_ = atoi(data);
- SQL->GetData(inter->sql_handle, 2, &data, &len); memcpy(p->name, data, min(len, NAME_LENGTH));
- SQL->GetData(inter->sql_handle, 3, &data, NULL); p->account_id = atoi(data);
- SQL->GetData(inter->sql_handle, 4, &data, NULL); p->char_id = atoi(data);
- SQL->GetData(inter->sql_handle, 5, &data, NULL); p->level = atoi(data);
- SQL->GetData(inter->sql_handle, 6, &data, NULL); p->egg_id = atoi(data);
- SQL->GetData(inter->sql_handle, 7, &data, NULL); p->equip = atoi(data);
- SQL->GetData(inter->sql_handle, 8, &data, NULL); p->intimate = atoi(data);
- SQL->GetData(inter->sql_handle, 9, &data, NULL); p->hungry = atoi(data);
- SQL->GetData(inter->sql_handle, 10, &data, NULL); p->rename_flag = atoi(data);
- SQL->GetData(inter->sql_handle, 11, &data, NULL); p->incubate = atoi(data);
- SQL->GetData(inter->sql_handle, 12, &data, NULL); p->autofeed = atoi(data);
-
- SQL->FreeResult(inter->sql_handle);
-
- p->hungry = cap_value(p->hungry, 0, 100);
- p->intimate = cap_value(p->intimate, 0, 1000);
-
- if (chr->show_save_log)
- ShowInfo("Pet loaded (%d - %s).\n", pet_id, p->name);
+ if (SQL_ERROR == SQL->StmtNextRow(stmt)) {
+ SqlStmt_ShowDebug(stmt);
+ SQL->StmtFree(stmt);
+ return 0;
}
+
+ SQL->StmtFree(stmt);
+
+ if (chr->show_save_log)
+ ShowInfo("Pet loaded %d - %s.\n", pet_id, p->name);
+
return 0;
}
//----------------------------------------------
@@ -160,41 +224,48 @@ static int inter_pet_delete(int pet_id)
return 0;
}
//------------------------------------------------------
+
+/**
+ * Creates a new pet and inserts its data into the `pet` SQL table.
+ *
+ * @param account_id The pet's master's account ID.
+ * @param char_id The pet's master's char ID.
+ * @param pet_class The pet's class/monster ID.
+ * @param pet_lv The pet's level.
+ * @param pet_egg_id The pet's egg's item ID.
+ * @param pet_equip The pet's equipment's item ID.
+ * @param intimate The pet's intimacy value.
+ * @param hungry The pet's hunger value.
+ * @param rename_flag The pet's rename flag.
+ * @param incubate The pet's incubate state.
+ * @param pet_name The pet's name.
+ * @return The created pet's data struct, or NULL in case of errors.
+ *
+ **/
static struct s_pet *inter_pet_create(int account_id, int char_id, int pet_class, int pet_lv, int pet_egg_id,
- int pet_equip, short intimate, short hungry, char rename_flag, char incubate, const char *pet_name)
+ int pet_equip, short intimate, short hungry, char rename_flag,
+ char incubate, const char *pet_name)
{
- nullpo_ret(pet_name);
+ nullpo_retr(NULL, pet_name);
+
memset(inter_pet->pt, 0, sizeof(struct s_pet));
safestrncpy(inter_pet->pt->name, pet_name, NAME_LENGTH);
- if(incubate == 1)
- inter_pet->pt->account_id = inter_pet->pt->char_id = 0;
- else {
- inter_pet->pt->account_id = account_id;
- inter_pet->pt->char_id = char_id;
- }
+ inter_pet->pt->account_id = (incubate == 1) ? 0 : account_id;
+ inter_pet->pt->char_id = (incubate == 1) ? 0 : char_id;
inter_pet->pt->class_ = pet_class;
inter_pet->pt->level = pet_lv;
inter_pet->pt->egg_id = pet_egg_id;
inter_pet->pt->equip = pet_equip;
- inter_pet->pt->intimate = intimate;
- inter_pet->pt->hungry = hungry;
+ inter_pet->pt->intimate = cap_value(intimate, PET_INTIMACY_NONE, PET_INTIMACY_MAX);
+ inter_pet->pt->hungry = cap_value(hungry, PET_HUNGER_STARVING, PET_HUNGER_STUFFED);
inter_pet->pt->rename_flag = rename_flag;
inter_pet->pt->incubate = incubate;
+ inter_pet->pt->pet_id = 0; // Signal NEW pet.
- if(inter_pet->pt->hungry < 0)
- inter_pet->pt->hungry = 0;
- else if(inter_pet->pt->hungry > 100)
- inter_pet->pt->hungry = 100;
- if(inter_pet->pt->intimate < 0)
- inter_pet->pt->intimate = 0;
- else if(inter_pet->pt->intimate > 1000)
- inter_pet->pt->intimate = 1000;
-
- inter_pet->pt->pet_id = 0; //Signal NEW pet.
if ((inter_pet->pt->pet_id = inter_pet->tosql(inter_pet->pt)) != 0)
return inter_pet->pt;
- else //Failed...
- return NULL;
+
+ return NULL;
}
static struct s_pet *inter_pet_load(int account_id, int char_id, int pet_id)
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 25ad350c0..9421f6e35 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -1378,6 +1378,27 @@ enum questinfo_type {
QINFO_MERCENARY_CLASS
};
+/** Pet hunger level **/
+enum e_pet_hunger_level {
+ PET_HUNGER_STARVING = 0,
+ PET_HUNGER_VERY_HUNGRY = 10,
+ PET_HUNGER_HUNGRY = 25,
+ PET_HUNGER_NEUTRAL = 75,
+ PET_HUNGER_SATISFIED = 90,
+ PET_HUNGER_STUFFED = 100
+};
+
+/** Pet intimacy level **/
+enum e_pet_intimacy_level {
+ PET_INTIMACY_NONE = 0,
+ PET_INTIMACY_AWKWARD = 1,
+ PET_INTIMACY_SHY = 100,
+ PET_INTIMACY_NEUTRAL = 250,
+ PET_INTIMACY_CORDIAL = 750,
+ PET_INTIMACY_LOYAL = 900,
+ PET_INTIMACY_MAX = 1000
+};
+
/* packet size constant for itemlist */
#if MAX_INVENTORY > MAX_STORAGE && MAX_INVENTORY > MAX_CART
#define MAX_ITEMLIST MAX_INVENTORY
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index d3368c3b0..6d7898fde 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -2744,42 +2744,49 @@ ACMD(guildlevelup)
return true;
}
-/*==========================================
+/**
+ * Creates a pet egg in the character's inventory.
*
- *------------------------------------------*/
+ * @code{.herc}
+ * @makeegg <pet>
+ * @endcode
+ *
+ **/
ACMD(makeegg)
{
- struct item_data *item_data;
- int id, pet_id;
-
- if (!*message) {
- clif->message(fd, msg_fd(fd,1015)); // Please enter a monster/egg name/ID (usage: @makeegg <pet>).
+ if (*message == '\0') {
+ clif->message(fd, msg_fd(fd, 1015)); // Please enter a monster/egg name/ID (usage: @makeegg <pet>).
return false;
}
- if ((item_data = itemdb->search_name(message)) != NULL) // for egg name
+ struct item_data *item_data = itemdb->search_name(message);
+ int id;
+
+ if (item_data != NULL) { // Egg name.
id = item_data->nameid;
- else
- if ((id = mob->db_searchname(message)) != 0) // for monster name
- ;
- else
- id = atoi(message);
+ } else {
+ id = mob->db_searchname(message); // Monster name.
- pet_id = pet->search_petDB_index(id, PET_CLASS);
- if (pet_id < 0)
+ if (id == 0)
+ id = atoi(message); // Egg/monster ID.
+ }
+
+ int pet_id = pet->search_petDB_index(id, PET_CLASS);
+
+ if (pet_id == INDEX_NOT_FOUND)
pet_id = pet->search_petDB_index(id, PET_EGG);
- if (pet_id >= 0) {
- sd->catch_target_class = pet->db[pet_id].class_;
- intif->create_pet(
- sd->status.account_id, sd->status.char_id,
- pet->db[pet_id].class_, mob->db(pet->db[pet_id].class_)->lv,
- pet->db[pet_id].EggID, 0, (short)pet->db[pet_id].intimate,
- 100, 0, 1, pet->db[pet_id].jname);
- } else {
- clif->message(fd, msg_fd(fd,180)); // The monster/egg name/id doesn't exist.
+
+ if (pet_id == INDEX_NOT_FOUND) {
+ clif->message(fd, msg_fd(fd, 180)); // The monster/egg name/ID doesn't exist.
return false;
}
+ sd->catch_target_class = pet->db[pet_id].class_;
+ intif->create_pet(sd->status.account_id, sd->status.char_id, pet->db[pet_id].class_,
+ mob->db(pet->db[pet_id].class_)->lv, pet->db[pet_id].EggID, 0,
+ (short)pet->db[pet_id].intimate, PET_HUNGER_STUFFED,
+ 0, 1,pet->db[pet_id].jname);
+
return true;
}
@@ -2798,72 +2805,90 @@ ACMD(hatch)
return true;
}
-/*==========================================
+/**
+ * Sets a pet's intimacy value.
*
- *------------------------------------------*/
+ * @code{.herc}
+ * @petfriendly <0-1000>
+ * @endcode
+ *
+ **/
ACMD(petfriendly)
{
- int friendly;
- struct pet_data *pd;
-
- if (!*message || (friendly = atoi(message)) < 0) {
- clif->message(fd, msg_fd(fd,1016)); // Please enter a valid value (usage: @petfriendly <0-1000>).
+ if (*message == '\0' || (atoi(message) == 0 && isdigit(*message) == 0)) {
+ clif->message(fd, msg_fd(fd, 1016)); // Please enter a valid value (usage: @petfriendly <0-1000>).
return false;
}
- pd = sd->pd;
- if (!pd) {
- clif->message(fd, msg_fd(fd,184)); // Sorry, but you have no pet.
+ int friendly = atoi(message);
+
+ if (friendly < PET_INTIMACY_NONE || friendly > PET_INTIMACY_MAX) {
+ clif->message(fd, msg_fd(fd, 1016)); // Please enter a valid value (usage: @petfriendly <0-1000>).
return false;
}
- if (friendly < 0 || friendly > 1000)
- {
- clif->message(fd, msg_fd(fd,37)); // An invalid number was specified.
+ struct pet_data *pd = sd->pd;
+
+ if (sd->status.pet_id == 0 || pd == NULL) {
+ clif->message(fd, msg_fd(fd, 184)); // Sorry, but you have no pet.
return false;
}
- if (friendly == pd->pet.intimate) {
- clif->message(fd, msg_fd(fd,183)); // Pet intimacy is already at maximum.
+ if (friendly == pd->pet.intimate && friendly == PET_INTIMACY_MAX) {
+ clif->message(fd, msg_fd(fd, 183)); // Pet intimacy is already at maximum.
return false;
}
- pet->set_intimate(pd, friendly);
- clif->send_petstatus(sd);
- clif->message(fd, msg_fd(fd,182)); // Pet intimacy changed.
+ if (friendly != pd->pet.intimate) { // No need to update the pet's status if intimacy value won't change.
+ pet->set_intimate(pd, friendly);
+ clif->send_petstatus(sd);
+ }
+
+ clif->message(fd, msg_fd(fd, 182)); // Pet intimacy changed. (Send message regardless of value has changed or not.)
+
return true;
}
-/*==========================================
+/**
+ * Sets a pet's hunger value.
*
- *------------------------------------------*/
+ * @code{.herc}
+ * @pethungry <0-100>
+ * @endcode
+ *
+ **/
ACMD(pethungry)
{
- int hungry;
- struct pet_data *pd;
-
- if (!*message || (hungry = atoi(message)) < 0) {
- clif->message(fd, msg_fd(fd,1017)); // Please enter a valid number (usage: @pethungry <0-100>).
+ if (*message == '\0' || (atoi(message) == 0 && isdigit(*message) == 0)) {
+ clif->message(fd, msg_fd(fd, 1017)); // Please enter a valid number (usage: @pethungry <0-100>).
return false;
}
- pd = sd->pd;
- if (!sd->status.pet_id || !pd) {
- clif->message(fd, msg_fd(fd,184)); // Sorry, but you have no pet.
+ int hungry = atoi(message);
+
+ if (hungry < PET_HUNGER_STARVING || hungry > PET_HUNGER_STUFFED) {
+ clif->message(fd, msg_fd(fd, 1017)); // Please enter a valid number (usage: @pethungry <0-100>).
return false;
}
- if (hungry < 0 || hungry > 100) {
- clif->message(fd, msg_fd(fd,37)); // An invalid number was specified.
+
+ struct pet_data *pd = sd->pd;
+
+ if (sd->status.pet_id == 0 || pd == NULL) {
+ clif->message(fd, msg_fd(fd, 184)); // Sorry, but you have no pet.
return false;
}
- if (hungry == pd->pet.hungry) {
- clif->message(fd, msg_fd(fd,186)); // Pet hunger is already at maximum.
+
+ if (hungry == pd->pet.hungry && hungry == PET_HUNGER_STUFFED) {
+ clif->message(fd, msg_fd(fd, 186)); // Pet hunger is already at maximum.
return false;
}
- pd->pet.hungry = hungry;
- clif->send_petstatus(sd);
- clif->message(fd, msg_fd(fd,185)); // Pet hunger changed.
+ if (hungry != pd->pet.hungry) { // No need to update the pet's status if hunger value won't change.
+ pd->pet.hungry = hungry;
+ clif->send_petstatus(sd);
+ }
+
+ clif->message(fd, msg_fd(fd, 185)); // Pet hunger changed. (Send message regardless of value has changed or not.)
return true;
}
diff --git a/src/map/battle.c b/src/map/battle.c
index 6519b1f37..40c645cf7 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -7085,16 +7085,15 @@ static const struct battle_data {
{ "guild_emperium_check", &battle_config.guild_emperium_check, 1, 0, 1, },
{ "guild_exp_limit", &battle_config.guild_exp_limit, 50, 0, 99, },
{ "player_invincible_time", &battle_config.pc_invincible_time, 5000, 0, INT_MAX, },
+ { "pet_catch_rate_official_formula", &battle_config.pet_catch_rate_official_formula, 1, 0, 1, },
{ "pet_catch_rate", &battle_config.pet_catch_rate, 100, 0, INT_MAX, },
{ "pet_rename", &battle_config.pet_rename, 0, 0, 1, },
{ "pet_friendly_rate", &battle_config.pet_friendly_rate, 100, 0, INT_MAX, },
{ "pet_hungry_delay_rate", &battle_config.pet_hungry_delay_rate, 100, 10, INT_MAX, },
- { "pet_hungry_friendly_decrease", &battle_config.pet_hungry_friendly_decrease, 5, 0, INT_MAX, },
{ "pet_status_support", &battle_config.pet_status_support, 0, 0, 1, },
{ "pet_attack_support", &battle_config.pet_attack_support, 0, 0, 1, },
{ "pet_damage_support", &battle_config.pet_damage_support, 0, 0, 1, },
{ "pet_support_min_friendly", &battle_config.pet_support_min_friendly, 900, 0, 950, },
- { "pet_equip_min_friendly", &battle_config.pet_equip_min_friendly, 900, 0, 950, },
{ "pet_support_rate", &battle_config.pet_support_rate, 100, 0, INT_MAX, },
{ "pet_attack_exp_to_master", &battle_config.pet_attack_exp_to_master, 0, 0, 1, },
{ "pet_attack_exp_rate", &battle_config.pet_attack_exp_rate, 100, 0, INT_MAX, },
diff --git a/src/map/battle.h b/src/map/battle.h
index 2e710f7f8..bb907d5b9 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -212,16 +212,15 @@ struct Battle_Config {
int guild_aura;
int pc_invincible_time;
+ int pet_catch_rate_official_formula;
int pet_catch_rate;
int pet_rename;
int pet_friendly_rate;
int pet_hungry_delay_rate;
- int pet_hungry_friendly_decrease;
int pet_status_support;
int pet_attack_support;
int pet_damage_support;
int pet_support_min_friendly; //[Skotlex]
- int pet_equip_min_friendly;
int pet_support_rate;
int pet_attack_exp_to_master;
int pet_attack_exp_rate;
diff --git a/src/map/clif.c b/src/map/clif.c
index 83f5751ba..e68028d9d 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -10540,51 +10540,60 @@ static void clif_parse_WantToConnection(int fd, struct map_session_data *sd)
chrif->authreq(sd,false);
}
+/**
+ * Notification from the client, that it has finished map loading and is about to display player's character. (CZ_NOTIFY_ACTORINIT)
+ *
+ * @code
+ * 007d
+ * @endcode
+ *
+ * @param fd The incoming file descriptor.
+ * @param sd The related character.
+ *
+ **/
static void clif_parse_LoadEndAck(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
-/// Notification from the client, that it has finished map loading and is about to display player's character (CZ_NOTIFY_ACTORINIT).
-/// 007d
static void clif_parse_LoadEndAck(int fd, struct map_session_data *sd)
{
- bool first_time = false;
-
- if(sd->bl.prev != NULL)
+ if (sd->bl.prev != NULL)
return;
- if (!sd->state.active) { //Character loading is not complete yet!
- //Let pc->reg_received reinvoke this when ready.
+ if (sd->state.active == 0) { // Character loading is not complete yet! Let pc->reg_received reinvoke this when ready.
sd->state.connect_new = 0;
return;
}
- if (sd->state.rewarp) { //Rewarp player.
+ if (sd->state.rewarp != 0) { // Rewarp character.
sd->state.rewarp = 0;
clif->changemap(sd, sd->bl.m, sd->bl.x, sd->bl.y);
return;
}
sd->state.warping = 0;
- sd->state.dialog = 0;/* reset when warping, client dialog will go missing */
+ sd->state.dialog = 0; // Reset when warping. Client dialog will go missing.
- // Character Looks
+ // Character looks.
#if PACKETVER < 4
clif->changelook(&sd->bl, LOOK_WEAPON, sd->status.look.weapon);
clif->changelook(&sd->bl, LOOK_SHIELD, sd->status.look.shield);
#else
- clif->changelook(&sd->bl,LOOK_WEAPON,0);
+ clif->changelook(&sd->bl, LOOK_WEAPON, 0);
#endif
- if(sd->vd.cloth_color)
- clif->refreshlook(&sd->bl,sd->bl.id,LOOK_CLOTHES_COLOR,sd->vd.cloth_color,SELF);
+ if (sd->vd.cloth_color != 0)
+ clif->refreshlook(&sd->bl, sd->bl.id, LOOK_CLOTHES_COLOR, sd->vd.cloth_color, SELF);
- if (sd->vd.body_style)
- clif->refreshlook(&sd->bl,sd->bl.id,LOOK_BODY2,sd->vd.body_style,SELF);
+ if (sd->vd.body_style != 0)
+ clif->refreshlook(&sd->bl, sd->bl.id, LOOK_BODY2, sd->vd.body_style, SELF);
- // Send character inventory to the client.
- // call this before pc->checkitem() so that the client isn't called to delete a non-existent item.
+ /**
+ * Send character inventory to the client.
+ * Call this before pc->checkitem() so that the client isn't called to delete a non-existent items.
+ *
+ **/
clif->inventoryList(sd);
// Send the cart inventory, counts & weight to the client.
- if(pc_iscarton(sd)) {
+ if (pc_iscarton(sd)) {
clif->cartList(sd);
clif->updatestatus(sd, SP_CARTINFO);
}
@@ -10655,309 +10664,330 @@ static void clif_parse_LoadEndAck(int fd, struct map_session_data *sd)
clif->updatestatus(sd, SP_WEIGHT);
clif->updatestatus(sd, SP_MAXWEIGHT);
- // guild
- // (needs to go before clif_spawn() to show guild emblems correctly)
- if(sd->status.guild_id)
- guild->send_memberinfoshort(sd,1);
+ // Send character's guild info to the client. Call this before clif->spawn() to show guild emblems correctly.
+ if (sd->status.guild_id != 0)
+ guild->send_memberinfoshort(sd, 1);
- if(battle_config.pc_invincible_time > 0) {
- pc->setinvincibletimer(sd,battle_config.pc_invincible_time);
- }
+ if (battle_config.pc_invincible_time > 0)
+ pc->setinvincibletimer(sd, battle_config.pc_invincible_time);
- if( map->list[sd->bl.m].users++ == 0 && battle_config.dynamic_mobs )
+ if (map->list[sd->bl.m].users++ == 0 && battle_config.dynamic_mobs != 0)
map->spawnmobs(sd->bl.m);
- if( map->list[sd->bl.m].instance_id >= 0 ) {
+ if (map->list[sd->bl.m].instance_id >= 0) {
instance->list[map->list[sd->bl.m].instance_id].users++;
instance->check_idle(map->list[sd->bl.m].instance_id);
}
- if( pc_has_permission(sd,PC_PERM_VIEW_HPMETER) ) {
+ if (pc_has_permission(sd, PC_PERM_VIEW_HPMETER)) {
map->list[sd->bl.m].hpmeter_visible++;
sd->state.hpmeter_visible = 1;
}
- if (!pc_isinvisible(sd)) { // increment the number of pvp players on the map
+ if (!pc_isinvisible(sd)) // Increment the number of pvp players on the map.
map->list[sd->bl.m].users_pvp++;
- }
-
- sd->state.debug_remove_map = 0; // temporary state to track double remove_map's [FlavioJS]
-
- // reset the callshop flag if the player changes map
- sd->state.callshop = 0;
- map->addblock(&sd->bl);
- clif->spawn(&sd->bl);
+ sd->state.debug_remove_map = 0; // Temporary state to track double calls of unit->remove_map(). [FlavioJS]
+ sd->state.callshop = 0; // Reset the callshop flag if the character changes map.
+ map->addblock(&sd->bl); // Add the character to the map.
+ clif->spawn(&sd->bl); // Spawn character client side.
- // Party
- // (needs to go after clif_spawn() to show hp bars correctly)
- if(sd->status.party_id) {
+ // Send character's party info to the client. Call this after clif->spawn() to show HP bars correctly.
+ if (sd->status.party_id != 0) {
party->send_movemap(sd);
- clif->party_hp(sd); // Show hp after displacement [LuzZza]
+ clif->party_hp(sd); // Show HP after displacement. [LuzZza]
}
- if( sd->bg_id ) clif->bg_hp(sd); // BattleGround System
+ if (sd->bg_id != 0)
+ clif->bg_hp(sd); // BattleGround system.
+
+ if (map->list[sd->bl.m].flag.pvp != 0 && !pc_isinvisible(sd)) {
+ if (battle_config.pk_mode == 0) { // Remove PVP stuff for pk_mode. [Valaris]
+ if (map->list[sd->bl.m].flag.pvp_nocalcrank == 0)
+ sd->pvp_timer = timer->add(timer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0);
- if (map->list[sd->bl.m].flag.pvp && !pc_isinvisible(sd)) {
- if(!battle_config.pk_mode) { // remove pvp stuff for pk_mode [Valaris]
- if (!map->list[sd->bl.m].flag.pvp_nocalcrank)
- sd->pvp_timer = timer->add(timer->gettick()+200, pc->calc_pvprank_timer, sd->bl.id, 0);
sd->pvp_rank = 0;
sd->pvp_lastusers = 0;
sd->pvp_point = 5;
sd->pvp_won = 0;
sd->pvp_lost = 0;
}
+
clif->map_property(sd, MAPPROPERTY_FREEPVPZONE);
- } else
- // set flag, if it's a duel [LuzZza]
- if(sd->duel_group)
+ } else if(sd->duel_group != 0) { // Set flag, if it's a duel. [LuzZza]
clif->map_property(sd, MAPPROPERTY_FREEPVPZONE);
+ }
- if (map->list[sd->bl.m].flag.gvg_dungeon)
+ if (map->list[sd->bl.m].flag.gvg_dungeon != 0)
clif->map_property(sd, MAPPROPERTY_FREEPVPZONE); //TODO: Figure out the real packet to send here.
- if( map_flag_gvg2(sd->bl.m) )
+ if (map_flag_gvg2(sd->bl.m))
clif->map_property(sd, MAPPROPERTY_AGITZONE);
- // info about nearby objects
- // must use foreachinarea (CIRCULAR_AREA interferes with foreachinrange)
- map->foreachinarea(clif->getareachar, sd->bl.m, sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_ALL, sd);
+ // Info about nearby objects. Must use map->foreachinarea(). (CIRCULAR_AREA interferes with map->foreachinrange().)
+ map->foreachinarea(clif->getareachar, sd->bl.m, sd->bl.x - AREA_SIZE, sd->bl.y - AREA_SIZE,
+ sd->bl.x + AREA_SIZE, sd->bl.y + AREA_SIZE, BL_ALL, sd);
- // pet
- if( sd->pd ) {
- if( battle_config.pet_no_gvg && map_flag_gvg2(sd->bl.m) ) { //Return the pet to egg. [Skotlex]
- clif->message(sd->fd, msg_sd(sd,866)); // "Pets are not allowed in Guild Wars."
- pet->menu(sd, 3); //Option 3 is return to egg.
+ // Spawn pet.
+ if (sd->pd != NULL) {
+ if (battle_config.pet_no_gvg != 0 && map_flag_gvg2(sd->bl.m)) { // Return the pet to egg. [Skotlex]
+ clif->message(sd->fd, msg_sd(sd, 866)); // "Pets are not allowed in Guild Wars."
+ pet->menu(sd, 3); // Option 3 is return to egg.
} else {
map->addblock(&sd->pd->bl);
clif->spawn(&sd->pd->bl);
- clif->send_petdata(sd,sd->pd,0,0);
+ clif->send_petdata(sd,sd->pd, 0, 0);
clif->send_petstatus(sd);
- //skill->unit_move(&sd->pd->bl,timer->gettick(),1);
}
}
- //homunculus [blackhole89]
- if( homun_alive(sd->hd) ) {
+ // Spawn homunculus. [blackhole89]
+ if (homun_alive(sd->hd)) {
map->addblock(&sd->hd->bl);
clif->spawn(&sd->hd->bl);
- clif->send_homdata(sd,SP_ACK,0);
- clif->hominfo(sd,sd->hd,1);
- clif->hominfo(sd,sd->hd,0); //for some reason, at least older clients want this sent twice
+ clif->send_homdata(sd, SP_ACK, 0);
+ clif->hominfo(sd,sd->hd, 1);
+ clif->hominfo(sd,sd->hd, 0); // For some reason, at least older clients want this sent twice.
clif->homskillinfoblock(sd);
- if( battle_config.hom_setting&0x8 )
- status_calc_bl(&sd->hd->bl, SCB_SPEED); //Homunc mimic their master's speed on each map change
- if( !(battle_config.hom_setting&0x2) )
- skill->unit_move(&sd->hd->bl,timer->gettick(),1); // apply land skills immediately
+
+ if ((battle_config.hom_setting & 0x8) != 0)
+ status_calc_bl(&sd->hd->bl, SCB_SPEED); // Homunculi mimic their master's speed on each map change.
+
+ if ((battle_config.hom_setting & 0x2) == 0)
+ skill->unit_move(&sd->hd->bl, timer->gettick(), 1); // Apply land skills immediately.
}
- if( sd->md ) {
+ // Spawn mercenary.
+ if (sd->md != NULL) {
map->addblock(&sd->md->bl);
clif->spawn(&sd->md->bl);
clif->mercenary_info(sd);
clif->mercenary_skillblock(sd);
- status_calc_bl(&sd->md->bl, SCB_SPEED); // Mercenary mimic their master's speed on each map change
+ status_calc_bl(&sd->md->bl, SCB_SPEED); // Mercenaries mimic their master's speed on each map change.
}
- if( sd->ed ) {
+ // Spawn elemental.
+ if (sd->ed != NULL) {
map->addblock(&sd->ed->bl);
clif->spawn(&sd->ed->bl);
clif->elemental_info(sd);
- clif->elemental_updatestatus(sd,SP_HP);
- clif->hpmeter_single(sd->fd,sd->ed->bl.id,sd->ed->battle_status.hp,sd->ed->battle_status.max_hp);
- clif->elemental_updatestatus(sd,SP_SP);
- status_calc_bl(&sd->ed->bl, SCB_SPEED); //Elemental mimic their master's speed on each map change
+ clif->elemental_updatestatus(sd, SP_HP);
+ clif->hpmeter_single(sd->fd, sd->ed->bl.id, sd->ed->battle_status.hp, sd->ed->battle_status.max_hp);
+ clif->elemental_updatestatus(sd, SP_SP);
+ status_calc_bl(&sd->ed->bl, SCB_SPEED); // Elementals mimic their master's speed on each map change.
}
- if(sd->state.connect_new) {
- int lv;
+ bool first_time = false;
+
+ if (sd->state.connect_new != 0) {
first_time = true;
sd->state.connect_new = 0;
clif->skillinfoblock(sd);
clif->hotkeysAll(sd);
- clif->updatestatus(sd,SP_BASEEXP);
- clif->updatestatus(sd,SP_NEXTBASEEXP);
- clif->updatestatus(sd,SP_JOBEXP);
- clif->updatestatus(sd,SP_NEXTJOBEXP);
- clif->updatestatus(sd,SP_SKILLPOINT);
+ clif->updatestatus(sd, SP_BASEEXP);
+ clif->updatestatus(sd, SP_NEXTBASEEXP);
+ clif->updatestatus(sd, SP_JOBEXP);
+ clif->updatestatus(sd, SP_NEXTJOBEXP);
+ clif->updatestatus(sd, SP_SKILLPOINT);
clif->initialstatus(sd);
- if (pc_isfalcon(sd))
- clif->status_change(&sd->bl, status->get_sc_icon(SC_FALCON), status->get_sc_relevant_bl_types(SC_FALCON), 1, 0, 0, 0, 0);
- if (pc_isridingpeco(sd) || pc_isridingdragon(sd))
- clif->status_change(&sd->bl, status->get_sc_icon(SC_RIDING), status->get_sc_relevant_bl_types(SC_RIDING), 1, 0, 0, 0, 0);
- else if (pc_isridingwug(sd))
- clif->status_change(&sd->bl, status->get_sc_icon(SC_WUGRIDER), status->get_sc_relevant_bl_types(SC_WUGRIDER), 1, 0, 0, 0, 0);
+ if (pc_isfalcon(sd)) {
+ int sc_icn = status->get_sc_icon(SC_FALCON);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_FALCON);
+ clif->status_change(&sd->bl, sc_icn, sc_typ, 1, 0, 0, 0, 0);
+ }
+
+ if (pc_isridingpeco(sd) || pc_isridingdragon(sd)) {
+ int sc_icn = status->get_sc_icon(SC_RIDING);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RIDING);
+ clif->status_change(&sd->bl, sc_icn, sc_typ, 1, 0, 0, 0, 0);
+ } else if (pc_isridingwug(sd)) {
+ int sc_icn = status->get_sc_icon(SC_WUGRIDER);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_WUGRIDER);
+ clif->status_change(&sd->bl, sc_icn, sc_typ, 1, 0, 0, 0, 0);
+ }
- if(sd->status.manner < 0)
- sc_start(NULL,&sd->bl,SC_NOCHAT,100,0,0);
+ if (sd->status.manner < 0)
+ sc_start(NULL, &sd->bl, SC_NOCHAT, 100, 0, 0);
- //Auron reported that This skill only triggers when you logon on the map o.O [Skotlex]
- if ((lv = pc->checkskill(sd,SG_KNOWLEDGE)) > 0) {
- int i;
- for (i = 0; i < MAX_PC_FEELHATE; i++) {
+ int lv = pc->checkskill(sd,SG_KNOWLEDGE);
+
+ // Auron reported that this skill only triggers when you logon on the map. [Skotlex]
+ if (lv > 0) {
+ for (int i = 0; i < MAX_PC_FEELHATE; i++) {
if (sd->bl.m == sd->feel_map[i].m) {
- sc_start(NULL,&sd->bl, SC_KNOWLEDGE, 100, lv, skill->get_time(SG_KNOWLEDGE, lv));
+ sc_start(NULL, &sd->bl, SC_KNOWLEDGE, 100, lv, skill->get_time(SG_KNOWLEDGE, lv));
break;
}
}
}
- if(sd->pd && sd->pd->pet.intimate > 900)
- clif->pet_emotion(sd->pd,(sd->pd->pet.class_ - 100)*100 + 50 + pet->hungry_val(sd->pd));
+ if (sd->pd != NULL && sd->pd->pet.intimate > PET_INTIMACY_LOYAL)
+ clif->pet_emotion(sd->pd, (sd->pd->pet.class_ - 100) * 100 + 50 + pet->hungry_val(sd->pd));
- if(homun_alive(sd->hd))
+ if (homun_alive(sd->hd))
homun->init_timers(sd->hd);
- if (map->night_flag && map->list[sd->bl.m].flag.nightenabled) {
+ if (map->night_flag != 0 && map->list[sd->bl.m].flag.nightenabled != 0) {
+ int sc_icn = status->get_sc_icon(SC_SKE);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_SKE);
+
sd->state.night = 1;
- clif->status_change(&sd->bl, status->get_sc_icon(SC_SKE), status->get_sc_relevant_bl_types(SC_SKE), 1, 0, 0, 0, 0);
+ clif->status_change(&sd->bl, sc_icn, sc_typ, 1, 0, 0, 0, 0);
}
- // Notify everyone that this char logged in [Skotlex].
+ // Notify everyone that this character logged in. [Skotlex]
map->foreachpc(clif->friendslist_toggle_sub, sd->status.account_id, sd->status.char_id, 1);
- //Login Event
+ // Run OnPCLoginEvent labels.
npc->script_event(sd, NPCE_LOGIN);
} else {
- //For some reason the client "loses" these on warp/map-change.
- clif->updatestatus(sd,SP_STR);
- clif->updatestatus(sd,SP_AGI);
- clif->updatestatus(sd,SP_VIT);
- clif->updatestatus(sd,SP_INT);
- clif->updatestatus(sd,SP_DEX);
- clif->updatestatus(sd,SP_LUK);
-
- if (sd->state.warp_clean) {
- // abort currently running script
+ // For some reason the client "loses" these on warp/map-change.
+ clif->updatestatus(sd, SP_STR);
+ clif->updatestatus(sd, SP_AGI);
+ clif->updatestatus(sd, SP_VIT);
+ clif->updatestatus(sd, SP_INT);
+ clif->updatestatus(sd, SP_DEX);
+ clif->updatestatus(sd, SP_LUK);
+
+ if (sd->state.warp_clean != 0) { // Abort currently running script.
sd->state.using_fake_npc = 0;
sd->state.menu_or_input = 0;
sd->npc_menu = 0;
- if(sd->npc_id)
+
+ if (sd->npc_id != 0)
npc->event_dequeue(sd);
} else {
sd->state.warp_clean = 1;
}
- if( sd->guild && ( battle_config.guild_notice_changemap == 2 || ( battle_config.guild_notice_changemap == 1 && sd->state.changemap ) ) )
- clif->guild_notice(sd,sd->guild);
+
+ if (sd->guild != NULL && ((battle_config.guild_notice_changemap == 1 && sd->state.changemap != 0)
+ || battle_config.guild_notice_changemap == 2)) {
+ clif->guild_notice(sd, sd->guild);
+ }
}
- if( sd->state.changemap ) {// restore information that gets lost on map-change
+ if (sd->state.changemap != 0) { // Restore information that gets lost on map-change.
#if PACKETVER >= 20070918
clif->partyinvitationstate(sd);
clif->equpcheckbox(sd);
#endif
#if PACKETVER_MAIN_NUM >= 20171025 || PACKETVER_RE_NUM >= 20170920
- if (sd->hd != NULL)
- clif->zc_config(sd, CZ_CONFIG_HOMUNCULUS_AUTOFEEDING, sd->hd->homunculus.autofeed);
- else
- clif->zc_config(sd, CZ_CONFIG_HOMUNCULUS_AUTOFEEDING, false);
+ if (sd->hd != NULL)
+ clif->zc_config(sd, CZ_CONFIG_HOMUNCULUS_AUTOFEEDING, sd->hd->homunculus.autofeed);
+ else
+ clif->zc_config(sd, CZ_CONFIG_HOMUNCULUS_AUTOFEEDING, false);
#endif
- if( (battle_config.bg_flee_penalty != 100 || battle_config.gvg_flee_penalty != 100)
- && (map_flag_gvg2(sd->state.pmap) || map_flag_gvg2(sd->bl.m)
- || map->list[sd->state.pmap].flag.battleground || map->list[sd->bl.m].flag.battleground) )
- status_calc_bl(&sd->bl, SCB_FLEE); //Refresh flee penalty
- if( map->night_flag && map->list[sd->bl.m].flag.nightenabled ) {
- //Display night.
- if( !sd->state.night ) {
+ bool flee_penalty = (battle_config.bg_flee_penalty != 100 || battle_config.gvg_flee_penalty != 100);
+ bool is_gvg = (map_flag_gvg2(sd->state.pmap) || map_flag_gvg2(sd->bl.m));
+ bool is_bg = (map->list[sd->state.pmap].flag.battleground != 0 || map->list[sd->bl.m].flag.battleground != 0);
+
+ if (flee_penalty && (is_gvg || is_bg))
+ status_calc_bl(&sd->bl, SCB_FLEE); // Refresh flee penalty.
+
+ if (map->night_flag != 0 && map->list[sd->bl.m].flag.nightenabled != 0) {
+ if (sd->state.night == 0) { // Display night.
+ int sc_icn = status->get_sc_icon(SC_SKE);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_SKE);
+
sd->state.night = 1;
- clif->status_change(&sd->bl, status->get_sc_icon(SC_SKE), status->get_sc_relevant_bl_types(SC_SKE), 1, 0, 0, 0, 0);
+ clif->status_change(&sd->bl, sc_icn, sc_typ, 1, 0, 0, 0, 0);
}
- } else if( sd->state.night ) { //Clear night display.
+ } else if (sd->state.night != 0) { // Clear night display.
sd->state.night = 0;
clif->sc_end(&sd->bl, sd->bl.id, SELF, status->get_sc_icon(SC_SKE));
}
- if( map->list[sd->bl.m].flag.battleground ) {
- clif->map_type(sd, MAPTYPE_BATTLEFIELD); // Battleground Mode
- if( map->list[sd->bl.m].flag.battleground == 2 )
+ if (map->list[sd->bl.m].flag.battleground != 0) {
+ clif->map_type(sd, MAPTYPE_BATTLEFIELD); // Battleground mode.
+
+ if (map->list[sd->bl.m].flag.battleground == 2)
clif->bg_updatescore_single(sd);
}
- if( map->list[sd->bl.m].flag.allowks && !map_flag_ks(sd->bl.m) ) {
+ if (map->list[sd->bl.m].flag.allowks != 0 && !map_flag_ks(sd->bl.m)) {
char output[128];
+
sprintf(output, "%s", msg_sd(sd, 893)); // [ Kill Steal Protection Disabled. KS is allowed in this map ]
clif->broadcast(&sd->bl, output, (int)strlen(output) + 1, BC_BLUE, SELF);
}
- map->iwall_get(sd); // Updates Walls Info on this Map to Client
- status_calc_pc(sd, SCO_NONE);/* some conditions are map-dependent so we must recalculate */
+ map->iwall_get(sd); // Updates walls info on this map to client.
+ status_calc_pc(sd, SCO_NONE); // Some conditions are map-dependent so we must recalculate.
sd->state.changemap = false;
- if (channel->config->local && channel->config->local_autojoin) {
+ if (channel->config->local && channel->config->local_autojoin)
channel->map_join(sd);
- }
- if (channel->config->irc && channel->config->irc_autojoin) {
+
+ if (channel->config->irc && channel->config->irc_autojoin)
channel->irc_join(sd);
- }
}
mail->clear(sd);
+ clif->maptypeproperty2(&sd->bl, SELF);
- clif->maptypeproperty2(&sd->bl,SELF);
-
- /* Guild Aura Init */
- if( sd->state.gmaster_flag ) {
- guild->aura_refresh(sd,GD_LEADERSHIP,guild->checkskill(sd->guild,GD_LEADERSHIP));
- guild->aura_refresh(sd,GD_GLORYWOUNDS,guild->checkskill(sd->guild,GD_GLORYWOUNDS));
- guild->aura_refresh(sd,GD_SOULCOLD,guild->checkskill(sd->guild,GD_SOULCOLD));
- guild->aura_refresh(sd,GD_HAWKEYES,guild->checkskill(sd->guild,GD_HAWKEYES));
+ // Init guild aura.
+ if (sd->state.gmaster_flag != 0) {
+ guild->aura_refresh(sd, GD_LEADERSHIP, guild->checkskill(sd->guild, GD_LEADERSHIP));
+ guild->aura_refresh(sd, GD_GLORYWOUNDS, guild->checkskill(sd->guild, GD_GLORYWOUNDS));
+ guild->aura_refresh(sd, GD_SOULCOLD, guild->checkskill(sd->guild, GD_SOULCOLD));
+ guild->aura_refresh(sd, GD_HAWKEYES, guild->checkskill(sd->guild, GD_HAWKEYES));
}
- if( sd->state.vending ) { /* show we have a vending */
- clif->openvending(sd,sd->bl.id,sd->vending);
- clif->showvendingboard(&sd->bl,sd->message,0);
+ if (sd->state.vending != 0) { // Character is vending.
+ clif->openvending(sd, sd->bl.id, sd->vending);
+ clif->showvendingboard(&sd->bl, sd->message, 0);
}
- if(map->list[sd->bl.m].flag.loadevent) // Lance
+ if (map->list[sd->bl.m].flag.loadevent != 0) // Run OnPCLoadMapEvent labels. [Lance]
npc->script_event(sd, NPCE_LOADMAP);
- if (pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd)) //blindness [Komurka]
+ if (pc->checkskill(sd, SG_DEVIL) > 0 && pc->nextjobexp(sd) == 0) // Blindness. [Komurka]
clif->sc_end(&sd->bl, sd->bl.id, SELF, status->get_sc_icon(SC_DEVIL1));
- if (sd->sc.opt2) //Client loses these on warp.
+ if (sd->sc.opt2 != 0) // Client loses these on warp.
clif->changeoption(&sd->bl);
- if( sd->sc.data[SC_MONSTER_TRANSFORM] && battle_config.mon_trans_disable_in_gvg && map_flag_gvg2(sd->bl.m) ){
+ if (sd->sc.data[SC_MONSTER_TRANSFORM] != NULL && battle_config.mon_trans_disable_in_gvg != 0
+ && map_flag_gvg2(sd->bl.m)) {
status_change_end(&sd->bl, SC_MONSTER_TRANSFORM, INVALID_TIMER);
- clif->message(sd->fd, msg_sd(sd,1488)); // Transforming into monster is not allowed in Guild Wars.
+ clif->message(sd->fd, msg_sd(sd, 1488)); // Transforming into monster is not allowed in Guild Wars.
}
clif->weather_check(sd);
- // This should be displayed last
- if( sd->guild && first_time )
+ // This should be displayed last.
+ if (sd->guild != NULL && first_time)
clif->guild_notice(sd, sd->guild);
- // For automatic triggering of NPCs after map loading (so you don't need to walk 1 step first)
- if (map->getcell(sd->bl.m, &sd->bl, sd->bl.x, sd->bl.y, CELL_CHKNPC))
- npc->touch_areanpc(sd,sd->bl.m,sd->bl.x,sd->bl.y);
+ // For automatic triggering of NPCs after map loading. (So you don't need to walk 1 step first.)
+ if (map->getcell(sd->bl.m, &sd->bl, sd->bl.x, sd->bl.y, CELL_CHKNPC) != 0)
+ npc->touch_areanpc(sd, sd->bl.m, sd->bl.x, sd->bl.y);
else
npc->untouch_areanpc(sd, sd->bl.m, sd->bl.x, sd->bl.y);
- /* it broke at some point (e.g. during a crash), so we make it visibly dead again. */
- if( !sd->status.hp && !pc_isdead(sd) && status->isdead(&sd->bl) )
+ // It broke at some point (e.g. during a crash), so we make it visibly dead again.
+ if (sd->status.hp == 0 && !pc_isdead(sd) && status->isdead(&sd->bl) != 0)
pc_setdead(sd);
- // If player is dead, and is spawned (such as @refresh) send death packet. [Valaris]
- if(pc_isdead(sd))
+ // Send death packet, if character is dead and is spawned (such as @refresh). [Valaris]
+ if (pc_isdead(sd)) {
clif->clearunit_area(&sd->bl, CLR_DEAD);
- else {
+ } else {
skill->usave_trigger(sd);
+
if (battle_config.player_warp_keep_direction == 1)
clif->changed_dir(&sd->bl, SELF); // Visually updates player facing direction
}
- // Trigger skill effects if you appear standing on them
- if(!battle_config.pc_invincible_time)
- skill->unit_move(&sd->bl,timer->gettick(),1);
+ // Trigger skill effects if you appear standing on them.
+ if (battle_config.pc_invincible_time == 0)
+ skill->unit_move(&sd->bl, timer->gettick(), 1);
- // NPC Quest / Event Icon Check [Kisuka]
#if PACKETVER >= 20090218
- quest->questinfo_refresh(sd);
+ quest->questinfo_refresh(sd); // NPC quest/event icon check. [Kisuka]
#endif
}
@@ -15205,58 +15235,68 @@ static void clif_parse_ChangePetName(int fd, struct map_session_data *sd)
pet->change_name(sd, RFIFOP(fd,2));
}
+/**
+ * Request to evolve the pet. (CZ_PET_EVOLUTION)
+ *
+ * @code
+ * 09fb <Length>.W <EvolvedPetEggID>.W {<index>.W <amount>.W}*items
+ * @endcode
+ *
+ * @param fd The incoming file descriptor.
+ * @param sd The related character.
+ *
+ **/
static void clif_parse_pet_evolution(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
-/// Request to Evolve the pet (CZ_PET_EVOLUTION) [Dastgir/Hercules]
-/// 09fb <Length>.W <EvolvedPetEggID>.W {<index>.W <amount>.W}*items
static void clif_parse_pet_evolution(int fd, struct map_session_data *sd)
{
- if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ if (sd->state.trading != 0 || pc_isdead(sd) || pc_isvending(sd))
return;
- const struct PACKET_CZ_PET_EVOLUTION *p = RP2PTR(fd);
- int i = 0, idx, petIndex;
-
- Assert_retv(p->PacketLength >= (uint16)sizeof(struct PACKET_CZ_PET_EVOLUTION));
-
- if (sd->status.pet_id == 0) {
+ if (sd->pd == NULL || sd->status.pet_id == 0) { // No pet.
clif->petEvolutionResult(fd, PET_EVOL_NO_CALLPET);
return;
}
- ARR_FIND(0, sd->status.inventorySize, idx, sd->status.inventory[idx].card[0] == CARD0_PET &&
- sd->status.pet_id == MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2]));
+ int inv_index;
+
+ ARR_FIND(0, sd->status.inventorySize, inv_index, sd->status.inventory[inv_index].card[0] == CARD0_PET
+ && sd->status.pet_id == MakeDWord(sd->status.inventory[inv_index].card[1],
+ sd->status.inventory[inv_index].card[2]));
- if (idx == sd->status.inventorySize) {
+ if (inv_index == sd->status.inventorySize) { // No pet egg.
clif->petEvolutionResult(fd, PET_EVOL_NO_PETEGG);
return;
}
- // Not Loyal Yet
- if (sd->pd == NULL || sd->pd->pet.intimate < 900) {
+ if (sd->pd->pet.intimate < PET_INTIMACY_LOYAL) { // Pet isn't loyal.
clif->petEvolutionResult(fd, PET_EVOL_RG_FAMILIAR);
return;
}
- ARR_FIND(0, MAX_PET_DB, petIndex, pet->db[petIndex].class_ == sd->pd->pet.class_);
+ int pet_index;
- if (petIndex == MAX_PET_DB) {
- // Which error?
- clif->petEvolutionResult(fd, PET_EVOL_UNKNOWN);
+ ARR_FIND(0, MAX_PET_DB, pet_index, pet->db[pet_index].class_ == sd->pd->pet.class_);
+
+ if (pet_index == MAX_PET_DB) {
+ clif->petEvolutionResult(fd, PET_EVOL_UNKNOWN); // Which error?
return;
}
+ const struct PACKET_CZ_PET_EVOLUTION *p = RP2PTR(fd);
+
+ Assert_retv(p->PacketLength >= (uint16)sizeof(struct PACKET_CZ_PET_EVOLUTION));
+
// Client side validation is not done as it is insecure.
- for (i = 0; i < VECTOR_LENGTH(pet->db[petIndex].evolve_data); i++) {
- struct pet_evolve_data *ped = &VECTOR_INDEX(pet->db[petIndex].evolve_data, i);
- if (ped->petEggId == p->EvolvedPetEggID) {
- int j;
- int pet_id;
+ for (int i = 0; i < VECTOR_LENGTH(pet->db[pet_index].evolve_data); i++) {
+ struct pet_evolve_data *ped = &VECTOR_INDEX(pet->db[pet_index].evolve_data, i);
+ if (ped->petEggId == p->EvolvedPetEggID) {
if (VECTOR_LENGTH(ped->items) == 0) {
clif->petEvolutionResult(fd, PET_EVOL_NO_RECIPE);
return;
}
- for (j = 0; j < VECTOR_LENGTH(ped->items); j++) {
+
+ for (int j = 0; j < VECTOR_LENGTH(ped->items); j++) {
struct itemlist_entry *list = &VECTOR_INDEX(ped->items, j);
int n = pc->search_inventory(sd, list->id);
@@ -15266,7 +15306,7 @@ static void clif_parse_pet_evolution(int fd, struct map_session_data *sd)
}
}
- for (j = 0; j < VECTOR_LENGTH(ped->items); j++) {
+ for (int j = 0; j < VECTOR_LENGTH(ped->items); j++) {
struct itemlist_entry *list = &VECTOR_INDEX(ped->items, j);
int n = pc->search_inventory(sd, list->id);
@@ -15276,27 +15316,26 @@ static void clif_parse_pet_evolution(int fd, struct map_session_data *sd)
}
}
- // Return to Egg
- pet->return_egg(sd, sd->pd);
+ pet->return_egg(sd, sd->pd); // Return pet to egg.
- if (pc->delitem(sd, idx, 1, 0, DELITEM_NORMAL, LOG_TYPE_EGG) == 1) {
+ if (pc->delitem(sd, inv_index, 1, 0, DELITEM_NORMAL, LOG_TYPE_EGG) == 1) {
clif->petEvolutionResult(fd, PET_EVOL_NO_PETEGG);
return;
}
- pet_id = pet->search_petDB_index(ped->petEggId, PET_EGG);
+ int pet_id = pet->search_petDB_index(ped->petEggId, PET_EGG);
+
if (pet_id >= 0) {
sd->catch_target_class = pet->db[pet_id].class_;
-
- intif->create_pet(
- sd->status.account_id, sd->status.char_id,
- pet->db[pet_id].class_, mob->db(pet->db[pet_id].class_)->lv,
- pet->db[pet_id].EggID, 0, (short)pet->db[pet_id].intimate,
- 100, 0, 1, pet->db[pet_id].jname);
+ intif->create_pet(sd->status.account_id, sd->status.char_id, pet->db[pet_id].class_,
+ mob->db(pet->db[pet_id].class_)->lv, pet->db[pet_id].EggID,
+ 0, (short)pet->db[pet_id].intimate, PET_HUNGER_STUFFED,
+ 0, 1, pet->db[pet_id].jname);
clif->petEvolutionResult(fd, PET_EVOL_SUCCESS);
} else {
clif->petEvolutionResult(fd, PET_EVOL_UNKNOWN);
}
+
return;
}
}
diff --git a/src/map/mob.h b/src/map/mob.h
index 8839809f2..4cfddc2cd 100644
--- a/src/map/mob.h
+++ b/src/map/mob.h
@@ -35,7 +35,7 @@ struct hplugin_data_store;
// Change this to increase the table size in your mob_db to accommodate a larger mob database.
// Be sure to note that IDs 4001 to 4048 are reserved for advanced/baby/expanded classes.
// Notice that the last 1000 entries are used for player clones, so always set this to desired value +1000
-#define MAX_MOB_DB 5000
+#define MAX_MOB_DB 22000
//The number of drops all mobs have and the max drop-slot that the steal skill will attempt to steal from.
#define MAX_MOB_DROP 10
diff --git a/src/map/pc.c b/src/map/pc.c
index 6dba997ef..90282209b 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -5700,7 +5700,7 @@ static int pc_steal_coin(struct map_session_data *sd, struct block_list *target,
return 0;
}
- /**
+/**
* Sets a character's position.
*
* @param sd The related character.
@@ -5717,233 +5717,278 @@ static int pc_steal_coin(struct map_session_data *sd, struct block_list *target,
**/
static int pc_setpos(struct map_session_data *sd, unsigned short map_index, int x, int y, enum clr_type clrtype)
{
- int16 m;
-
nullpo_retr(3, sd);
- if( !map_index || !mapindex_id2name(map_index) || ( m = map->mapindex2mapid(map_index) ) == -1 ) {
- ShowDebug("pc_setpos: Passed mapindex(%d) is invalid!\n", map_index);
+ int map_id = map->mapindex2mapid(map_index);
+
+ if (map_index == 0 || !mapindex_id2name(map_index) || map_id == INDEX_NOT_FOUND) {
+ ShowDebug("pc_setpos: Passed mapindex %d is invalid!\n", map_index);
return 1;
}
- if( pc_isdead(sd) ) { //Revive dead people before warping them
+ if (pc_isdead(sd)) { // Revive dead character before warping.
pc->setstand(sd);
- pc->setrestartvalue(sd,1);
+ pc->setrestartvalue(sd, 1);
}
- if( map->list[m].flag.src4instance ) {
- struct party_data *p;
+ if (map->list[map_id].flag.src4instance != 0) {
bool stop = false;
- int i = 0, j = 0;
- if( sd->instances ) {
- for( i = 0; i < sd->instances; i++ ) {
- if( sd->instance[i] >= 0 ) {
- ARR_FIND(0, instance->list[sd->instance[i]].num_map, j, map->list[instance->list[sd->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[sd->instance[i]].map[j]].custom_name);
- if( j != instance->list[sd->instance[i]].num_map )
+ if (sd->instances != 0) {
+ int i, j = 0;
+
+ for (i = 0; i < sd->instances; i++) {
+ if (sd->instance[i] >= 0) {
+ ARR_FIND(0, instance->list[sd->instance[i]].num_map, j,
+ map->list[instance->list[sd->instance[i]].map[j]].instance_src_map == map_id
+ && !map->list[instance->list[sd->instance[i]].map[j]].custom_name);
+
+ if (j != instance->list[sd->instance[i]].num_map)
break;
}
}
- if( i != sd->instances ) {
- m = instance->list[sd->instance[i]].map[j];
- map_index = map_id2index(m);
+
+ if (i != sd->instances) {
+ map_id = instance->list[sd->instance[i]].map[j];
+ map_index = map_id2index(map_id);
stop = true;
}
}
- if ( !stop && sd->status.party_id && (p = party->search(sd->status.party_id)) != NULL && p->instances ) {
- for( i = 0; i < p->instances; i++ ) {
- if( p->instance[i] >= 0 ) {
- ARR_FIND(0, instance->list[p->instance[i]].num_map, j, map->list[instance->list[p->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[p->instance[i]].map[j]].custom_name);
- if( j != instance->list[p->instance[i]].num_map )
+
+ struct party_data *p = party->search(sd->status.party_id);
+
+ if (!stop && sd->status.party_id != 0 && p != NULL && p->instances != 0) {
+ int i, j = 0;
+
+ for (i = 0; i < p->instances; i++) {
+ if (p->instance[i] >= 0) {
+ ARR_FIND(0, instance->list[p->instance[i]].num_map, j,
+ map->list[instance->list[p->instance[i]].map[j]].instance_src_map == map_id
+ && !map->list[instance->list[p->instance[i]].map[j]].custom_name);
+
+ if (j != instance->list[p->instance[i]].num_map)
break;
}
}
- if( i != p->instances ) {
- m = instance->list[p->instance[i]].map[j];
- map_index = map_id2index(m);
+
+ if (i != p->instances) {
+ map_id = instance->list[p->instance[i]].map[j];
+ map_index = map_id2index(map_id);
stop = true;
}
}
- if ( !stop && sd->status.guild_id && sd->guild && sd->guild->instances ) {
- for( i = 0; i < sd->guild->instances; i++ ) {
- if( sd->guild->instance[i] >= 0 ) {
- ARR_FIND(0, instance->list[sd->guild->instance[i]].num_map, j, map->list[instance->list[sd->guild->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[sd->guild->instance[i]].map[j]].custom_name);
- if( j != instance->list[sd->guild->instance[i]].num_map )
+
+ if (!stop && sd->status.guild_id != 0 && sd->guild != NULL && sd->guild->instances != 0) {
+ int i, j = 0;
+
+ for (i = 0; i < sd->guild->instances; i++) {
+ if (sd->guild->instance[i] >= 0) {
+ ARR_FIND(0, instance->list[sd->guild->instance[i]].num_map, j,
+ map->list[instance->list[sd->guild->instance[i]].map[j]].instance_src_map == map_id
+ && !map->list[instance->list[sd->guild->instance[i]].map[j]].custom_name);
+
+ if (j != instance->list[sd->guild->instance[i]].num_map)
break;
}
}
- if( i != sd->guild->instances ) {
- m = instance->list[sd->guild->instance[i]].map[j];
- map_index = map_id2index(m);
- //stop = true; Uncomment if adding new checks
+
+ if (i != sd->guild->instances) {
+ map_id = instance->list[sd->guild->instance[i]].map[j];
+ map_index = map_id2index(map_id);
+ //stop = true; Uncomment when adding new checks.
}
}
- /* we hit a instance, if empty we populate the spawn data */
- if( map->list[m].instance_id >= 0 && instance->list[map->list[m].instance_id].respawn.map == 0 &&
- instance->list[map->list[m].instance_id].respawn.x == 0 &&
- instance->list[map->list[m].instance_id].respawn.y == 0) {
- instance->list[map->list[m].instance_id].respawn.map = map_index;
- instance->list[map->list[m].instance_id].respawn.x = x;
- instance->list[map->list[m].instance_id].respawn.y = y;
+ // We hit an instance. If empty we populate the spawn data.
+ if (map->list[map_id].instance_id >= 0 && instance->list[map->list[map_id].instance_id].respawn.map == 0
+ && instance->list[map->list[map_id].instance_id].respawn.x == 0
+ && instance->list[map->list[map_id].instance_id].respawn.y == 0) {
+ instance->list[map->list[map_id].instance_id].respawn.map = map_index;
+ instance->list[map->list[map_id].instance_id].respawn.x = x;
+ instance->list[map->list[map_id].instance_id].respawn.y = y;
}
}
- sd->state.changemap = (sd->mapindex != map_index);
+ sd->state.changemap = (sd->mapindex != map_index) ? 1 : 0;
sd->state.warping = 1;
sd->state.workinprogress = 0;
- if( sd->state.changemap ) { // Misc map-changing settings
- int i;
+
+ if (sd->state.changemap != 0) { // Miscellaneous map-changing settings.
sd->state.pmap = sd->bl.m;
- for (i = 0; i < VECTOR_LENGTH(sd->script_queues); i++) {
+ for (int i = 0; i < VECTOR_LENGTH(sd->script_queues); i++) {
struct script_queue *queue = script->queue(VECTOR_INDEX(sd->script_queues, i));
- if (queue && queue->event_mapchange[0] != '\0') {
- pc->setregstr(sd, script->add_variable("@Queue_Destination_Map$"), map->list[m].name);
+
+ if (queue != NULL && queue->event_mapchange[0] != '\0') {
+ pc->setregstr(sd, script->add_variable("@Queue_Destination_Map$"), map->list[map_id].name);
npc->event(sd, queue->event_mapchange, 0);
}
}
- if( map->list[m].cell == (struct mapcell *)0xdeadbeaf )
- map->cellfromcache(&map->list[m]);
- if (sd->sc.count) { // Cancel some map related stuff.
- if (sd->sc.data[SC_JAILED])
- return 4; //You may not get out!
+ if (map->list[map_id].cell == (struct mapcell *)0xdeadbeaf)
+ map->cellfromcache(&map->list[map_id]);
+
+ if (sd->sc.count != 0) { // Cancel some map related stuff.
+ if (sd->sc.data[SC_JAILED] != NULL)
+ return 4; // You may not get out!
+
status_change_end(&sd->bl, SC_CASH_BOSS_ALARM, INVALID_TIMER);
status_change_end(&sd->bl, SC_WARM, INVALID_TIMER);
status_change_end(&sd->bl, SC_SUN_COMFORT, INVALID_TIMER);
status_change_end(&sd->bl, SC_MOON_COMFORT, INVALID_TIMER);
status_change_end(&sd->bl, SC_STAR_COMFORT, INVALID_TIMER);
status_change_end(&sd->bl, SC_MIRACLE, INVALID_TIMER);
- status_change_end(&sd->bl, SC_NEUTRALBARRIER_MASTER, INVALID_TIMER);//Will later check if this is needed. [Rytech]
+ status_change_end(&sd->bl, SC_NEUTRALBARRIER_MASTER, INVALID_TIMER); // Will later check if this is needed. [Rytech]
status_change_end(&sd->bl, SC_NEUTRALBARRIER, INVALID_TIMER);
status_change_end(&sd->bl, SC_STEALTHFIELD_MASTER, INVALID_TIMER);
status_change_end(&sd->bl, SC_STEALTHFIELD, INVALID_TIMER);
- if (sd->sc.data[SC_KNOWLEDGE]) {
+
+ if (sd->sc.data[SC_KNOWLEDGE] != NULL) {
struct status_change_entry *sce = sd->sc.data[SC_KNOWLEDGE];
+
if (sce->timer != INVALID_TIMER)
timer->delete(sce->timer, status->change_timer);
- sce->timer = timer->add(timer->gettick() + skill->get_time(SG_KNOWLEDGE, sce->val1), status->change_timer, sd->bl.id, SC_KNOWLEDGE);
+
+ sce->timer = timer->add(timer->gettick() + skill->get_time(SG_KNOWLEDGE, sce->val1),
+ status->change_timer, sd->bl.id, SC_KNOWLEDGE);
}
+
status_change_end(&sd->bl, SC_PROPERTYWALK, INVALID_TIMER);
status_change_end(&sd->bl, SC_CLOAKING, INVALID_TIMER);
status_change_end(&sd->bl, SC_CLOAKINGEXCEED, INVALID_TIMER);
}
- for( i = 0; i < EQI_MAX; i++ ) {
- if( sd->equip_index[ i ] >= 0 )
- if( !pc->isequip( sd , sd->equip_index[ i ] ) )
- pc->unequipitem(sd, sd->equip_index[i], PCUNEQUIPITEM_FORCE);
+
+ for (int i = 0; i < EQI_MAX; i++) {
+ if (sd->equip_index[i] >= 0 && pc->isequip(sd , sd->equip_index[i]) == 0)
+ pc->unequipitem(sd, sd->equip_index[i], PCUNEQUIPITEM_FORCE);
}
- if (battle_config.clear_unit_onwarp&BL_PC)
+
+ if ((battle_config.clear_unit_onwarp & BL_PC) != 0)
skill->clear_unitgroup(&sd->bl);
- party->send_dot_remove(sd); //minimap dot fix [Kevin]
+
+ party->send_dot_remove(sd); // Minimap dot fix. [Kevin]
guild->send_dot_remove(sd);
bg->send_dot_remove(sd);
- if (sd->regen.state.gc)
+
+ if (sd->regen.state.gc != 0)
sd->regen.state.gc = 0;
- // make sure vending is allowed here
- if (sd->state.vending && map->list[m].flag.novending) {
- clif->message (sd->fd, msg_sd(sd,276)); // "You can't open a shop on this map"
+
+ // Make sure that vending is allowed here.
+ if (sd->state.vending != 0 && map->list[map_id].flag.novending != 0) {
+ clif->message(sd->fd, msg_sd(sd, 276)); // "You can't open a shop on this map"
vending->close(sd);
}
- if (sd->mapindex != 0) {
- // Only if the character is already on a map
- if (map->list[sd->bl.m].channel) {
- channel->leave(map->list[sd->bl.m].channel,sd);
- }
- }
+ if (sd->mapindex != 0 && map->list[sd->bl.m].channel != NULL) // Only if the character is already on a map.
+ channel->leave(map->list[sd->bl.m].channel, sd);
}
- if( m < 0 ) {
+ if (map_id < 0) {
uint32 ip;
uint16 port;
- //if can't find any map-servers, just abort setting position.
- if(!sd->mapindex || map->mapname2ipport(map_index,&ip,&port))
+
+ // If can't find any map-servers, just abort setting position.
+ if (sd->mapindex == 0 || map->mapname2ipport(map_index, &ip, &port) != 0)
return 2;
- if (sd->npc_id)
+ if (sd->npc_id != 0)
npc->event_dequeue(sd);
+
npc->script_event(sd, NPCE_LOGOUT);
- //remove from map, THEN change x/y coordinates
- unit->remove_map_pc(sd,clrtype);
+
+ // Remove from map, THEN change x/y coordinates.
+ unit->remove_map_pc(sd, clrtype);
+
if (battle_config.player_warp_keep_direction == 0)
- sd->ud.dir = 0; // makes character face north
+ sd->ud.dir = 0; /// Make character facing north.
+
sd->mapindex = map_index;
- sd->bl.x=x;
- sd->bl.y=y;
+ sd->bl.x= x;
+ sd->bl.y= y;
pc->clean_skilltree(sd);
- chrif->save(sd,2);
- chrif->changemapserver(sd, ip, (short)port);
+ chrif->save(sd, 2);
+ chrif->changemapserver(sd, ip, port);
- //Free session data from this map server [Kevin]
+ // Free session data from this map server. [Kevin]
unit->free_pc(sd);
return 0;
}
- if( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) {
- ShowError("pc_setpos: attempt to place player %s (%d:%d) on invalid coordinates (%s-%d,%d)\n", sd->status.name, sd->status.account_id, sd->status.char_id, mapindex_id2name(map_index),x,y);
- x = y = 0; // make it random
+ if (x < 0 || x >= map->list[map_id].xs || y < 0 || y >= map->list[map_id].ys) { // Invalid coordinates. Randomize them.
+ ShowError("pc_setpos: Attempt to place player %s (%d:%d) on invalid coordinates (%s-%d,%d)!\n",
+ sd->status.name, sd->status.account_id, sd->status.char_id,
+ mapindex_id2name(map_index), x, y);
+ x = 0;
+ y = 0;
}
- if( x == 0 && y == 0 ) {// pick a random walkable cell
+ if (x == 0 && y == 0) { // Pick a random walkable cell.
do {
- x=rnd()%(map->list[m].xs-2)+1;
- y=rnd()%(map->list[m].ys-2)+1;
- } while(map->getcell(m, &sd->bl, x, y, CELL_CHKNOPASS));
+ x = rnd() % (map->list[map_id].xs - 2) + 1;
+ y = rnd() % (map->list[map_id].ys - 2) + 1;
+ } while(map->getcell(map_id, &sd->bl, x, y, CELL_CHKNOPASS) != 0);
}
- if (sd->state.vending && map->getcell(m, &sd->bl, x, y, CELL_CHKNOVENDING)) {
- clif->message (sd->fd, msg_sd(sd,204)); // "You can't open a shop on this cell."
+ if (sd->state.vending != 0 && map->getcell(map_id, &sd->bl, x, y, CELL_CHKNOVENDING) != 0) {
+ clif->message(sd->fd, msg_sd(sd, 204)); // "You can't open a shop on this cell."
vending->close(sd);
}
if (battle_config.player_warp_keep_direction == 0)
- sd->ud.dir = 0; // makes character face north
+ sd->ud.dir = 0; // Make character facing north.
- if(sd->bl.prev != NULL){
- unit->remove_map_pc(sd,clrtype);
- clif->changemap(sd,m,x,y); // [MouseJstr]
- } else if(sd->state.active)
- //Tag player for rewarping after map-loading is done. [Skotlex]
- sd->state.rewarp = 1;
+ if (sd->bl.prev != NULL) {
+ unit->remove_map_pc(sd, clrtype);
+ clif->changemap(sd, map_id, x, y); // [MouseJstr]
+ } else if (sd->state.active != 0) {
+ sd->state.rewarp = 1; // Tag character for re-warping after map-loading is done. [Skotlex]
+ }
sd->mapindex = map_index;
- sd->bl.m = m;
- sd->bl.x = sd->ud.to_x = x;
- sd->bl.y = sd->ud.to_y = y;
+ sd->bl.m = map_id;
+ sd->bl.x = x;
+ sd->bl.y = y;
+ sd->ud.to_x = x;
+ sd->ud.to_y = y;
- if( sd->status.guild_id > 0 && map->list[m].flag.gvg_castle ) { // Increased guild castle regen [Valaris]
+ if (sd->status.guild_id > 0 && map->list[map_id].flag.gvg_castle != 0) { // Double regeneration in guild castle. [Valaris]
struct guild_castle *gc = guild->mapindex2gc(sd->mapindex);
- if(gc && gc->guild_id == sd->status.guild_id)
+
+ if (gc != NULL && gc->guild_id == sd->status.guild_id)
sd->regen.state.gc = 1;
}
- if( sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > 0 ) {
- sd->pd->bl.m = m;
- sd->pd->bl.x = sd->pd->ud.to_x = x;
- sd->pd->bl.y = sd->pd->ud.to_y = y;
+ if (sd->status.pet_id > 0 && sd->pd != NULL && sd->pd->pet.intimate > PET_INTIMACY_NONE) {
+ sd->pd->bl.m = map_id;
+ sd->pd->bl.x = x;
+ sd->pd->bl.y = y;
+ sd->pd->ud.to_x = x;
+ sd->pd->ud.to_y = y;
sd->pd->ud.dir = sd->ud.dir;
}
- if( homun_alive(sd->hd) ) {
- sd->hd->bl.m = m;
- sd->hd->bl.x = sd->hd->ud.to_x = x;
- sd->hd->bl.y = sd->hd->ud.to_y = y;
+ if (homun_alive(sd->hd)) {
+ sd->hd->bl.m = map_id;
+ sd->hd->bl.x = x;
+ sd->hd->bl.y = y;
+ sd->hd->ud.to_x = x;
+ sd->hd->ud.to_y = y;
sd->hd->ud.dir = sd->ud.dir;
}
- if( sd->md ) {
- sd->md->bl.m = m;
- sd->md->bl.x = sd->md->ud.to_x = x;
- sd->md->bl.y = sd->md->ud.to_y = y;
+ if (sd->md != NULL) {
+ sd->md->bl.m = map_id;
+ sd->md->bl.x = x;
+ sd->md->bl.y = y;
+ sd->md->ud.to_x = x;
+ sd->md->ud.to_y = y;
sd->md->ud.dir = sd->ud.dir;
}
- /* given autotrades have no clients you have to trigger this manually otherwise they get stuck in memory limbo bugreport:7495 */
- if( sd->state.autotrade )
- clif->pLoadEndAck(0,sd);
+ // Given autotrades have no clients. You have to trigger this manually, otherwise they get stuck in memory limbo. (bugreport:7495)
+ if (sd->state.autotrade != 0)
+ clif->pLoadEndAck(0, sd);
return 0;
}
@@ -8023,163 +8068,177 @@ static void pc_damage(struct map_session_data *sd, struct block_list *src, unsig
}
}
-/*==========================================
- * Invoked when a player has negative current hp
- *------------------------------------------*/
+/**
+ * Invoked when a character died.
+ *
+ * @param sd The died character.
+ * @param src The unit which caused the death.
+ * @retval 0 Death canceled.
+ * @retval 1 Standard death.
+ * @retval 9 Died in PVP/GVG/BG.
+ *
+ **/
static int pc_dead(struct map_session_data *sd, struct block_list *src)
{
- int i=0,j=0;
- int64 tick = timer->gettick();
+ nullpo_ret(sd);
- nullpo_retr(0, sd);
+ for (int i = 0; i < MAX_PC_DEVOTION; i++) {
+ if (sd->devotion[i] != 0) {
+ struct map_session_data *devsd = map->id2sd(sd->devotion[i]);
- for (j = 0; j < MAX_PC_DEVOTION; j++) {
- if (sd->devotion[j]) {
- struct map_session_data *devsd = map->id2sd(sd->devotion[j]);
- if (devsd)
+ if (devsd != NULL)
status_change_end(&devsd->bl, SC_DEVOTION, INVALID_TIMER);
- sd->devotion[j] = 0;
+
+ sd->devotion[i] = 0;
}
}
- if(sd->status.pet_id > 0 && sd->pd) {
+ if (sd->status.pet_id > 0 && sd->pd != NULL) {
struct pet_data *pd = sd->pd;
- if( !map->list[sd->bl.m].flag.noexppenalty ) {
+
+ if (map->list[sd->bl.m].flag.noexppenalty == 0) {
pet->set_intimate(pd, pd->pet.intimate - pd->petDB->die);
- if( pd->pet.intimate < 0 )
- pd->pet.intimate = 0;
- clif->send_petdata(sd,sd->pd,1,pd->pet.intimate);
+ clif->send_petdata(sd, sd->pd, 1, pd->pet.intimate);
}
- if( sd->pd->target_id ) // Unlock all targets...
+
+ if (sd->pd->target_id != 0) // Unlock all targets.
pet->unlocktarget(sd->pd);
}
- if (sd->status.hom_id > 0){
- if(battle_config.homunculus_auto_vapor && sd->hd)
- homun->vaporize(sd, HOM_ST_REST, true);
- }
+ if (sd->status.hom_id > 0 && sd->hd != NULL && battle_config.homunculus_auto_vapor != 0)
+ homun->vaporize(sd, HOM_ST_REST, true);
- if( sd->md )
- mercenary->delete(sd->md, 3); // Your mercenary soldier has ran away.
+ if (sd->md != NULL)
+ mercenary->delete(sd->md, 3); // Your mercenary soldier ran away.
- if( sd->ed )
+ if (sd->ed != NULL)
elemental->delete(sd->ed, 0);
- // Leave duel if you die [LuzZza]
- if(battle_config.duel_autoleave_when_die) {
- if(sd->duel_group > 0)
+ if (battle_config.duel_autoleave_when_die != 0) { // Leave duel if character died. [LuzZza]
+ if (sd->duel_group > 0)
duel->leave(sd->duel_group, sd);
- if(sd->duel_invite > 0)
+ if (sd->duel_invite > 0)
duel->reject(sd->duel_invite, sd);
}
- if (sd->npc_id && sd->st && sd->st->state != RUN)
+ if (sd->npc_id != 0 && sd->st != NULL && sd->st->state != RUN)
npc->event_dequeue(sd);
- pc_setglobalreg(sd,script->add_variable("PC_DIE_COUNTER"),sd->die_counter+1);
- pc->setparam(sd, SP_KILLERRID, src?src->id:0);
+ pc_setglobalreg(sd, script->add_variable("PC_DIE_COUNTER"), sd->die_counter + 1);
+ pc->setparam(sd, SP_KILLERRID, (src != NULL) ? src->id : 0);
+
+ if (sd->bg_id != 0) { //TODO: Purge when bgqueue is deemed ok.
+ struct battleground_data *bgd = bg->team_search(sd->bg_id);
- if( sd->bg_id ) {/* TODO: purge when bgqueue is deemed ok */
- struct battleground_data *bgd;
- if( (bgd = bg->team_search(sd->bg_id)) != NULL && bgd->die_event[0] )
+ if (bgd != NULL && bgd->die_event[0] != '\0')
npc->event(sd, bgd->die_event, 0);
}
- for (i = 0; i < VECTOR_LENGTH(sd->script_queues); i++ ) {
+ for (int i = 0; i < VECTOR_LENGTH(sd->script_queues); i++) {
struct script_queue *queue = script->queue(VECTOR_INDEX(sd->script_queues, i));
- if (queue && queue->event_death[0] != '\0')
+
+ if (queue != NULL && queue->event_death[0] != '\0')
npc->event(sd, queue->event_death, 0);
}
- npc->script_event(sd,NPCE_DIE);
+ npc->script_event(sd, NPCE_DIE);
- // Clear anything NPC-related when you die and was interacting with one.
- if ( (sd->npc_id || sd->npc_shopid) && sd->state.dialog) {
- if (sd->state.using_fake_npc) {
+ // Clear anything NPC-related if character died while interacting with one.
+ if ((sd->npc_id != 0 || sd->npc_shopid != 0) && sd->state.dialog != 0) {
+ if (sd->state.using_fake_npc != 0) {
clif->clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd);
sd->state.using_fake_npc = 0;
}
- if (sd->state.menu_or_input)
+
+ if (sd->state.menu_or_input != 0)
sd->state.menu_or_input = 0;
- if (sd->npc_menu)
+
+ if (sd->npc_menu != 0)
sd->npc_menu = 0;
sd->npc_id = 0;
sd->npc_shopid = 0;
- if (sd->st && sd->st->state != END)
+
+ if (sd->st != NULL && sd->st->state != END)
sd->st->state = END;
}
- /* e.g. not killed through pc->damage */
- if( pc_issit(sd) ) {
+ // E.g. not killed through pc->damage().
+ if (pc_issit(sd))
clif->sc_end(&sd->bl, sd->bl.id, SELF, status->get_sc_icon(SC_SIT));
- }
pc_setdead(sd);
-
clif->party_dead_notification(sd);
pc->autocast_clear(sd); // Unset auto-cast data.
- // Reset menu skills.
- if (sd->menuskill_id)
- sd->menuskill_id = sd->menuskill_val = 0;
- //Reset ticks.
- sd->hp_loss.tick = sd->sp_loss.tick = sd->hp_regen.tick = sd->sp_regen.tick = 0;
+ if (sd->menuskill_id != 0) { // Reset menu skills.
+ sd->menuskill_id = 0;
+ sd->menuskill_val = 0;
+ }
+
+ // Reset ticks.
+ sd->hp_loss.tick = 0;
+ sd->sp_loss.tick = 0;
+ sd->hp_regen.tick = 0;
+ sd->sp_regen.tick = 0;
- if ( sd->spiritball )
+ if (sd->spiritball != 0)
pc->delspiritball(sd, sd->spiritball, 0);
+
if (sd->charm_type != CHARM_TYPE_NONE && sd->charm_count > 0)
pc->del_charm(sd, sd->charm_count, sd->charm_type);
+ int64 tick = timer->gettick();
+
if (src != NULL) {
switch (src->type) {
- case BL_MOB:
- {
- struct mob_data *md = BL_UCAST(BL_MOB, src);
- if (md->target_id==sd->bl.id)
- mob->unlocktarget(md,tick);
- if (battle_config.mobs_level_up && md->status.hp
- && md->level < pc->maxbaselv(sd)
- && !md->guardian_data && md->special_state.ai == AI_NONE// Guardians/summons should not level. [Skotlex]
- ) {
- // monster level up [Valaris]
- clif->misceffect(&md->bl,0);
- md->level++;
- status_calc_mob(md, SCO_NONE);
- status_percent_heal(src,10,0);
-
- if( battle_config.show_mob_info&4 )
- {// update name with new level
- clif->blname_ack(0, &md->bl);
- }
- }
- src = battle->get_master(src); // Maybe Player Summon
+ case BL_MOB: {
+ struct mob_data *md = BL_UCAST(BL_MOB, src);
+
+ if (md->target_id == sd->bl.id)
+ mob->unlocktarget(md, tick);
+
+ if (battle_config.mobs_level_up != 0 && md->status.hp != 0 && md->level < pc->maxbaselv(sd)
+ && md->guardian_data == NULL && md->special_state.ai == AI_NONE) { // Guardians/summons should not level up. [Skotlex]
+ /// Monster level up. [Valaris]
+ clif->misceffect(&md->bl, 0);
+ md->level++;
+ status_calc_mob(md, SCO_NONE);
+ status_percent_heal(src, 10, 0);
+
+ if ((battle_config.show_mob_info & 4) != 0)
+ clif->blname_ack(0, &md->bl); // Update name with new level.
}
+
+ src = battle->get_master(src); // Maybe character summon.
break;
- case BL_PET: //Pass on to master...
- src = &BL_UCAST(BL_PET, src)->msd->bl;
+ }
+ case BL_PET:
+ src = &BL_UCAST(BL_PET, src)->msd->bl; // Pass on to master.
break;
- case BL_HOM:
- src = &BL_UCAST(BL_HOM, src)->master->bl;
+ case BL_HOM:
+ src = &BL_UCAST(BL_HOM, src)->master->bl; // Pass on to master.
break;
- case BL_MER:
- src = &BL_UCAST(BL_MER, src)->master->bl;
+ case BL_MER:
+ src = &BL_UCAST(BL_MER, src)->master->bl; // Pass on to master.
break;
}
}
if (src != NULL && src->type == BL_PC) {
struct map_session_data *ssd = BL_UCAST(BL_PC, src);
+
pc->setparam(ssd, SP_KILLEDRID, sd->bl.id);
npc->script_event(ssd, NPCE_KILLPC);
+ achievement->validate_pc_kill(ssd, sd);
- achievement->validate_pc_kill(ssd, sd); // Achievements [Smokexyz/Hercules]
-
- if (battle_config.pk_mode&2) {
+ if ((battle_config.pk_mode & 2) != 0) {
ssd->status.manner -= 5;
- if(ssd->status.manner < 0)
- sc_start(NULL,src,SC_NOCHAT,100,0,0);
+
+ if (ssd->status.manner < 0)
+ sc_start(NULL, src, SC_NOCHAT, 100, 0, 0);
+
#if 0
// PK/Karma system code (not enabled yet) [celest]
// originally from Kade Online, so i don't know if any of these is correct ^^;
@@ -8191,14 +8250,15 @@ static int pc_dead(struct map_session_data *sd, struct block_list *src)
// If player killed was more evil
sd->status.karma--;
ssd->status.karma--;
- }
- else if (sd->status.karma < ssd->status.karma) // If player killed was more good
+ } else if (sd->status.karma < ssd->status.karma) { // If player killed was more good
ssd->status.karma++;
+ }
// or the PK System way...
if (sd->status.karma > 0) // player killed is dishonourable?
ssd->status.karma--; // honour points earned
+
sd->status.karma++; // honour points lost
// To-do: Receive exp on certain occasions
@@ -8206,137 +8266,156 @@ static int pc_dead(struct map_session_data *sd, struct block_list *src)
}
}
- if( battle_config.bone_drop==2
- || (battle_config.bone_drop==1 && map->list[sd->bl.m].flag.pvp)
- ) {
+ if (battle_config.bone_drop == 2 || (battle_config.bone_drop == 1 && map->list[sd->bl.m].flag.pvp != 0)) {
struct item item_tmp;
- memset(&item_tmp,0,sizeof(item_tmp));
- item_tmp.nameid=ITEMID_SKULL_;
- item_tmp.identify=1;
- item_tmp.card[0]=CARD0_CREATE;
- item_tmp.card[1]=0;
- item_tmp.card[2]=GetWord(sd->status.char_id,0); // CharId
- item_tmp.card[3]=GetWord(sd->status.char_id,1);
+
+ memset(&item_tmp, 0, sizeof(item_tmp));
+ item_tmp.nameid = ITEMID_SKULL_;
+ item_tmp.identify = 1;
+ item_tmp.card[0] = CARD0_CREATE;
+ item_tmp.card[1] = 0;
+ item_tmp.card[2] = GetWord(sd->status.char_id, 0);
+ item_tmp.card[3] = GetWord(sd->status.char_id, 1);
map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false);
}
- // activate Steel body if a super novice dies at 99+% exp [celest]
- if ((sd->job & MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && !sd->state.snovice_dead_flag) {
+ // Activate Steel Body if a Super Novice dies at 99+% EXP. [celest]
+ if ((sd->job & MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->state.snovice_dead_flag == 0) {
uint64 next = pc->nextbaseexp(sd);
- if( next == 0 ) next = pc->thisbaseexp(sd);
+
+ if (next == 0)
+ next = pc->thisbaseexp(sd);
+
if (get_percentage64(sd->status.base_exp, next) >= 99) {
sd->state.snovice_dead_flag = 1;
pc->setstand(sd);
status_percent_heal(&sd->bl, 100, 100);
clif->resurrection(&sd->bl, 1);
- if(battle_config.pc_invincible_time)
+
+ if (battle_config.pc_invincible_time != 0)
pc->setinvincibletimer(sd, battle_config.pc_invincible_time);
- sc_start(NULL,&sd->bl,status->skill2sc(MO_STEELBODY),100,1,skill->get_time(MO_STEELBODY,1));
- if(map_flag_gvg2(sd->bl.m))
+
+ sc_start(NULL, &sd->bl, status->skill2sc(MO_STEELBODY), 100, 1, skill->get_time(MO_STEELBODY, 1));
+
+ if (map_flag_gvg2(sd->bl.m))
pc->respawn_timer(INVALID_TIMER, timer->gettick(), sd->bl.id, 0);
+
return 0;
}
}
- // changed penalty options, added death by player if pk_mode [Valaris]
- if (battle_config.death_penalty_type
- && pc->isDeathPenaltyJob(sd->job)
- && !map->list[sd->bl.m].flag.noexppenalty && !map_flag_gvg2(sd->bl.m)
- && !sd->sc.data[SC_BABY] && !sd->sc.data[SC_CASH_DEATHPENALTY]
- && !pc->auto_exp_insurance(sd)
- ) {
+ if (battle_config.death_penalty_type != 0 && pc->isDeathPenaltyJob(sd->job) && !map_flag_gvg2(sd->bl.m)
+ && map->list[sd->bl.m].flag.noexppenalty == 0 && sd->sc.data[SC_BABY] == NULL
+ && sd->sc.data[SC_CASH_DEATHPENALTY] == NULL && !pc->auto_exp_insurance(sd)) {
if (battle_config.death_penalty_base > 0) {
unsigned int base_penalty = 0;
+ int rate = battle_config.death_penalty_base;
+
switch (battle_config.death_penalty_type) {
- case 1:
- base_penalty = (unsigned int) apply_percentrate64(pc->nextbaseexp(sd), battle_config.death_penalty_base, 10000);
- break;
- case 2:
- base_penalty = (unsigned int) apply_percentrate64(sd->status.base_exp, battle_config.death_penalty_base, 10000);
- break;
+ case 1:
+ base_penalty = (unsigned int)apply_percentrate64(pc->nextbaseexp(sd), rate, 10000);
+ break;
+ case 2:
+ base_penalty = (unsigned int)apply_percentrate64(sd->status.base_exp, rate, 10000);
+ break;
}
if (base_penalty != 0) {
- if (battle_config.pk_mode && src && src->type==BL_PC)
- base_penalty*=2;
- if( sd->status.mod_death != 100 )
- base_penalty = base_penalty * sd->status.mod_death / 100;
+ if (battle_config.pk_mode != 0 && src != NULL && src->type == BL_PC)
+ base_penalty *= 2;
+
+ if (sd->status.mod_death != 100)
+ base_penalty *= sd->status.mod_death / 100;
+
sd->status.base_exp -= min(sd->status.base_exp, base_penalty);
- clif->updatestatus(sd,SP_BASEEXP);
+ clif->updatestatus(sd, SP_BASEEXP);
}
}
- if(battle_config.death_penalty_job > 0) {
+ if (battle_config.death_penalty_job > 0) {
unsigned int job_penalty = 0;
+ int rate = battle_config.death_penalty_job;
switch (battle_config.death_penalty_type) {
- case 1:
- job_penalty = (unsigned int) apply_percentrate64(pc->nextjobexp(sd), battle_config.death_penalty_job, 10000);
- break;
- case 2:
- job_penalty = (unsigned int) apply_percentrate64(sd->status.job_exp, battle_config.death_penalty_job, 10000);
- break;
+ case 1:
+ job_penalty = (unsigned int)apply_percentrate64(pc->nextjobexp(sd), rate, 10000);
+ break;
+ case 2:
+ job_penalty = (unsigned int)apply_percentrate64(sd->status.job_exp, rate, 10000);
+ break;
}
if (job_penalty != 0) {
- if (battle_config.pk_mode && src && src->type==BL_PC)
- job_penalty*=2;
- if( sd->status.mod_death != 100 )
- job_penalty = job_penalty * sd->status.mod_death / 100;
+ if (battle_config.pk_mode != 0 && src != NULL && src->type == BL_PC)
+ job_penalty *= 2;
+
+ if (sd->status.mod_death != 100)
+ job_penalty *= sd->status.mod_death / 100;
+
sd->status.job_exp -= min(sd->status.job_exp, job_penalty);
- clif->updatestatus(sd,SP_JOBEXP);
+ clif->updatestatus(sd, SP_JOBEXP);
}
}
- if (battle_config.zeny_penalty > 0 && !map->list[sd->bl.m].flag.nozenypenalty) {
+ if (battle_config.zeny_penalty > 0 && map->list[sd->bl.m].flag.nozenypenalty == 0) {
int zeny_penalty = apply_percentrate(sd->status.zeny, battle_config.zeny_penalty, 10000);
+
if (zeny_penalty != 0)
pc->payzeny(sd, zeny_penalty, LOG_TYPE_PICKDROP_PLAYER, NULL);
}
}
- if(map->list[sd->bl.m].flag.pvp_nightmaredrop) {
- // Moved this outside so it works when PVP isn't enabled and during pk mode [Ancyker]
- for(j=0;j<map->list[sd->bl.m].drop_list_count;j++){
- int id = map->list[sd->bl.m].drop_list[j].drop_id;
- int type = map->list[sd->bl.m].drop_list[j].drop_type;
- int per = map->list[sd->bl.m].drop_list[j].drop_per;
- if(id == 0)
+ if (map->list[sd->bl.m].flag.pvp_nightmaredrop != 0) {
+ // Moved this outside so it works when PVP isn't enabled and during pk mode. [Ancyker]
+ for (int i = 0; i < map->list[sd->bl.m].drop_list_count; i++) {
+ int id = map->list[sd->bl.m].drop_list[i].drop_id;
+ int type = map->list[sd->bl.m].drop_list[i].drop_type;
+ int per = map->list[sd->bl.m].drop_list[i].drop_per;
+
+ if (id == 0)
continue;
- if(id == -1){
- int eq_num = 0, eq_n[MAX_INVENTORY], k;
- memset(eq_n,0,sizeof(eq_n));
- for(i = 0; i < sd->status.inventorySize; i++) {
- if( (type == 1 && !sd->status.inventory[i].equip)
- || (type == 2 && sd->status.inventory[i].equip)
- || type == 3)
- {
+
+ if (id == -1) {
+ int eq_num = 0;
+ int eq_n[MAX_INVENTORY];
+
+ memset(eq_n, 0, sizeof(eq_n));
+
+ for (int j = 0; j < sd->status.inventorySize; j++) {
+ bool is_equipped = (sd->status.inventory[j].equip != 0);
+
+ if ((type == 1 && !is_equipped) || (type == 2 && is_equipped) || type == 3) {
+ int k;
+
ARR_FIND(0, sd->status.inventorySize, k, eq_n[k] <= 0);
+
if (k < sd->status.inventorySize)
- eq_n[k] = i;
+ eq_n[k] = j;
eq_num++;
}
}
- if(eq_num > 0){
- int n = eq_n[rnd()%eq_num];
- if(rnd()%10000 < per){
- if(sd->status.inventory[n].equip)
+
+ if (eq_num > 0) {
+ int n = eq_n[rnd() % eq_num];
+
+ if (rnd() % 10000 < per) {
+ if (sd->status.inventory[n].equip != 0)
pc->unequipitem(sd, n, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
- pc->dropitem(sd,n,1);
+
+ pc->dropitem(sd, n, 1);
}
}
- }
- else if(id > 0){
- for( i = 0; i < sd->status.inventorySize; i++) {
- if(sd->status.inventory[i].nameid == id
- && rnd()%10000 < per
- && ((type == 1 && !sd->status.inventory[i].equip)
- || (type == 2 && sd->status.inventory[i].equip)
- || type == 3) ){
- if(sd->status.inventory[i].equip)
- pc->unequipitem(sd, i, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
- pc->dropitem(sd,i,1);
+ } else if (id > 0) {
+ for (int j = 0; j < sd->status.inventorySize; j++) {
+ bool is_equipped = (sd->status.inventory[j].equip != 0);
+
+ if (((type == 1 && !is_equipped) || (type == 2 && is_equipped) || type == 3)
+ && sd->status.inventory[j].nameid == id && rnd() % 10000 < per) {
+ if (is_equipped)
+ pc->unequipitem(sd, j, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
+
+ pc->dropitem(sd, j, 1);
break;
}
}
@@ -8344,46 +8423,51 @@ static int pc_dead(struct map_session_data *sd, struct block_list *src)
}
}
- // Remove autotrade to prevent autotrading from save point
- if( (sd->state.standalone || sd->state.autotrade)
- && (map->list[sd->bl.m].flag.pvp || map->list[sd->bl.m].flag.gvg)
- ) {
+ // Remove autotrade to prevent autotrading from save point.
+ if ((map->list[sd->bl.m].flag.pvp != 0 || map->list[sd->bl.m].flag.gvg != 0)
+ && (sd->state.standalone != 0 || sd->state.autotrade != 0)) {
sd->state.autotrade = 0;
sd->state.standalone = 0;
- pc->autotrade_update(sd,PAUC_REMOVE);
+ pc->autotrade_update(sd, PAUC_REMOVE);
map->quit(sd);
}
- // pvp
- // disable certain pvp functions on pk_mode [Valaris]
- if( map->list[sd->bl.m].flag.pvp && !battle_config.pk_mode && !map->list[sd->bl.m].flag.pvp_nocalcrank ) {
+ // Disable certain PVP functions on pk_mode. [Valaris]
+ if (map->list[sd->bl.m].flag.pvp != 0 && battle_config.pk_mode == 0
+ && map->list[sd->bl.m].flag.pvp_nocalcrank == 0) {
sd->pvp_point -= 5;
sd->pvp_lost++;
+
if (src != NULL && src->type == BL_PC) {
struct map_session_data *ssd = BL_UCAST(BL_PC, src);
+
ssd->pvp_point++;
ssd->pvp_won++;
}
- if( sd->pvp_point < 0 )
- {
- timer->add(tick+1, pc->respawn_timer,sd->bl.id,0);
+
+ if (sd->pvp_point < 0) {
+ timer->add(tick + 1, pc->respawn_timer, sd->bl.id, 0);
return 1|8;
}
}
- //GvG
- if( map_flag_gvg2(sd->bl.m) ) {
- timer->add(tick+1, pc->respawn_timer, sd->bl.id, 0);
+
+ // GVG
+ if (map_flag_gvg2(sd->bl.m)) {
+ timer->add(tick + 1, pc->respawn_timer, sd->bl.id, 0);
return 1|8;
- } else if( sd->bg_id ) {
+ }
+
+ if (sd->bg_id != 0) {
struct battleground_data *bgd = bg->team_search(sd->bg_id);
- if( bgd && bgd->mapindex > 0 ) { // Respawn by BG
- timer->add(tick+1000, pc->respawn_timer, sd->bl.id, 0);
+
+ if (bgd != NULL && bgd->mapindex > 0) { // Respawn by BG.
+ timer->add(tick + 1000, pc->respawn_timer, sd->bl.id, 0);
return 1|8;
}
}
- //Reset "can log out" tick.
- if( battle_config.prevent_logout )
+ // Reset "can log out" tick.
+ if (battle_config.prevent_logout != 0)
sd->canlog_tick = timer->gettick() - battle_config.prevent_logout;
return 1;
diff --git a/src/map/pet.c b/src/map/pet.c
index aeb372c05..620779765 100644
--- a/src/map/pet.c
+++ b/src/map/pet.c
@@ -60,62 +60,101 @@ struct pet_interface *pet;
#define MIN_PETTHINKTIME 100
+/**
+ * Gets a pet's hunger value, depending it's hunger level.
+ * This value is only used in clif_parse_LoadEndAck() when calling clif_pet_emotion().
+ *
+ * @param pd The pet.
+ * @return The pet's hunger value.
+ *
+ **/
static int pet_hungry_val(struct pet_data *pd)
{
nullpo_ret(pd);
- if(pd->pet.hungry > 90)
+ if (pd->pet.hungry > PET_HUNGER_SATISFIED)
return 4;
- else if(pd->pet.hungry > 75)
+ else if (pd->pet.hungry > PET_HUNGER_NEUTRAL)
return 3;
- else if(pd->pet.hungry > 25)
+ else if (pd->pet.hungry > PET_HUNGER_HUNGRY)
return 2;
- else if(pd->pet.hungry > 10)
+ else if (pd->pet.hungry > PET_HUNGER_VERY_HUNGRY)
return 1;
else
return 0;
}
-static void pet_set_intimate(struct pet_data *pd, int value)
+/**
+ * Sets a pet's hunger value.
+ *
+ * @param pd The pet.
+ * @param value The pet's new hunger value.
+ *
+ **/
+static void pet_set_hunger(struct pet_data *pd, int value)
{
- int intimate;
- struct map_session_data *sd;
+ nullpo_retv(pd);
+
+ pd->pet.hungry = cap_value(value, PET_HUNGER_STARVING, PET_HUNGER_STUFFED);
+}
+/**
+ * Sets a pet's intimacy value.
+ * Deletes the pet if its intimacy value reaches PET_INTIMACY_NONE (0).
+ *
+ * @param pd The pet.
+ * @param value The pet's new intimacy value.
+ *
+ **/
+static void pet_set_intimate(struct pet_data *pd, int value)
+{
nullpo_retv(pd);
- intimate = pd->pet.intimate;
- sd = pd->msd;
+ nullpo_retv(pd->msd);
+
+ pd->pet.intimate = cap_value(value, PET_INTIMACY_NONE, PET_INTIMACY_MAX);
- pd->pet.intimate = value;
+ struct map_session_data *sd = pd->msd;
- if( (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);
+ status_calc_pc(sd, SCO_NONE);
- /* Pet is lost, delete the egg */
- if (value <= 0) {
+ if (pd->pet.intimate == PET_INTIMACY_NONE) { /// Pet is lost. Delete the egg.
int i;
- ARR_FIND(0, sd->status.inventorySize, i, sd->status.inventory[i].card[0] == CARD0_PET &&
- pd->pet.pet_id == MakeDWord(sd->status.inventory[i].card[1], sd->status.inventory[i].card[2]));
+ ARR_FIND(0, sd->status.inventorySize, i, sd->status.inventory[i].card[0] == CARD0_PET
+ && pd->pet.pet_id == MakeDWord(sd->status.inventory[i].card[1],
+ sd->status.inventory[i].card[2]));
- if (i != sd->status.inventorySize) {
+ if (i != sd->status.inventorySize)
pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_EGG);
- }
}
}
+/**
+ * Creates a pet egg.
+ *
+ * @param sd The character who tries to create the pet egg.
+ * @param item_id The pet egg's item ID.
+ * @return 0 on failure, 1 on success.
+ *
+ **/
static int pet_create_egg(struct map_session_data *sd, int item_id)
{
- int pet_id = pet->search_petDB_index(item_id, PET_EGG);
nullpo_ret(sd);
- if (pet_id < 0) return 0; //No pet egg here.
- if (!pc->inventoryblank(sd)) return 0; // Inventory full
+
+ int pet_id = pet->search_petDB_index(item_id, PET_EGG);
+
+ if (pet_id == INDEX_NOT_FOUND) // No pet egg here.
+ return 0;
+
+ if (pc->inventoryblank(sd) == 0) // Inventory full.
+ return 0;
+
sd->catch_target_class = pet->db[pet_id].class_;
- intif->create_pet(sd->status.account_id, sd->status.char_id,
- pet->db[pet_id].class_,
- mob->db(pet->db[pet_id].class_)->lv,
- pet->db[pet_id].EggID, 0,
- (short)pet->db[pet_id].intimate,
- 100, 0, 1, pet->db[pet_id].jname);
+ intif->create_pet(sd->status.account_id, sd->status.char_id, pet->db[pet_id].class_,
+ mob->db(pet->db[pet_id].class_)->lv, pet->db[pet_id].EggID, 0,
+ (short)pet->db[pet_id].intimate, PET_HUNGER_STUFFED,
+ 0, 1, pet->db[pet_id].jname);
+
return 1;
}
@@ -162,48 +201,42 @@ static int pet_attackskill(struct pet_data *pd, int target_id)
return 0;
}
+/**
+ * Checks if a pet can attack a target.
+ *
+ * @param sd The pet's master.
+ * @param bl The pet's target.
+ * @param type 0 - Support master when attacking. Not 0 - Support master when being attacked.
+ * @return 0 on failure, 1 on success.
+ *
+ **/
static int pet_target_check(struct map_session_data *sd, struct block_list *bl, int type)
{
- struct pet_data *pd;
- int rate;
-
nullpo_ret(sd);
- pd = sd->pd;
+ nullpo_ret(sd->pd);
+ nullpo_ret(bl);
+ Assert_ret(sd->pd->msd == NULL || sd->pd->msd->pd == sd->pd);
- Assert_ret(pd->msd == 0 || pd->msd->pd == pd);
+ struct pet_data *pd = sd->pd;
- 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.class_ == status->get_class(bl))
- return 0;
+ if ((type == 0 && pd->petDB->attack_rate == 0) || (type != 0 && pd->petDB->defence_attack_rate == 0))
+ return 0; // If base rate is 0, there's nothing to do.
- if( pd->bl.m != bl->m
- || !check_distance_bl(&pd->bl, bl, pd->db->range2))
+ if (bl->type != BL_MOB || bl->prev == NULL || pd->pet.intimate < battle_config.pet_support_min_friendly
+ || pd->pet.hungry <= PET_HUNGER_STARVING || pd->pet.class_ == status->get_class(bl)
+ || pd->bl.m != bl->m || !check_distance_bl(&pd->bl, bl, pd->db->range2)
+ || status->check_skilluse(&pd->bl, bl, 0, 0) == 0) {
return 0;
+ }
- if (!status->check_skilluse(&pd->bl, bl, 0, 0))
- return 0;
+ int rate = ((type == 0) ? pd->petDB->attack_rate : pd->petDB->defence_attack_rate) * pd->rate_fix / 1000;
- if(!type) {
- rate = pd->petDB->attack_rate;
- rate = rate * pd->rate_fix/1000;
- if(pd->petDB->attack_rate > 0 && rate <= 0)
- rate = 1;
- } else {
- rate = pd->petDB->defence_attack_rate;
- rate = rate * pd->rate_fix/1000;
- if(pd->petDB->defence_attack_rate > 0 && rate <= 0)
- rate = 1;
- }
- if(rnd()%10000 < rate)
- {
- if(pd->target_id == 0 || rnd()%10000 < pd->petDB->change_target_rate)
- pd->target_id = bl->id;
- }
+ if (rnd() % 10000 < max(rate, 1) && (pd->target_id == 0 || rnd() % 10000 < pd->petDB->change_target_rate))
+ pd->target_id = bl->id;
return 0;
}
+
/*==========================================
* Pet SC Check [Skotlex]
*------------------------------------------*/
@@ -226,59 +259,72 @@ static int pet_sc_check(struct map_session_data *sd, int type)
return 0;
}
+/**
+ * Updates a pet's hunger value and timer and updates the pet's intimacy value if starving.
+ *
+ * @param tid The timer ID.
+ * @param tick The base amount of ticks to add to the pet's hunger timer. (The timer's current ticks when calling this fuction.)
+ * @param id The pet master's account ID.
+ * @param data Unused.
+ * @return 1 on failure, 0 on success.
+ *
+ **/
static int pet_hungry(int tid, int64 tick, int id, intptr_t data)
{
- struct map_session_data *sd;
- struct pet_data *pd;
- int interval;
+ struct map_session_data *sd = map->id2sd(id);
- sd=map->id2sd(id);
- if(!sd)
+ if (sd == NULL || sd->status.pet_id == 0 || sd->pd == NULL)
return 1;
- if(!sd->status.pet_id || !sd->pd)
- return 1;
+ struct pet_data *pd = sd->pd;
- pd = sd->pd;
- if(pd->pet_hungry_timer != tid){
- ShowError("pet_hungry_timer %d != %d\n",pd->pet_hungry_timer,tid);
+ /**
+ * If HungerDelay is 0, there's nothing to do.
+ * Actually this shouldn't happen, since the timer wasn't added in pet_data_init(), but just to be sure...
+ *
+ **/
+ if (pd->petDB->hungry_delay == 0) {
+ pet->hungry_timer_delete(pd);
return 0;
}
+
+ if (pd->pet_hungry_timer != tid) {
+ ShowError("pet_hungry: pet_hungry_timer %d != %d\n", pd->pet_hungry_timer, tid);
+ return 1;
+ }
+
pd->pet_hungry_timer = INVALID_TIMER;
- if (pd->pet.intimate <= 0)
- return 1; //You lost the pet already, the rest is irrelevant.
+ if (pd->pet.intimate <= PET_INTIMACY_NONE)
+ return 1; // You lost the pet already, the rest is irrelevant.
+
+ pet->set_hunger(pd, pd->pet.hungry - pd->petDB->hunger_decrement);
- pd->pet.hungry--;
- /* Pet Autofeed */
- if (battle_config.feature_enable_pet_autofeed != 0) {
- if (pd->petDB->autofeed == 1 && pd->pet.autofeed == 1 && pd->pet.hungry <= 25) {
+ // Pet auto-feed.
+ if (battle_config.feature_enable_pet_autofeed == 1) {
+ if (pd->petDB->autofeed == 1 && pd->pet.autofeed == 1 && pd->pet.hungry <= PET_HUNGER_HUNGRY)
pet->food(sd, pd);
- }
}
- if( pd->pet.hungry < 0 )
- {
+ int interval = pd->petDB->hungry_delay;
+
+ if (pd->pet.hungry == PET_HUNGER_STARVING) {
pet_stop_attack(pd);
- pd->pet.hungry = 0;
- pet->set_intimate(pd, pd->pet.intimate - battle_config.pet_hungry_friendly_decrease);
- if( pd->pet.intimate <= 0 )
- {
- pd->pet.intimate = 0;
+ pet->set_intimate(pd, pd->pet.intimate - pd->petDB->starving_decrement);
+
+ if (pd->pet.intimate == PET_INTIMACY_NONE)
pd->status.speed = pd->db->status.speed;
- }
+
status_calc_pet(pd, SCO_NONE);
- clif->send_petdata(sd,pd,1,pd->pet.intimate);
+ clif->send_petdata(sd, pd, 1, pd->pet.intimate);
+
+ if (pd->petDB->starving_delay > 0)
+ interval = pd->petDB->starving_delay;
}
- clif->send_petdata(sd,pd,2,pd->pet.hungry);
- if(battle_config.pet_hungry_delay_rate != 100)
- interval = (pd->petDB->hungry_delay*battle_config.pet_hungry_delay_rate)/100;
- else
- interval = pd->petDB->hungry_delay;
- if(interval <= 0)
- interval = 1;
- pd->pet_hungry_timer = timer->add(tick+interval,pet->hungry,sd->bl.id,0);
+ clif->send_petdata(sd, pd, 2, pd->pet.hungry);
+ interval *= battle_config.pet_hungry_delay_rate / 100;
+ pd->pet_hungry_timer = timer->add(tick + max(interval, 1), pet->hungry, sd->bl.id, 0);
return 0;
}
@@ -315,21 +361,31 @@ static int pet_hungry_timer_delete(struct pet_data *pd)
return 1;
}
+/**
+ * Makes a pet start performing/dancing.
+ *
+ * @param sd Unused.
+ * @param pd The pet.
+ * @return 0 on failure, 1 on success.
+ *
+ **/
static int pet_performance(struct map_session_data *sd, struct pet_data *pd)
{
+ nullpo_ret(pd);
+
int val;
- nullpo_retr(1, pd);
- if (pd->pet.intimate > 900)
- val = (pd->petDB->s_perfor > 0)? 4:3;
- else if(pd->pet.intimate > 750) //TODO: this is way too high
+ if (pd->pet.intimate > PET_INTIMACY_LOYAL)
+ val = (pd->petDB->s_perfor > 0) ? 4 : 3;
+ else if (pd->pet.intimate > PET_INTIMACY_CORDIAL) //TODO: This is way too high.
val = 2;
else
val = 1;
- pet_stop_walking(pd,STOPWALKING_FLAG_NONE | (2000<<8)); // Stop walking for 2000ms
- clif->send_petdata(NULL, pd, 4, rnd()%val + 1);
- pet->lootitem_drop(pd,NULL);
+ pet_stop_walking(pd, STOPWALKING_FLAG_NONE | (2000 << 8)); // Stop walking for 2 seconds.
+ clif->send_petdata(NULL, pd, 4, rnd() % val + 1);
+ pet->lootitem_drop(pd, NULL);
+
return 1;
}
@@ -377,78 +433,80 @@ static int pet_return_egg(struct map_session_data *sd, struct pet_data *pd)
return 1;
}
+/**
+ * Initializes a pet.
+ *
+ * @param sd The pet's master.
+ * @param petinfo The pet's status data.
+ * @return 1 on failure, 0 on success.
+ *
+ **/
static int pet_data_init(struct map_session_data *sd, struct s_pet *petinfo)
{
- struct pet_data *pd;
- int i=0,interval=0;
-
nullpo_retr(1, sd);
nullpo_retr(1, petinfo);
- Assert_retr(1, sd->status.pet_id == 0 || sd->pd == 0 || sd->pd->msd == sd);
+ Assert_retr(1, sd->status.pet_id == 0 || sd->pd == NULL || sd->pd->msd == sd);
- if(sd->status.account_id != petinfo->account_id || sd->status.char_id != petinfo->char_id) {
+ if (sd->status.account_id != petinfo->account_id || sd->status.char_id != petinfo->char_id) {
sd->status.pet_id = 0;
return 1;
}
+
if (sd->status.pet_id != petinfo->pet_id) {
- if (sd->status.pet_id) {
- //Wrong pet?? Set incubate to no and send it back for saving.
+ if (sd->status.pet_id != 0) { // Wrong pet? Set incubate to no and send it back for saving.
petinfo->incubate = 1;
- intif->save_petdata(sd->status.account_id,petinfo);
+ intif->save_petdata(sd->status.account_id, petinfo);
sd->status.pet_id = 0;
return 1;
}
- //The pet_id value was lost? odd... restore it.
- sd->status.pet_id = petinfo->pet_id;
+
+ sd->status.pet_id = petinfo->pet_id; // The pet_id value was lost? Odd... Restore it.
}
- i = pet->search_petDB_index(petinfo->class_,PET_CLASS);
- if(i < 0) {
+ int i = pet->search_petDB_index(petinfo->class_, PET_CLASS);
+
+ if (i == INDEX_NOT_FOUND) {
sd->status.pet_id = 0;
return 1;
}
+
+ struct pet_data *pd;
+
CREATE(pd, struct pet_data, 1);
- pd->bl.type = BL_PET;
- pd->bl.id = npc->get_new_npc_id();
+ memcpy(&pd->pet, petinfo, sizeof(struct s_pet));
sd->pd = pd;
-
pd->msd = sd;
pd->petDB = &pet->db[i];
- pd->db = mob->db(petinfo->class_);
- memcpy(&pd->pet, petinfo, sizeof(struct s_pet));
- status->set_viewdata(&pd->bl, petinfo->class_);
+ pd->db = mob->db(pd->petDB->class_);
+ pd->bl.type = BL_PET;
+ pd->bl.id = npc->get_new_npc_id();
+ status->set_viewdata(&pd->bl, pd->petDB->class_);
unit->dataset(&pd->bl);
pd->ud.dir = sd->ud.dir;
-
pd->bl.m = sd->bl.m;
pd->bl.x = sd->bl.x;
pd->bl.y = sd->bl.y;
unit->calc_pos(&pd->bl, sd->bl.x, sd->bl.y, sd->ud.dir);
pd->bl.x = pd->ud.to_x;
pd->bl.y = pd->ud.to_y;
-
map->addiddb(&pd->bl);
- status_calc_pet(pd,SCO_FIRST);
-
+ status_calc_pet(pd, SCO_FIRST);
pd->last_thinktime = timer->gettick();
pd->state.skillbonus = 0;
- if( battle_config.pet_status_support )
- script->run_pet(pet->db[i].pet_script,0,sd->bl.id,0);
+ if (pd->petDB->pet_script != NULL && battle_config.pet_status_support == 1)
+ script->run_pet(pd->petDB->pet_script, 0, sd->bl.id, 0);
- if( pd->petDB ) {
- if( pd->petDB->equip_script )
- status_calc_pc(sd,SCO_NONE);
+ if (pd->petDB->equip_script != NULL)
+ status_calc_pc(sd, SCO_NONE);
- if( battle_config.pet_hungry_delay_rate != 100 )
- interval = (pd->petDB->hungry_delay*battle_config.pet_hungry_delay_rate)/100;
- else
- interval = pd->petDB->hungry_delay;
+ pd->pet_hungry_timer = INVALID_TIMER;
+
+ if (pd->petDB->hungry_delay > 0) {
+ int interval = pd->petDB->hungry_delay * battle_config.pet_hungry_delay_rate / 100;
+ pd->pet_hungry_timer = timer->add(timer->gettick() + max(interval, 1), pet->hungry, sd->bl.id, 0);
}
- if( interval <= 0 )
- interval = 1;
- pd->pet_hungry_timer = timer->add(timer->gettick() + interval, pet->hungry, sd->bl.id, 0);
return 0;
}
@@ -563,57 +621,66 @@ static int pet_catch_process1(struct map_session_data *sd, int target_class)
return 0;
}
+/**
+ * Begins the actual process of catching a monster.
+ *
+ * @param sd The character who tries to catch the monster.
+ * @param target_id The monster ID of the pet, which the character tries to catch.
+ * @return 1 on failure, 0 on success.
+ *
+ **/
static int pet_catch_process2(struct map_session_data *sd, int target_id)
{
- struct mob_data *md = NULL;
- struct block_list *bl = NULL;
- int i = 0, pet_catch_rate = 0;
-
nullpo_retr(1, sd);
- bl = map->id2bl(target_id); // TODO: Why does this not use map->id2md?
- md = BL_CAST(BL_MOB, bl);
- if (md == NULL || md->bl.prev == NULL) {
- // Invalid inputs/state, abort capture.
- clif->pet_roulette(sd,0);
+ struct mob_data *md = BL_CAST(BL_MOB, map->id2bl(target_id)); //TODO: Why does this not use map->id2md?
+
+ if (md == NULL || md->bl.prev == NULL) { // Invalid inputs/state, abort capture.
+ clif->pet_roulette(sd, 0);
sd->catch_target_class = -1;
sd->itemid = -1;
sd->itemindex = -1;
return 1;
}
- //FIXME: delete taming item here, if this was an item-invoked capture and the item was flagged as delay-consume [ultramage]
+ //FIXME: Delete taming item here, if this was an item-invoked capture and the item was flagged as delay-consume. [ultramage]
- i = pet->search_petDB_index(md->class_,PET_CLASS);
- //catch_target_class == 0 is used for universal lures (except bosses for now). [Skotlex]
- if (sd->catch_target_class == 0 && !(md->status.mode&MD_BOSS))
+ // catch_target_class == 0 is used for universal lures (except bosses for now). [Skotlex]
+ if (sd->catch_target_class == 0 && (md->status.mode & MD_BOSS) == 0)
sd->catch_target_class = md->class_;
- if(i < 0 || sd->catch_target_class != md->class_) {
- clif->emotion(&md->bl, E_AG); //mob will do /ag if wrong lure is used on them.
- clif->pet_roulette(sd,0);
+
+ int i = pet->search_petDB_index(md->class_, PET_CLASS);
+
+ if (i == INDEX_NOT_FOUND || sd->catch_target_class != md->class_) {
+ clif->emotion(&md->bl, E_AG); // Mob will do /ag if wrong lure is used on it.
+ clif->pet_roulette(sd, 0);
sd->catch_target_class = -1;
return 1;
}
- pet_catch_rate = (pet->db[i].capture + (sd->status.base_level - md->level)*30 + sd->battle_status.luk*20)*(200 - get_percentage(md->status.hp, md->status.max_hp))/100;
+ int pet_catch_rate;
+ int capture = pet->db[i].capture;
+ int mob_hp_perc = get_percentage(md->status.hp, md->status.max_hp);
+
+ if (battle_config.pet_catch_rate_official_formula == 1) {
+ pet_catch_rate = capture * (100 - mob_hp_perc) / 100 + capture;
+ } else {
+ int lvl_diff_mod = (sd->status.base_level - md->level) * 30;
+ int char_luk_mod = sd->battle_status.luk * 20;
+ pet_catch_rate = (capture + lvl_diff_mod + char_luk_mod) * (200 - mob_hp_perc) / 100;
+ }
- if(pet_catch_rate < 1) pet_catch_rate = 1;
- if(battle->bc->pet_catch_rate != 100)
- pet_catch_rate = (pet_catch_rate*battle->bc->pet_catch_rate)/100;
+ pet_catch_rate = cap_value(pet_catch_rate, 1, 10000) * battle_config.pet_catch_rate / 100;
- if(rnd()%10000 < pet_catch_rate)
- {
- unit->remove_map(&md->bl,CLR_OUTSIGHT,ALC_MARK);
+ if (rnd() % 10000 < pet_catch_rate) {
+ unit->remove_map(&md->bl, CLR_OUTSIGHT, ALC_MARK);
status_kill(&md->bl);
- clif->pet_roulette(sd,1);
- intif->create_pet(sd->status.account_id,sd->status.char_id,pet->db[i].class_,mob->db(pet->db[i].class_)->lv,
- pet->db[i].EggID,0,pet->db[i].intimate,100,0,1,pet->db[i].jname);
-
+ clif->pet_roulette(sd, 1);
+ intif->create_pet(sd->status.account_id, sd->status.char_id, pet->db[i].class_, mob->db(pet->db[i].class_)->lv,
+ pet->db[i].EggID, 0, pet->db[i].intimate, PET_HUNGER_STUFFED, 0, 1, pet->db[i].jname);
achievement->validate_taming(sd, pet->db[i].class_);
- }
- else
- {
- clif->pet_roulette(sd,0);
+ } else {
+ clif->pet_roulette(sd, 0);
sd->catch_target_class = -1;
}
@@ -670,42 +737,52 @@ static bool pet_get_egg(int account_id, int pet_class, int pet_id)
return true;
}
+/**
+ * Performs selected pet menu option.
+ *
+ * @param sd The pet's master.
+ * @param menunum The selected menu option.
+ * @return 1 on failure, 0 on success.
+ *
+ **/
static int pet_menu(struct map_session_data *sd, int menunum)
{
- struct item_data *egg_id;
- nullpo_ret(sd);
- if (sd->pd == NULL)
- return 1;
+ nullpo_retr(1, sd);
+ nullpo_retr(1, sd->pd);
- //You lost the pet already.
- if(!sd->status.pet_id || sd->pd->pet.intimate <= 0 || sd->pd->pet.incubate)
- return 1;
+ if (sd->status.pet_id == 0 || sd->pd->pet.intimate <= PET_INTIMACY_NONE || sd->pd->pet.incubate != 0)
+ return 1; // You lost the pet already.
+
+ struct item_data *egg_id = itemdb->exists(sd->pd->petDB->EggID);
- egg_id = itemdb->exists(sd->pd->petDB->EggID);
- if (egg_id) {
- if ((egg_id->flag.trade_restriction&ITR_NODROP) && !pc->inventoryblank(sd)) {
- clif->message(sd->fd, msg_sd(sd,451)); // You can't return your pet because your inventory is full.
+ if (egg_id != NULL) {
+ if ((egg_id->flag.trade_restriction & ITR_NODROP) != 0 && pc->inventoryblank(sd) == 0) {
+ clif->message(sd->fd, msg_sd(sd, 451)); // You can't return your pet because your inventory is full.
return 1;
}
}
- switch(menunum) {
- case 0:
- clif->send_petstatus(sd);
- break;
- case 1:
- pet->food(sd, sd->pd);
- break;
- case 2:
- pet->performance(sd, sd->pd);
- break;
- case 3:
- pet->return_egg(sd, sd->pd);
- break;
- case 4:
- pet->unequipitem(sd, sd->pd);
- break;
+ switch (menunum) {
+ case 0:
+ clif->send_petstatus(sd);
+ break;
+ case 1:
+ pet->food(sd, sd->pd);
+ break;
+ case 2:
+ pet->performance(sd, sd->pd);
+ break;
+ case 3:
+ pet->return_egg(sd, sd->pd);
+ break;
+ case 4:
+ pet->unequipitem(sd, sd->pd);
+ break;
+ default: ;
+ ShowError("pet_menu: Unexpected menu option: %d\n", menunum);
+ return 1;
}
+
return 0;
}
@@ -830,49 +907,56 @@ static int pet_unequipitem(struct map_session_data *sd, struct pet_data *pd)
return 0;
}
+/**
+ * Feeds a pet and updates its intimacy value.
+ *
+ * @param sd The pet's master.
+ * @param pd The pet.
+ * @return 1 on failure, 0 on success.
+ *
+ **/
static int pet_food(struct map_session_data *sd, struct pet_data *pd)
{
- int i, food_id;
-
+ nullpo_retr(1, sd);
nullpo_retr(1, pd);
- food_id = pd->petDB->FoodID;
- i = pc->search_inventory(sd, food_id);
- if(i == INDEX_NOT_FOUND) {
- clif->pet_food(sd, food_id, 0);
+
+ int i = pc->search_inventory(sd, pd->petDB->FoodID);
+
+ if (i == INDEX_NOT_FOUND) {
+ clif->pet_food(sd, pd->petDB->FoodID, 0);
return 1;
}
+
pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_CONSUME);
- if (pd->pet.hungry > 90) {
- pet->set_intimate(pd, pd->pet.intimate - pd->petDB->r_full);
- } else {
- int add_intimate = 0;
- if (battle_config.pet_friendly_rate != 100)
- add_intimate = (pd->petDB->r_hungry * battle_config.pet_friendly_rate)/100;
- else
- add_intimate = pd->petDB->r_hungry;
- if (pd->pet.hungry > 75) {
- add_intimate = add_intimate >> 1;
- if (add_intimate <= 0)
- add_intimate = 1;
- }
- pet->set_intimate(pd, pd->pet.intimate + add_intimate);
- }
- if (pd->pet.intimate <= 0) {
- pd->pet.intimate = 0;
+ int intimacy = 0;
+
+ if (pd->pet.hungry >= PET_HUNGER_STUFFED)
+ intimacy -= pd->petDB->r_full; // Decrease intimacy by OverFeedDecrement.
+ else if (pd->pet.hungry > PET_HUNGER_SATISFIED)
+ intimacy -= pd->petDB->r_full / 2; // Decrease intimacy by 50% of OverFeedDecrement.
+ else if (pd->pet.hungry > PET_HUNGER_NEUTRAL)
+ intimacy -= pd->petDB->r_full * 5 / 100; // Decrease intimacy by 5% of OverFeedDecrement.
+ else if (pd->pet.hungry > PET_HUNGER_HUNGRY)
+ intimacy += pd->petDB->r_hungry * 75 / 100; // Increase intimacy by 75% of FeedIncrement.
+ else if (pd->pet.hungry > PET_HUNGER_VERY_HUNGRY)
+ intimacy += pd->petDB->r_hungry; // Increase intimacy by FeedIncrement.
+ else
+ intimacy += pd->petDB->r_hungry / 2; // Increase intimacy by 50% of FeedIncrement.
+
+ intimacy *= battle_config.pet_friendly_rate / 100;
+ pet->set_intimate(pd, pd->pet.intimate + intimacy);
+
+ if (pd->pet.intimate == PET_INTIMACY_NONE) {
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 += pd->petDB->fullness;
- if( pd->pet.hungry > 100 )
- pd->pet.hungry = 100;
- clif->send_petdata(sd,pd,2,pd->pet.hungry);
- clif->send_petdata(sd,pd,1,pd->pet.intimate);
- clif->pet_food(sd,pd->petDB->FoodID,1);
+ status_calc_pet(pd, SCO_NONE);
+ pet->set_hunger(pd, pd->pet.hungry + pd->petDB->fullness);
+ clif->send_petdata(sd, pd, 2, pd->pet.hungry);
+ clif->send_petdata(sd, pd, 1, pd->pet.intimate);
+ clif->pet_food(sd, pd->petDB->FoodID, 1);
return 0;
}
@@ -919,117 +1003,128 @@ static int pet_randomwalk(struct pet_data *pd, int64 tick)
return 0;
}
+/**
+ * Performs pet's AI actions. (Moving, attacking, etc.)
+ *
+ * @param pd The pet.
+ * @param sd The pet's master.
+ * @param tick Timestamp of last support.
+ * @return Always 0.
+ *
+ **/
static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, int64 tick)
{
- struct block_list *target = NULL;
nullpo_ret(pd);
+ nullpo_ret(pd->bl.prev);
+ nullpo_ret(sd);
+ nullpo_ret(sd->bl.prev);
- if(pd->bl.prev == NULL || sd == NULL || sd->bl.prev == NULL)
+ if (DIFF_TICK(tick, pd->last_thinktime) < MIN_PETTHINKTIME)
return 0;
- if(DIFF_TICK(tick,pd->last_thinktime) < MIN_PETTHINKTIME)
- return 0;
- pd->last_thinktime=tick;
+ pd->last_thinktime = tick;
- if(pd->ud.attacktimer != INVALID_TIMER || pd->ud.skilltimer != INVALID_TIMER || pd->bl.m != sd->bl.m)
+ if (pd->ud.attacktimer != INVALID_TIMER || pd->ud.skilltimer != INVALID_TIMER || pd->bl.m != sd->bl.m)
return 0;
- if(pd->ud.walktimer != INVALID_TIMER && pd->ud.walkpath.path_pos <= 2)
- return 0; //No thinking when you just started to walk.
+ 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) {
- //Pet should just... well, random walk.
- pet->randomwalk(pd,tick);
+ if (pd->pet.intimate <= PET_INTIMACY_NONE) {
+ pet->randomwalk(pd, tick); // Pet should just... well, random walk.
return 0;
}
- if (!check_distance_bl(&sd->bl, &pd->bl, pd->db->range3)) {
- //Master too far, chase.
- if(pd->target_id)
+ if (!check_distance_bl(&sd->bl, &pd->bl, pd->db->range3)) { // Master too far away. Chase him.
+ if (pd->target_id != 0)
pet->unlocktarget(pd);
- if(pd->ud.walktimer != INVALID_TIMER && pd->ud.target == sd->bl.id)
- return 0; //Already walking to him
+
+ if (pd->ud.walktimer != INVALID_TIMER && pd->ud.target == sd->bl.id)
+ return 0; // Already walking to him.
+
if (DIFF_TICK(tick, pd->ud.canmove_tick) < 0)
- return 0; //Can't move yet.
- pd->status.speed = (sd->battle_status.speed>>1);
- if(pd->status.speed <= 0)
- pd->status.speed = 1;
- if (!unit->walktobl(&pd->bl, &sd->bl, 3, 0))
- pet->randomwalk(pd,tick);
+ return 0; // Can't move yet.
+
+ pd->status.speed = max(sd->battle_status.speed / 2, MIN_WALK_SPEED);
+
+ if (unit->walktobl(&pd->bl, &sd->bl, 3, 0) == 0)
+ pet->randomwalk(pd, tick);
+
return 0;
}
- //Return speed to normal.
- if (pd->status.speed != pd->petDB->speed) {
+ if (pd->status.speed != pd->petDB->speed) { // Reset speed to normal.
if (pd->ud.walktimer != INVALID_TIMER)
- return 0; //Wait until the pet finishes walking back to master.
+ return 0; // Wait until the pet finishes walking back to master.
+
pd->status.speed = pd->petDB->speed;
- pd->ud.state.change_walk_target = pd->ud.state.speed_changed = 1;
+ pd->ud.state.speed_changed = 1;
+ pd->ud.state.change_walk_target = 1;
}
- if (pd->target_id) {
- target= map->id2bl(pd->target_id);
- if (!target || pd->bl.m != target->m || status->isdead(target)
- || !check_distance_bl(&pd->bl, target, pd->db->range3)
- ) {
+ struct block_list *target = NULL;
+
+ if (pd->target_id != 0) {
+ target = map->id2bl(pd->target_id);
+
+ if (target == NULL || pd->bl.m != target->m || status->isdead(target) == 1
+ || !check_distance_bl(&pd->bl, target, pd->db->range3)) {
target = NULL;
pet->unlocktarget(pd);
}
}
- if(!target && pd->loot && pd->msd && pc_has_permission(pd->msd, PC_PERM_TRADE) && pd->loot->count < pd->loot->max && DIFF_TICK(tick,pd->ud.canact_tick)>0) {
- //Use half the pet's range of sight.
- map->foreachinrange(pet->ai_sub_hard_lootsearch,&pd->bl,
- pd->db->range2/2, BL_ITEM,pd,&target);
+ if (target == NULL && pd->loot != NULL && pd->msd != NULL && pc_has_permission(pd->msd, PC_PERM_TRADE)
+ && pd->loot->count < pd->loot->max && DIFF_TICK(tick, pd->ud.canact_tick) > 0) { // Use half the pet's range of sight.
+ map->foreachinrange(pet->ai_sub_hard_lootsearch, &pd->bl, pd->db->range2 / 2, BL_ITEM, pd, &target);
}
- if (!target) {
- //Just walk around.
+ if (target == NULL) { // Just walk around.
if (check_distance_bl(&sd->bl, &pd->bl, 3))
- return 0; //Already next to master.
+ return 0; // Already next to master.
- if(pd->ud.walktimer != INVALID_TIMER && check_distance_blxy(&sd->bl, pd->ud.to_x,pd->ud.to_y, 3))
- return 0; //Already walking to him
+ if (pd->ud.walktimer != INVALID_TIMER && check_distance_blxy(&sd->bl, pd->ud.to_x, pd->ud.to_y, 3))
+ return 0; // Already walking to him.
unit->calc_pos(&pd->bl, sd->bl.x, sd->bl.y, sd->ud.dir);
+
if (unit->walk_toxy(&pd->bl, pd->ud.to_x, pd->ud.to_y, 0) != 0)
- pet->randomwalk(pd,tick);
+ pet->randomwalk(pd, tick);
return 0;
}
- if(pd->ud.target == target->id &&
- (pd->ud.attacktimer != INVALID_TIMER || pd->ud.walktimer != INVALID_TIMER))
- return 0; //Target already locked.
+ if (pd->ud.target == target->id && (pd->ud.attacktimer != INVALID_TIMER || pd->ud.walktimer != INVALID_TIMER))
+ return 0; // Target already locked.
+
+ if (target->type != BL_ITEM) { // Target is enemy. Chase or attack it.
+ if (!battle->check_range(&pd->bl, target, pd->status.rhw.range)) { // Chase enemy.
+ if (unit->walktobl(&pd->bl, target, pd->status.rhw.range, 2) == 0) // Enemy is unreachable.
+ pet->unlocktarget(pd);
- if (target->type != BL_ITEM)
- { //enemy targetted
- if(!battle->check_range(&pd->bl,target,pd->status.rhw.range)) {
- //Chase
- if(!unit->walktobl(&pd->bl, target, pd->status.rhw.range, 2))
- pet->unlocktarget(pd); //Unreachable target.
return 0;
}
- //Continuous attack.
- unit->attack(&pd->bl, pd->target_id, 1);
- } else {
- //Item Targeted, attempt loot
- if (!check_distance_bl(&pd->bl, target, 1)) {
- //Out of range
- if(!unit->walktobl(&pd->bl, target, 1, 1)) //Unreachable target.
+
+ unit->attack(&pd->bl, pd->target_id, 1); // Start/continue attacking.
+ } else { // Target is item. Attempt looting.
+ if (!check_distance_bl(&pd->bl, target, 1)) { // Item is out of range.
+ if (unit->walktobl(&pd->bl, target, 1, 1) == 0) // Item is unreachable.
pet->unlocktarget(pd);
+
return 0;
- } else{
+ }
+
+ if (pd->loot->count < pd->loot->max) {
struct flooritem_data *fitem = BL_UCAST(BL_ITEM, target);
- if(pd->loot->count < pd->loot->max){
- memcpy(&pd->loot->item[pd->loot->count++],&fitem->item_data,sizeof(pd->loot->item[0]));
- pd->loot->weight += itemdb_weight(fitem->item_data.nameid)*fitem->item_data.amount;
- map->clearflooritem(target);
- }
- //Target is unlocked regardless of whether it was picked or not.
- pet->unlocktarget(pd);
+
+ memcpy(&pd->loot->item[pd->loot->count++], &fitem->item_data, sizeof(pd->loot->item[0]));
+ pd->loot->weight += itemdb_weight(fitem->item_data.nameid) * fitem->item_data.amount;
+ map->clearflooritem(target);
}
+
+ pet->unlocktarget(pd); // Target is unlocked regardless of whether the item was picked or not.
}
+
return 0;
}
@@ -1143,45 +1238,54 @@ static int pet_lootitem_drop(struct pet_data *pd, struct map_session_data *sd)
return 1;
}
-/*==========================================
- * pet bonus giving skills [Valaris] / Rewritten by [Skotlex]
- *------------------------------------------*/
+/**
+ * Applies pet's stat bonuses to its master. (See petskillbonus() script command.)
+ *
+ * @param tid The timer ID
+ * @param tick The base amount of ticks to add to the pet's bonus timer. (The timer's current ticks when calling this fuction.)
+ * @param id The pet's master's account ID.
+ * @param data Unused.
+ * @return 1 on failure, 0 on success.
+ *
+ **/
static int pet_skill_bonus_timer(int tid, int64 tick, int id, intptr_t data)
{
- struct map_session_data *sd=map->id2sd(id);
- struct pet_data *pd;
- int bonus;
- int duration = 0;
+ struct map_session_data *sd = map->id2sd(id);
- if(sd == NULL || sd->pd==NULL || sd->pd->bonus == NULL)
+ if (sd == NULL || sd->pd == NULL || sd->pd->bonus == NULL)
return 1;
- pd=sd->pd;
+ struct pet_data *pd = sd->pd;
- if(pd->bonus->timer != tid) {
- ShowError("pet_skill_bonus_timer %d != %d\n",pd->bonus->timer,tid);
+ if (pd->bonus->timer != tid) {
+ ShowError("pet_skill_bonus_timer %d != %d\n", pd->bonus->timer, tid);
pd->bonus->timer = INVALID_TIMER;
- return 0;
+ return 1;
}
- // determine the time for the next timer
- if (pd->state.skillbonus && pd->bonus->delay > 0) {
+ int bonus;
+ int duration;
+
+ // Determine the time for the next timer.
+ if (pd->state.skillbonus == 1 && pd->bonus->delay > 0) {
bonus = 0;
- duration = pd->bonus->delay*1000; // the duration until pet bonuses will be reactivated again
- } else if (pd->pet.intimate) {
+ duration = pd->bonus->delay * 1000; // The duration until pet bonuses will be reactivated again.
+ } else if (pd->pet.intimate > PET_INTIMACY_NONE) {
bonus = 1;
- duration = pd->bonus->duration*1000; // the duration for pet bonuses to be in effect
- } else { //Lost pet...
+ duration = pd->bonus->duration * 1000; // The duration for pet bonuses to be in effect.
+ } else { // Lost pet...
pd->bonus->timer = INVALID_TIMER;
- return 0;
+ return 1;
}
if (pd->state.skillbonus != bonus) {
pd->state.skillbonus = bonus;
status_calc_pc(sd, SCO_NONE);
}
- // wait for the next timer
- pd->bonus->timer=timer->add(tick+duration,pet->skill_bonus_timer,sd->bl.id,0);
+
+ // Wait for the next timer.
+ pd->bonus->timer = timer->add(tick + duration, pet->skill_bonus_timer, sd->bl.id, 0);
+
return 0;
}
@@ -1327,115 +1431,155 @@ static int pet_read_db_libconfig(const char *filename, bool ignore_missing)
return count;
}
+/**
+ * Reads a single pet from DB.
+ *
+ * @param it The libconfig settings block, which contains the pet's data.
+ * @param n The pet's index in pet->db[].
+ * @param source The pet DB's file name.
+ * @return 0 on failure, the pet's ID on success.
+ *
+ **/
static int pet_read_db_sub(struct config_setting_t *it, int n, const char *source)
{
- struct config_setting_t *t = NULL;
- struct item_data *data = NULL;
- const char *str = NULL;
- int i32 = 0;
-
nullpo_ret(it);
nullpo_ret(source);
Assert_ret(n >= 0 && n < MAX_PET_DB);
- if (!libconfig->setting_lookup_int(it, "Id", &i32)) {
+ int i32 = 0;
+
+ if (libconfig->setting_lookup_int(it, "Id", &i32) == CONFIG_FALSE) {
ShowWarning("pet_read_db_sub: Missing Id in \"%s\", entry #%d, skipping.\n", source, n);
return 0;
}
- pet->db[n].class_ = i32;
- if (!libconfig->setting_lookup_string(it, "SpriteName", &str) || !*str ) {
- ShowWarning("pet_read_db_sub: Missing SpriteName in pet %d of \"%s\", skipping.\n", pet->db[n].class_, source);
+ if (mob->db_checkid(i32) == 0) {
+ ShowWarning("pet_read_db_sub: Invalid Id in \"%s\", entry #%d, skipping.\n", source, n);
return 0;
}
- safestrncpy(pet->db[n].name, str, sizeof(pet->db[n].name));
- if (!libconfig->setting_lookup_string(it, "Name", &str) || !*str) {
- ShowWarning("pet_read_db_sub: Missing Name in pet %d of \"%s\", skipping.\n", pet->db[n].class_, source);
+ pet->db[n].class_ = i32;
+ safestrncpy(pet->db[n].name, mob->db(i32)->sprite, sizeof(pet->db[n].name));
+
+ const char *str;
+
+ if (libconfig->setting_lookup_string(it, "Name", &str) == CONFIG_FALSE || *str == '\0') {
+ ShowWarning("pet_read_db_sub: Missing Name in pet %d of \"%s\", skipping.\n",
+ pet->db[n].class_, source);
return 0;
}
+
safestrncpy(pet->db[n].jname, str, sizeof(pet->db[n].jname));
- if (libconfig->setting_lookup_string(it, "TamingItem", &str)) {
- if (!(data = itemdb->name2id(str))) {
- ShowWarning("pet_read_db_sub: Invalid item '%s' in pet %d of \"%s\", defaulting to 0.\n", str, pet->db[n].class_, source);
- } else {
- pet->db[n].itemID = data->nameid;
- }
+ if (libconfig->setting_lookup_string(it, "EggItem", &str) == CONFIG_FALSE || *str == '\0') {
+ ShowWarning("pet_read_db_sub: Missing EggItem in pet %d of \"%s\", skipping.\n",
+ pet->db[n].class_, source);
+ return 0;
}
- if (libconfig->setting_lookup_string(it, "EggItem", &str)) {
- if (!(data = itemdb->name2id(str))) {
- ShowWarning("pet_read_db_sub: Invalid item '%s' in pet %d of \"%s\", defaulting to 0.\n", str, pet->db[n].class_, source);
- } else {
- pet->db[n].EggID = data->nameid;
- }
+ struct item_data *data;
+
+ if ((data = itemdb->name2id(str)) == NULL) {
+ ShowWarning("pet_read_db_sub: Invalid EggItem '%s' in pet %d of \"%s\", skipping.\n",
+ str, pet->db[n].class_, source);
+ return 0;
}
- if (libconfig->setting_lookup_string(it, "AccessoryItem", &str)) {
- if (!(data = itemdb->name2id(str))) {
- ShowWarning("pet_read_db_sub: Invalid item '%s' in pet %d of \"%s\", defaulting to 0.\n", str, pet->db[n].class_, source);
- } else {
- pet->db[n].AcceID = data->nameid;
- }
+ pet->db[n].EggID = data->nameid;
+
+ if (libconfig->setting_lookup_string(it, "TamingItem", &str) == CONFIG_TRUE) {
+ if ((data = itemdb->name2id(str)) == NULL)
+ ShowWarning("pet_read_db_sub: Invalid TamingItem '%s' in pet %d of \"%s\", defaulting to 0.\n",
+ str, pet->db[n].class_, source);
+ else
+ pet->db[n].itemID = data->nameid;
}
- if (libconfig->setting_lookup_string(it, "FoodItem", &str)) {
- if (!(data = itemdb->name2id(str))) {
- ShowWarning("pet_read_db_sub: Invalid item '%s' in pet %d of \"%s\", defaulting to 0.\n", str, pet->db[n].class_, source);
- } else {
+ pet->db[n].FoodID = 537;
+
+ if (libconfig->setting_lookup_string(it, "FoodItem", &str) == CONFIG_TRUE) {
+ if ((data = itemdb->name2id(str)) == NULL)
+ ShowWarning("pet_read_db_sub: Invalid FoodItem '%s' in pet %d of \"%s\", defaulting to Pet_Food (ID=537).\n",
+ str, pet->db[n].class_, source);
+ else
pet->db[n].FoodID = data->nameid;
- }
}
- if (libconfig->setting_lookup_int(it, "FoodEffectiveness", &i32))
- pet->db[n].fullness = i32;
+ if (libconfig->setting_lookup_string(it, "AccessoryItem", &str) == CONFIG_TRUE) {
+ if ((data = itemdb->name2id(str)) == NULL)
+ ShowWarning("pet_read_db_sub: Invalid AccessoryItem '%s' in pet %d of \"%s\", defaulting to 0.\n",
+ str, pet->db[n].class_, source);
+ else
+ pet->db[n].AcceID = data->nameid;
+ }
- if (libconfig->setting_lookup_int(it, "HungerDelay", &i32))
- pet->db[n].hungry_delay = i32 * 1000;
+ int ret = libconfig->setting_lookup_int(it, "FoodEffectiveness", &i32);
+ pet->db[n].fullness = (ret == CONFIG_FALSE) ? 80 : cap_value(i32, 1, PET_HUNGER_STUFFED);
- if ((t = libconfig->setting_get_member(it, "Intimacy"))) {
- if (config_setting_is_group(t)) {
- pet->read_db_sub_intimacy(n, t);
- }
- }
- if (pet->db[n].r_hungry <= 0)
- pet->db[n].r_hungry = 1;
+ ret = libconfig->setting_lookup_int(it, "HungerDelay", &i32);
+ pet->db[n].hungry_delay = (ret == CONFIG_FALSE) ? 60000 : cap_value(1000 * i32, 0, INT_MAX);
- if (libconfig->setting_lookup_int(it, "CaptureRate", &i32))
- pet->db[n].capture = i32;
+ ret = libconfig->setting_lookup_int(it, "HungerDecrement", &i32);
+ pet->db[n].hunger_decrement = (ret == CONFIG_FALSE) ? 1 : cap_value(i32, PET_HUNGER_STARVING, PET_HUNGER_STUFFED - 1);
- if (libconfig->setting_lookup_int(it, "Speed", &i32))
- pet->db[n].speed = i32;
+ if (pet->db[n].hunger_decrement == PET_HUNGER_STARVING)
+ pet->db[n].hungry_delay = 0;
- if ((t = libconfig->setting_get_member(it, "SpecialPerformance")) && (i32 = libconfig->setting_get_bool(t)))
- pet->db[n].s_perfor = (char)i32;
+ /**
+ * Preventively set default intimacy values here, just in case that 'Intimacy' block is not defined,
+ * or pet_read_db_sub_intimacy() fails execution.
+ *
+ **/
+ pet->db[n].intimate = PET_INTIMACY_NEUTRAL;
+ pet->db[n].r_hungry = 10;
+ pet->db[n].r_full = 100;
+ pet->db[n].die = 20;
+ pet->db[n].starving_delay = min(20000, pet->db[n].hungry_delay);
+ pet->db[n].starving_decrement = 20;
- if ((t = libconfig->setting_get_member(it, "TalkWithEmotes")) && (i32 = libconfig->setting_get_bool(t)))
- pet->db[n].talk_convert_class = i32;
+ struct config_setting_t *t;
- if (libconfig->setting_lookup_int(it, "AttackRate", &i32))
- pet->db[n].attack_rate = i32;
+ if ((t = libconfig->setting_get_member(it, "Intimacy")) != NULL && config_setting_is_group(t))
+ pet->read_db_sub_intimacy(n, t);
- if (libconfig->setting_lookup_int(it, "DefendRate", &i32))
- pet->db[n].defence_attack_rate = i32;
+ ret = libconfig->setting_lookup_int(it, "CaptureRate", &i32);
+ pet->db[n].capture = (ret == CONFIG_FALSE) ? 1000 : cap_value(i32, 1, 10000);
- if (libconfig->setting_lookup_int(it, "ChangeTargetRate", &i32))
- pet->db[n].change_target_rate = i32;
+ ret = libconfig->setting_lookup_int(it, "Speed", &i32);
+ pet->db[n].speed = (ret == CONFIG_FALSE) ? DEFAULT_WALK_SPEED : cap_value(i32, MIN_WALK_SPEED, MAX_WALK_SPEED);
- // Pet Evolution
- if ((t = libconfig->setting_get_member(it, "Evolve")) && config_setting_is_group(t)) {
- pet->read_db_sub_evolution(t, n);
+ if ((t = libconfig->setting_get_member(it, "SpecialPerformance")) != NULL
+ && (i32 = libconfig->setting_get_bool(t)) != 0) {
+ pet->db[n].s_perfor = (char)i32;
}
- if ((t = libconfig->setting_get_member(it, "AutoFeed")) && (i32 = libconfig->setting_get_bool(t)))
+ if ((t = libconfig->setting_get_member(it, "TalkWithEmotes")) != NULL
+ && (i32 = libconfig->setting_get_bool(t)) != 0) {
+ pet->db[n].talk_convert_class = i32;
+ }
+
+ ret = libconfig->setting_lookup_int(it, "AttackRate", &i32);
+ pet->db[n].attack_rate = (ret == CONFIG_FALSE) ? 300 : cap_value(i32, 0, 10000);
+
+ ret = libconfig->setting_lookup_int(it, "DefendRate", &i32);
+ pet->db[n].defence_attack_rate = (ret == CONFIG_FALSE) ? 300 : cap_value(i32, 0, 10000);
+
+ ret = libconfig->setting_lookup_int(it, "ChangeTargetRate", &i32);
+ pet->db[n].change_target_rate = (ret == CONFIG_FALSE) ? 800 : cap_value(i32, 0, 10000);
+
+ if ((t = libconfig->setting_get_member(it, "AutoFeed")) != NULL && (i32 = libconfig->setting_get_bool(t)) != 0)
pet->db[n].autofeed = i32;
- if (libconfig->setting_lookup_string(it, "PetScript", &str))
- pet->db[n].pet_script = *str ? script->parse(str, source, -pet->db[n].class_, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
+ pet->db[n].pet_script = NULL;
+ if (libconfig->setting_lookup_string(it, "PetScript", &str) == CONFIG_TRUE && *str != '\0')
+ pet->db[n].pet_script = script->parse(str, source, -pet->db[n].class_, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL);
+
+ pet->db[n].equip_script = NULL;
+ if (libconfig->setting_lookup_string(it, "EquipScript", &str) == CONFIG_TRUE && *str != '\0')
+ pet->db[n].equip_script = script->parse(str, source, -pet->db[n].class_, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL);
- if (libconfig->setting_lookup_string(it, "EquipScript", &str))
- pet->db[n].equip_script = *str ? script->parse(str, source, -pet->db[n].class_, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
+ if ((t = libconfig->setting_get_member(it, "Evolve")) != NULL && config_setting_is_group(t))
+ pet->read_db_sub_evolution(t, n);
return pet->db[n].class_;
}
@@ -1515,24 +1659,41 @@ static void pet_read_db_sub_evolution(struct config_setting_t *t, int n)
}
}
+/**
+ * Reads a pet's intimacy data from DB.
+ *
+ * @param idx The pet's index in pet->db[].
+ * @param t The libconfig settings block, which contains the pet's intimacy data.
+ * @return false on failure, true on success.
+ *
+ **/
static bool pet_read_db_sub_intimacy(int idx, struct config_setting_t *t)
{
+ nullpo_retr(false, t);
+ Assert_retr(false, idx >= 0 && idx < MAX_PET_DB);
+
int i32 = 0;
- nullpo_retr(false, t);
- Assert_ret(idx >= 0 && idx < MAX_PET_DB);
+ if (libconfig->setting_lookup_int(t, "Initial", &i32) == CONFIG_TRUE)
+ pet->db[idx].intimate = cap_value(i32, PET_INTIMACY_AWKWARD, PET_INTIMACY_MAX);
+
+ if (libconfig->setting_lookup_int(t, "FeedIncrement", &i32) == CONFIG_TRUE)
+ pet->db[idx].r_hungry = cap_value(i32, PET_INTIMACY_AWKWARD, PET_INTIMACY_MAX);
+
+ if (libconfig->setting_lookup_int(t, "OverFeedDecrement", &i32) == CONFIG_TRUE)
+ pet->db[idx].r_full = cap_value(i32, PET_INTIMACY_NONE, PET_INTIMACY_MAX);
- if (libconfig->setting_lookup_int(t, "Initial", &i32))
- pet->db[idx].intimate = i32;
+ if (libconfig->setting_lookup_int(t, "OwnerDeathDecrement", &i32) == CONFIG_TRUE)
+ pet->db[idx].die = cap_value(i32, PET_INTIMACY_NONE, PET_INTIMACY_MAX);
- if (libconfig->setting_lookup_int(t, "FeedIncrement", &i32))
- pet->db[idx].r_hungry = i32;
+ if (libconfig->setting_lookup_int(t, "StarvingDelay", &i32) == CONFIG_TRUE)
+ pet->db[idx].starving_delay = cap_value(1000 * i32, 0, pet->db[idx].hungry_delay);
- if (libconfig->setting_lookup_int(t, "OverFeedDecrement", &i32))
- pet->db[idx].r_full = i32;
+ if (libconfig->setting_lookup_int(t, "StarvingDecrement", &i32) == CONFIG_TRUE)
+ pet->db[idx].starving_decrement = cap_value(i32, PET_INTIMACY_NONE, PET_INTIMACY_MAX);
- if (libconfig->setting_lookup_int(t, "OwnerDeathDecrement", &i32))
- pet->db[idx].die = i32;
+ if (pet->db[idx].starving_decrement == PET_INTIMACY_NONE)
+ pet->db[idx].starving_delay = 0;
return true;
}
@@ -1626,6 +1787,7 @@ void pet_defaults(void)
pet->final = do_final_pet;
pet->hungry_val = pet_hungry_val;
+ pet->set_hunger = pet_set_hunger;
pet->set_intimate = pet_set_intimate;
pet->create_egg = pet_create_egg;
pet->unlocktarget = pet_unlocktarget;
diff --git a/src/map/pet.h b/src/map/pet.h
index e0a5529a6..fa37e896a 100644
--- a/src/map/pet.h
+++ b/src/map/pet.h
@@ -57,6 +57,9 @@ struct s_pet_db {
int defence_attack_rate;
int change_target_rate;
int autofeed;
+ int hunger_decrement;
+ int starving_delay;
+ int starving_decrement;
struct script_code *equip_script;
struct script_code *pet_script;
@@ -143,6 +146,7 @@ struct pet_interface {
int (*final) (void);
/* */
int (*hungry_val) (struct pet_data *pd);
+ void (*set_hunger) (struct pet_data *pd, int value);
void (*set_intimate) (struct pet_data *pd, int value);
int (*create_egg) (struct map_session_data *sd, int item_id);
int (*unlocktarget) (struct pet_data *pd);
diff --git a/src/map/script.c b/src/map/script.c
index d575c5925..ca13e8861 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -19411,26 +19411,25 @@ static BUILDIN(getunittype)
/**
* Sets real-time unit data for a game object.
- * Setunitdata <GUID>,<DataType>,<Val1>{,<Val2>,<Val3>}
+ *
+ * @code{.herc}
+ * setunitdata <GUID>, <DataType>, <Val1>{, <Val2>, <Val3>}
+ * @endcode
+ *
* @param1 GUID GID of the unit.
* @param2 DataType Type of Data to be set for the unit.
* @param3 Value#1 Value to be passed as change in data.
* @param4 Value#2 Optional int value to be passed for certain data types.
* @param5 Value#3 Optional int value to be passed for certain data types.
* @return 1 on success, 0 on failure.
-
- Note: Please make this script command only modify ONE INTEGER value.
- If need to modify string type data, or having multiple arguments, please
- introduce a new script command.
- */
+ *
+ * Note: Please make this script command only modify ONE INTEGER value.
+ * If need to modify string type data, or having multiple arguments, please introduce a new script command.
+ *
+ **/
static BUILDIN(setunitdata)
{
- struct block_list *bl = NULL;
- const char *mapname = NULL, *udtype = NULL;
- int type = 0, val = 0, val2 = 0, val3 = 0;
- struct map_session_data *tsd = NULL;
-
- bl = map->id2bl(script_getnum(st, 2));
+ struct block_list *bl = map->id2bl(script_getnum(st, 2));
if (bl == NULL) {
ShowWarning("buildin_setunitdata: Error in finding object with given GID %d!\n", script_getnum(st, 2));
@@ -19438,22 +19437,26 @@ static BUILDIN(setunitdata)
return false;
}
- type = script_getnum(st, 3);
+ int type = script_getnum(st, 3);
- /* type bounds */
+ // Type bounds.
if (type < UDT_SIZE || type >= UDT_MAX) { // Note: UDT_TYPE is not valid here
ShowError("buildin_setunitdata: Invalid unit data type %d provided.\n", type);
script_pushint(st, 0);
return false;
}
- /* Mandatory Argument 3. Subject to deprecate. */
+ const char *mapname = NULL;
+ int val = 0;
+
+ // Mandatory argument #3. Subject to deprecate.
if (type == UDT_MAPIDXY) {
if (!script_isstringtype(st, 4)) {
ShowError("buildin_setunitdata: Invalid data type for argument #3.\n");
script_pushint(st, 0);
return false;
}
+
mapname = script_getstr(st, 4);
} else {
if (script_isstringtype(st, 4)) {
@@ -19461,68 +19464,87 @@ static BUILDIN(setunitdata)
script_pushint(st, 0);
return false;
}
+
val = script_getnum(st, 4);
}
-/* checks if value is out of bounds. */
+
+/****************************************************************************************************
+ * Define temporary macros. [BEGIN]
+ ****************************************************************************************************/
+
+// Checks if value is out of bounds.
#define setunitdata_check_bounds(arg, min, max) \
do { \
if (script_getnum(st, (arg)) < (min) || script_getnum(st, (arg)) > (max)) { \
- ShowError("buildin_setunitdata: Invalid value %d for argument #%d. (min: %d, max: %d)\n", script_getnum(st, (arg)), (arg)-1, (min), (max)); \
+ ShowError("buildin_setunitdata: Invalid value %d for argument #%d. (min: %d, max: %d)\n", \
+ script_getnum(st, (arg)), (arg) - 1, (min), (max)); \
script_pushint(st, 0); \
return false; \
} \
} while(0);
-/* checks if value is out of bounds. */
+
+// Checks if value is too low.
#define setunitdata_check_min(arg, min) \
do { \
if (script_getnum(st, (arg)) < (min)) { \
- ShowError("buildin_setunitdata: Invalid value %d for argument #%d. (min: %d)\n", script_getnum(st, (arg)), (arg)-1, (min)); \
+ ShowError("buildin_setunitdata: Invalid value %d for argument #%d. (min: %d)\n", \
+ script_getnum(st, (arg)), (arg) - 1, (min)); \
script_pushint(st, 0); \
return false; \
} \
} while(0);
-/* checks if the argument doesn't exist, if required.
- * also checks if the argument exists, if not required. */
+
+// Checks if the argument doesn't exist, if required. Also checks if the argument exists, if not required.
#define setunitdata_assert_arg(arg, required) \
do { \
if (required && !script_hasdata(st, (arg))) { \
- ShowError("buildin_setunitdata: Type %d reqires argument #%d.\n", type, (arg)-1); \
+ ShowError("buildin_setunitdata: Type %d reqires argument #%d.\n", type, (arg) - 1); \
script_pushint(st, 0); \
return false; \
} else if (!required && script_hasdata(st, arg)) { \
- ShowError("buildin_setunitdata: Argument %d is not required for type %d.\n", (arg)-1, type); \
+ ShowError("buildin_setunitdata: Argument %d is not required for type %d.\n", (arg) - 1, type); \
script_pushint(st, 0); \
return false; \
} \
} while (0);
-/* checks if the data is an integer. */
+
+// Checks if the data is an integer.
#define setunitdata_check_int(arg) \
do { \
setunitdata_assert_arg((arg), true); \
if (script_isstringtype(st, (arg))) { \
- ShowError("buildin_setunitdata: Argument #%d expects integer, string given.\n", (arg)-1); \
+ ShowError("buildin_setunitdata: Argument #%d expects integer, string given.\n", (arg) - 1); \
script_pushint(st, 0); \
return false; \
} \
} while(0);
-/* checks if the data is a string. */
+
+// Checks if the data is a string.
#define setunitdata_check_string(arg) \
do { \
setunitdata_assert_arg((arg), true); \
if (script_isinttype(st, (arg))) { \
- ShowError("buildin_setunitdata: Argument #%d expects string, integer given.\n", (arg)-1); \
+ ShowError("buildin_setunitdata: Argument #%d expects string, integer given.\n", (arg) - 1); \
script_pushint(st, 0); \
return false; \
} \
} while(0);
+/****************************************************************************************************
+ * Define temporary macros. [END]
+ ****************************************************************************************************/
+
if (type != UDT_MAPIDXY && type != UDT_WALKTOXY) {
setunitdata_assert_arg(5, false);
setunitdata_assert_arg(6, false);
}
- switch (type)
- {
+ int val2 = 0;
+ int val3 = 0;
+
+ struct map_session_data *tsd = NULL;
+
+ switch (type) {
case UDT_SIZE:
setunitdata_check_bounds(4, SZ_SMALL, SZ_BIG);
break;
@@ -19548,30 +19570,36 @@ static BUILDIN(setunitdata)
case UDT_MASTERAID:
setunitdata_check_min(4, 0);
tsd = map->id2sd(val);
+
if (tsd == NULL) {
- ShowWarning("buildin_setunitdata: Account ID %d not found for master change!\n",val);
+ ShowWarning("buildin_setunitdata: Account ID %d not found for master change!\n", val);
script_pushint(st, 0);
return false;
}
+
break;
case UDT_MASTERCID:
setunitdata_check_min(4, 0);
tsd = map->charid2sd(val);
+
if (tsd == NULL) {
- ShowWarning("buildin_setunitdata: Character ID %d not found for master change!\n",val);
+ ShowWarning("buildin_setunitdata: Character ID %d not found for master change!\n", val);
script_pushint(st, 0);
return false;
}
+
break;
case UDT_MAPIDXY:
- if ((val = map->mapname2mapid(mapname)) == -1) {
+ if ((val = map->mapname2mapid(mapname)) == INDEX_NOT_FOUND) {
ShowError("buildin_setunitdata: Non-existent map %s provided.\n", mapname);
+ script_pushint(st, 0);
return false;
}
+
setunitdata_check_int(5);
setunitdata_check_int(6);
- setunitdata_check_bounds(5, 0, MAX_MAP_SIZE/2);
- setunitdata_check_bounds(6, 0, MAX_MAP_SIZE/2);
+ setunitdata_check_bounds(5, 0, MAX_MAP_SIZE / 2);
+ setunitdata_check_bounds(6, 0, MAX_MAP_SIZE / 2);
val2 = script_getnum(st, 5);
val3 = script_getnum(st, 6);
break;
@@ -19579,8 +19607,8 @@ static BUILDIN(setunitdata)
setunitdata_assert_arg(6, false);
setunitdata_check_int(5);
val2 = script_getnum(st, 5);
- setunitdata_check_bounds(4, 0, MAX_MAP_SIZE/2);
- setunitdata_check_bounds(5, 0, MAX_MAP_SIZE/2);
+ setunitdata_check_bounds(4, 0, MAX_MAP_SIZE / 2);
+ setunitdata_check_bounds(5, 0, MAX_MAP_SIZE / 2);
break;
case UDT_SPEED:
setunitdata_check_bounds(4, 0, MAX_WALK_SPEED);
@@ -19635,7 +19663,7 @@ static BUILDIN(setunitdata)
setunitdata_check_bounds(4, 0, SHRT_MAX);
break;
case UDT_HUNGER:
- setunitdata_check_bounds(4, 0, 99);
+ setunitdata_check_bounds(4, PET_HUNGER_STARVING, PET_HUNGER_STUFFED); // Pets and Homunculi have the same hunger value bounds.
break;
case UDT_RACE:
case UDT_ELETYPE:
@@ -19643,19 +19671,20 @@ static BUILDIN(setunitdata)
setunitdata_check_bounds(4, 0, CHAR_MAX);
break;
case UDT_GROUP:
- {
setunitdata_check_bounds(4, 0, INT_MAX);
+
struct unit_data *ud = unit->bl2ud2(bl);
+
if (ud == NULL) {
ShowError("buildin_setunitdata: ud is NULL!\n");
script_pushint(st, 0);
return false;
}
+
ud->groupId = script_getnum(st, 4);
clif->blname_ack(0, bl); // Send update to client.
script_pushint(st, 1);
return true;
- }
case UDT_DAMAGE_TAKEN_RATE:
setunitdata_check_bounds(4, 1, INT_MAX);
break;
@@ -19663,67 +19692,81 @@ static BUILDIN(setunitdata)
break;
}
+/****************************************************************************************************
+ * Undefine temporary macros. [BEGIN]
+ ****************************************************************************************************/
+
#undef setunitdata_check_bounds
+#undef setunitdata_check_min
#undef setunitdata_assert_arg
#undef setunitdata_check_int
#undef setunitdata_check_string
- /* Set the values */
+/****************************************************************************************************
+ * Undefine temporary macros. [END]
+ ****************************************************************************************************/
+
+ // Set the values.
switch (bl->type) {
- case BL_MOB:
- {
+ case BL_MOB: {
struct mob_data *md = BL_UCAST(BL_MOB, bl);
- nullpo_retr(false, md);
- switch (type)
- {
+ if (md == NULL) {
+ ShowError("buildin_setunitdata: Can't find monster for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
+
+ switch (type) {
case UDT_SIZE:
- md->status.size = (unsigned char) val;
+ md->status.size = (unsigned char)val;
break;
case UDT_LEVEL:
md->level = val;
- if (battle_config.show_mob_info & 4)
+
+ if ((battle_config.show_mob_info & 4) != 0)
clif->blname_ack(0, &md->bl);
+
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
clif->blname_ack(0, &md->bl);
break;
case UDT_MAXHP:
- md->status.max_hp = (unsigned int) val;
+ md->status.max_hp = (unsigned int)val;
clif->blname_ack(0, &md->bl);
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- md->status.max_sp = (unsigned int) val;
+ md->status.max_sp = (unsigned int)val;
break;
case UDT_MASTERAID:
md->master_id = val;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- md->status.speed = (unsigned short) val;
+ md->status.speed = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_MODE:
- md->status.mode = (enum e_mode) val;
+ md->status.mode = (enum e_mode)val;
break;
case UDT_AI:
- md->special_state.ai = (enum ai) val;
+ md->special_state.ai = (enum ai)val;
break;
case UDT_SCOPTION:
- md->sc.option = (unsigned int) val;
+ md->sc.option = (unsigned int)val;
break;
case UDT_SEX:
- md->vd->sex = (char) val;
+ md->vd->sex = (char)val;
break;
case UDT_CLASS:
mob->class_change(md, val);
@@ -19759,112 +19802,115 @@ static BUILDIN(setunitdata)
md->ud.canmove_tick = val;
break;
case UDT_STR:
- md->status.str = (unsigned short) val;
+ md->status.str = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_AGI:
- md->status.agi = (unsigned short) val;
+ md->status.agi = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_VIT:
- md->status.vit = (unsigned short) val;
+ md->status.vit = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_INT:
- md->status.int_ = (unsigned short) val;
+ md->status.int_ = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_DEX:
- md->status.dex = (unsigned short) val;
+ md->status.dex = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_LUK:
- md->status.luk = (unsigned short) val;
+ md->status.luk = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_ATKRANGE:
- md->status.rhw.range = (unsigned short) val;
+ md->status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- md->status.rhw.atk = (unsigned short) val;
+ md->status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- md->status.rhw.atk2 = (unsigned short) val;
+ md->status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- md->status.matk_min = (unsigned short) val;
+ md->status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- md->status.matk_max = (unsigned short) val;
+ md->status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- md->status.def = (defType) val;
+ md->status.def = (defType)val;
break;
case UDT_MDEF:
- md->status.mdef = (defType) val;
+ md->status.mdef = (defType)val;
break;
case UDT_HIT:
- md->status.hit = (short) val;
+ md->status.hit = (short)val;
break;
case UDT_FLEE:
- md->status.flee = (short) val;
+ md->status.flee = (short)val;
break;
case UDT_PDODGE:
- md->status.flee2 = (short) val;
+ md->status.flee2 = (short)val;
break;
case UDT_CRIT:
- md->status.cri = (short) val;
+ md->status.cri = (short)val;
break;
case UDT_RACE:
- md->status.race = (unsigned char) val;
+ md->status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- md->status.def_ele = (unsigned char) val;
+ md->status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- md->status.ele_lv = (unsigned char) val;
+ md->status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- md->status.amotion = (unsigned short) val;
+ md->status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- md->status.adelay = (unsigned short) val;
+ md->status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- md->status.dmotion = (unsigned short) val;
+ md->status.dmotion = (unsigned short)val;
break;
case UDT_DAMAGE_TAKEN_RATE:
- md->dmg_taken_rate = (int) val;
+ md->dmg_taken_rate = (int)val;
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for mob unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for mob unit.\n", type);
script_pushint(st, 0);
return false;
}
- }
+
break;
- case BL_HOM:
- {
+ }
+ case BL_HOM: {
struct homun_data *hd = BL_UCAST(BL_HOM, bl);
- nullpo_retr(false, hd);
+ if (hd == NULL) {
+ ShowError("buildin_setunitdata: Can't find Homunculus for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- hd->base_status.size = (unsigned char) val;
+ hd->base_status.size = (unsigned char)val;
break;
case UDT_LEVEL:
- hd->homunculus.level = (short) val;
+ hd->homunculus.level = (short)val;
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
hd->homunculus.max_hp = val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
hd->homunculus.max_sp = val;
@@ -19874,14 +19920,14 @@ static BUILDIN(setunitdata)
hd->master = tsd;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- hd->base_status.speed = (unsigned short) val;
+ hd->base_status.speed = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_LOOKDIR:
@@ -19891,136 +19937,138 @@ static BUILDIN(setunitdata)
hd->ud.canmove_tick = val;
break;
case UDT_STR:
- hd->base_status.str = (unsigned short) val;
+ hd->base_status.str = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_AGI:
- hd->base_status.agi = (unsigned short) val;
+ hd->base_status.agi = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_VIT:
- hd->base_status.vit = (unsigned short) val;
+ hd->base_status.vit = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_INT:
- hd->base_status.int_ = (unsigned short) val;
+ hd->base_status.int_ = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_DEX:
- hd->base_status.dex = (unsigned short) val;
+ hd->base_status.dex = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_LUK:
- hd->base_status.luk = (unsigned short) val;
+ hd->base_status.luk = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_ATKRANGE:
- hd->base_status.rhw.range = (unsigned short) val;
+ hd->base_status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- hd->base_status.rhw.atk = (unsigned short) val;
+ hd->base_status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- hd->base_status.rhw.atk2 = (unsigned short) val;
+ hd->base_status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- hd->base_status.matk_min = (unsigned short) val;
+ hd->base_status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- hd->base_status.matk_max = (unsigned short) val;
+ hd->base_status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- hd->base_status.def = (defType) val;
+ hd->base_status.def = (defType)val;
break;
case UDT_MDEF:
- hd->base_status.mdef = (defType) val;
+ hd->base_status.mdef = (defType)val;
break;
case UDT_HIT:
- hd->base_status.hit = (short) val;
+ hd->base_status.hit = (short)val;
break;
case UDT_FLEE:
- hd->base_status.flee = (short) val;
+ hd->base_status.flee = (short)val;
break;
case UDT_PDODGE:
- hd->base_status.flee2 = (short) val;
+ hd->base_status.flee2 = (short)val;
break;
case UDT_CRIT:
- hd->base_status.cri = (short) val;
+ hd->base_status.cri = (short)val;
break;
case UDT_RACE:
- hd->base_status.race = (unsigned char) val;
+ hd->base_status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- hd->base_status.def_ele = (unsigned char) val;
+ hd->base_status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- hd->base_status.ele_lv = (unsigned char) val;
+ hd->base_status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- hd->base_status.amotion = (unsigned short) val;
+ hd->base_status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- hd->base_status.adelay = (unsigned short) val;
+ hd->base_status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- hd->base_status.dmotion = (unsigned short) val;
+ hd->base_status.dmotion = (unsigned short)val;
break;
case UDT_HUNGER:
- hd->homunculus.hunger = (short) val;
+ hd->homunculus.hunger = (short)val;
clif->send_homdata(hd->master, SP_HUNGRY, hd->homunculus.hunger);
break;
case UDT_INTIMACY:
- homun->add_intimacy(hd, (unsigned int) val);
+ homun->add_intimacy(hd, (unsigned int)val);
clif->send_homdata(hd->master, SP_INTIMATE, hd->homunculus.intimacy / 100);
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for homunculus unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for homunculus unit.\n", type);
script_pushint(st, 0);
return false;
}
- clif->send_homdata(hd->master, SP_ACK, 0); // send homun data
- }
+ clif->send_homdata(hd->master, SP_ACK, 0); // Send Homunculus data.
break;
- case BL_PET:
- {
+ }
+ case BL_PET: {
struct pet_data *pd = BL_UCAST(BL_PET, bl);
- nullpo_retr(false, pd);
+ if (pd == NULL) {
+ ShowError("buildin_setunitdata: Can't find pet for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- pd->status.size = (unsigned char) val;
+ pd->status.size = (unsigned char)val;
break;
case UDT_LEVEL:
- pd->pet.level = (short) val;
+ pd->pet.level = (short)val;
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
- pd->status.max_hp = (unsigned int) val;
+ pd->status.max_hp = (unsigned int)val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- pd->status.max_sp = (unsigned int) val;
+ pd->status.max_sp = (unsigned int)val;
break;
case UDT_MASTERAID:
pd->pet.account_id = val;
pd->msd = tsd;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- pd->status.speed = (unsigned short) val;
+ pd->status.speed = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_LOOKDIR:
@@ -20030,130 +20078,133 @@ static BUILDIN(setunitdata)
pd->ud.canmove_tick = val;
break;
case UDT_STR:
- pd->status.str = (unsigned short) val;
+ pd->status.str = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_AGI:
- pd->status.agi = (unsigned short) val;
+ pd->status.agi = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_VIT:
- pd->status.vit = (unsigned short) val;
+ pd->status.vit = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_INT:
- pd->status.int_ = (unsigned short) val;
+ pd->status.int_ = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_DEX:
- pd->status.dex = (unsigned short) val;
+ pd->status.dex = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_LUK:
- pd->status.luk = (unsigned short) val;
+ pd->status.luk = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_ATKRANGE:
- pd->status.rhw.range = (unsigned short) val;
+ pd->status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- pd->status.rhw.atk = (unsigned short) val;
+ pd->status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- pd->status.rhw.atk2 = (unsigned short) val;
+ pd->status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- pd->status.matk_min = (unsigned short) val;
+ pd->status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- pd->status.matk_max = (unsigned short) val;
+ pd->status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- pd->status.def = (defType) val;
+ pd->status.def = (defType)val;
break;
case UDT_MDEF:
- pd->status.mdef = (defType) val;
+ pd->status.mdef = (defType)val;
break;
case UDT_HIT:
- pd->status.hit = (short) val;
+ pd->status.hit = (short)val;
break;
case UDT_FLEE:
- pd->status.flee = (short) val;
+ pd->status.flee = (short)val;
break;
case UDT_PDODGE:
- pd->status.flee2 = (short) val;
+ pd->status.flee2 = (short)val;
break;
case UDT_CRIT:
- pd->status.cri = (short) val;
+ pd->status.cri = (short)val;
break;
case UDT_RACE:
- pd->status.race = (unsigned char) val;
+ pd->status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- pd->status.def_ele = (unsigned char) val;
+ pd->status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- pd->status.ele_lv = (unsigned char) val;
+ pd->status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- pd->status.amotion = (unsigned short) val;
+ pd->status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- pd->status.adelay = (unsigned short) val;
+ pd->status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- pd->status.dmotion = (unsigned short) val;
+ pd->status.dmotion = (unsigned short)val;
break;
case UDT_INTIMACY:
pet->set_intimate(pd, val);
clif->send_petdata(pd->msd, pd, 1, pd->pet.intimate);
break;
case UDT_HUNGER:
- pd->pet.hungry = (short) val;
+ pet->set_hunger(pd, val);
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for pet unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for pet unit.\n", type);
script_pushint(st, 0);
return false;
}
- clif->send_petstatus(pd->msd); // send pet data
- }
+
+ clif->send_petstatus(pd->msd); // Send pet data.
break;
- case BL_MER:
- {
+ }
+ case BL_MER: {
struct mercenary_data *mc = BL_UCAST(BL_MER, bl);
- nullpo_retr(false, mc);
+ if (mc == NULL) {
+ ShowError("buildin_setunitdata: Can't find mercenary for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- mc->base_status.size = (unsigned char) val;
+ mc->base_status.size = (unsigned char)val;
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
- mc->base_status.max_hp = (unsigned int) val;
+ mc->base_status.max_hp = (unsigned int)val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- mc->base_status.max_sp = (unsigned int) val;
+ mc->base_status.max_sp = (unsigned int)val;
break;
case UDT_MASTERCID:
mc->mercenary.char_id = val;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- mc->base_status.size = (unsigned char) val;
+ mc->base_status.size = (unsigned char)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_LOOKDIR:
@@ -20163,131 +20214,134 @@ static BUILDIN(setunitdata)
mc->ud.canmove_tick = val;
break;
case UDT_STR:
- mc->base_status.str = (unsigned short) val;
+ mc->base_status.str = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_AGI:
- mc->base_status.agi = (unsigned short) val;
+ mc->base_status.agi = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_VIT:
- mc->base_status.vit = (unsigned short) val;
+ mc->base_status.vit = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_INT:
- mc->base_status.int_ = (unsigned short) val;
+ mc->base_status.int_ = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_DEX:
- mc->base_status.dex = (unsigned short) val;
+ mc->base_status.dex = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_LUK:
- mc->base_status.luk = (unsigned short) val;
+ mc->base_status.luk = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_ATKRANGE:
- mc->base_status.rhw.range = (unsigned short) val;
+ mc->base_status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- mc->base_status.rhw.atk = (unsigned short) val;
+ mc->base_status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- mc->base_status.rhw.atk2 = (unsigned short) val;
+ mc->base_status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- mc->base_status.matk_min = (unsigned short) val;
+ mc->base_status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- mc->base_status.matk_max = (unsigned short) val;
+ mc->base_status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- mc->base_status.def = (defType) val;
+ mc->base_status.def = (defType)val;
break;
case UDT_MDEF:
- mc->base_status.mdef = (defType) val;
+ mc->base_status.mdef = (defType)val;
break;
case UDT_HIT:
- mc->base_status.hit = (short) val;
+ mc->base_status.hit = (short)val;
break;
case UDT_FLEE:
- mc->base_status.flee = (short) val;
+ mc->base_status.flee = (short)val;
break;
case UDT_PDODGE:
- mc->base_status.flee2 = (short) val;
+ mc->base_status.flee2 = (short)val;
break;
case UDT_CRIT:
- mc->base_status.cri = (short) val;
+ mc->base_status.cri = (short)val;
break;
case UDT_RACE:
- mc->base_status.race = (unsigned char) val;
+ mc->base_status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- mc->base_status.def_ele = (unsigned char) val;
+ mc->base_status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- mc->base_status.ele_lv = (unsigned char) val;
+ mc->base_status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- mc->base_status.amotion = (unsigned short) val;
+ mc->base_status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- mc->base_status.adelay = (unsigned short) val;
+ mc->base_status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- mc->base_status.dmotion = (unsigned short) val;
+ mc->base_status.dmotion = (unsigned short)val;
break;
case UDT_MERC_KILLCOUNT:
- mc->mercenary.kill_count = (unsigned int) val;
+ mc->mercenary.kill_count = (unsigned int)val;
break;
case UDT_LIFETIME:
- mc->mercenary.life_time = (unsigned int) val;
+ mc->mercenary.life_time = (unsigned int)val;
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for mercenary unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for mercenary unit.\n", type);
script_pushint(st, 0);
return false;
}
+ // Send mercenary data.
clif->mercenary_info(map->charid2sd(mc->mercenary.char_id));
clif->mercenary_skillblock(map->charid2sd(mc->mercenary.char_id));
- }
break;
- case BL_ELEM:
- {
+ }
+ case BL_ELEM: {
struct elemental_data *ed = BL_UCAST(BL_ELEM, bl);
- nullpo_retr(false, ed);
+ if (ed == NULL) {
+ ShowError("buildin_setunitdata: Can't find Elemental for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- ed->base_status.size = (unsigned char) val;
+ ed->base_status.size = (unsigned char)val;
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
- ed->base_status.max_hp = (unsigned int) val;
+ ed->base_status.max_hp = (unsigned int)val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- ed->base_status.max_sp = (unsigned int) val;
+ ed->base_status.max_sp = (unsigned int)val;
break;
case UDT_MASTERCID:
ed->elemental.char_id = val;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- ed->base_status.speed = (unsigned short) val;
+ ed->base_status.speed = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_LOOKDIR:
@@ -20297,211 +20351,214 @@ static BUILDIN(setunitdata)
ed->ud.canmove_tick = val;
break;
case UDT_STR:
- ed->base_status.str = (unsigned short) val;
+ ed->base_status.str = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_AGI:
- ed->base_status.agi = (unsigned short) val;
+ ed->base_status.agi = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_VIT:
- ed->base_status.vit = (unsigned short) val;
+ ed->base_status.vit = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_INT:
- ed->base_status.int_ = (unsigned short) val;
+ ed->base_status.int_ = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_DEX:
- ed->base_status.dex = (unsigned short) val;
+ ed->base_status.dex = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_LUK:
- ed->base_status.luk = (unsigned short) val;
+ ed->base_status.luk = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_ATKRANGE:
- ed->base_status.rhw.range = (unsigned short) val;
+ ed->base_status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- ed->base_status.rhw.atk = (unsigned short) val;
+ ed->base_status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- ed->base_status.rhw.atk2 = (unsigned short) val;
+ ed->base_status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- ed->base_status.matk_min = (unsigned short) val;
+ ed->base_status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- ed->base_status.matk_max = (unsigned short) val;
+ ed->base_status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- ed->base_status.def = (defType) val;
+ ed->base_status.def = (defType)val;
break;
case UDT_MDEF:
- ed->base_status.mdef = (defType) val;
+ ed->base_status.mdef = (defType)val;
break;
case UDT_HIT:
- ed->base_status.hit = (short) val;
+ ed->base_status.hit = (short)val;
break;
case UDT_FLEE:
- ed->base_status.flee = (short) val;
+ ed->base_status.flee = (short)val;
break;
case UDT_PDODGE:
- ed->base_status.flee2 = (short) val;
+ ed->base_status.flee2 = (short)val;
break;
case UDT_CRIT:
- ed->base_status.cri = (short) val;
+ ed->base_status.cri = (short)val;
break;
case UDT_RACE:
- ed->base_status.race = (unsigned char) val;
+ ed->base_status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- ed->base_status.def_ele = (unsigned char) val;
+ ed->base_status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- ed->base_status.ele_lv = (unsigned char) val;
+ ed->base_status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- ed->base_status.amotion = (unsigned short) val;
+ ed->base_status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- ed->base_status.adelay = (unsigned short) val;
+ ed->base_status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- ed->base_status.dmotion = (unsigned short) val;
+ ed->base_status.dmotion = (unsigned short)val;
break;
case UDT_LIFETIME:
ed->elemental.life_time = val;
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for elemental unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for elemental unit.\n", type);
script_pushint(st, 0);
return false;
}
- clif->elemental_info(ed->master);
- }
+
+ clif->elemental_info(ed->master); // Send Elemental data.
break;
- case BL_NPC:
- {
+ }
+ case BL_NPC: {
struct npc_data *nd = BL_UCAST(BL_NPC, bl);
- nullpo_retr(false, nd);
+ if (nd == NULL) {
+ ShowError("buildin_setunitdata: Can't find NPC for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- nd->status.size = (unsigned char) val;
+ nd->status.size = (unsigned char)val;
break;
case UDT_LEVEL:
- nd->level = (unsigned short) val;
+ nd->level = (unsigned short)val;
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
- nd->status.max_hp = (unsigned int) val;
+ nd->status.max_hp = (unsigned int)val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- nd->status.max_sp = (unsigned int) val;
+ nd->status.max_sp = (unsigned int)val;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_CLASS:
- npc->setclass(nd, (short) val);
+ npc->setclass(nd, (short)val);
break;
case UDT_SPEED:
- nd->speed = (short) val;
+ nd->speed = (short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_LOOKDIR:
unit->set_dir(bl, (enum unit_dir)val);
break;
case UDT_STR:
- nd->status.str = (unsigned short) val;
+ nd->status.str = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_AGI:
- nd->status.agi = (unsigned short) val;
+ nd->status.agi = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_VIT:
- nd->status.vit = (unsigned short) val;
+ nd->status.vit = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_INT:
- nd->status.int_ = (unsigned short) val;
+ nd->status.int_ = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_DEX:
- nd->status.dex = (unsigned short) val;
+ nd->status.dex = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_LUK:
- nd->status.luk = (unsigned short) val;
+ nd->status.luk = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_STATPOINT:
- nd->stat_point = (unsigned short) val;
+ nd->stat_point = (unsigned short)val;
break;
case UDT_ATKRANGE:
- nd->status.rhw.range = (unsigned short) val;
+ nd->status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- nd->status.rhw.atk = (unsigned short) val;
+ nd->status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- nd->status.rhw.atk2 = (unsigned short) val;
+ nd->status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- nd->status.matk_min = (unsigned short) val;
+ nd->status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- nd->status.matk_max = (unsigned short) val;
+ nd->status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- nd->status.def = (defType) val;
+ nd->status.def = (defType)val;
break;
case UDT_MDEF:
- nd->status.mdef = (defType) val;
+ nd->status.mdef = (defType)val;
break;
case UDT_HIT:
- nd->status.hit = (short) val;
+ nd->status.hit = (short)val;
break;
case UDT_FLEE:
- nd->status.flee = (short) val;
+ nd->status.flee = (short)val;
break;
case UDT_PDODGE:
- nd->status.flee2 = (short) val;
+ nd->status.flee2 = (short)val;
break;
case UDT_CRIT:
- nd->status.cri = (short) val;
+ nd->status.cri = (short)val;
break;
case UDT_RACE:
- nd->status.race = (unsigned char) val;
+ nd->status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- nd->status.def_ele = (unsigned char) val;
+ nd->status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- nd->status.ele_lv = (unsigned char) val;
+ nd->status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- nd->status.amotion = (unsigned short) val;
+ nd->status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- nd->status.adelay = (unsigned short) val;
+ nd->status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- nd->status.dmotion = (unsigned short) val;
+ nd->status.dmotion = (unsigned short)val;
break;
case UDT_SEX:
nd->vd.sex = (char)val;
@@ -20538,19 +20595,21 @@ static BUILDIN(setunitdata)
clif->changelook(bl, LOOK_BODY2, val);
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for NPC unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for NPC unit.\n", type);
script_pushint(st, 0);
return false;
}
- }
+
break;
+ }
default:
ShowError("buildin_setunitdata: Unknown object!\n");
script_pushint(st, 0);
return false;
- } // end of bl->type switch
+ } // End of bl->type switch.
script_pushint(st, 1);
+
return true;
}
@@ -27713,6 +27772,23 @@ static void script_hardcoded_constants(void)
script->set_constant("PETINFO_EVO_EGGID", PETINFO_EVO_EGGID, false, false);
script->set_constant("PETINFO_AUTOFEED", PETINFO_AUTOFEED, false, false);
+ script->constdb_comment("Pet hunger levels");
+ script->set_constant("PET_HUNGER_STARVING", PET_HUNGER_STARVING, false, false);
+ script->set_constant("PET_HUNGER_VERY_HUNGRY", PET_HUNGER_VERY_HUNGRY, false, false);
+ script->set_constant("PET_HUNGER_HUNGRY", PET_HUNGER_HUNGRY, false, false);
+ script->set_constant("PET_HUNGER_NEUTRAL", PET_HUNGER_NEUTRAL, false, false);
+ script->set_constant("PET_HUNGER_SATISFIED", PET_HUNGER_SATISFIED, false, false);
+ script->set_constant("PET_HUNGER_STUFFED", PET_HUNGER_STUFFED, false, false);
+
+ script->constdb_comment("Pet intimacy levels");
+ script->set_constant("PET_INTIMACY_NONE", PET_INTIMACY_NONE, false, false);
+ script->set_constant("PET_INTIMACY_AWKWARD", PET_INTIMACY_AWKWARD, false, false);
+ script->set_constant("PET_INTIMACY_SHY", PET_INTIMACY_SHY, false, false);
+ script->set_constant("PET_INTIMACY_NEUTRAL", PET_INTIMACY_NEUTRAL, false, false);
+ script->set_constant("PET_INTIMACY_CORDIAL", PET_INTIMACY_CORDIAL, false, false);
+ script->set_constant("PET_INTIMACY_LOYAL", PET_INTIMACY_LOYAL, false, false);
+ script->set_constant("PET_INTIMACY_MAX", PET_INTIMACY_MAX, false, false);
+
script->constdb_comment("monster skill states");
script->set_constant("MSS_ANY", MSS_ANY, false, false);
script->set_constant("MSS_IDLE", MSS_IDLE, false, false);
diff --git a/src/map/status.c b/src/map/status.c
index 4e7094569..d3e85e5be 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -2579,12 +2579,16 @@ static int status_calc_pc_(struct map_session_data *sd, enum e_status_calc_opt o
status->calc_pc_additional(sd, opt);
- if( sd->pd ) { // Pet Bonus
+ if (sd->pd != NULL) { // Pet bonus.
struct pet_data *pd = sd->pd;
- if( pd && pd->petDB && pd->petDB->equip_script && pd->pet.intimate >= battle_config.pet_equip_min_friendly )
- script->run(pd->petDB->equip_script,0,sd->bl.id,0);
- if( pd && 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);
+
+ if (pd->petDB != NULL && pd->petDB->equip_script != NULL)
+ script->run(pd->petDB->equip_script, 0, sd->bl.id, 0);
+
+ if (pd->pet.intimate > PET_INTIMACY_NONE && pd->state.skillbonus == 1 && pd->bonus != NULL
+ && (battle_config.pet_equip_required == 0 || pd->pet.equip > 0)) {
+ pc->bonus(sd, pd->bonus->type, pd->bonus->val);
+ }
}
//param_bonus now holds card bonuses.
diff --git a/src/map/unit.c b/src/map/unit.c
index 56ddb5917..015f755bb 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -898,7 +898,7 @@ static int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int eas
} else
npc->untouch_areanpc(sd, bl->m, bl->x, bl->y);
- 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_INTIMACY_NONE)
{ // Check if pet needs to be teleported. [Skotlex]
int flag = 0;
struct block_list* pbl = &sd->pd->bl;
@@ -2722,7 +2722,7 @@ static int unit_remove_map(struct block_list *bl, enum clr_type clrtype, const c
case BL_PET:
{
struct pet_data *pd = BL_UCAST(BL_PET, bl);
- if( pd->pet.intimate <= 0 && !(pd->msd && !pd->msd->state.active) ) {
+ if (pd->pet.intimate <= PET_INTIMACY_NONE && !(pd->msd && !pd->msd->state.active)) {
//If logging out, this is deleted on unit->free
clif->clearunit_area(bl,clrtype);
map->delblock(bl);
@@ -2936,7 +2936,7 @@ static int unit_free(struct block_list *bl, enum clr_type clrtype)
aFree (pd->loot);
pd->loot = NULL;
}
- if (pd->pet.intimate > 0) {
+ if (pd->pet.intimate > PET_INTIMACY_NONE) {
intif->save_petdata(pd->pet.account_id,&pd->pet);
} else {
//Remove pet.