diff options
53 files changed, 3540 insertions, 3206 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/constants.conf b/db/constants.conf index 6f87b2d51..9b11a43e9 100644 --- a/db/constants.conf +++ b/db/constants.conf @@ -1417,6 +1417,13 @@ constants_db: { SC_RESIST_PROPERTY_WIND: 667 SC_CLIENT_ONLY_EQUIP_ARROW: 668 SC_MADOGEAR: 669 + SC_POPECOOKIE: 670 + SC_VITALIZE_POTION: 671 + SC_SKF_MATK: 672 + SC_SKF_ATK: 673 + SC_SKF_ASPD: 674 + SC_SKF_CAST: 675 + SC_ALMIGHTY: 676 comment__: "Emotes" e_gasp: 0 diff --git a/db/pre-re/item_db.conf b/db/pre-re/item_db.conf index fa204f04b..74aeaa460 100644 --- a/db/pre-re/item_db.conf +++ b/db/pre-re/item_db.conf @@ -70971,6 +70971,18 @@ item_db: ( Buy: 10 Weight: 10 BuyingStore: true + Trade: { + nodrop: true + notrade: true + nocart: true + nomail: true + noauction: true + nogstorage: true + } + Script: <" + specialeffect(EF_STEAL, AREA, playerattached()); + sc_start4(SC_POPECOOKIE, 1200000, 3, 3, 3, 0); + "> }, { Id: 12380 @@ -71380,7 +71392,7 @@ item_db: ( { Id: 12404 AegisName: "Acti_Potion" - Name: "Acti Potion" + Name: "Activation Potion" Type: "IT_USABLE" Buy: 20 Weight: 10 @@ -71393,6 +71405,10 @@ item_db: ( nomail: true noauction: true } + Script: <" + specialeffect(EF_STEAL, AREA, playerattached()); + sc_start4(SC_VITALIZE_POTION, 120000, 2, 2, 10, 0); + "> }, { Id: 12405 @@ -73162,6 +73178,90 @@ item_db: ( OnRentalEndScript: <" sc_end(SC_ALL_RIDING); "> }, { + Id: 12666 + AegisName: "Thai_Perfume_MATK" + Name: "Thai Perfume(MATK)" + Type: "IT_USABLE" + Buy: 20 + Weight: 10 + Trade: { + nodrop: true + notrade: true + noselltonpc: true + nocart: true + nogstorage: true + nomail: true + noauction: true + } + Script: <" + specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); + sc_start(SC_SKF_MATK, 600000, 24); + "> +}, +{ + Id: 12667 + AegisName: "Thai_Perfume_ATK" + Name: "Thai Perfume(ATK)" + Type: "IT_USABLE" + Buy: 20 + Weight: 10 + Trade: { + nodrop: true + notrade: true + noselltonpc: true + nocart: true + nogstorage: true + nomail: true + noauction: true + } + Script: <" + specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); + sc_start(SC_SKF_ATK, 600000, 24); + "> +}, +{ + Id: 12668 + AegisName: "Thai_Perfume_ASPD" + Name: "Thai Perfume(ASPD)" + Type: "IT_USABLE" + Buy: 20 + Weight: 10 + Trade: { + nodrop: true + notrade: true + noselltonpc: true + nocart: true + nogstorage: true + nomail: true + noauction: true + } + Script: <" + specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); + sc_start(SC_SKF_ASPD, 600000, 3); + "> +}, +{ + Id: 12669 + AegisName: "Thai_Perfume_CAST" + Name: "Thai Perfume(CAST)" + Type: "IT_USABLE" + Buy: 20 + Weight: 10 + Trade: { + nodrop: true + notrade: true + noselltonpc: true + nocart: true + nogstorage: true + nomail: true + noauction: true + } + Script: <" + specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); + sc_start(SC_SKF_CAST, 600000, 5); + "> +}, +{ Id: 12701 AegisName: "Old_Blue_Box_F" Name: "Old Blue Box" @@ -74233,6 +74333,33 @@ item_db: ( "> }, { + Id: 12883 + AegisName: "Almighty" + Name: "Almighty" + Type: "IT_USABLE" + Buy: 20 + Weight: 10 + Trade: { + nodrop: true + notrade: true + noselltonpc: true + nocart: true + nogstorage: true + nomail: true + noauction: true + } + Script: <" + specialeffect(EF_BASH3D, AREA, playerattached()); + sc_start(SC_FOOD_STR_CASH, 1800000, 10); + sc_start(SC_FOOD_VIT_CASH, 1800000, 10); + sc_start(SC_FOOD_AGI_CASH, 1800000, 10); + sc_start(SC_FOOD_INT_CASH, 1800000, 10); + sc_start(SC_FOOD_DEX_CASH, 1800000, 10); + sc_start(SC_FOOD_LUK_CASH, 1800000, 10); + sc_start2(SC_ALMIGHTY, 1800000, 30, 30); + "> +}, +{ Id: 12900 AegisName: "Battle_Manual_Box" Name: "Battle Manual Box" @@ -93997,6 +94124,24 @@ item_db: ( }, */ { + Id: 16254 + AegisName: "Energizing_Potion_Box" + Name: "Activation Potion Box" + Type: "IT_CASH" + Buy: 20 + Weight: 10 + Trade: { + nodrop: true + notrade: true + noselltonpc: true + nocart: true + nogstorage: true + nomail: true + noauction: true + } + Script: <" getitem(Acti_Potion, 5); "> +}, +{ Id: 16257 AegisName: "Buddah_Scroll" Name: "Buddah Scroll" @@ -94465,6 +94610,23 @@ item_db: ( Script: <" getitem(Clothing_Dye_Coupon2, 1); "> }, { + Id: 17224 + AegisName: "Almighty_Box" + Name: "Almighty Box" + Type: "IT_CASH" + Weight: 10 + Trade: { + nodrop: true + notrade: true + noselltonpc: true + nocart: true + nogstorage: true + nomail: true + noauction: true + } + Script: <" getitem(Almighty, 10); "> +}, +{ Id: 17336 AegisName: "Jeremy_Beauty_Coupon_Box" Name: "Jeremy's Beauty Coupon Box" 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/item_db.conf b/db/re/item_db.conf index dbe3531b0..cf2bd7da2 100644 --- a/db/re/item_db.conf +++ b/db/re/item_db.conf @@ -90584,6 +90584,18 @@ item_db: ( Buy: 10 Weight: 10 BuyingStore: true + Trade: { + nodrop: true + notrade: true + nocart: true + nomail: true + noauction: true + nogstorage: true + } + Script: <" + specialeffect(EF_STEAL, AREA, playerattached()); + sc_start4(SC_POPECOOKIE, 1200000, 3, 3, 3, 0); + "> }, { Id: 12380 @@ -91001,6 +91013,10 @@ item_db: ( nomail: true noauction: true } + Script: <" + specialeffect(EF_STEAL, AREA, playerattached()); + sc_start4(SC_VITALIZE_POTION, 120000, 2, 2, 10, 0); + "> }, { Id: 12405 @@ -94088,33 +94104,85 @@ item_db: ( Id: 12666 AegisName: "Thai_Perfume_MATK" Name: "Thai Perfume(MATK)" - Type: "IT_DELAYCONSUME" + Type: "IT_USABLE" Buy: 20 Weight: 10 + Trade: { + nodrop: true + notrade: true + noselltonpc: true + nocart: true + nogstorage: true + nomail: true + noauction: true + } + Script: <" + specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); + sc_start(SC_SKF_MATK, 600000, 24); + "> }, { Id: 12667 AegisName: "Thai_Perfume_ATK" Name: "Thai Perfume(ATK)" - Type: "IT_DELAYCONSUME" + Type: "IT_USABLE" Buy: 20 Weight: 10 + Trade: { + nodrop: true + notrade: true + noselltonpc: true + nocart: true + nogstorage: true + nomail: true + noauction: true + } + Script: <" + specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); + sc_start(SC_SKF_ATK, 600000, 24); + "> }, { Id: 12668 AegisName: "Thai_Perfume_ASPD" Name: "Thai Perfume(ASPD)" - Type: "IT_DELAYCONSUME" + Type: "IT_USABLE" Buy: 20 Weight: 10 + Trade: { + nodrop: true + notrade: true + noselltonpc: true + nocart: true + nogstorage: true + nomail: true + noauction: true + } + Script: <" + specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); + sc_start(SC_SKF_ASPD, 600000, 3); + "> }, { Id: 12669 AegisName: "Thai_Perfume_CAST" Name: "Thai Perfume(CAST)" - Type: "IT_DELAYCONSUME" + Type: "IT_USABLE" Buy: 20 Weight: 10 + Trade: { + nodrop: true + notrade: true + noselltonpc: true + nocart: true + nogstorage: true + nomail: true + noauction: true + } + Script: <" + specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); + sc_start(SC_SKF_CAST, 600000, 5); + "> }, { Id: 12670 @@ -96029,6 +96097,33 @@ item_db: ( Script: <" autobonus "{ heal -3000,0; bonus2 bResEff,Eff_Blind,10000; }",10,0,0,SI_GVG_BLIND; "> }, { + Id: 12883 + AegisName: "Almighty" + Name: "Almighty" + Type: "IT_USABLE" + Buy: 20 + Weight: 10 + Trade: { + nodrop: true + notrade: true + noselltonpc: true + nocart: true + nogstorage: true + nomail: true + noauction: true + } + Script: <" + specialeffect(EF_BASH3D, AREA, playerattached()); + sc_start(SC_FOOD_STR_CASH, 1800000, 10); + sc_start(SC_FOOD_VIT_CASH, 1800000, 10); + sc_start(SC_FOOD_AGI_CASH, 1800000, 10); + sc_start(SC_FOOD_INT_CASH, 1800000, 10); + sc_start(SC_FOOD_DEX_CASH, 1800000, 10); + sc_start(SC_FOOD_LUK_CASH, 1800000, 10); + sc_start2(SC_ALMIGHTY, 1800000, 30, 30); + "> +}, +{ Id: 12884 AegisName: "C_Center_Potion" Name: "Infinite Concentration Potion" @@ -127064,6 +127159,7 @@ item_db: ( Name: "Activation Potion Box" Type: "IT_CASH" Buy: 20 + Weight: 10 Trade: { nodrop: true notrade: true @@ -127073,6 +127169,7 @@ item_db: ( nomail: true noauction: true } + Script: <" getitem(Acti_Potion, 5); "> }, { Id: 16257 @@ -130581,6 +130678,23 @@ item_db: ( Script: <" packageitem(); "> }, { + Id: 17224 + AegisName: "Almighty_Box" + Name: "Almighty Box" + Type: "IT_CASH" + Weight: 10 + Trade: { + nodrop: true + notrade: true + noselltonpc: true + nocart: true + nogstorage: true + nomail: true + noauction: true + } + Script: <" getitem(Almighty, 10); "> +}, +{ Id: 17226 AegisName: "C_Center_Potion_Box" Name: "Infinite Concentration Potion Box" 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/db/re/skill_db.conf b/db/re/skill_db.conf index 376fba179..8cb55d918 100644 --- a/db/re/skill_db.conf +++ b/db/re/skill_db.conf @@ -16043,6 +16043,7 @@ skill_db: ( } AmmoTypes: { A_BULLET: true + A_GRENADE: true } AmmoAmount: 5 } diff --git a/db/sc_config.conf b/db/sc_config.conf index 2520fc595..11f8579e5 100644 --- a/db/sc_config.conf +++ b/db/sc_config.conf @@ -3675,3 +3675,57 @@ SC_MADOGEAR: { } Icon: "SI_MADOGEAR" } +SC_POPECOOKIE: { + Flags: { + NoDispelReset: true + NoClearanceReset: true + Buff: true + } + Icon: "SI_POPECOOKIE" +} +SC_VITALIZE_POTION: { + Flags: { + NoDispelReset: true + } + Icon: "SI_VITALIZE_POTION" +} +SC_SKF_MATK: { + Flags: { + NoDispelReset: true + NoClearanceReset: true + Buff: true + } + Icon: "SI_SKF_MATK" +} +SC_SKF_ATK: { + Flags: { + NoDispelReset: true + NoClearanceReset: true + Buff: true + } + Icon: "SI_SKF_ATK" +} +SC_SKF_ASPD: { + Flags: { + NoDispelReset: true + NoClearanceReset: true + Buff: true + } + Icon: "SI_SKF_ASPD" +} +SC_SKF_CAST: { + Flags: { + NoDispelReset: true + NoClearanceReset: true + Buff: true + } + Icon: "SI_SKF_CAST" +} +SC_ALMIGHTY: { + Flags: { + NoDeathReset: true + NoDispelReset: true + NoClearanceReset: true + } + Icon: "SI_ALMIGHTY" +} diff --git a/doc/atcommands.txt b/doc/atcommands.txt index 0cddc1680..65c3bb091 100644 --- a/doc/atcommands.txt +++ b/doc/atcommands.txt @@ -968,10 +968,19 @@ If no position is given, the command defaults to headgear. --------------------------------------- -@fakename {<text string>} - -Temporarily changes name to the specified string. -If no string is given, the character's real name will be re-applied. +@fakename {<options>} {<fake_name>} + +Temporarily changes the character's name to <fake_name>. +If no parameter is passed, the character's real name will be re-applied. +The <options> parameter is used, to modify which names will be displayed. +The fake name will always be displayed, regardless of <options>. +Valid <options> flags (combinable): + 0 - Only the fake name is displayed. (Default value.) + 1 - Display party name. + 2 - Display guild name. + 4 - Display guild position. + 8 - Display clan position. + 16 - Display title. --------------------------------------- diff --git a/doc/constants.md b/doc/constants.md index fb175ce83..f0c7f50c8 100644 --- a/doc/constants.md +++ b/doc/constants.md @@ -1339,6 +1339,13 @@ - `SC_RESIST_PROPERTY_WIND`: 667 - `SC_CLIENT_ONLY_EQUIP_ARROW`: 668 - `SC_MADOGEAR`: 669 +- `SC_POPECOOKIE`: 670 +- `SC_VITALIZE_POTION`: 671 +- `SC_SKF_MATK`: 672 +- `SC_SKF_ATK`: 673 +- `SC_SKF_ASPD`: 674 +- `SC_SKF_CAST`: 675 +- `SC_ALMIGHTY`: 676 ### Emotes @@ -4665,8 +4672,8 @@ - `MAX_ITEM_ID`: 2147483647 - `MAX_MENU_OPTIONS`: 255 - `MAX_MENU_LENGTH`: 2048 -- `MOB_CLONE_START`: 4001 -- `MOB_CLONE_END`: 5000 +- `MOB_CLONE_START`: 21001 +- `MOB_CLONE_END`: 22000 - `MAX_NPC_PER_MAP`: 512 ### status options @@ -5022,6 +5029,25 @@ - `PETINFO_EVO_EGGID`: 11 - `PETINFO_AUTOFEED`: 12 +### Pet hunger levels + +- `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 levels + +- `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 + ### monster skill states - `MSS_ANY`: -1 @@ -14774,6 +14800,7 @@ - `Elf_Tear_Curse`: 12880 - `Elf_Tear_Silence`: 12881 - `Elf_Tear_Blind`: 12882 +- `Almighty`: 12883 - `C_Center_Potion`: 12884 - `C_Awakening_Potion`: 12885 - `C_Berserk_Potion`: 12886 @@ -16642,6 +16669,7 @@ - `Tw_Red_Scroll`: 17210 - `Tw_Orange_Scroll`: 17211 - `Tw_Yellow_Scroll`: 17212 +- `Almighty_Box`: 17224 - `C_Center_Potion_Box`: 17226 - `C_Awakening_Potion_Box`: 17227 - `C_Berserk_Potion_Box`: 17228 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/doc/script_commands.txt b/doc/script_commands.txt index 392aa0c1f..3b77aeb2c 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -6575,17 +6575,22 @@ Examples: --------------------------------------- -*setpcblock(<type>,<option>) -*checkpcblock() +*setpcblock(<type>, <option>{, <account id>}) +*checkpcblock({<account id>}) -Prevents the player from doing the following action. +Prevents a character from doing the following action. For setpcblock, when the <option> is true(1) will block them, and false(0) will allow those actions again. +The setpcblock command returns 1 on success or 0 if no character was attached. + The checkpcblock command returned value is a bit mask of the currently enabled block flags (or PCBLOCK_NONE when none is set). +Parameter <account id> is optional for both commands. +If omitted, the currently attached character is used. + The <type> listed are a bit mask of the following: PCBLOCK_NONE (only used by checkpcblock) PCBLOCK_MOVE diff --git a/sql-files/item_db.sql b/sql-files/item_db.sql index 90a0844e5..ac3cad389 100644 --- a/sql-files/item_db.sql +++ b/sql-files/item_db.sql @@ -4749,7 +4749,7 @@ REPLACE INTO `item_db` VALUES ('12375','Acaraje','Akaraje','2','0','0','0','80', REPLACE INTO `item_db` VALUES ('12376','Mysterious_Can2','Mysterious Can2','2','0','10','5','100','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'1',NULL,'0',NULL,'0','percentheal(3, 0); itemskill(PR_GLORIA, 2, ISF_INSTANTCAST | ISF_CASTONSELF);','',''); REPLACE INTO `item_db` VALUES ('12377','Mysterious_PET_Bottle2','Mysterious PET Bottle2','2','0','10','5','100','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'1',NULL,'0',NULL,'0','percentheal(0, 3); itemskill(PR_MAGNIFICAT, 1, ISF_INSTANTCAST | ISF_CASTONSELF);','',''); REPLACE INTO `item_db` VALUES ('12378','2009_Rice_Cake_Soup','Rice Cake Soup','2','0','10','5','100','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','percentheal 50, 50;','',''); -REPLACE INTO `item_db` VALUES ('12379','Popes_Cookie','Pope Cookie','2','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); +REPLACE INTO `item_db` VALUES ('12379','Popes_Cookie','Pope Cookie','2','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','467',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_STEAL, AREA, playerattached()); sc_start4(SC_POPECOOKIE, 1200000, 3, 3, 3, 0);','',''); REPLACE INTO `item_db` VALUES ('12380','Desert_Wolf_Babe_Scroll','Job Change Flute','2','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','mercenary_create M_DESERT_WOLF_B, 1800000;','',''); REPLACE INTO `item_db` VALUES ('12381','ValkyrieA_Scroll','Ancient Languages Scroll','2','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','if (strcharinfo(PC_MAP) == \"job3_arch02\") { mercenary_create VALKYRIE_A, 1800000; }','',''); REPLACE INTO `item_db` VALUES ('12382','ValkyrieB_Scroll','Ancient Languages Scroll','2','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','if (strcharinfo(PC_MAP) == \"job3_arch02\") { mercenary_create VALKYRIE_B, 1800000; }','',''); @@ -4774,7 +4774,7 @@ REPLACE INTO `item_db` VALUES ('12400','Water_Of_Blessing_','Water Of Blessing ' REPLACE INTO `item_db` VALUES ('12401','Rune_Kn_Test_Int','Rune Kn Test Int','2','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start SC_FOOD_INT,300000,40;','',''); REPLACE INTO `item_db` VALUES ('12402','29Fruit','29Fruit','2','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','','',''); REPLACE INTO `item_db` VALUES ('12403','Lucky_Egg_C2','Lucky Egg2','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); -REPLACE INTO `item_db` VALUES ('12404','Acti_Potion','Acti Potion','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','','',''); +REPLACE INTO `item_db` VALUES ('12404','Acti_Potion','Activation Potion','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_STEAL, AREA, playerattached()); sc_start4(SC_VITALIZE_POTION, 120000, 2, 2, 10, 0);','',''); REPLACE INTO `item_db` VALUES ('12405','Underripe_Yggseed','Underripe Yggseed','2','0','20','10','50','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','percentheal(30, 30); itemskill(AL_BLESSING, 5, ISF_INSTANTCAST | ISF_CASTONSELF);','',''); REPLACE INTO `item_db` VALUES ('12406','Psychic_ArmorS','Psychic ArmorS','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_ENERGYCOAT, AREA, playerattached()); sc_start4 SC_ARMOR_PROPERTY, 10000, 1, Ele_Neutral, 1, 0;','',''); REPLACE INTO `item_db` VALUES ('12407','PCBang_Coupon_Box','PCBang Coupon Box','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); @@ -4953,6 +4953,10 @@ REPLACE INTO `item_db` VALUES ('12581','Vending_Search_Scroll2','Universal Catal REPLACE INTO `item_db` VALUES ('12591','Uni_Catalog_Bz','Universal Catalog Bronze','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','searchstores 10,1;','',''); REPLACE INTO `item_db` VALUES ('12609','Old_Ore_Box','Old Ore Box','2','0','20','10','100','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','packageitem();','',''); REPLACE INTO `item_db` VALUES ('12622','Boarding_Halter','Halter Lead','11','0','20','10','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','3000','507',NULL,'0',NULL,'0',NULL,'0','setcashmount();','',''); +REPLACE INTO `item_db` VALUES ('12666','Thai_Perfume_MATK','Thai Perfume(MATK)','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); sc_start(SC_SKF_MATK, 600000, 24);','',''); +REPLACE INTO `item_db` VALUES ('12667','Thai_Perfume_ATK','Thai Perfume(ATK)','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); sc_start(SC_SKF_ATK, 600000, 24);','',''); +REPLACE INTO `item_db` VALUES ('12668','Thai_Perfume_ASPD','Thai Perfume(ASPD)','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); sc_start(SC_SKF_ASPD, 600000, 3);','',''); +REPLACE INTO `item_db` VALUES ('12669','Thai_Perfume_CAST','Thai Perfume(CAST)','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); sc_start(SC_SKF_CAST, 600000, 5);','',''); REPLACE INTO `item_db` VALUES ('12701','Old_Blue_Box_F','Old Blue Box','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); REPLACE INTO `item_db` VALUES ('12702','Old_Bleu_Box','Old Navy Box','2','0','0','0','200','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getrandgroupitem Old_Bleu_Box,1; getrandgroupitem Old_Bleu_Box,1;','',''); REPLACE INTO `item_db` VALUES ('12703','Holy_Egg_2','Holy Egg','11','0','0','0','50','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); @@ -5030,6 +5034,7 @@ REPLACE INTO `item_db` VALUES ('12786','Change_Slot_Card','Character Position Ch REPLACE INTO `item_db` VALUES ('12790','Change_Name_Card','Name Change Coupon','2','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','CharRename += 1;','',''); REPLACE INTO `item_db` VALUES ('12831','Potion_Box','Potion Box','2','0','0','0','50','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','getitem Red_Slim_Potion, 100; getitem Yellow_Slim_Potion, 100; getitem White_Slim_Potion, 100; getitem Blue_Potion, 100;','',''); REPLACE INTO `item_db` VALUES ('12848','Falcon_Flute','Falcon Flute','11','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','if (getskilllv(HT_FALCON)) { if (checkoption(Option_Wug) || checkoption(Option_Wugrider)) end; if (checkfalcon() == 1) { setfalcon 0; } else { setfalcon 1; } }','',''); +REPLACE INTO `item_db` VALUES ('12883','Almighty','Almighty','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_BASH3D, AREA, playerattached()); sc_start(SC_FOOD_STR_CASH, 1800000, 10); sc_start(SC_FOOD_VIT_CASH, 1800000, 10); sc_start(SC_FOOD_AGI_CASH, 1800000, 10); sc_start(SC_FOOD_INT_CASH, 1800000, 10); sc_start(SC_FOOD_DEX_CASH, 1800000, 10); sc_start(SC_FOOD_LUK_CASH, 1800000, 10); sc_start2(SC_ALMIGHTY, 1800000, 30, 30);','',''); REPLACE INTO `item_db` VALUES ('12900','Battle_Manual_Box','Battle Manual Box','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','457',NULL,'0',NULL,'0',NULL,'0','getitem 12208,10;','',''); REPLACE INTO `item_db` VALUES ('12901','Insurance_Package','Insurance Package','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','457',NULL,'0',NULL,'0',NULL,'0','getitem 12209,10;','',''); REPLACE INTO `item_db` VALUES ('12902','Bubble_Gum_Box','Bubble Gum Box','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','457',NULL,'0',NULL,'0',NULL,'0','getitem 12210,10;','',''); @@ -6268,6 +6273,7 @@ REPLACE INTO `item_db` VALUES ('16134','King_Frog_Hat_Box','Frog King Hat Box',' REPLACE INTO `item_db` VALUES ('16135','Evils_Bone_Hat_Box','Satanic Bone Helm Box','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','457',NULL,'0',NULL,'0',NULL,'0','getitem 5529,1;','',''); REPLACE INTO `item_db` VALUES ('16247','Dragon_Arhat_Mask_Box','Dragon Arhat Mask Box','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','getitem 5565,1;','',''); REPLACE INTO `item_db` VALUES ('16248','Tiger_Arhat_Mask_Box','Tiger Arhat Mask Box','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','getitem 5566,1;','',''); +REPLACE INTO `item_db` VALUES ('16254','Energizing_Potion_Box','Activation Potion Box','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','getitem(Acti_Potion, 5);','',''); REPLACE INTO `item_db` VALUES ('16257','Buddah_Scroll','Buddah Scroll','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','73',NULL,'0',NULL,'0',NULL,'0','packageitem();','',''); REPLACE INTO `item_db` VALUES ('16304','Evil_Incarnation_Disable','Evil Incarnation','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','packageitem();','',''); REPLACE INTO `item_db` VALUES ('16371','Tw_Aug_Scroll','Tw Aug Scroll','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','73',NULL,'0',NULL,'0',NULL,'0','packageitem();','',''); @@ -6280,6 +6286,7 @@ REPLACE INTO `item_db` VALUES ('16777','Universal_Catalog_Gold_Box50','Universal REPLACE INTO `item_db` VALUES ('16843','Beauty_Gift_Box','Beauty Gift Box','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem(New_Style_Coupon, 1);','',''); REPLACE INTO `item_db` VALUES ('16854','Clothing_Dye_Box','Clothing Dye Box','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem(Clothing_Dye_Coupon, 1);','',''); REPLACE INTO `item_db` VALUES ('16855','Clothing_Dye_Orig_Box','Clothing Dye Orig Box','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem(Clothing_Dye_Coupon2, 1);','',''); +REPLACE INTO `item_db` VALUES ('17224','Almighty_Box','Almighty Box','18','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','getitem(Almighty, 10);','',''); REPLACE INTO `item_db` VALUES ('17336','Jeremy_Beauty_Coupon_Box','Jeremy\'s Beauty Coupon Box','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','getitem(Cash_Hair_Coupon, 1);','',''); REPLACE INTO `item_db` VALUES ('17774','Almighty_Plus_Box3','Almighty_Plus_Box3','3','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); REPLACE INTO `item_db` VALUES ('17775','Almighty100_PlusBox3','Almighty100_PlusBox3','3','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); diff --git a/sql-files/item_db_re.sql b/sql-files/item_db_re.sql index 143600284..a24b385f7 100644 --- a/sql-files/item_db_re.sql +++ b/sql-files/item_db_re.sql @@ -6219,7 +6219,7 @@ REPLACE INTO `item_db` VALUES ('12375','Acaraje','Akaraje','2','0','0','0','80', REPLACE INTO `item_db` VALUES ('12376','Mysterious_Can2','Mysterious Can2','2','0','10','5','100','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'1',NULL,'0',NULL,'0','percentheal(3, 0); itemskill(PR_GLORIA, 2, ISF_INSTANTCAST | ISF_CASTONSELF);','',''); REPLACE INTO `item_db` VALUES ('12377','Mysterious_PET_Bottle2','Mysterious PET Bottle2','2','0','10','5','100','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'1',NULL,'0',NULL,'0','percentheal(0, 3); itemskill(PR_MAGNIFICAT, 1, ISF_INSTANTCAST | ISF_CASTONSELF);','',''); REPLACE INTO `item_db` VALUES ('12378','2009_Rice_Cake_Soup','Rice Cake Soup','2','0','10','5','100','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','percentheal 50, 50;','',''); -REPLACE INTO `item_db` VALUES ('12379','Popes_Cookie','Pope Cookie','2','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); +REPLACE INTO `item_db` VALUES ('12379','Popes_Cookie','Pope Cookie','2','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','1','0','467',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_STEAL, AREA, playerattached()); sc_start4(SC_POPECOOKIE, 1200000, 3, 3, 3, 0);','',''); REPLACE INTO `item_db` VALUES ('12380','Desert_Wolf_Babe_Scroll','Job Change Flute','2','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','mercenary_create M_DESERT_WOLF_B, 1800000;','',''); REPLACE INTO `item_db` VALUES ('12381','ValkyrieA_Scroll','Ancient Language Scroll','2','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','if (strcharinfo(PC_MAP) == \"job3_arch02\") { mercenary_create VALKYRIE_A, 1800000; }','',''); REPLACE INTO `item_db` VALUES ('12382','ValkyrieB_Scroll','Ancient Language Scroll','2','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','if (strcharinfo(PC_MAP) == \"job3_arch02\") { mercenary_create VALKYRIE_B, 1800000; }','',''); @@ -6244,7 +6244,7 @@ REPLACE INTO `item_db` VALUES ('12400','Water_Of_Blessing_','Water Of Blessing', REPLACE INTO `item_db` VALUES ('12401','Rune_Kn_Test_Int','Rune Kn Test Int','2','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','sc_start SC_FOOD_INT,300000,40;','',''); REPLACE INTO `item_db` VALUES ('12402','29Fruit','29Truth','0','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','percentheal 5,5;','',''); REPLACE INTO `item_db` VALUES ('12403','Lucky_Egg_C2','RWC2011 Lucky Scroll','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','','',''); -REPLACE INTO `item_db` VALUES ('12404','Acti_Potion','Activation Potion','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','','',''); +REPLACE INTO `item_db` VALUES ('12404','Acti_Potion','Activation Potion','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_STEAL, AREA, playerattached()); sc_start4(SC_VITALIZE_POTION, 120000, 2, 2, 10, 0);','',''); REPLACE INTO `item_db` VALUES ('12405','Underripe_Yggseed','Unripe Seed Of Yggdrasil','2','0','20','10','50','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','percentheal(30, 30); itemskill(AL_BLESSING, 5, ISF_INSTANTCAST | ISF_CASTONSELF);','',''); REPLACE INTO `item_db` VALUES ('12406','Psychic_ArmorS','Psychic Armor Scroll','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_ENERGYCOAT, AREA, playerattached()); sc_start4 SC_ARMOR_PROPERTY, 10000, 1, Ele_Neutral, 1, 0;','',''); REPLACE INTO `item_db` VALUES ('12407','PCBang_Coupon_Box','PCRoom Coupon Box','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','','',''); @@ -6497,10 +6497,10 @@ REPLACE INTO `item_db` VALUES ('12662','Trans_Scroll_Banshee','Transformation Sc REPLACE INTO `item_db` VALUES ('12663','Trans_Scroll_Poring','Transformation Scroll(Poring)','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_CLOAKING, AREA, playerattached()); showscript \"Trans-Form-!! Poring Fo-rm!!\"; montransform PORING, 1200000, SC_MTF_CRIDAMAGE, 5;','',''); REPLACE INTO `item_db` VALUES ('12664','Trans_Scroll_Golem','Transformation Scroll(Golem)','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_CLOAKING, AREA, playerattached()); showscript \"Trans-Form-!! Golem Fo-rm!!\"; montransform GOLEM, 1200000, SC_MTF_MLEATKED, 2;','',''); REPLACE INTO `item_db` VALUES ('12665','Grovel_Buff','Grovel Buff','2','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); -REPLACE INTO `item_db` VALUES ('12666','Thai_Perfume_MATK','Thai Perfume(MATK)','11','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); -REPLACE INTO `item_db` VALUES ('12667','Thai_Perfume_ATK','Thai Perfume(ATK)','11','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); -REPLACE INTO `item_db` VALUES ('12668','Thai_Perfume_ASPD','Thai Perfume(ASPD)','11','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); -REPLACE INTO `item_db` VALUES ('12669','Thai_Perfume_CAST','Thai Perfume(CAST)','11','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); +REPLACE INTO `item_db` VALUES ('12666','Thai_Perfume_MATK','Thai Perfume(MATK)','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); sc_start(SC_SKF_MATK, 600000, 24);','',''); +REPLACE INTO `item_db` VALUES ('12667','Thai_Perfume_ATK','Thai Perfume(ATK)','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); sc_start(SC_SKF_ATK, 600000, 24);','',''); +REPLACE INTO `item_db` VALUES ('12668','Thai_Perfume_ASPD','Thai Perfume(ASPD)','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); sc_start(SC_SKF_ASPD, 600000, 3);','',''); +REPLACE INTO `item_db` VALUES ('12669','Thai_Perfume_CAST','Thai Perfume(CAST)','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_MAGICALATTHIT, AREA, playerattached()); sc_start(SC_SKF_CAST, 600000, 5);','',''); REPLACE INTO `item_db` VALUES ('12670','Beast_Powder','Beast Powder','11','0','20','10','100','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); REPLACE INTO `item_db` VALUES ('12671','99lv_Battle_Manual','99lv Battle Manual','11','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); REPLACE INTO `item_db` VALUES ('12672','Start_New_Box','Start New Box','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','499',NULL,'0',NULL,'0',NULL,'0','getitem Old_Violet_Box, 2; getitem Comp_Battle_Manual, 2; getitem Recall_MaleGM, 3; getitem Recall_FemaleGM, 2;','',''); @@ -6669,6 +6669,7 @@ REPLACE INTO `item_db` VALUES ('12879','Elf_Tear_Sleep','Elf Tear Sleep','2','0' REPLACE INTO `item_db` VALUES ('12880','Elf_Tear_Curse','Elf Tear Curse','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','autobonus \"{ heal -3000,0; bonus2 bResEff,Eff_Curse,10000; }\",10,0,0,SI_GVG_CURSE;','',''); REPLACE INTO `item_db` VALUES ('12881','Elf_Tear_Silence','Elf Tear Silence','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','autobonus \"{ heal -3000,0; bonus2 bResEff,Eff_Silence,10000; }\",10,0,0,SI_GVG_SILENCE;','',''); REPLACE INTO `item_db` VALUES ('12882','Elf_Tear_Blind','Elf Tear Blind','2','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','autobonus \"{ heal -3000,0; bonus2 bResEff,Eff_Blind,10000; }\",10,0,0,SI_GVG_BLIND;','',''); +REPLACE INTO `item_db` VALUES ('12883','Almighty','Almighty','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','specialeffect(EF_BASH3D, AREA, playerattached()); sc_start(SC_FOOD_STR_CASH, 1800000, 10); sc_start(SC_FOOD_VIT_CASH, 1800000, 10); sc_start(SC_FOOD_AGI_CASH, 1800000, 10); sc_start(SC_FOOD_INT_CASH, 1800000, 10); sc_start(SC_FOOD_DEX_CASH, 1800000, 10); sc_start(SC_FOOD_LUK_CASH, 1800000, 10); sc_start2(SC_ALMIGHTY, 1800000, 30, 30);','',''); REPLACE INTO `item_db` VALUES ('12884','C_Center_Potion','Infinite Concentration Potion','11','0','0','0','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','507',NULL,'0',NULL,'0',NULL,'0','sc_start SC_ATTHASTE_POTION1,1800000,4; specialeffect(EF_POTION_CON, AREA, playerattached()); /* NOTE: No special effect when used. */','',''); REPLACE INTO `item_db` VALUES ('12885','C_Awakening_Potion','Infinite Awakening Potion','11','0','0','0','0','0','0','0','0','0','2145902319','63','2','0','0','40',NULL,'0','1','0','0','0','0','0','507',NULL,'0',NULL,'0',NULL,'0','sc_start SC_ATTHASTE_POTION2,1800000,6; specialeffect(EF_POTION_, AREA, playerattached()); /* NOTE: No special effect when used. */','',''); REPLACE INTO `item_db` VALUES ('12886','C_Berserk_Potion','Infinite Berserk Potion','11','0','0','0','0','0','0','0','0','0','31868582','63','2','0','0','85',NULL,'0','1','0','0','0','0','0','507',NULL,'0',NULL,'0',NULL,'0','sc_start SC_ATTHASTE_POTION3,1800000,9; specialeffect(EF_POTION_BERSERK, AREA, playerattached()); /* NOTE: No special effect when used. */','',''); @@ -8235,7 +8236,7 @@ REPLACE INTO `item_db` VALUES ('16249','Knight_Gift_Box','Knight\'s Gift Box','2 REPLACE INTO `item_db` VALUES ('16251','Gemini_Diadem_Box','Gemini Diadem Box','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','getitem 5569,1;','',''); REPLACE INTO `item_db` VALUES ('16252','Gemini_Crown_Box','Gemini Crown Box','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','getitem 5570,1;','',''); REPLACE INTO `item_db` VALUES ('16253','Rabbit_Scroll','Rabbit Scroll','2','0','20','10','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','','',''); -REPLACE INTO `item_db` VALUES ('16254','Energizing_Potion_Box','Activation Potion Box','18','0','20','10','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','','',''); +REPLACE INTO `item_db` VALUES ('16254','Energizing_Potion_Box','Activation Potion Box','18','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','getitem(Acti_Potion, 5);','',''); REPLACE INTO `item_db` VALUES ('16257','Buddah_Scroll','French Heart Scroll','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','packageitem();','',''); REPLACE INTO `item_db` VALUES ('16258','HD_Bradium_Box5','HD Bradium 5 Box','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','getitem 6226,5;','',''); REPLACE INTO `item_db` VALUES ('16259','HD_Carnium_Box5','HD Carnium 5 Box','2','0','20','10','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','getitem 6225,5;','',''); @@ -8537,6 +8538,7 @@ REPLACE INTO `item_db` VALUES ('17209','Tw_Rainbow_Scroll','Tw Rainbow Scroll',' REPLACE INTO `item_db` VALUES ('17210','Tw_Red_Scroll','Tw Red Scroll','2','0','20','10','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','packageitem();','',''); REPLACE INTO `item_db` VALUES ('17211','Tw_Orange_Scroll','Tw Orange Scroll','2','0','20','10','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','packageitem();','',''); REPLACE INTO `item_db` VALUES ('17212','Tw_Yellow_Scroll','Tw Yellow Scroll','2','0','20','10','0','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','0',NULL,'0',NULL,'0',NULL,'0','packageitem();','',''); +REPLACE INTO `item_db` VALUES ('17224','Almighty_Box','Almighty Box','18','0','0','0','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','getitem(Almighty, 10);','',''); REPLACE INTO `item_db` VALUES ('17226','C_Center_Potion_Box','Infinite Concentration Potion Box','18','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','rentitem C_Center_Potion,604800;','',''); REPLACE INTO `item_db` VALUES ('17227','C_Awakening_Potion_Box','Infinite Awakening Potion Box','18','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','rentitem C_Awakening_Potion,604800;','',''); REPLACE INTO `item_db` VALUES ('17228','C_Berserk_Potion_Box','Infinite Berserk Potion Box','18','0','10','5','10','0','0','0','0','0','18446744073709551615','63','2','0','0','0',NULL,'0','1','0','0','0','0','0','475',NULL,'0',NULL,'0',NULL,'0','rentitem Infinite_Berserk_Potion,604800;','',''); diff --git a/sql-files/main.sql b/sql-files/main.sql index 4e75ccc8b..dcd7e543d 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -617,7 +617,7 @@ CREATE TABLE IF NOT EXISTS `inventory` ( -- CREATE TABLE IF NOT EXISTS `ipbanlist` ( - `list` VARCHAR(13) NOT NULL DEFAULT '', + `list` VARCHAR(39) NOT NULL DEFAULT '', `btime` DATETIME NULL, `rtime` DATETIME NULL, `reason` VARCHAR(255) NOT NULL DEFAULT '', @@ -630,7 +630,7 @@ CREATE TABLE IF NOT EXISTS `ipbanlist` ( CREATE TABLE IF NOT EXISTS `login` ( `account_id` INT UNSIGNED NOT NULL AUTO_INCREMENT, - `userid` VARCHAR(23) NOT NULL DEFAULT '', + `userid` VARCHAR(23) NOT NULL, `user_pass` VARCHAR(32) NOT NULL DEFAULT '', `sex` ENUM('M','F','S') NOT NULL DEFAULT 'M', `email` VARCHAR(39) NOT NULL DEFAULT '', @@ -646,7 +646,7 @@ CREATE TABLE IF NOT EXISTS `login` ( `pincode` VARCHAR(4) NOT NULL DEFAULT '', `pincode_change` INT UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY (`account_id`), - KEY `name` (`userid`) + UNIQUE KEY `name` (`userid`) ) ENGINE=MyISAM AUTO_INCREMENT=2000000; -- added standard accounts for servers, VERY INSECURE!!! @@ -936,6 +936,8 @@ INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1570309293); -- 2019-10-0 INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1570870260); -- 2019-10-21--14-21.sql INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1574463539); -- 2019-11-22--23-58.sql INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1579817630); -- 2020-01-24--01-09.sql +INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1584838560); -- 2020-03-22--01-56.sql +INSERT IGNORE INTO `sql_updates` (`timestamp`) VALUES (1584842940); -- 2020-03-22--03-09.sql -- -- Table structure for table `storage` diff --git a/sql-files/upgrades/2020-03-22--01-56.sql b/sql-files/upgrades/2020-03-22--01-56.sql new file mode 100644 index 000000000..58f090a67 --- /dev/null +++ b/sql-files/upgrades/2020-03-22--01-56.sql @@ -0,0 +1,23 @@ +#1584838560 + +-- This file is part of Hercules. +-- http://herc.ws - http://github.com/HerculesWS/Hercules +-- +-- Copyright (C) 2019-2020 Hercules Dev Team +-- +-- Hercules is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. + + +ALTER TABLE `ipbanlist` MODIFY `list` VARCHAR(39) NOT NULL DEFAULT ''; +INSERT INTO `sql_updates` (`timestamp`) VALUES (1584838560); diff --git a/sql-files/upgrades/2020-03-22--03-09.sql b/sql-files/upgrades/2020-03-22--03-09.sql new file mode 100644 index 000000000..dbdf65c5c --- /dev/null +++ b/sql-files/upgrades/2020-03-22--03-09.sql @@ -0,0 +1,24 @@ +#1584842940 + +-- This file is part of Hercules. +-- http://herc.ws - http://github.com/HerculesWS/Hercules +-- +-- Copyright (C) 2019-2020 Hercules Dev Team +-- +-- Hercules is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. + +ALTER TABLE `login` ALTER `userid` DROP DEFAULT; +ALTER TABLE `login` DROP INDEX `name`; +ALTER TABLE `login` ADD CONSTRAINT `name` UNIQUE (`userid`); +INSERT INTO `sql_updates` (`timestamp`) VALUES (1584842940); diff --git a/sql-files/upgrades/index.txt b/sql-files/upgrades/index.txt index 1ddd8b831..fdd5fcc5a 100644 --- a/sql-files/upgrades/index.txt +++ b/sql-files/upgrades/index.txt @@ -60,3 +60,5 @@ 2019-10-12--14-21.sql 2019-11-22--23-58.sql 2020-01-24--01-09.sql +2020-03-22--01-56.sql +2020-03-22--03-09.sql 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/HPMDataCheck.h b/src/common/HPMDataCheck.h index d2e491ad2..72ae64525 100644 --- a/src/common/HPMDataCheck.h +++ b/src/common/HPMDataCheck.h @@ -738,7 +738,6 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = { { "PACKET_ZC_REPAIRITEMLIST", sizeof(struct PACKET_ZC_REPAIRITEMLIST), SERVER_TYPE_MAP }, { "PACKET_ZC_REPAIRITEMLIST_sub", sizeof(struct PACKET_ZC_REPAIRITEMLIST_sub), SERVER_TYPE_MAP }, { "PACKET_ZC_ROLE_CHANGE", sizeof(struct PACKET_ZC_ROLE_CHANGE), SERVER_TYPE_MAP }, - { "PACKET_ZC_SE_CASHSHOP_OPEN", sizeof(struct PACKET_ZC_SE_CASHSHOP_OPEN), SERVER_TYPE_MAP }, { "PACKET_ZC_SEARCH_STORE_INFO_ACK", sizeof(struct PACKET_ZC_SEARCH_STORE_INFO_ACK), SERVER_TYPE_MAP }, { "PACKET_ZC_SEARCH_STORE_INFO_ACK_sub", sizeof(struct PACKET_ZC_SEARCH_STORE_INFO_ACK_sub), SERVER_TYPE_MAP }, { "PACKET_ZC_SKILL_SCALE", sizeof(struct PACKET_ZC_SKILL_SCALE), SERVER_TYPE_MAP }, @@ -859,6 +858,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = { #define MAP_PC_GROUPS_H #endif // MAP_PC_GROUPS_H #ifdef MAP_PC_H + { "autocast_data", sizeof(struct autocast_data), SERVER_TYPE_MAP }, { "autotrade_vending", sizeof(struct autotrade_vending), SERVER_TYPE_MAP }, { "class_exp_group", sizeof(struct class_exp_group), SERVER_TYPE_MAP }, { "class_exp_tables", sizeof(struct class_exp_tables), SERVER_TYPE_MAP }, 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/common/packets/packets2020_len_main.h b/src/common/packets/packets2020_len_main.h index 2a6058f65..d3adf8405 100644 --- a/src/common/packets/packets2020_len_main.h +++ b/src/common/packets/packets2020_len_main.h @@ -4617,7 +4617,9 @@ packetLen(0x0b6f, 177) #endif // Packet: 0x0b70 -#if PACKETVER >= 20200122 +#if PACKETVER >= 20200318 +packetLen(0x0b70, -1) +#elif PACKETVER >= 20200122 packetLen(0x0b70, 8) #endif @@ -4627,7 +4629,9 @@ packetLen(0x0b71, 177) #endif // Packet: 0x0b72 -#if PACKETVER >= 20200122 +#if PACKETVER >= 20200318 +packetLen(0x0b72, -1) +#elif PACKETVER >= 20200122 packetLen(0x0b72, 4) #endif @@ -4646,5 +4650,10 @@ packetLen(0x0b74, 1026) packetLen(0x0b75, 1026) #endif +// Packet: 0x0b76 +#if PACKETVER >= 20200401 +packetLen(0x0b76, 77) +#endif + #endif /* COMMON_PACKETS2020_LEN_MAIN_H */ diff --git a/src/common/packets/packets2020_len_zero.h b/src/common/packets/packets2020_len_zero.h index c1ffbecf6..888d7999b 100644 --- a/src/common/packets/packets2020_len_zero.h +++ b/src/common/packets/packets2020_len_zero.h @@ -4617,7 +4617,9 @@ packetLen(0x0b6f, 177) #endif // Packet: 0x0b70 -#if PACKETVER >= 20200129 +#if PACKETVER >= 20200401 +packetLen(0x0b70, -1) +#elif PACKETVER >= 20200129 packetLen(0x0b70, 8) #endif @@ -4627,7 +4629,9 @@ packetLen(0x0b71, 177) #endif // Packet: 0x0b72 -#if PACKETVER >= 20200129 +#if PACKETVER >= 20200401 +packetLen(0x0b72, -1) +#elif PACKETVER >= 20200129 packetLen(0x0b72, 4) #endif @@ -4646,5 +4650,10 @@ packetLen(0x0b74, 1026) packetLen(0x0b75, 1026) #endif +// Packet: 0x0b76 +#if PACKETVER >= 20200401 +packetLen(0x0b76, 77) +#endif + #endif /* COMMON_PACKETS2020_LEN_ZERO_H */ diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 410cd7af7..91ddc3ef9 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. + + if (id == 0) + id = atoi(message); // Egg/monster ID. + } + + int pet_id = pet->search_petDB_index(id, PET_CLASS); - pet_id = pet->search_petDB_index(id, PET_CLASS); - if (pet_id < 0) + 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; } @@ -5671,6 +5696,8 @@ ACMD(useskill) return false; } + pc->autocast_clear(sd); + if (skill_id >= HM_SKILLBASE && skill_id < HM_SKILLBASE+MAX_HOMUNSKILL && sd->hd && homun_alive(sd->hd)) // (If used with @useskill, put the homunc as dest) bl = &sd->hd->bl; @@ -7865,39 +7892,61 @@ ACMD(monsterignore) return true; } -/*========================================== - * @fakename - * => Gives your character a fake name. [Valaris] - *------------------------------------------*/ + +/** + * Temporarily changes the character's name to the specified string. + * + * @code{.herc} + * @fakename {<options>} {<fake_name>} + * @endcode + * + **/ ACMD(fakename) { - if (!*message) - { - if (sd->fakename[0]) - { + if (*message == '\0') { + if (sd->fakename[0] != '\0') { sd->fakename[0] = '\0'; + sd->fakename_options = FAKENAME_OPTION_NONE; clif->blname_ack(0, &sd->bl); - if( sd->disguise ) + + if (sd->disguise != 0) // Another packet should be sent so the client updates the name for sd. clif->blname_ack(sd->fd, &sd->bl); - clif->message(sd->fd, msg_fd(fd,1307)); // Returned to real name. + + clif->message(sd->fd, msg_fd(fd, 1307)); // Returned to real name. return true; } - clif->message(sd->fd, msg_fd(fd,1308)); // You must enter a name. + clif->message(sd->fd, msg_fd(fd, 1308)); // You must enter a name. return false; } - if (strlen(message) < 2) - { - clif->message(sd->fd, msg_fd(fd,1309)); // Fake name must be at least two characters. + int options = FAKENAME_OPTION_NONE; + char buf[NAME_LENGTH] = {'\0'}; + const char *fake_name = NULL; + + if (sscanf(message, "%d %23[^\n]", &options, buf) == 2) { + fake_name = buf; + } else { + options = FAKENAME_OPTION_NONE; + fake_name = message; + } + + if (strlen(fake_name) < 2) { + clif->message(sd->fd, msg_fd(fd, 1309)); // Fake name must be at least two characters. return false; } - safestrncpy(sd->fakename, message, sizeof(sd->fakename)); + if (options < FAKENAME_OPTION_NONE) + options = FAKENAME_OPTION_NONE; + + safestrncpy(sd->fakename, fake_name, sizeof(sd->fakename)); + sd->fakename_options = options; clif->blname_ack(0, &sd->bl); - if (sd->disguise) // Another packet should be sent so the client updates the name for sd + + if (sd->disguise != 0) // Another packet should be sent so the client updates the name for sd. clif->blname_ack(sd->fd, &sd->bl); - clif->message(sd->fd, msg_fd(fd,1310)); // Fake name enabled. + + clif->message(sd->fd, msg_fd(fd, 1310)); // Fake name enabled. return true; } diff --git a/src/map/atcommand.h b/src/map/atcommand.h index 66827b3b2..f3a5155ab 100644 --- a/src/map/atcommand.h +++ b/src/map/atcommand.h @@ -54,6 +54,16 @@ typedef enum { COMMAND_CHARCOMMAND = 2, } AtCommandType; +/** @fakename display option flags **/ +enum fakename_option_flag { + FAKENAME_OPTION_NONE = 0x00, + FAKENAME_OPTION_SHOW_PARTYNAME = 0x01, + FAKENAME_OPTION_SHOW_GUILDNAME = 0x02, + FAKENAME_OPTION_SHOW_GUILDPOSITION = 0x04, + FAKENAME_OPTION_SHOW_CLANPOSITION = 0x08, + FAKENAME_OPTION_SHOW_TITLE = 0x10 +}; + /** * Typedef **/ diff --git a/src/map/battle.c b/src/map/battle.c index 985d2bca4..40c645cf7 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -5928,21 +5928,21 @@ static void battle_reflect_damage(struct block_list *target, struct block_list * delay += 100;/* gradual increase so the numbers don't clip in the client */ } if( sc->data[SC_LG_REFLECTDAMAGE] && rnd()%100 < (30 + 10*sc->data[SC_LG_REFLECTDAMAGE]->val1) ) { - bool change = false; - NORMALIZE_RDAMAGE(damage * sc->data[SC_LG_REFLECTDAMAGE]->val2 / 100); trdamage -= rdamage;/* wont count towards total */ - if( sd && !sd->state.autocast ) { - change = true; - sd->state.autocast = 1; + enum autocast_type ac_type; + + if (sd != NULL) { + ac_type = sd->autocast.type; + sd->autocast.type = AUTOCAST_TEMP; } map->foreachinshootrange(battle->damage_area,target,skill->get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,tick,target,delay,wd->dmotion,rdamage,status_get_race(target)); - if( change ) - sd->state.autocast = 0; + if (sd != NULL) + sd->autocast.type = ac_type; delay += 150;/* gradual increase so the numbers don't clip in the client */ @@ -6132,7 +6132,7 @@ static int battle_damage_area(struct block_list *bl, va_list ap) else status_fix_damage(src,bl,damage,0); clif->damage(bl,bl,amotion,dmotion,damage,1,BDT_ENDURE,0); - if (src->type != BL_PC || !BL_UCCAST(BL_PC, src)->state.autocast) + if (src->type != BL_PC || BL_UCCAST(BL_PC, src)->autocast.type != AUTOCAST_TEMP) skill->additional_effect(src, bl, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick); map->freeblock_unlock(); } @@ -6456,10 +6456,10 @@ static enum damage_lv battle_weapon_attack(struct block_list *src, struct block_ } } - sd->state.autocast = 1; + sd->autocast.type = AUTOCAST_TEMP; skill->consume_requirement(sd,r_skill,r_lv,3); skill->castend_type(type, src, target, r_skill, r_lv, tick, flag); - sd->state.autocast = 0; + sd->autocast.type = AUTOCAST_NONE; sd->ud.canact_tick = tick + skill->delay_fix(src, r_skill, r_lv); clif->status_change(src, status->get_sc_icon(SC_POSTDELAY), status->get_sc_relevant_bl_types(SC_POSTDELAY), 1, skill->delay_fix(src, r_skill, r_lv), 0, 0, 1); } @@ -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 c9e018f73..496a8beda 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -6766,7 +6766,7 @@ static void clif_item_skill(struct map_session_data *sd, uint16 skill_id, uint16 struct PACKET_ZC_AUTORUN_SKILL *p = WFIFOP(fd, 0); int type = skill->get_inf(skill_id); - if (sd->state.itemskill_castonself == 1 && skill->is_item_skill(sd, skill_id, skill_lv)) + if (sd->autocast.itemskill_cast_on_self && sd->autocast.type == AUTOCAST_ITEM) type = INF_SELF_SKILL; p->packetType = HEADER_ZC_AUTORUN_SKILL; @@ -9382,82 +9382,98 @@ static void clif_send_selforarea(int fd, struct block_list *bl, const void *buf, } } -/// Updates the object's (bl) name on client. -/// 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME) -/// 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL) -/// 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2) +/** + * Updates a character's name on client. + * + * @code + * 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME) + * 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL) + * 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2) + * @endcode + * + * @param fd The incoming file descriptor. + * @param bl The related character's block list. + * + **/ static void clif_pcname_ack(int fd, struct block_list *bl) { nullpo_retv(bl); Assert_retv(bl->type == BL_PC); - struct PACKET_ZC_ACK_REQNAMEALL packet = { 0 }; - int len = sizeof(struct PACKET_ZC_ACK_REQNAMEALL); + struct PACKET_ZC_ACK_REQNAMEALL packet = {0}; + packet.packet_id = HEADER_ZC_ACK_REQNAMEALL; packet.gid = bl->id; const struct map_session_data *ssd = BL_UCCAST(BL_PC, bl); - if (ssd->fakename[0] != '\0') { - packet.packet_id = reqName; - len = sizeof(struct packet_reqname_ack); - } else { - packet.packet_id = HEADER_ZC_ACK_REQNAMEALL; - len = sizeof(struct PACKET_ZC_ACK_REQNAMEALL); - } - - //Requesting your own "shadow" name. [Skotlex] - if (ssd->fd == fd && ssd->disguise != -1) { + if (ssd->fd == fd && ssd->disguise != -1) // Requesting your own "shadow" name. packet.gid = -bl->id; - } - if (ssd->fakename[0] != '\0') { + if (ssd->fakename[0] != '\0') memcpy(packet.name, ssd->fakename, NAME_LENGTH); - } else { -#if PACKETVER_MAIN_NUM >= 20150225 || PACKETVER_RE_NUM >= 20141126 || defined(PACKETVER_ZERO) - // Title System [Dastgir/Hercules] - if (ssd->status.title_id > 0) { - packet.title_id = ssd->status.title_id; - } -#endif + else memcpy(packet.name, ssd->status.name, NAME_LENGTH); - const struct party_data *p = NULL; - int ps = -1; - if (ssd->status.party_id != 0) { - p = party->search(ssd->status.party_id); - } - const struct guild *g = NULL; - if (ssd->status.guild_id != 0) { - if ((g = ssd->guild) != NULL) { - int i; - ARR_FIND(0, g->max_member, i, g->member[i].account_id == ssd->status.account_id && g->member[i].char_id == ssd->status.char_id); - if (i < g->max_member) - ps = g->member[i].position; - } - } + const struct party_data *p = NULL; - if (!battle_config.display_party_name && g == NULL) { - // do not display party unless the player is also in a guild - p = NULL; - } + if (ssd->status.party_id != 0) + p = party->search(ssd->status.party_id); + + const struct guild *g = NULL; + int pos_idx = INDEX_NOT_FOUND; + + if (ssd->status.guild_id != 0 && (g = ssd->guild) != NULL) { + int i; + int acc_id = ssd->status.account_id; + int chr_id = ssd->status.char_id; + + ARR_FIND(0, g->max_member, i, g->member[i].account_id == acc_id && g->member[i].char_id == chr_id); + + if (i < g->max_member) + pos_idx = g->member[i].position; + } + + if (battle_config.display_party_name == 0 && g == NULL) + p = NULL; // Do not display party name, unless the character is also in a guild. - if (p != NULL) { + if (p != NULL) { + if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_PARTYNAME) != 0) + || ssd->fakename[0] == '\0') { memcpy(packet.party_name, p->party.name, NAME_LENGTH); } + } - if (g != NULL && ps >= 0 && ps < MAX_GUILDPOSITION) { + if (g != NULL && pos_idx >= 0 && pos_idx < MAX_GUILDPOSITION) { + if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_GUILDNAME) != 0) + || ssd->fakename[0] == '\0') { memcpy(packet.guild_name, g->name,NAME_LENGTH); - memcpy(packet.position_name, g->position[ps].name, NAME_LENGTH); } - else if (ssd->status.clan_id != 0) { - struct clan *c = clan->search(ssd->status.clan_id); - if (c != 0) { + + if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_GUILDPOSITION) != 0) + || ssd->fakename[0] == '\0') { + memcpy(packet.position_name, g->position[pos_idx].name, NAME_LENGTH); + } + } else if (ssd->status.clan_id != 0) { + struct clan *c = clan->search(ssd->status.clan_id); + + if (c != 0) { + if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_CLANPOSITION) != 0) + || ssd->fakename[0] == '\0') { memcpy(packet.position_name, c->name, NAME_LENGTH); } } } - clif->send_selforarea(fd, bl, &packet, len); +#if PACKETVER_MAIN_NUM >= 20150225 || PACKETVER_RE_NUM >= 20141126 || defined(PACKETVER_ZERO) // Title system. + if (ssd->status.title_id > 0) { + if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_TITLE) != 0) + || ssd->fakename[0] == '\0') { + packet.title_id = ssd->status.title_id; + } + } +#endif + + clif->send_selforarea(fd, bl, &packet, sizeof(struct PACKET_ZC_ACK_REQNAMEALL)); } /// Updates the object's (bl) name on client. @@ -9710,6 +9726,7 @@ static void clif_unknownname_ack(int fd, struct block_list *bl) { nullpo_retv(bl); ShowError("clif_blname_ack: bad type %u(%d)\n", bl->type, bl->id); + Assert_retv(0); } static void clif_blname_ack(int fd, struct block_list *bl) @@ -9747,56 +9764,90 @@ static void clif_blname_ack(int fd, struct block_list *bl) } } -//Used to update when a char leaves a party/guild. [Skotlex] -//Needed because when you send a 0x95 packet, the client will not remove the cached party/guild info that is not sent. +/** + * Updates a character's name on client when leaving a party/guild. + * + * @code + * 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL) + * 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2) + * @endcode + * + * @param ssd The related character. + * + **/ static void clif_charnameupdate(struct map_session_data *ssd) { - int ps = -1; - struct party_data *p = NULL; - struct guild *g = NULL; - struct PACKET_ZC_ACK_REQNAMEALL packet = { 0 }; - nullpo_retv(ssd); - if (ssd->fakename[0]) - return; //No need to update as the party/guild was not displayed anyway. - + struct PACKET_ZC_ACK_REQNAMEALL packet = {0}; packet.packet_id = HEADER_ZC_ACK_REQNAMEALL; packet.gid = ssd->bl.id; - memcpy(packet.name, ssd->status.name, NAME_LENGTH); + if (ssd->fakename[0] != '\0') + memcpy(packet.name, ssd->fakename, NAME_LENGTH); + else + memcpy(packet.name, ssd->status.name, NAME_LENGTH); - if (!battle_config.display_party_name) { - if (ssd->status.party_id > 0 && ssd->status.guild_id > 0 && (g = ssd->guild) != NULL) - p = party->search(ssd->status.party_id); - } else { - if (ssd->status.party_id > 0) - p = party->search(ssd->status.party_id); - } + struct party_data *p = NULL; + + if (ssd->status.party_id != 0) + p = party->search(ssd->status.party_id); + + struct guild *g = NULL; + int pos_idx = INDEX_NOT_FOUND; - if (ssd->status.guild_id > 0 && (g = ssd->guild) != NULL) { + if (ssd->status.guild_id != 0 && (g = ssd->guild) != NULL) { int i; - ARR_FIND(0, g->max_member, i, g->member[i].account_id == ssd->status.account_id && g->member[i].char_id == ssd->status.char_id); - if( i < g->max_member ) ps = g->member[i].position; + int acc_id = ssd->status.account_id; + int chr_id = ssd->status.char_id; + + ARR_FIND(0, g->max_member, i, g->member[i].account_id == acc_id && g->member[i].char_id == chr_id); + + if (i < g->max_member) + pos_idx = g->member[i].position; } - if (p != NULL) - memcpy(packet.party_name, p->party.name, NAME_LENGTH); + if (battle_config.display_party_name == 0 && g == NULL) + p = NULL; // Do not display party name, unless the character is also in a guild. - if (g != NULL && ps >= 0 && ps < MAX_GUILDPOSITION) { - memcpy(packet.guild_name, g->name,NAME_LENGTH); - memcpy(packet.position_name, g->position[ps].name, NAME_LENGTH); + if (p != NULL) { + if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_PARTYNAME) != 0) + || ssd->fakename[0] == '\0') { + memcpy(packet.party_name, p->party.name, NAME_LENGTH); + } } -#if PACKETVER_MAIN_NUM >= 20150225 || PACKETVER_RE_NUM >= 20141126 || defined(PACKETVER_ZERO) - // Achievement System [Dastgir/Hercules] + if (g != NULL && pos_idx >= 0 && pos_idx < MAX_GUILDPOSITION) { + if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_GUILDNAME) != 0) + || ssd->fakename[0] == '\0') { + memcpy(packet.guild_name, g->name,NAME_LENGTH); + } + + if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_GUILDPOSITION) != 0) + || ssd->fakename[0] == '\0') { + memcpy(packet.position_name, g->position[pos_idx].name, NAME_LENGTH); + } + } else if (ssd->status.clan_id != 0) { + struct clan *c = clan->search(ssd->status.clan_id); + + if (c != 0) { + if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_CLANPOSITION) != 0) + || ssd->fakename[0] == '\0') { + memcpy(packet.position_name, c->name, NAME_LENGTH); + } + } + } + +#if PACKETVER_MAIN_NUM >= 20150225 || PACKETVER_RE_NUM >= 20141126 || defined(PACKETVER_ZERO) // Title system. if (ssd->status.title_id > 0) { - packet.title_id = ssd->status.title_id; + if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_TITLE) != 0) + || ssd->fakename[0] == '\0') { + packet.title_id = ssd->status.title_id; + } } #endif - // Update nearby clients - clif->send(&packet, sizeof(packet), &ssd->bl, AREA); + clif->send(&packet, sizeof(packet), &ssd->bl, AREA); // Update nearby clients. } /// Taekwon Jump (TK_HIGHJUMP) effect (ZC_HIGHJUMP). @@ -10539,51 +10590,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); } @@ -10654,309 +10714,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(sd->status.manner < 0) - sc_start(NULL,&sd->bl,SC_NOCHAT,100,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); + } - //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++) { + if (sd->status.manner < 0) + sc_start(NULL, &sd->bl, SC_NOCHAT, 100, 0, 0); + + 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 } @@ -12706,6 +12787,14 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill { int64 tick = timer->gettick(); + /** + * According to Skotlex' comment below, the client sometimes passes 0 for the skill level. + * Even though this seems to only affect guild skills, sd->autocast.skill_lv is used + * for the auto-cast data validation if skill_lv is 0. + * + **/ + skill->validate_autocast_data(sd, skill_id, (skill_lv == 0) ? sd->autocast.skill_lv : skill_lv); + if (skill_lv < 1) skill_lv = 1; //No clue, I have seen the client do this with guild skills :/ [Skotlex] @@ -12759,7 +12848,7 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill if (skill_id != SA_CASTCANCEL && skill_id != SO_SPELLFIST) return; } else if (DIFF_TICK(tick, sd->ud.canact_tick) < 0) { - if (sd->skillitem != skill_id) { + if (sd->autocast.type == AUTOCAST_NONE) { clif->skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0, 0); return; } @@ -12777,16 +12866,16 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill } else if (sd->menuskill_id != SA_AUTOSPELL) return; //Can't use skills while a menu is open. } - if (sd->skillitem == skill_id) { - if (skill_lv != sd->skillitemlv) - skill_lv = sd->skillitemlv; + if (sd->autocast.type != AUTOCAST_NONE) { + if (skill_lv != sd->autocast.skill_lv) + skill_lv = sd->autocast.skill_lv; if (!(tmp&INF_SELF_SKILL)) pc->delinvincibletimer(sd); // Target skills through items cancel invincibility. [Inkfish] unit->skilluse_id(&sd->bl, target_id, skill_id, skill_lv); return; } - sd->skillitem = sd->skillitemlv = 0; + pc->autocast_clear(sd); if (skill_id >= GD_SKILLBASE && skill_id < GD_MAX) { if (sd->state.gmaster_flag) @@ -12847,6 +12936,16 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin int64 tick = timer->gettick(); nullpo_retv(sd); + + /** + * When using clif_item_skill() to initiate the execution of ground skills, + * the client sometimes passes 0 for the skill level in packet 0x0af4. + * In that case sd->autocast.skill_lv is used for the auto-cast data validation, + * since clif_item_skill() is only used for auto-cast skills. + * + **/ + skill->validate_autocast_data(sd, skill_id, (skill_lv == 0) ? sd->autocast.skill_lv : skill_lv); + if( !(skill->get_inf(skill_id)&INF_GROUND_SKILL) ) return; //Using a target skill on the ground? WRONG. @@ -12887,7 +12986,7 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin return; if( DIFF_TICK(tick, sd->ud.canact_tick) < 0 ) { - if( sd->skillitem != skill_id ) { + if (sd->autocast.type == AUTOCAST_NONE) { clif->skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0, 0); return; } @@ -12908,13 +13007,13 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin pc->delinvincibletimer(sd); - if( sd->skillitem == skill_id ) { - if( skill_lv != sd->skillitemlv ) - skill_lv = sd->skillitemlv; + if (sd->autocast.type != AUTOCAST_NONE) { + if (skill_lv != sd->autocast.skill_lv) + skill_lv = sd->autocast.skill_lv; unit->skilluse_pos(&sd->bl, x, y, skill_id, skill_lv); } else { int lv; - sd->skillitem = sd->skillitemlv = 0; + pc->autocast_clear(sd); if( (lv = pc->checkskill(sd, skill_id)) > 0 ) { if( skill_lv > lv ) skill_lv = lv; @@ -12985,9 +13084,15 @@ static void clif_parse_UseSkillMap(int fd, struct map_session_data *sd) return; } + /** + * Since no skill level was passed use 0 to notify skill_validate_autocast_data() of this special case. + * + **/ + skill->validate_autocast_data(sd, skill_id, 0); + pc->delinvincibletimer(sd); skill->castend_map(sd,skill_id,map_name); - pc->itemskill_clear(sd); + pc->autocast_clear(sd); } static void clif_parse_RequestMemo(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); @@ -15180,58 +15285,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; - if (idx == sd->status.inventorySize) { + 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 (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; + + ARR_FIND(0, MAX_PET_DB, pet_index, pet->db[pet_index].class_ == sd->pd->pet.class_); - if (petIndex == MAX_PET_DB) { - // Which error? - clif->petEvolutionResult(fd, PET_EVOL_UNKNOWN); + 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); @@ -15241,7 +15356,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); @@ -15251,27 +15366,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; } } @@ -20091,7 +20205,7 @@ static void clif_parse_cashShopOpen2(int fd, struct map_session_data *sd) static void clif_cashShopOpen(int fd, struct map_session_data *sd, int tab) { -#if PACKETVER_MAIN_NUM >= 20101123 || PACKETVER_RE_NUM >= 20120328 || PACKETVER_ZERO_NUM >= defined(PACKETVER_ZERO) +#if PACKETVER_MAIN_NUM >= 20101123 || PACKETVER_RE_NUM >= 20120328 || defined(PACKETVER_ZERO) WFIFOHEAD(fd, sizeof(struct PACKET_ZC_SE_CASHSHOP_OPEN)); struct PACKET_ZC_SE_CASHSHOP_OPEN *p = WFIFOP(fd, 0); p->packetType = HEADER_ZC_SE_CASHSHOP_OPEN; diff --git a/src/map/map.c b/src/map/map.c index defa56b2e..b2c9c77c3 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -6047,11 +6047,15 @@ static bool map_add_questinfo(int m, struct npc_data *nd) nullpo_retr(false, nd); Assert_retr(false, m >= 0 && m < map->count); - if (&VECTOR_LAST(map->list[m].qi_list) == nd) + int i; + ARR_FIND(0, VECTOR_LENGTH(map->list[m].qi_list), i, VECTOR_INDEX(map->list[m].qi_list, i) == nd); + + if (i < VECTOR_LENGTH(map->list[m].qi_list)) { return false; + } VECTOR_ENSURE(map->list[m].qi_list, 1, 1); - VECTOR_PUSH(map->list[m].qi_list, *nd); + VECTOR_PUSH(map->list[m].qi_list, nd); return true; } @@ -6062,7 +6066,7 @@ static bool map_remove_questinfo(int m, struct npc_data *nd) Assert_retr(false, m >= 0 && m < map->count); int i; - ARR_FIND(0, VECTOR_LENGTH(map->list[m].qi_list), i, &VECTOR_INDEX(map->list[m].qi_list, i) == nd); + ARR_FIND(0, VECTOR_LENGTH(map->list[m].qi_list), i, VECTOR_INDEX(map->list[m].qi_list, i) == nd); if (i != VECTOR_LENGTH(map->list[m].qi_list)) { VECTOR_ERASE(map->list[m].qi_list, i); return true; diff --git a/src/map/map.h b/src/map/map.h index a876539d0..2de6df2f7 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -846,7 +846,7 @@ struct map_data { } cell_buf; /* questinfo entries list */ - VECTOR_DECL(struct npc_data) qi_list; + VECTOR_DECL(struct npc_data *) qi_list; /* speeds up clif_updatestatus processing by causing hpmeter to run only when someone with the permission can view it */ unsigned short hpmeter_visible; 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/npc.c b/src/map/npc.c index 2ac99948b..40ec380ee 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -1799,6 +1799,7 @@ static void npc_expanded_barter_fromsql(void) ) { SqlStmt_ShowDebug(stmt); SQL->StmtFree(stmt); + StrBuf->Destroy(&buf); return; } diff --git a/src/map/packets_keys_main.h b/src/map/packets_keys_main.h index 5fddf9eaf..e3a89827c 100644 --- a/src/map/packets_keys_main.h +++ b/src/map/packets_keys_main.h @@ -37,7 +37,7 @@ packetKeys(0x49357d72,0x22c370a1,0x5f836591); #endif -// 2010-11-23aRagexeRE, 2010-11-24aRagexeRE, 2010-11-24bRagexeRE, 2010-11-25aRagexeRE, 2010-11-26aRagexeRE, 2010-11-30aRagexeRE, 2010-12-07aRagexeRE, 2010-12-14aRagexeRE, 2010-12-21aRagexeRE, 2010-12-23aRagexeRE, 2010-12-28aRagexeRE, 2011-01-04aRagexeRE, 2011-01-05aRagexeRE, 2011-01-11aRagexeRE, 2011-01-18aRagexeRE, 2011-01-25aRagexeRE, 2011-01-26aRagexeRE, 2011-01-26bRagexeRE, 2011-01-31aRagexeRE, 2011-01-31bRagexeRE, 2011-01-31cRagexeRE, 2011-02-08aRagexeRE, 2011-02-15aRagexeRE, 2011-02-22aRagexeRE, 2011-02-23aRagexeRE, 2011-02-23bRagexeRE, 2011-02-24aRagexeRE, 2011-02-25aRagexeRE, 2011-02-28aRagexeRE, 2011-03-08aRagexeRE, 2011-03-09aRagexeRE, 2011-03-09bRagexeRE, 2011-03-09cRagexeRE, 2011-03-09dRagexeRE, 2011-03-15aRagexeRE, 2011-03-22aRagexeRE, 2011-03-29aRagexeRE, 2011-03-30aRagexeRE, 2011-03-30cRagexeRE, 2011-04-05aRagexeRE, 2011-04-12aRagexeRE, 2011-04-19aRagexeRE, 2011-04-20aRagexeRE, 2011-04-26aRagexeRE, 2011-04-27aRagexeRE, 2011-05-03aRagexeRE, 2011-05-11aRagexeRE, 2011-05-17bRagexeRE, 2011-05-24aRagexeRE, 2011-05-26aRagexeRE, 2011-05-31aRagexeRE, 2011-06-07aRagexeRE, 2011-06-08aRagexeRE, 2011-06-08bRagexeRE, 2011-06-08cRagexeRE, 2011-06-09aRagexeRE, 2011-06-14bRagexeRE, 2011-06-22aRagexeRE, 2011-06-28aRagexeRE, 2011-07-06aRagexeRE, 2011-07-13aRagexeRE, 2011-07-13bRagexeRE, 2011-07-13cRagexeRE, 2011-07-19aRagexeRE, 2011-07-26aRagexeRE, 2011-08-03aRagexeRE, 2011-08-03bRagexeRE, 2011-08-10aRagexeRE, 2013-12-23aRagexeRE, 2014-05-08aRagexe, 2014-05-08aRagexeRE, 2014-06-11eRagexe, 2015-02-25hRagexe, 2018-03-15aRagexe, 2018-03-21aRagexe, 2018-03-21aRagexeRE, 2018-03-28bRagexe, 2018-03-28bRagexeRE, 2018-04-04bRagexe, 2018-04-04cRagexeRE, 2018-04-18aRagexe, 2018-04-18bRagexeRE, 2018-04-25cRagexe, 2018-04-25cRagexeRE, 2018-05-02bRagexe, 2018-05-02bRagexeRE, 2018-05-02dRagexeRE, 2018-05-09aRagexe, 2018-05-16cRagexe, 2018-05-16cRagexeRE, 2018-05-23aRagexe, 2018-05-23aRagexeRE, 2018-05-30aRagexe, 2018-05-30bRagexeRE, 2018-05-30cRagexeRE, 2018-06-05bRagexe, 2018-06-05bRagexeRE, 2018-06-12aRagexeRE, 2018-06-12bRagexeRE, 2018-06-20cRagexe, 2018-06-20dRagexeRE, 2018-06-20eRagexe, 2018-06-20eRagexeRE, 2018-06-21aRagexe, 2018-06-21aRagexeRE, 2018-07-04aRagexe, 2018-07-04aRagexeRE, 2018-07-11aRagexeRE, 2018-07-18bRagexe, 2018-07-18bRagexeRE, 2018-07-18bRagexeRE1, 2018-07-18cRagexe, 2018-07-18cRagexeRE, 2018-08-01cRagexe, 2018-08-01cRagexeRE, 2018-08-08bRagexe, 2018-08-08bRagexeRE, 2018-08-22cRagexe, 2018-08-22cRagexeRE, 2018-08-29aRagexe, 2018-08-29aRagexeRE, 2018-08-29bRagexeRE, 2018-08-31aRagexe, 2018-09-12dRagexe, 2018-09-12dRagexeRE, 2018-09-19aRagexe, 2018-09-19aRagexeRE, 2018-10-02aRagexe, 2018-10-02aRagexeRE, 2018-10-02bRagexe, 2018-10-02bRagexeRE, 2018-10-17_02aRagexe, 2018-10-17_02aRagexeRE, 2018-10-17_03aRagexe, 2018-10-17_03aRagexeRE, 2018-10-17bRagexe, 2018-10-17bRagexeRE, 2018-10-24bRagexe, 2018-10-31aRagexe, 2018-10-31bRagexe, 2018-10-31cRagexeRE, 2018-11-07aRagexe, 2018-11-07aRagexeRE, 2018-11-14cRagexe, 2018-11-14cRagexeRE, 2018-11-14dRagexe, 2018-11-14dRagexeRE, 2018-11-21bRagexe, 2018-11-21cRagexeRE, 2018-11-28aRagexe, 2018-11-28aRagexeRE, 2018-11-28bRagexe, 2018-11-28cRagexe, 2018-12-05aRagexe, 2018-12-05bRagexeRE, 2018-12-12aRagexe, 2018-12-12aRagexeRE, 2018-12-12bRagexe, 2018-12-12bRagexeRE, 2018-12-19bRagexe, 2018-12-19bRagexeRE, 2018-12-26aRagexe, 2018-12-26aRagexeRE, 2019-01-09aRagexe, 2019-01-09bRagexeRE, 2019-01-16bRagexe, 2019-01-16bRagexeRE, 2019-01-16cRagexe, 2019-01-16cRagexeRE, 2019-01-23dRagexe, 2019-01-23dRagexeRE, 2019-02-13IRagexeRE, 2019-02-13bRagexe, 2019-02-13eRagexe, 2019-02-20aRagexeRE, 2019-02-27aRagexe, 2019-02-27bRagexeRE, 2019-02-28aRagexe, 2019-02-28aRagexeRE, 2019-03-06bRagexe, 2019-03-06bRagexeRE, 2019-03-06cRagexe, 2019-03-06cRagexeRE, 2019-03-13aRagexe, 2019-03-20aRagexe, 2019-03-20aRagexeRE, 2019-03-22aRagexe, 2019-03-22aRagexeRE, 2019-03-27bRagexe, 2019-03-27bRagexeRE, 2019-04-03aRagexe, 2019-04-03bRagexeRE, 2019-04-03cRagexeRE, 2019-04-17aRagexe, 2019-04-17cRagexeRE, 2019-04-18aRagexe, 2019-04-18aRagexeRE, 2019-05-08cRagexe, 2019-05-08dRagexeRE, 2019-05-08eRagexeRE, 2019-05-22bRagexe, 2019-05-22bRagexeRE, 2019-05-22cRagexe, 2019-05-22cRagexeRE, 2019-05-23aRagexe, 2019-05-29aRagexe, 2019-05-29bRagexeRE, 2019-05-29cRagexe, 2019-05-29cRagexeRE, 2019-05-30aRagexe, 2019-05-30aRagexeRE, 2019-06-05JRagexeRE, 2019-06-05KRagexe, 2019-06-05LRagexeRE, 2019-06-05fRagexe, 2019-06-05hRagexeRE, 2019-06-19bRagexe, 2019-06-19cRagexeRE, 2019-06-19eRagexe, 2019-06-19hRagexe, 2019-06-26bRagexeRE, 2019-07-03aRagexe, 2019-07-03bRagexeRE, 2019-07-17aRagexe, 2019-07-17cRagexeRE, 2019-07-17dRagexe, 2019-07-17dRagexeRE, 2019-07-24aRagexe, 2019-07-24bRagexeRE, 2019-07-31bRagexe, 2019-07-31bRagexeRE, 2019-08-02aRagexe, 2019-08-02aRagexeRE, 2019-08-07aRagexe, 2019-08-07dRagexeRE, 2019-08-21aRagexe, 2019-08-21cRagexeRE, 2019-08-21dRagexeRE, 2019-08-28aRagexe, 2019-08-28aRagexeRE, 2019-09-04aRagexe, 2019-09-04bRagexe, 2019-09-04bRagexeRE, 2019-09-18bRagexe, 2019-09-18cRagexeRE, 2019-09-25aRagexe, 2019-09-25aRagexeRE, 2019-09-25bRagexe, 2019-09-25bRagexeRE, 2019-10-02bRagexeRE, 2019-10-02cRagexe, 2019-10-02dRagexe, 2019-10-02dRagexeRE, 2019-10-02dRagexeRE_2, 2019-10-16fRagexe, 2019-10-16fRagexeRE, 2019-10-16gRagexe, 2019-10-16gRagexeRE, 2019-10-18aRagexe, 2019-10-23aRagexe, 2019-10-23aRagexeRE, 2019-10-30bRagexeRE, 2019-10-30cRagexe, 2019-11-06aRagexe, 2019-11-06bRagexeRE, 2019-11-07aRagexe, 2019-11-07aRagexeRE, 2019-11-13cRagexe, 2019-11-13eRagexe, 2019-11-13eRagexeRE, 2019-11-20aRagexe, 2019-11-20cRagexeRE, 2019-11-20dRagexe, 2019-11-27aRagexe, 2019-11-27aRagexeRE, 2019-11-27bRagexe, 2019-12-04aRagexe, 2019-12-04aRagexeRE, 2019-12-04bRagexe, 2019-12-04bRagexeRE, 2019-12-04cRagexeRE, 2019-12-11aRagexe, 2019-12-11fRagexeRE, 2019-12-18bRagexe, 2019-12-18bRagexeRE, 2019-12-24aRagexe, 2019-12-24aRagexeRE, 2019-12-24bRagexe, 2019-12-24bRagexeRE, 2020-01-08aRagexe, 2020-01-08bRagexeRE, 2020-01-22cRagexe, 2020-01-22cRagexeRE, 2020-01-29bRagexe, 2020-01-30aRagexe, 2020-02-05aRagexe, 2020-02-05aRagexeRE, 2020-02-06aRagexe, 2020-02-12aRagexe, 2020-02-12aRagexeRE, 2020-02-19dRagexe, 2020-02-19eRagexeRE, 2020-03-04aRagexe, 2020-03-04aRagexeRE +// 2010-11-23aRagexeRE, 2010-11-24aRagexeRE, 2010-11-24bRagexeRE, 2010-11-25aRagexeRE, 2010-11-26aRagexeRE, 2010-11-30aRagexeRE, 2010-12-07aRagexeRE, 2010-12-14aRagexeRE, 2010-12-21aRagexeRE, 2010-12-23aRagexeRE, 2010-12-28aRagexeRE, 2011-01-04aRagexeRE, 2011-01-05aRagexeRE, 2011-01-11aRagexeRE, 2011-01-18aRagexeRE, 2011-01-25aRagexeRE, 2011-01-26aRagexeRE, 2011-01-26bRagexeRE, 2011-01-31aRagexeRE, 2011-01-31bRagexeRE, 2011-01-31cRagexeRE, 2011-02-08aRagexeRE, 2011-02-15aRagexeRE, 2011-02-22aRagexeRE, 2011-02-23aRagexeRE, 2011-02-23bRagexeRE, 2011-02-24aRagexeRE, 2011-02-25aRagexeRE, 2011-02-28aRagexeRE, 2011-03-08aRagexeRE, 2011-03-09aRagexeRE, 2011-03-09bRagexeRE, 2011-03-09cRagexeRE, 2011-03-09dRagexeRE, 2011-03-15aRagexeRE, 2011-03-22aRagexeRE, 2011-03-29aRagexeRE, 2011-03-30aRagexeRE, 2011-03-30cRagexeRE, 2011-04-05aRagexeRE, 2011-04-12aRagexeRE, 2011-04-19aRagexeRE, 2011-04-20aRagexeRE, 2011-04-26aRagexeRE, 2011-04-27aRagexeRE, 2011-05-03aRagexeRE, 2011-05-11aRagexeRE, 2011-05-17bRagexeRE, 2011-05-24aRagexeRE, 2011-05-26aRagexeRE, 2011-05-31aRagexeRE, 2011-06-07aRagexeRE, 2011-06-08aRagexeRE, 2011-06-08bRagexeRE, 2011-06-08cRagexeRE, 2011-06-09aRagexeRE, 2011-06-14bRagexeRE, 2011-06-22aRagexeRE, 2011-06-28aRagexeRE, 2011-07-06aRagexeRE, 2011-07-13aRagexeRE, 2011-07-13bRagexeRE, 2011-07-13cRagexeRE, 2011-07-19aRagexeRE, 2011-07-26aRagexeRE, 2011-08-03aRagexeRE, 2011-08-03bRagexeRE, 2011-08-10aRagexeRE, 2013-12-23aRagexeRE, 2014-05-08aRagexe, 2014-05-08aRagexeRE, 2014-06-11eRagexe, 2015-02-25hRagexe, 2018-03-15aRagexe, 2018-03-21aRagexe, 2018-03-21aRagexeRE, 2018-03-28bRagexe, 2018-03-28bRagexeRE, 2018-04-04bRagexe, 2018-04-04cRagexeRE, 2018-04-18aRagexe, 2018-04-18bRagexeRE, 2018-04-25cRagexe, 2018-04-25cRagexeRE, 2018-05-02bRagexe, 2018-05-02bRagexeRE, 2018-05-02dRagexeRE, 2018-05-09aRagexe, 2018-05-16cRagexe, 2018-05-16cRagexeRE, 2018-05-23aRagexe, 2018-05-23aRagexeRE, 2018-05-30aRagexe, 2018-05-30bRagexeRE, 2018-05-30cRagexeRE, 2018-06-05bRagexe, 2018-06-05bRagexeRE, 2018-06-12aRagexeRE, 2018-06-12bRagexeRE, 2018-06-20cRagexe, 2018-06-20dRagexeRE, 2018-06-20eRagexe, 2018-06-20eRagexeRE, 2018-06-21aRagexe, 2018-06-21aRagexeRE, 2018-07-04aRagexe, 2018-07-04aRagexeRE, 2018-07-11aRagexeRE, 2018-07-18bRagexe, 2018-07-18bRagexeRE, 2018-07-18bRagexeRE1, 2018-07-18cRagexe, 2018-07-18cRagexeRE, 2018-08-01cRagexe, 2018-08-01cRagexeRE, 2018-08-08bRagexe, 2018-08-08bRagexeRE, 2018-08-22cRagexe, 2018-08-22cRagexeRE, 2018-08-29aRagexe, 2018-08-29aRagexeRE, 2018-08-29bRagexeRE, 2018-08-31aRagexe, 2018-09-12dRagexe, 2018-09-12dRagexeRE, 2018-09-19aRagexe, 2018-09-19aRagexeRE, 2018-10-02aRagexe, 2018-10-02aRagexeRE, 2018-10-02bRagexe, 2018-10-02bRagexeRE, 2018-10-17_02aRagexe, 2018-10-17_02aRagexeRE, 2018-10-17_03aRagexe, 2018-10-17_03aRagexeRE, 2018-10-17bRagexe, 2018-10-17bRagexeRE, 2018-10-24bRagexe, 2018-10-31aRagexe, 2018-10-31bRagexe, 2018-10-31cRagexeRE, 2018-11-07aRagexe, 2018-11-07aRagexeRE, 2018-11-14cRagexe, 2018-11-14cRagexeRE, 2018-11-14dRagexe, 2018-11-14dRagexeRE, 2018-11-21bRagexe, 2018-11-21cRagexeRE, 2018-11-28aRagexe, 2018-11-28aRagexeRE, 2018-11-28bRagexe, 2018-11-28cRagexe, 2018-12-05aRagexe, 2018-12-05bRagexeRE, 2018-12-12aRagexe, 2018-12-12aRagexeRE, 2018-12-12bRagexe, 2018-12-12bRagexeRE, 2018-12-19bRagexe, 2018-12-19bRagexeRE, 2018-12-26aRagexe, 2018-12-26aRagexeRE, 2019-01-09aRagexe, 2019-01-09bRagexeRE, 2019-01-16bRagexe, 2019-01-16bRagexeRE, 2019-01-16cRagexe, 2019-01-16cRagexeRE, 2019-01-23dRagexe, 2019-01-23dRagexeRE, 2019-02-13IRagexeRE, 2019-02-13bRagexe, 2019-02-13eRagexe, 2019-02-20aRagexeRE, 2019-02-27aRagexe, 2019-02-27bRagexeRE, 2019-02-28aRagexe, 2019-02-28aRagexeRE, 2019-03-06bRagexe, 2019-03-06bRagexeRE, 2019-03-06cRagexe, 2019-03-06cRagexeRE, 2019-03-13aRagexe, 2019-03-20aRagexe, 2019-03-20aRagexeRE, 2019-03-22aRagexe, 2019-03-22aRagexeRE, 2019-03-27bRagexe, 2019-03-27bRagexeRE, 2019-04-03aRagexe, 2019-04-03bRagexeRE, 2019-04-03cRagexeRE, 2019-04-17aRagexe, 2019-04-17cRagexeRE, 2019-04-18aRagexe, 2019-04-18aRagexeRE, 2019-05-08cRagexe, 2019-05-08dRagexeRE, 2019-05-08eRagexeRE, 2019-05-22bRagexe, 2019-05-22bRagexeRE, 2019-05-22cRagexe, 2019-05-22cRagexeRE, 2019-05-23aRagexe, 2019-05-29aRagexe, 2019-05-29bRagexeRE, 2019-05-29cRagexe, 2019-05-29cRagexeRE, 2019-05-30aRagexe, 2019-05-30aRagexeRE, 2019-06-05JRagexeRE, 2019-06-05KRagexe, 2019-06-05LRagexeRE, 2019-06-05fRagexe, 2019-06-05hRagexeRE, 2019-06-19bRagexe, 2019-06-19cRagexeRE, 2019-06-19eRagexe, 2019-06-19hRagexe, 2019-06-26bRagexeRE, 2019-07-03aRagexe, 2019-07-03bRagexeRE, 2019-07-17aRagexe, 2019-07-17cRagexeRE, 2019-07-17dRagexe, 2019-07-17dRagexeRE, 2019-07-24aRagexe, 2019-07-24bRagexeRE, 2019-07-31bRagexe, 2019-07-31bRagexeRE, 2019-08-02aRagexe, 2019-08-02aRagexeRE, 2019-08-07aRagexe, 2019-08-07dRagexeRE, 2019-08-21aRagexe, 2019-08-21cRagexeRE, 2019-08-21dRagexeRE, 2019-08-28aRagexe, 2019-08-28aRagexeRE, 2019-09-04aRagexe, 2019-09-04bRagexe, 2019-09-04bRagexeRE, 2019-09-18bRagexe, 2019-09-18cRagexeRE, 2019-09-25aRagexe, 2019-09-25aRagexeRE, 2019-09-25bRagexe, 2019-09-25bRagexeRE, 2019-10-02bRagexeRE, 2019-10-02cRagexe, 2019-10-02dRagexe, 2019-10-02dRagexeRE, 2019-10-02dRagexeRE_2, 2019-10-16fRagexe, 2019-10-16fRagexeRE, 2019-10-16gRagexe, 2019-10-16gRagexeRE, 2019-10-18aRagexe, 2019-10-23aRagexe, 2019-10-23aRagexeRE, 2019-10-30bRagexeRE, 2019-10-30cRagexe, 2019-11-06aRagexe, 2019-11-06bRagexeRE, 2019-11-07aRagexe, 2019-11-07aRagexeRE, 2019-11-13cRagexe, 2019-11-13eRagexe, 2019-11-13eRagexeRE, 2019-11-20aRagexe, 2019-11-20cRagexeRE, 2019-11-20dRagexe, 2019-11-27aRagexe, 2019-11-27aRagexeRE, 2019-11-27bRagexe, 2019-12-04aRagexe, 2019-12-04aRagexeRE, 2019-12-04bRagexe, 2019-12-04bRagexeRE, 2019-12-04cRagexeRE, 2019-12-11aRagexe, 2019-12-11fRagexeRE, 2019-12-18bRagexe, 2019-12-18bRagexeRE, 2019-12-24aRagexe, 2019-12-24aRagexeRE, 2019-12-24bRagexe, 2019-12-24bRagexeRE, 2020-01-08aRagexe, 2020-01-08bRagexeRE, 2020-01-22cRagexe, 2020-01-22cRagexeRE, 2020-01-29bRagexe, 2020-01-30aRagexe, 2020-02-05aRagexe, 2020-02-05aRagexeRE, 2020-02-06aRagexe, 2020-02-12aRagexe, 2020-02-12aRagexeRE, 2020-02-19dRagexe, 2020-02-19eRagexeRE, 2020-03-04aRagexe, 2020-03-04aRagexeRE, 2020-03-18bRagexe, 2020-04-01bRagexe #if PACKETVER == 20101123 || \ PACKETVER == 20101124 || \ PACKETVER == 20101125 || \ @@ -189,7 +189,9 @@ PACKETVER == 20200206 || \ PACKETVER == 20200212 || \ PACKETVER == 20200219 || \ - PACKETVER >= 20200304 + PACKETVER == 20200304 || \ + PACKETVER == 20200318 || \ + PACKETVER >= 20200401 packetKeys(0x00000000,0x00000000,0x00000000); #endif diff --git a/src/map/packets_keys_zero.h b/src/map/packets_keys_zero.h index facf0e151..f189032d3 100644 --- a/src/map/packets_keys_zero.h +++ b/src/map/packets_keys_zero.h @@ -30,7 +30,7 @@ /* This file is autogenerated, please do not commit manual changes */ -// 2017-10-18aRagexe_zero, 2017-10-19aRagexe_zero, 2017-10-23aRagexe_zero, 2017-10-23bRagexe_zero, 2017-10-23cRagexe_zero, 2017-10-24aRagexe_2_zero, 2017-10-24aRagexe_zero, 2017-10-25bRagexe_zero, 2017-10-27aRagexe_zero, 2017-10-27bRagexe_zero, 2017-10-30aRagexe_zero, 2017-10-31aRagexe_zero, 2017-11-09aRagexe_zero, 2017-11-13aRagexe_zero, 2017-11-13bRagexe_zero, 2018-03-15aRagexe_zero, 2018-03-21aRagexe_zero, 2018-03-21bRagexe_zero, 2018-03-28_1aRagexe_zero, 2018-03-28cRagexe_zero, 2018-04-11aRagexe_zero, 2018-04-25_3aRagexe_zero, 2018-05-09_3aRagexe_zero, 2018-05-23aRagexe_zero, 2018-06-05bRagexe_zero, 2018-06-05cRagexe_zero, 2018-06-27aRagexe_zero, 2018-07-03aRagexe_zero, 2018-07-11_2aRagexe_zero, 2018-07-25_2aRagexe_zero, 2018-08-01aRagexe_zero, 2018-08-08_2aRagexe_zero, 2018-08-22aRagexe_zero, 2018-08-29aRagexe_zero, 2018-09-05aRagexe_zero, 2018-09-12aRagexe_zero, 2018-09-19aRagexe_zero, 2018-09-28aRagexe_zero, 2018-10-10_2aRagexe_zero, 2018-10-24_2aRagexe_zero, 2018-11-14aRagexe_zero, 2018-11-20aRagexe_zero, 2018-11-28aRagexe_zero, 2018-12-12aRagexe_zero, 2018-12-19aRagexe_zero, 2018-12-26_2aRagexe_zero, 2019-01-16_2aRagexe_zero, 2019-01-17_1aRagexe_zero, 2019-01-30_2aRagexe_zero, 2019-02-13aRagexe_zero, 2019-02-20aRagexe_zero, 2019-02-27aRagexe_zero, 2019-03-13aRagexe_zero, 2019-03-27_2aRagexe_zero, 2019-03-27_3aRagexe_zero, 2019-04-03aRagexe_zero, 2019-04-10bRagexe_zero, 2019-04-24aRagexe_zero, 2019-05-02aRagexe_zero, 2019-05-08_2aRagexe_zero, 2019-05-08aRagexe_zero, 2019-05-15aRagexe_zero, 2019-05-29aRagexe_zero, 2019-05-30aRagexe_zero, 2019-06-05_2aRagexe_zero, 2019-06-26_2aRagexe_zero, 2019-06-26_3aRagexe_zero, 2019-07-09aRagexe_zero, 2019-07-10_3aRagexe_zero, 2019-07-17aRagexe_zero, 2019-07-24aRagexe_zero, 2019-08-14_3aRagexe_zero, 2019-08-28_2aRagexe_zero, 2019-08-28_3aRagexe_zero, 2019-09-11aRagexe_zero, 2019-09-18_2aRagexe_zero, 2019-09-18aRagexe_zero, 2019-09-25_3aRagexe_zero, 2019-09-25_5aRagexe_zero, 2019-10-08_2aRagexe_zero, 2019-10-23_2aRagexe_zero, 2019-11-06aRagexe_zero, 2019-11-13aRagexe_zero, 2019-11-27_2aRagexe_zero, 2019-11-27aRagexe_zero, 2019-12-04aRagexe_zero, 2019-12-11_2aRagexe_zero, 2019-12-24_4aRagexe_zero, 2019-12-24_5aRagexe_zero, 2020-01-15_2aRagexe_zero, 2020-01-15aRagexe_zero, 2020-01-29_2aRagexe_zero, 2020-01-29aRagexe_zero, 2020-02-12aRagexe_zero, 2020-02-26aRagexe_zero, 2020-02-26bRagexe_zero, 2020-03-04aRagexe_zero +// 2017-10-18aRagexe_zero, 2017-10-19aRagexe_zero, 2017-10-23aRagexe_zero, 2017-10-23bRagexe_zero, 2017-10-23cRagexe_zero, 2017-10-24aRagexe_2_zero, 2017-10-24aRagexe_zero, 2017-10-25bRagexe_zero, 2017-10-27aRagexe_zero, 2017-10-27bRagexe_zero, 2017-10-30aRagexe_zero, 2017-10-31aRagexe_zero, 2017-11-09aRagexe_zero, 2017-11-13aRagexe_zero, 2017-11-13bRagexe_zero, 2018-03-15aRagexe_zero, 2018-03-21aRagexe_zero, 2018-03-21bRagexe_zero, 2018-03-28_1aRagexe_zero, 2018-03-28cRagexe_zero, 2018-04-11aRagexe_zero, 2018-04-25_3aRagexe_zero, 2018-05-09_3aRagexe_zero, 2018-05-23aRagexe_zero, 2018-06-05bRagexe_zero, 2018-06-05cRagexe_zero, 2018-06-27aRagexe_zero, 2018-07-03aRagexe_zero, 2018-07-11_2aRagexe_zero, 2018-07-25_2aRagexe_zero, 2018-08-01aRagexe_zero, 2018-08-08_2aRagexe_zero, 2018-08-22aRagexe_zero, 2018-08-29aRagexe_zero, 2018-09-05aRagexe_zero, 2018-09-12aRagexe_zero, 2018-09-19aRagexe_zero, 2018-09-28aRagexe_zero, 2018-10-10_2aRagexe_zero, 2018-10-24_2aRagexe_zero, 2018-11-14aRagexe_zero, 2018-11-20aRagexe_zero, 2018-11-28aRagexe_zero, 2018-12-12aRagexe_zero, 2018-12-19aRagexe_zero, 2018-12-26_2aRagexe_zero, 2019-01-16_2aRagexe_zero, 2019-01-17_1aRagexe_zero, 2019-01-30_2aRagexe_zero, 2019-02-13aRagexe_zero, 2019-02-20aRagexe_zero, 2019-02-27aRagexe_zero, 2019-03-13aRagexe_zero, 2019-03-27_2aRagexe_zero, 2019-03-27_3aRagexe_zero, 2019-04-03aRagexe_zero, 2019-04-10bRagexe_zero, 2019-04-24aRagexe_zero, 2019-05-02aRagexe_zero, 2019-05-08_2aRagexe_zero, 2019-05-08aRagexe_zero, 2019-05-15aRagexe_zero, 2019-05-29aRagexe_zero, 2019-05-30aRagexe_zero, 2019-06-05_2aRagexe_zero, 2019-06-26_2aRagexe_zero, 2019-06-26_3aRagexe_zero, 2019-07-09aRagexe_zero, 2019-07-10_3aRagexe_zero, 2019-07-17aRagexe_zero, 2019-07-24aRagexe_zero, 2019-08-14_3aRagexe_zero, 2019-08-28_2aRagexe_zero, 2019-08-28_3aRagexe_zero, 2019-09-11aRagexe_zero, 2019-09-18_2aRagexe_zero, 2019-09-18aRagexe_zero, 2019-09-25_3aRagexe_zero, 2019-09-25_5aRagexe_zero, 2019-10-08_2aRagexe_zero, 2019-10-23_2aRagexe_zero, 2019-11-06aRagexe_zero, 2019-11-13aRagexe_zero, 2019-11-27_2aRagexe_zero, 2019-11-27aRagexe_zero, 2019-12-04aRagexe_zero, 2019-12-11_2aRagexe_zero, 2019-12-24_4aRagexe_zero, 2019-12-24_5aRagexe_zero, 2020-01-15_2aRagexe_zero, 2020-01-15aRagexe_zero, 2020-01-29_2aRagexe_zero, 2020-01-29aRagexe_zero, 2020-02-12aRagexe_zero, 2020-02-26aRagexe_zero, 2020-02-26bRagexe_zero, 2020-03-04aRagexe_zero, 2020-03-18_2aRagexe_zero, 2020-04-01_2aRagexe_zero #if PACKETVER == 20171018 || \ PACKETVER == 20171019 || \ PACKETVER == 20171023 || \ @@ -108,7 +108,9 @@ PACKETVER == 20200129 || \ PACKETVER == 20200212 || \ PACKETVER == 20200226 || \ - PACKETVER >= 20200304 + PACKETVER == 20200304 || \ + PACKETVER == 20200318 || \ + PACKETVER >= 20200401 packetKeys(0x00000000,0x00000000,0x00000000); #endif diff --git a/src/map/packets_shuffle_main.h b/src/map/packets_shuffle_main.h index 25024c9f9..beedc950f 100644 --- a/src/map/packets_shuffle_main.h +++ b/src/map/packets_shuffle_main.h @@ -9794,7 +9794,7 @@ packet(0x083c,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK // 14 #endif -// 2019-09-04aRagexe, 2019-09-04bRagexe, 2019-09-18bRagexe, 2019-09-25aRagexe, 2019-09-25bRagexe, 2019-10-02cRagexe, 2019-10-02dRagexe, 2019-10-16fRagexe, 2019-10-16gRagexe, 2019-10-18aRagexe, 2019-10-23aRagexe, 2019-10-30cRagexe, 2019-11-06aRagexe, 2019-11-07aRagexe, 2019-11-13cRagexe, 2019-11-13eRagexe, 2019-11-20aRagexe, 2019-11-20dRagexe, 2019-11-27aRagexe, 2019-11-27bRagexe, 2019-12-04aRagexe, 2019-12-04bRagexe, 2019-12-11aRagexe, 2019-12-18bRagexe, 2019-12-24aRagexe, 2019-12-24bRagexe, 2020-01-08aRagexe, 2020-01-22cRagexe, 2020-01-29bRagexe, 2020-01-30aRagexe, 2020-02-05aRagexe, 2020-02-06aRagexe, 2020-02-12aRagexe, 2020-02-19dRagexe, 2020-03-04aRagexe +// 2019-09-04aRagexe, 2019-09-04bRagexe, 2019-09-18bRagexe, 2019-09-25aRagexe, 2019-09-25bRagexe, 2019-10-02cRagexe, 2019-10-02dRagexe, 2019-10-16fRagexe, 2019-10-16gRagexe, 2019-10-18aRagexe, 2019-10-23aRagexe, 2019-10-30cRagexe, 2019-11-06aRagexe, 2019-11-07aRagexe, 2019-11-13cRagexe, 2019-11-13eRagexe, 2019-11-20aRagexe, 2019-11-20dRagexe, 2019-11-27aRagexe, 2019-11-27bRagexe, 2019-12-04aRagexe, 2019-12-04bRagexe, 2019-12-11aRagexe, 2019-12-18bRagexe, 2019-12-24aRagexe, 2019-12-24bRagexe, 2020-01-08aRagexe, 2020-01-22cRagexe, 2020-01-29bRagexe, 2020-01-30aRagexe, 2020-02-05aRagexe, 2020-02-06aRagexe, 2020-02-12aRagexe, 2020-02-19dRagexe, 2020-03-04aRagexe, 2020-03-18bRagexe, 2020-04-01bRagexe #if PACKETVER == 20190904 || \ PACKETVER == 20190918 || \ PACKETVER == 20190925 || \ @@ -9820,7 +9820,9 @@ PACKETVER == 20200206 || \ PACKETVER == 20200212 || \ PACKETVER == 20200219 || \ - PACKETVER == 20200304 + PACKETVER == 20200304 || \ + PACKETVER == 20200318 || \ + PACKETVER == 20200401 packet(0x0202,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS // 26 packet(0x022d,clif->pHomMenu,2,4); // CZ_COMMAND_MER // 5 packet(0x023b,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD // 36 diff --git a/src/map/packets_shuffle_zero.h b/src/map/packets_shuffle_zero.h index b7c26dbe7..15936f854 100644 --- a/src/map/packets_shuffle_zero.h +++ b/src/map/packets_shuffle_zero.h @@ -803,7 +803,7 @@ packet(0x083c,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK // 14 #endif -// 2019-08-28_2aRagexe_zero, 2019-08-28_3aRagexe_zero, 2019-09-11aRagexe_zero, 2019-09-18_2aRagexe_zero, 2019-09-18aRagexe_zero, 2019-09-25_3aRagexe_zero, 2019-09-25_5aRagexe_zero, 2019-10-08_2aRagexe_zero, 2019-10-23_2aRagexe_zero, 2019-11-06aRagexe_zero, 2019-11-13aRagexe_zero, 2019-11-27_2aRagexe_zero, 2019-11-27aRagexe_zero, 2019-12-04aRagexe_zero, 2019-12-11_2aRagexe_zero, 2019-12-24_4aRagexe_zero, 2019-12-24_5aRagexe_zero, 2020-01-15_2aRagexe_zero, 2020-01-15aRagexe_zero, 2020-01-29_2aRagexe_zero, 2020-01-29aRagexe_zero, 2020-02-12aRagexe_zero, 2020-02-26aRagexe_zero, 2020-02-26bRagexe_zero, 2020-03-04aRagexe_zero +// 2019-08-28_2aRagexe_zero, 2019-08-28_3aRagexe_zero, 2019-09-11aRagexe_zero, 2019-09-18_2aRagexe_zero, 2019-09-18aRagexe_zero, 2019-09-25_3aRagexe_zero, 2019-09-25_5aRagexe_zero, 2019-10-08_2aRagexe_zero, 2019-10-23_2aRagexe_zero, 2019-11-06aRagexe_zero, 2019-11-13aRagexe_zero, 2019-11-27_2aRagexe_zero, 2019-11-27aRagexe_zero, 2019-12-04aRagexe_zero, 2019-12-11_2aRagexe_zero, 2019-12-24_4aRagexe_zero, 2019-12-24_5aRagexe_zero, 2020-01-15_2aRagexe_zero, 2020-01-15aRagexe_zero, 2020-01-29_2aRagexe_zero, 2020-01-29aRagexe_zero, 2020-02-12aRagexe_zero, 2020-02-26aRagexe_zero, 2020-02-26bRagexe_zero, 2020-03-04aRagexe_zero, 2020-03-18_2aRagexe_zero, 2020-04-01_2aRagexe_zero #if PACKETVER == 20190828 || \ PACKETVER == 20190911 || \ PACKETVER == 20190918 || \ @@ -820,7 +820,9 @@ PACKETVER == 20200129 || \ PACKETVER == 20200212 || \ PACKETVER == 20200226 || \ - PACKETVER == 20200304 + PACKETVER == 20200304 || \ + PACKETVER == 20200318 || \ + PACKETVER == 20200401 packet(0x0202,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS // 26 packet(0x022d,clif->pHomMenu,2,4); // CZ_COMMAND_MER // 5 packet(0x023b,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD // 36 diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index 71f986a90..ca2fb8aef 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -3779,7 +3779,7 @@ struct PACKET_ZC_SE_CASHSHOP_OPEN { } __attribute__((packed)); DEFINE_PACKET_HEADER(ZC_SE_CASHSHOP_OPEN, 0x0b6e); // for ragexeRE in some version this packet unused [4144] -#elif PACKETVER_MAIN_NUM >= 20101123 || PACKETVER_RE_NUM >= 20120328 || PACKETVER_ZERO_NUM >= defined(PACKETVER_ZERO) +#elif PACKETVER_MAIN_NUM >= 20101123 || PACKETVER_RE_NUM >= 20120328 || defined(PACKETVER_ZERO) struct PACKET_ZC_SE_CASHSHOP_OPEN { int16 packetType; uint32 cashPoints; diff --git a/src/map/pc.c b/src/map/pc.c index c604e16dc..90282209b 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -5295,10 +5295,6 @@ static int pc_useitem(struct map_session_data *sd, int n) if(sd->catch_target_class != -1) //Abort pet catching. sd->catch_target_class = -1; - // Removes abracadabra/randomize spell flag for delayed consume items or item doesn't get consumed - if (sd->inventory_data[n]->flag.delay_consume) - sd->state.abra_flag = 0; - amount = sd->status.inventory[n].amount; //Check if the item is to be consumed immediately [Skotlex] if (sd->inventory_data[n]->flag.delay_consume || sd->inventory_data[n]->flag.keepafteruse) @@ -5337,21 +5333,22 @@ static int pc_useitem(struct map_session_data *sd, int n) } /** - * Sets state flags and helper variables, used by itemskill() script command, to 0. + * Unsets a character's auto-cast related data. * * @param sd The character's session data. * @return 0 if parameter sd is NULL, otherwise 1. */ -static int pc_itemskill_clear(struct map_session_data *sd) +static int pc_autocast_clear(struct map_session_data *sd) { nullpo_ret(sd); - sd->itemskill_id = 0; - sd->itemskill_lv = 0; - sd->state.itemskill_conditions_checked = 0; - sd->state.itemskill_check_conditions = 0; - sd->state.itemskill_no_casttime = 0; - sd->state.itemskill_castonself = 0; + sd->autocast.type = AUTOCAST_NONE; + sd->autocast.skill_id = 0; + sd->autocast.skill_lv = 0; + sd->autocast.itemskill_conditions_checked = false; + sd->autocast.itemskill_check_conditions = false; + sd->autocast.itemskill_instant_cast = false; + sd->autocast.itemskill_cast_on_self = false; return 1; } @@ -5703,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. @@ -5720,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; } @@ -8026,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 ) {/* 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 (sd->bg_id != 0) { //TODO: Purge when bgqueue is deemed ok. + struct battleground_data *bgd = bg->team_search(sd->bg_id); + + 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); - //Reset menu skills/item skills - if (sd->skillitem) - sd->skillitem = sd->skillitemlv = 0; - 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; + pc->autocast_clear(sd); // Unset auto-cast data. + + 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 ^^; @@ -8194,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 @@ -8209,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; } } @@ -8347,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; @@ -8809,6 +8890,10 @@ static int pc_itemheal(struct map_session_data *sd, int itemid, int hp, int sp) // 2014 Halloween Event : Pumpkin Bonus if ( sd->sc.data[SC_MTF_PUMPKIN] && itemid == ITEMID_PUMPKIN ) hp += (int)(hp * sd->sc.data[SC_MTF_PUMPKIN]->val1/100); + + // Activation Potion + if (sd->sc.data[SC_VITALIZE_POTION] != NULL) + hp += hp * sd->sc.data[SC_VITALIZE_POTION]->val3 / 100; } if(sp) { bonus = 100 + (sd->battle_status.int_<<1) @@ -12726,7 +12811,7 @@ void pc_defaults(void) pc->unequipitem_pos = pc_unequipitem_pos; pc->checkitem = pc_checkitem; pc->useitem = pc_useitem; - pc->itemskill_clear = pc_itemskill_clear; + pc->autocast_clear = pc_autocast_clear; pc->skillatk_bonus = pc_skillatk_bonus; pc->skillheal_bonus = pc_skillheal_bonus; diff --git a/src/map/pc.h b/src/map/pc.h index 8d1ae3607..2699b7882 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -173,6 +173,17 @@ struct pc_combos { int id; /* this combo id */ }; +/** Auto-cast related data. **/ +struct autocast_data { + enum autocast_type type; // The auto-cast type. + int skill_id; // The auto-cast skill ID. + int skill_lv; // The auto-cast skill level. + bool itemskill_conditions_checked; // Used by itemskill() script command, to prevent second check of conditions after target was selected. + bool itemskill_check_conditions; // Used by itemskill() script command, to check skill conditions and consume them. + bool itemskill_instant_cast; // Used by itemskill() script command, to cast skill instantaneously. + bool itemskill_cast_on_self; // Used by itemskill() script command, to forcefully cast skill on invoking character. +}; + struct map_session_data { struct block_list bl; struct unit_data ud; @@ -181,6 +192,7 @@ struct map_session_data { struct status_change sc; struct regen_data regen; struct regen_data_sub sregen, ssregen; + struct autocast_data autocast; //NOTE: When deciding to add a flag to state or special_state, take into consideration that state is preserved in //status_calc_pc, while special_state is recalculated in each call. [Skotlex] struct { @@ -194,8 +206,6 @@ struct map_session_data { unsigned int rest : 1; unsigned int storage_flag : 2; // @see enum storage_flag unsigned int snovice_dead_flag : 1; //Explosion spirits on death: 0 off, 1 used. - unsigned int abra_flag : 2; // Abracadabra bugfix by Aru - unsigned int autocast : 1; // Autospell flag [Inkfish] unsigned int autotrade : 2; //By Fantik unsigned int showdelay :1; unsigned int showexp :1; @@ -240,10 +250,6 @@ struct map_session_data { unsigned int refine_ui : 1; unsigned int npc_unloaded : 1; ///< The player is talking with an unloaded NPCs (respawned tombstones) unsigned int lapine_ui : 1; - unsigned int itemskill_conditions_checked : 1; // Used by itemskill() script command, to prevent second check of conditions after target was selected. - unsigned int itemskill_check_conditions : 1; // Used by itemskill() script command, to check skill conditions and consume them. - unsigned int itemskill_no_casttime : 1; // Used by itemskill() script command, to cast skill instantaneously. - unsigned int itemskill_castonself : 1; // Used by itemskill() script command, to forcefully cast skill on invoking character. } state; struct { unsigned char no_weapon_damage, no_magic_damage, no_misc_damage; @@ -298,7 +304,6 @@ struct map_session_data { int followtimer; // [MouseJstr] int followtarget; time_t emotionlasttime; // to limit flood with emotion packets - int skillitem,skillitemlv; uint16 skill_id_old,skill_lv_old; uint16 skill_id_dance,skill_lv_dance; short cook_mastery; // range: [0,1999] [Inkfish] @@ -492,6 +497,7 @@ END_ZEROED_BLOCK; int change_level_3rd; // job level when changing from 2nd to 3rd class [jobchange_level_3rd in global_reg_value] char fakename[NAME_LENGTH]; // fake names [Valaris] + int fakename_options; // Fake name display options. int duel_group; // duel vars [LuzZza] int duel_invite; @@ -647,15 +653,6 @@ END_ZEROED_BLOCK; bool achievements_received; // Title VECTOR_DECL(int) title_ids; - - /* - * itemskill_conditions_checked/itemskill_no_conditions/itemskill_no_casttime/itemskill_castonself abuse prevention. - * If a skill, casted by itemskill() script command, is aborted while target selection, - * the map server gets no notification where these states could be unset. - * Thus we need this helper variables to prevent abusing these states for next skill cast. - */ - int itemskill_id; - int itemskill_lv; }; #define EQP_WEAPON EQP_HAND_R @@ -1034,7 +1031,7 @@ END_ZEROED_BLOCK; /* End */ void (*unequipitem_pos) (struct map_session_data *sd, int n, int pos); int (*checkitem) (struct map_session_data *sd); int (*useitem) (struct map_session_data *sd,int n); - int (*itemskill_clear) (struct map_session_data *sd); + int (*autocast_clear) (struct map_session_data *sd); int (*skillatk_bonus) (struct map_session_data *sd, uint16 skill_id); int (*skillheal_bonus) (struct map_session_data *sd, uint16 skill_id); 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/quest.c b/src/map/quest.c index 10ea668a6..217acfa19 100644 --- a/src/map/quest.c +++ b/src/map/quest.c @@ -675,7 +675,7 @@ static void quest_questinfo_refresh(struct map_session_data *sd) nullpo_retv(sd); for (int i = 0; i < VECTOR_LENGTH(map->list[sd->bl.m].qi_list); i++) { - struct npc_data *nd = &VECTOR_INDEX(map->list[sd->bl.m].qi_list, i); + struct npc_data *nd = VECTOR_INDEX(map->list[sd->bl.m].qi_list, i); int j; ARR_FIND(0, VECTOR_LENGTH(nd->qi_data), j, quest->questinfo_validate(sd, &VECTOR_INDEX(nd->qi_data, j)) == true); diff --git a/src/map/script.c b/src/map/script.c index b8a7979a7..c08f5e829 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -11001,33 +11001,29 @@ static BUILDIN(itemskill) if (sd == NULL || sd->ud.skilltimer != INVALID_TIMER) return true; - pc->itemskill_clear(sd); - sd->skillitem = script_isstringtype(st, 2) ? skill->name2id(script_getstr(st, 2)) : script_getnum(st, 2); - sd->skillitemlv = script_getnum(st, 3); - sd->state.itemskill_conditions_checked = 0; // Skill casting items will check the conditions prior to the target selection in AEGIS. Thus we need a flag to prevent checking them twice. + pc->autocast_clear(sd); + sd->autocast.type = AUTOCAST_ITEM; + sd->autocast.skill_id = script_isstringtype(st, 2) ? skill->name2id(script_getstr(st, 2)) : script_getnum(st, 2); + sd->autocast.skill_lv = script_getnum(st, 3); int flag = script_hasdata(st, 4) ? script_getnum(st, 4) : ISF_NONE; - sd->state.itemskill_check_conditions = ((flag & ISF_CHECKCONDITIONS) == ISF_CHECKCONDITIONS) ? 1 : 0; // Unset in pc_itemskill_clear(). + sd->autocast.itemskill_check_conditions = ((flag & ISF_CHECKCONDITIONS) == ISF_CHECKCONDITIONS); - if (sd->state.itemskill_check_conditions == 1) { - if (skill->check_condition_castbegin(sd, sd->skillitem, sd->skillitemlv) == 0 - || skill->check_condition_castend(sd, sd->skillitem, sd->skillitemlv) == 0) { - pc->itemskill_clear(sd); + if (sd->autocast.itemskill_check_conditions) { + if (skill->check_condition_castbegin(sd, sd->autocast.skill_id, sd->autocast.skill_lv) == 0 + || skill->check_condition_castend(sd, sd->autocast.skill_id, sd->autocast.skill_lv) == 0) { + pc->autocast_clear(sd); return true; } - sd->state.itemskill_conditions_checked = 1; // Unset in pc_itemskill_clear(). + sd->autocast.itemskill_conditions_checked = true; } - sd->state.itemskill_no_casttime = ((flag & ISF_INSTANTCAST) == ISF_INSTANTCAST) ? 1 : 0; // Unset in pc_itemskill_clear(). - sd->state.itemskill_castonself = ((flag & ISF_CASTONSELF) == ISF_CASTONSELF) ? 1 : 0; // Unset in pc_itemskill_clear(). + sd->autocast.itemskill_instant_cast = ((flag & ISF_INSTANTCAST) == ISF_INSTANTCAST); + sd->autocast.itemskill_cast_on_self = ((flag & ISF_CASTONSELF) == ISF_CASTONSELF); - // itemskill_conditions_checked/itemskill_no_conditions/itemskill_no_casttime/itemskill_castonself abuse prevention. Unset in pc_itemskill_clear(). - sd->itemskill_id = sd->skillitem; - sd->itemskill_lv = sd->skillitemlv; - - clif->item_skill(sd, sd->skillitem, sd->skillitemlv); + clif->item_skill(sd, sd->autocast.skill_id, sd->autocast.skill_lv); return true; } @@ -14952,10 +14948,10 @@ static BUILDIN(getiteminfo) script_pushint(st, it->nameid); break; case ITEMINFO_AEGISNAME: - script_pushstr(st, it->name); + script_pushstrcopy(st, it->name); break; case ITEMINFO_NAME: - script_pushstr(st, it->jname); + script_pushstrcopy(st, it->jname); break; default: ShowError("buildin_getiteminfo: Invalid item info type %d.\n", type); @@ -19267,12 +19263,14 @@ static BUILDIN(pcblockmove) static BUILDIN(setpcblock) { - struct map_session_data *sd = script->rid2sd(st); + struct map_session_data *sd = script_hasdata(st, 4) ? script->id2sd(st, script_getnum(st, 4)) : script->rid2sd(st); enum pcblock_action_flag type = script_getnum(st, 2); int state = (script_getnum(st, 3) > 0) ? 1 : 0; - if (sd == NULL) + if (sd == NULL) { + script_pushint(st, 0); return true; + } if ((type & PCBLOCK_MOVE) != 0) sd->block_action.move = state; @@ -19301,12 +19299,13 @@ static BUILDIN(setpcblock) if ((type & PCBLOCK_NPC) != 0) sd->block_action.npc = state; + script_pushint(st, 1); return true; } static BUILDIN(checkpcblock) { - struct map_session_data *sd = script->rid2sd(st); + struct map_session_data *sd = script_hasdata(st, 2) ? script->id2sd(st, script_getnum(st, 2)) : script->rid2sd(st); int retval = PCBLOCK_NONE; if (sd == NULL) { @@ -19415,26 +19414,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)); @@ -19442,22 +19440,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)) { @@ -19465,68 +19467,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; @@ -19552,30 +19573,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; @@ -19583,8 +19610,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); @@ -19639,7 +19666,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: @@ -19647,19 +19674,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; @@ -19667,67 +19695,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); @@ -19763,112 +19805,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; @@ -19878,14 +19923,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: @@ -19895,136 +19940,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: @@ -20034,130 +20081,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: @@ -20167,131 +20217,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: @@ -20301,211 +20354,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; @@ -20542,19 +20598,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; } @@ -21429,7 +21487,10 @@ static BUILDIN(unitskilluseid) } else { status_calc_npc(nd, SCO_NONE); } + } else if (bl->type == BL_PC) { + pc->autocast_clear(BL_UCAST(BL_PC, bl)); } + unit->skilluse_id(bl, target_id, skill_id, skill_lv); } @@ -21465,7 +21526,10 @@ static BUILDIN(unitskillusepos) } else { status_calc_npc(nd, SCO_NONE); } + } else if (bl->type == BL_PC) { + pc->autocast_clear(BL_UCAST(BL_PC, bl)); } + unit->skilluse_pos(bl, skill_x, skill_y, skill_id, skill_lv); } @@ -22021,12 +22085,13 @@ static BUILDIN(setquestinfo) return false; } - qi = &VECTOR_LAST(nd->qi_data); - if (qi == NULL) { + if (VECTOR_LENGTH(nd->qi_data) == 0) { ShowWarning("buildin_setquestinfo: no valide questinfo data has been found for this npc.\n"); return false; } + qi = &VECTOR_LAST(nd->qi_data); + switch (type) { case QINFO_JOB: { @@ -27085,8 +27150,8 @@ static void script_parse_builtin(void) BUILDIN_DEF(pcfollow,"ii"), BUILDIN_DEF(pcstopfollow,"i"), BUILDIN_DEF_DEPRECATED(pcblockmove,"ii"), // Deprecated 2018-05-04 - BUILDIN_DEF(setpcblock, "ii"), - BUILDIN_DEF(checkpcblock, ""), + BUILDIN_DEF(setpcblock, "ii?"), + BUILDIN_DEF(checkpcblock, "?"), // <--- [zBuffer] List of player cont commands // [zBuffer] List of mob control commands ---> BUILDIN_DEF(getunittype,"i"), @@ -27711,6 +27776,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/skill.c b/src/map/skill.c index a1a22f74f..3dccf7a9e 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -935,6 +935,8 @@ static int skill_calc_heal(struct block_list *src, struct block_list *target, ui hp -= hp * 20/100; if(sc->data[SC_HEALPLUS] && skill_id != NPC_EVILLAND && skill_id != BA_APPLEIDUN) hp += hp * sc->data[SC_HEALPLUS]->val1/100; // Only affects Heal, Sanctuary and PotionPitcher.(like bHealPower) [Inkfish] + if (sc->data[SC_VITALIZE_POTION] != NULL && skill_id != NPC_EVILLAND && skill_id != BA_APPLEIDUN) + hp += hp * sc->data[SC_VITALIZE_POTION]->val3 / 100; if(sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 2) hp += hp / 10; if (sc->data[SC_VITALITYACTIVATION]) @@ -1010,14 +1012,14 @@ static int skillnotok(uint16 skill_id, struct map_session_data *sd) if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL)) return 0; // can do any damn thing they want - if( skill_id == AL_TELEPORT && sd->skillitem == skill_id && sd->skillitemlv > 2 ) - return 0; // Teleport lv 3 bypasses this check.[Inkfish] + if (skill_id == AL_TELEPORT && sd->autocast.type == AUTOCAST_ITEM && sd->autocast.skill_lv > 2) + return 0; // Teleport level 3 and higher bypasses this check if cast by itemskill() script commands. // Epoque: // This code will compare the player's attack motion value which is influenced by ASPD before // allowing a skill to be cast. This is to prevent no-delay ACT files from spamming skills such as // AC_DOUBLE which do not have a skill delay and are not regarded in terms of attack motion. - if( !sd->state.autocast && sd->skillitem != skill_id && sd->canskill_tick && + if (sd->autocast.type == AUTOCAST_NONE && sd->canskill_tick != 0 && DIFF_TICK(timer->gettick(), sd->canskill_tick) < (sd->battle_status.amotion * (battle_config.skill_amotion_leniency) / 100) ) {// attempted to cast a skill before the attack motion has finished return 1; @@ -1032,7 +1034,7 @@ static int skillnotok(uint16 skill_id, struct map_session_data *sd) * It has been confirmed on a official server (thanks to Yommy) that item-cast skills bypass all the restrictions below * Also, without this check, an exploit where an item casting + healing (or any other kind buff) isn't deleted after used on a restricted map **/ - if( sd->skillitem == skill_id ) + if (sd->autocast.type == AUTOCAST_ITEM) return 0; if( sd->sc.data[SC_ALL_RIDING] ) @@ -1177,6 +1179,31 @@ static int skillnotok_mercenary(uint16 skill_id, struct mercenary_data *md) return skill->not_ok(skill_id, md->master); } +/** + * Validates the plausibility of auto-cast related data and calls pc_autocast_clear() if necessary. + * + * @param sd The character who cast the skill. + * @param skill_id The cast skill's ID. + * @param skill_lv The cast skill's level. (clif_parse_UseSkillMap() passes 0.) + * + **/ +static void skill_validate_autocast_data(struct map_session_data *sd, int skill_id, int skill_lv) +{ + nullpo_retv(sd); + + // Determine if called by clif_parse_UseSkillMap(). + bool use_skill_map = (skill_lv == 0 && (skill_id == AL_WARP || skill_id == AL_TELEPORT)); + + if (sd->autocast.type == AUTOCAST_NONE) + pc->autocast_clear(sd); // No auto-cast type set. Preventively unset all auto-cast related data. + else if (sd->autocast.type == AUTOCAST_TEMP) + pc->autocast_clear(sd); // AUTOCAST_TEMP should have been unset straight after usage. + else if (sd->autocast.skill_id == 0 || skill_id == 0 || sd->autocast.skill_id != skill_id) + pc->autocast_clear(sd); // Implausible skill ID. + else if (sd->autocast.skill_lv == 0 || (!use_skill_map && (skill_lv == 0 || sd->autocast.skill_lv != skill_lv))) + pc->autocast_clear(sd); // Implausible skill level. +} + static struct s_skill_unit_layout *skill_get_unit_layout(uint16 skill_id, uint16 skill_lv, struct block_list *src, int x, int y) { int pos = skill->get_unit_layout_type(skill_id,skill_lv); @@ -2065,9 +2092,9 @@ static int skill_additional_effect(struct block_list *src, struct block_list *bl temp = (sd->autospell[i].id > 0) ? sd->autospell[i].id : -sd->autospell[i].id; - sd->state.autocast = 1; + sd->autocast.type = AUTOCAST_TEMP; notok = skill->not_ok(temp, sd); - sd->state.autocast = 0; + sd->autocast.type = AUTOCAST_NONE; if ( notok ) continue; @@ -2118,11 +2145,12 @@ static int skill_additional_effect(struct block_list *src, struct block_list *bl else if (temp == PF_SPIDERWEB) //Special case, due to its nature of coding. type = CAST_GROUND; - sd->state.autocast = 1; + sd->autocast.type = AUTOCAST_TEMP; skill->consume_requirement(sd,temp,auto_skill_lv,1); skill->toggle_magicpower(src, temp); skill->castend_type(type, src, tbl, temp, auto_skill_lv, tick, 0); - sd->state.autocast = 0; + sd->autocast.type = AUTOCAST_NONE; + //Set canact delay. [Skotlex] ud = unit->bl2ud(src); if (ud) { @@ -2191,6 +2219,9 @@ static int skill_onskillusage(struct map_session_data *sd, struct block_list *bl if( sd == NULL || !skill_id ) return 0; + // Preserve auto-cast type if bAutoSpellOnSkill was triggered by a skill which was cast by Abracadabra, Improvised Song or an item. + enum autocast_type ac_type = sd->autocast.type; + for( i = 0; i < ARRAYLENGTH(sd->autospell3) && sd->autospell3[i].flag; i++ ) { if( sd->autospell3[i].flag != skill_id ) continue; @@ -2200,9 +2231,9 @@ static int skill_onskillusage(struct map_session_data *sd, struct block_list *bl temp = (sd->autospell3[i].id > 0) ? sd->autospell3[i].id : -sd->autospell3[i].id; - sd->state.autocast = 1; + sd->autocast.type = AUTOCAST_TEMP; notok = skill->not_ok(temp, sd); - sd->state.autocast = 0; + sd->autocast.type = AUTOCAST_NONE; if ( notok ) continue; @@ -2248,14 +2279,16 @@ static int skill_onskillusage(struct map_session_data *sd, struct block_list *bl !battle->check_range(&sd->bl, tbl, skill->get_range2(&sd->bl, temp,skill_lv) + (temp == RG_CLOSECONFINE?0:1)) ) continue; - sd->state.autocast = 1; sd->autospell3[i].lock = true; + sd->autocast.type = AUTOCAST_TEMP; skill->consume_requirement(sd,temp,skill_lv,1); skill->castend_type(type, &sd->bl, tbl, temp, skill_lv, tick, 0); + sd->autocast.type = AUTOCAST_NONE; sd->autospell3[i].lock = false; - sd->state.autocast = 0; } + sd->autocast.type = ac_type; + if (sd->autobonus3[0].rate) { for( i = 0; i < ARRAYLENGTH(sd->autobonus3); i++ ) { if( rnd()%1000 >= sd->autobonus3[i].rate ) @@ -2402,6 +2435,9 @@ static int skill_counter_additional_effect(struct block_list *src, struct block_ struct unit_data *ud; int i, auto_skill_id, auto_skill_lv, type, notok; + // Preserve auto-cast type if bAutoSpellWhenHit was triggered during cast of a skill which was cast by Abracadabra, Improvised Song or an item. + enum autocast_type ac_type = dstsd->autocast.type; + for (i = 0; i < ARRAYLENGTH(dstsd->autospell2) && dstsd->autospell2[i].id; i++) { if(!(dstsd->autospell2[i].flag&attack_type&BF_WEAPONMASK && @@ -2417,9 +2453,9 @@ static int skill_counter_additional_effect(struct block_list *src, struct block_ if (attack_type&BF_LONG) rate>>=1; - dstsd->state.autocast = 1; + dstsd->autocast.type = AUTOCAST_TEMP; notok = skill->not_ok(auto_skill_id, dstsd); - dstsd->state.autocast = 0; + dstsd->autocast.type = AUTOCAST_NONE; if ( notok ) continue; @@ -2460,10 +2496,11 @@ static int skill_counter_additional_effect(struct block_list *src, struct block_ if( !battle->check_range(src, tbl, skill->get_range2(src, auto_skill_id,auto_skill_lv) + (auto_skill_id == RG_CLOSECONFINE?0:1)) && battle_config.autospell_check_range ) continue; - dstsd->state.autocast = 1; + dstsd->autocast.type = AUTOCAST_TEMP; skill->consume_requirement(dstsd,auto_skill_id,auto_skill_lv,1); skill->castend_type(type, bl, tbl, auto_skill_id, auto_skill_lv, tick, 0); - dstsd->state.autocast = 0; + dstsd->autocast.type = AUTOCAST_NONE; + // Set canact delay. [Skotlex] ud = unit->bl2ud(bl); if (ud) { @@ -2475,6 +2512,8 @@ static int skill_counter_additional_effect(struct block_list *src, struct block_ } } } + + dstsd->autocast.type = ac_type; } //Autobonus when attacked @@ -4197,11 +4236,6 @@ static void skill_castend_type(int type, struct block_list *src, struct block_li skill->castend_damage_id(src, bl, skill_id, skill_lv, tick, flag); break; } - - struct map_session_data *sd = BL_CAST(BL_PC, src); - - if (sd != NULL) - pc->itemskill_clear(sd); } /*========================================== @@ -5792,7 +5826,7 @@ static int skill_castend_id(int tid, int64 tick, int id, intptr_t data) if (ud->walktimer != INVALID_TIMER && ud->skill_id != TK_RUN && ud->skill_id != RA_WUGDASH) unit->stop_walking(src, STOPWALKING_FLAG_FIXPOS); - if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) ) + if (sd == NULL || sd->autocast.skill_id != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) != 0) ud->canact_tick = tick + skill->delay_fix(src, ud->skill_id, ud->skill_lv); // Tests show wings don't overwrite the delay but skill scrolls do. [Inkfish] if (sd) { // Cooldown application int i, cooldown = skill->get_cooldown(ud->skill_id, ud->skill_lv); @@ -5861,7 +5895,7 @@ static int skill_castend_id(int tid, int64 tick, int id, intptr_t data) } if( sd && ud->skill_id != SA_ABRACADABRA && ud->skill_id != WM_RANDOMIZESPELL ) // they just set the data so leave it as it is.[Inkfish] - sd->skillitem = sd->skillitemlv = 0; + pc->autocast_clear(sd); if (ud->skilltimer == INVALID_TIMER) { if(md) md->skill_idx = -1; @@ -5910,14 +5944,14 @@ static int skill_castend_id(int tid, int64 tick, int id, intptr_t data) } } - if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) ) + if (sd == NULL || sd->autocast.skill_id != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) != 0) ud->canact_tick = tick; ud->skill_id = ud->skill_lv = ud->skilltarget = 0; //You can't place a skill failed packet here because it would be //sent in ALL cases, even cases where skill_check_condition fails //which would lead to double 'skill failed' messages u.u [Skotlex] if(sd) - sd->skillitem = sd->skillitemlv = 0; + pc->autocast_clear(sd); else if(md) md->skill_idx = -1; return 0; @@ -6299,9 +6333,9 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * if (sd) { // player-casted - sd->state.abra_flag = 1; - sd->skillitem = abra_skill_id; - sd->skillitemlv = abra_skill_lv; + sd->autocast.type = AUTOCAST_ABRA; + sd->autocast.skill_id = abra_skill_id; + sd->autocast.skill_lv = abra_skill_lv; clif->item_skill(sd, abra_skill_id, abra_skill_lv); } else { // mob-casted @@ -7430,7 +7464,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * map->freeblock_unlock(); return 1; } - if( sd->skillitem != skill_id ) + if (sd->autocast.type == AUTOCAST_NONE) status_zap(src, 0, skill->get_sp(skill_id, skill_lv)); // consume sp only if succeeded } break; @@ -7467,7 +7501,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * break; } - if( sd->state.autocast || ( (sd->skillitem == AL_TELEPORT || battle_config.skip_teleport_lv1_menu) && skill_lv == 1 ) || skill_lv == 3 ) + if (sd->autocast.type == AUTOCAST_TEMP || ((sd->autocast.skill_id == AL_TELEPORT || battle_config.skip_teleport_lv1_menu) && skill_lv == 1) || skill_lv == 3) { if( skill_lv == 1 ) pc->randomwarp(sd,CLR_TELEPORT); @@ -10041,9 +10075,9 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * clif->skill_nodamage (src, bl, skill_id, skill_lv, 1); if (sd != NULL) { - sd->state.abra_flag = 2; - sd->skillitem = improv_skill_id; - sd->skillitemlv = improv_skill_lv; + sd->autocast.type = AUTOCAST_IMPROVISE; + sd->autocast.skill_id = improv_skill_id; + sd->autocast.skill_lv = improv_skill_lv; clif->item_skill(sd, improv_skill_id, improv_skill_lv); } else { struct unit_data *ud = unit->bl2ud(src); @@ -10812,7 +10846,7 @@ static int skill_castend_pos(int tid, int64 tick, int id, intptr_t data) if (ud->walktimer != INVALID_TIMER) unit->stop_walking(src, STOPWALKING_FLAG_FIXPOS); - if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) ) + if (sd == NULL || sd->autocast.skill_id != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) != 0) ud->canact_tick = tick + skill->delay_fix(src, ud->skill_id, ud->skill_lv); if (sd) { //Cooldown application int i, cooldown = skill->get_cooldown(ud->skill_id, ud->skill_lv); @@ -10841,8 +10875,8 @@ static int skill_castend_pos(int tid, int64 tick, int id, intptr_t data) map->freeblock_lock(); skill->castend_pos2(src,ud->skillx,ud->skilly,ud->skill_id,ud->skill_lv,tick,0); - if( sd && sd->skillitem != AL_WARP ) // Warp-Portal thru items will clear data in skill_castend_map. [Inkfish] - sd->skillitem = sd->skillitemlv = 0; + if (sd != NULL && sd->autocast.skill_id != AL_WARP) // Warp-Portal thru items will clear data in skill_castend_map. [Inkfish] + pc->autocast_clear(sd); unit->set_dir(src, map->calc_dir(src, ud->skillx, ud->skilly)); @@ -10856,11 +10890,11 @@ static int skill_castend_pos(int tid, int64 tick, int id, intptr_t data) return 1; } while(0); - if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) ) + if (sd == NULL || sd->autocast.skill_id != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) != 0) ud->canact_tick = tick; ud->skill_id = ud->skill_lv = 0; if(sd) - sd->skillitem = sd->skillitemlv = 0; + pc->autocast_clear(sd); else if(md) md->skill_idx = -1; return 0; @@ -10990,7 +11024,7 @@ static int skill_castend_map(struct map_session_data *sd, uint16 skill_id, const } } - lv = sd->skillitem==skill_id?sd->skillitemlv:pc->checkskill(sd,skill_id); + lv = (sd->autocast.type > AUTOCAST_TEMP) ? sd->autocast.skill_lv : pc->checkskill(sd, skill_id); wx = sd->menuskill_val>>16; wy = sd->menuskill_val&0xffff; @@ -11013,7 +11047,7 @@ static int skill_castend_map(struct map_session_data *sd, uint16 skill_id, const } skill->consume_requirement(sd,sd->menuskill_id,lv,2); - sd->skillitem = sd->skillitemlv = 0; // Clear data that's skipped in 'skill_castend_pos' [Inkfish] + pc->autocast_clear(sd); // Clear data which was skipped in skill_castend_pos(). if((group=skill->unitsetting(&sd->bl,skill_id,lv,wx,wy,0))==NULL) { skill_failed(sd); @@ -14012,22 +14046,6 @@ static bool skill_is_combo(int skill_id) return false; } -/** - * Checks if a skill is casted by an item (itemskill() script command). - * - * @param sd The charcater's session data. - * @param skill_id The skill's ID. - * @param skill_lv The skill's level. - * @return true if skill is casted by an item, otherwise false. - */ -static bool skill_is_item_skill(struct map_session_data *sd, int skill_id, int skill_lv) -{ - nullpo_retr(false, sd); - - return (sd->skillitem == skill_id && sd->skillitemlv == skill_lv - && sd->itemskill_id == skill_id && sd->itemskill_lv == skill_lv); -} - static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv) { struct status_data *st; @@ -14042,13 +14060,13 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s if (sd->chat_id != 0) return 0; - if ((sd->state.itemskill_conditions_checked == 1 || sd->state.itemskill_check_conditions == 0) - && skill->is_item_skill(sd, skill_id, skill_lv)) { + if (((sd->autocast.itemskill_conditions_checked || !sd->autocast.itemskill_check_conditions) + && sd->autocast.type == AUTOCAST_ITEM) || sd->autocast.type == AUTOCAST_IMPROVISE) { return 1; } - if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill_id) { - //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex] + if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->autocast.type != AUTOCAST_ITEM) { + // GMs don't override the AUTOCAST_ITEM check, otherwise they can use items without them being consumed! sd->state.arrow_atk = skill->get_ammotype(skill_id)?1:0; //Need to do arrow state check. sd->spiritball_old = sd->spiritball; //Need to do Spiritball check. return 1; @@ -14079,30 +14097,7 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s if( !sc->count ) sc = NULL; - if( sd->skillitem == skill_id ) { - if( sd->state.abra_flag ) // Hocus-Pocus was used. [Inkfish] - sd->state.abra_flag = 0; - else { - int i; - // When a target was selected, consume items that were skipped in pc_use_item [Skotlex] - if( (i = sd->itemindex) == -1 || - sd->status.inventory[i].nameid != sd->itemid || - sd->inventory_data[i] == NULL || - sd->status.inventory[i].amount < 1 - ) { - //Something went wrong, item exploit? - sd->itemid = sd->itemindex = -1; - return 0; - } - - //Consume - sd->itemid = sd->itemindex = -1; - if (sd->status.inventory[i].expire_time == 0 && sd->inventory_data[i]->flag.delay_consume == 1) // Rental usable items are not consumed until expiration - pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_CONSUME); - } - } - - if (pc_is90overweight(sd) && sd->skillitem != skill_id) { /// Skill casting items ignore the overweight restriction. [Kenpachi] + if (pc_is90overweight(sd) && sd->autocast.type != AUTOCAST_ITEM) { // Skill casting items ignore the overweight restriction. clif->skill_fail(sd, skill_id, USESKILL_FAIL_WEIGHTOVER, 0, 0); return 0; } @@ -14973,7 +14968,7 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s return 0; } - if (require.sp > 0 && st->sp < (unsigned int)require.sp && sd->skillitem != skill_id) { /// Skill casting items and Hocus-Pocus skills don't consume SP. [Kenpachi] + if (require.sp > 0 && st->sp < (unsigned int)require.sp && sd->autocast.type == AUTOCAST_NONE) { // Auto-cast skills don't consume SP. clif->skill_fail(sd, skill_id, USESKILL_FAIL_SP_INSUFFICIENT, 0, 0); return 0; } @@ -15031,13 +15026,13 @@ static int skill_check_condition_castend(struct map_session_data *sd, uint16 ski if (sd->chat_id != 0) return 0; - if ((sd->state.itemskill_conditions_checked == 1 || sd->state.itemskill_check_conditions == 0) - && skill->is_item_skill(sd, skill_id, skill_lv)) { + if (((sd->autocast.itemskill_conditions_checked || !sd->autocast.itemskill_check_conditions) + && sd->autocast.type == AUTOCAST_ITEM) || sd->autocast.type == AUTOCAST_IMPROVISE) { return 1; } - if( pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill_id ) { - //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex] + if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->autocast.type != AUTOCAST_ITEM) { + // GMs don't override the AUTOCAST_ITEM check, otherwise they can use items without them being consumed! sd->state.arrow_atk = skill->get_ammotype(skill_id)?1:0; //Need to do arrow state check. sd->spiritball_old = sd->spiritball; //Need to do Spiritball check. return 1; @@ -15064,7 +15059,7 @@ static int skill_check_condition_castend(struct map_session_data *sd, uint16 ski break; } - if (pc_is90overweight(sd) && sd->skillitem != skill_id) { /// Skill casting items ignore the overweight restriction. [Kenpachi] + if (pc_is90overweight(sd) && sd->autocast.type != AUTOCAST_ITEM) { // Skill casting items ignore the overweight restriction. clif->skill_fail(sd, skill_id, USESKILL_FAIL_WEIGHTOVER, 0, 0); return 0; } @@ -15170,10 +15165,8 @@ static int skill_check_condition_castend(struct map_session_data *sd, uint16 ski clif->messagecolor_self(sd->fd, COLOR_RED, e_msg); return 0; } - if (!(require.ammo&1<<sd->inventory_data[i]->subtype)) { //Ammo type check. Send the "wrong weapon type" message - //which is the closest we have to wrong ammo type. [Skotlex] - clif->arrow_fail(sd,0); //Haplo suggested we just send the equip-arrows message instead. [Skotlex] - //clif->skill_fail(sd, skill_id, USESKILL_FAIL_THIS_WEAPON, 0, 0); + if ((require.ammo & (1 << sd->inventory_data[i]->subtype)) == 0 || !battle->check_arrows(sd)) { // Ammo type check. + clif->arrow_fail(sd, 0); // "Please equip the proper ammunition first." return 0; } } @@ -15237,8 +15230,10 @@ static int skill_consume_requirement(struct map_session_data *sd, uint16 skill_i nullpo_ret(sd); - if (sd->state.itemskill_check_conditions == 0 && skill->is_item_skill(sd, skill_id, skill_lv)) + if ((!sd->autocast.itemskill_check_conditions && sd->autocast.type == AUTOCAST_ITEM) + || sd->autocast.type == AUTOCAST_IMPROVISE) { return 1; + } req = skill->get_requirement(sd,skill_id,skill_lv); @@ -15254,7 +15249,7 @@ static int skill_consume_requirement(struct map_session_data *sd, uint16 skill_i break; default: - if (sd->state.autocast == 1 || sd->skillitem == skill_id) /// Skill casting items and Hocus-Pocus skills don't consume SP. [Kenpachi] + if (sd->autocast.type != AUTOCAST_NONE) // Auto-cast skills don't consume SP. req.sp = 0; break; @@ -15742,6 +15737,8 @@ static int skill_castfix_sc(struct block_list *bl, int time) } if (sc->data[SC_POEMBRAGI]) time -= time * sc->data[SC_POEMBRAGI]->val2 / 100; + if (sc->data[SC_SKF_CAST] != NULL) + time -= time * sc->data[SC_SKF_CAST]->val1 / 100; if (sc->data[SC_IZAYOI]) time -= time * 50 / 100; } @@ -15843,6 +15840,8 @@ static int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id, } if (sc->data[SC_MYSTICSCROLL]) VARCAST_REDUCTION(sc->data[SC_MYSTICSCROLL]->val1); + if (sc->data[SC_SKF_CAST] != NULL) + VARCAST_REDUCTION(sc->data[SC_SKF_CAST]->val1); // Fixed cast reduction bonuses if( sc->data[SC__LAZINESS] ) @@ -21636,7 +21635,6 @@ void skill_defaults(void) skill->cast_fix_sc = skill_castfix_sc; skill->vf_cast_fix = skill_vfcastfix; skill->delay_fix = skill_delay_fix; - skill->is_item_skill = skill_is_item_skill; skill->check_condition_castbegin = skill_check_condition_castbegin; skill->check_condition_castend = skill_check_condition_castend; skill->consume_requirement = skill_consume_requirement; @@ -21662,6 +21660,7 @@ void skill_defaults(void) skill->not_ok_hom = skillnotok_hom; skill->not_ok_hom_unknown = skillnotok_hom_unknown; skill->not_ok_mercenary = skillnotok_mercenary; + skill->validate_autocast_data = skill_validate_autocast_data; skill->chastle_mob_changetarget = skill_chastle_mob_changetarget; skill->can_produce_mix = skill_can_produce_mix; skill->produce_mix = skill_produce_mix; diff --git a/src/map/skill.h b/src/map/skill.h index c65547181..65195dc75 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -1724,6 +1724,15 @@ enum { UNT_MAX = 0x190 }; +/** Constants to identify the auto-cast type. **/ +enum autocast_type { + AUTOCAST_NONE = 0, + AUTOCAST_TEMP, // Used when type is only required during the execution of the calling instance. (For example bAutoSpell* skills.) + AUTOCAST_ABRA, // Used for Abracadabra (Hocus pocus). + AUTOCAST_IMPROVISE, // Used for Improvised Song. + AUTOCAST_ITEM, // Used for itemskill() script command. +}; + /** * Structures **/ @@ -2020,7 +2029,6 @@ struct skill_interface { int (*cast_fix_sc) ( struct block_list *bl, int time); int (*vf_cast_fix) ( struct block_list *bl, double time, uint16 skill_id, uint16 skill_lv); int (*delay_fix) ( struct block_list *bl, uint16 skill_id, uint16 skill_lv); - bool (*is_item_skill) (struct map_session_data *sd, int skill_id, int skill_lv); int (*check_condition_castbegin) (struct map_session_data *sd, uint16 skill_id, uint16 skill_lv); int (*check_condition_castend) (struct map_session_data *sd, uint16 skill_id, uint16 skill_lv); int (*consume_requirement) (struct map_session_data *sd, uint16 skill_id, uint16 skill_lv, short type); @@ -2046,6 +2054,7 @@ struct skill_interface { int (*not_ok_hom) (uint16 skill_id, struct homun_data *hd); int (*not_ok_hom_unknown) (uint16 skill_id, struct homun_data *hd); int (*not_ok_mercenary) (uint16 skill_id, struct mercenary_data *md); + void (*validate_autocast_data) (struct map_session_data *sd, int skill_id, int skill_lv); int (*chastle_mob_changetarget) (struct block_list *bl,va_list ap); int (*can_produce_mix) ( struct map_session_data *sd, int nameid, int trigger, int qty); int (*produce_mix) ( struct map_session_data *sd, uint16 skill_id, int nameid, int slot1, int slot2, int slot3, int qty ); diff --git a/src/map/status.c b/src/map/status.c index 4d798b606..d3e85e5be 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -884,6 +884,13 @@ static void initChangeTables(void) status->dbs->ChangeFlagTable[SC_PHI_DEMON] |= SCB_ALL; status->dbs->ChangeFlagTable[SC_MAGIC_CANDY] |= SCB_MATK | SCB_ALL; status->dbs->ChangeFlagTable[SC_MYSTICPOWDER] |= SCB_FLEE | SCB_LUK; + status->dbs->ChangeFlagTable[SC_POPECOOKIE] |= SCB_BASE | SCB_BATK | SCB_MATK; + status->dbs->ChangeFlagTable[SC_VITALIZE_POTION] |= SCB_BATK | SCB_MATK; + status->dbs->ChangeFlagTable[SC_SKF_MATK] |= SCB_MATK; + status->dbs->ChangeFlagTable[SC_SKF_ATK] |= SCB_BATK; + status->dbs->ChangeFlagTable[SC_SKF_ASPD] |= SCB_ASPD; + status->dbs->ChangeFlagTable[SC_SKF_CAST] |= SCB_NONE; + status->dbs->ChangeFlagTable[SC_ALMIGHTY] |= SCB_BATK | SCB_MATK; // Cash Items status->dbs->ChangeFlagTable[SC_FOOD_STR_CASH] |= SCB_STR; @@ -1584,7 +1591,7 @@ static int status_check_skilluse(struct block_list *src, struct block_list *targ } if( skill_id ) { - if (src != NULL && (sd == NULL || sd->skillitem == 0)) { + if (src != NULL && (sd == NULL || sd->autocast.type != AUTOCAST_ITEM)) { // Items that cast skills using 'itemskill' will not be handled by map_zone_db. int i; @@ -1628,7 +1635,7 @@ static int status_check_skilluse(struct block_list *src, struct block_list *targ if (src != NULL && map->getcell(src->m, src, src->x, src->y, CELL_CHKLANDPROTECTOR) && !(st->mode&MD_BOSS) - && (src->type != BL_PC || sd->skillitem != skill_id)) + && (src->type != BL_PC || sd->autocast.type != AUTOCAST_ITEM)) return 0; break; default: @@ -1707,7 +1714,7 @@ static int status_check_skilluse(struct block_list *src, struct block_list *targ return 0; //Can't amp out of Wand of Hermode :/ [Skotlex] } - if (skill_id != 0 /* Do not block item-casted skills.*/ && (src->type != BL_PC || sd->skillitem != skill_id)) { + if (skill_id != 0 /* Do not block item-casted skills.*/ && (src->type != BL_PC || sd->autocast.type != AUTOCAST_ITEM)) { //Skills blocked through status changes... if (!flag && ( //Blocked only from using the skill (stuff like autospell may still go through sc->data[SC_SILENCE] || @@ -2572,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. @@ -3038,6 +3049,18 @@ static int status_calc_pc_(struct map_session_data *sd, enum e_status_calc_opt o sd->subele[ELE_EARTH] += i; sd->subele[ELE_FIRE] -= i; } + if (sc->data[SC_POPECOOKIE] != NULL) { + i = sc->data[SC_POPECOOKIE]->val3; + sd->subele[ELE_WATER] += i; + sd->subele[ELE_EARTH] += i; + sd->subele[ELE_FIRE] += i; + sd->subele[ELE_WIND] += i; + sd->subele[ELE_POISON] += i; + sd->subele[ELE_HOLY] += i; + sd->subele[ELE_DARK] += i; + sd->subele[ELE_GHOST] += i; + sd->subele[ELE_UNDEAD] += i; + } if (sc->data[SC_MTF_MLEATKED]) sd->subele[ELE_NEUTRAL] += sc->data[SC_MTF_MLEATKED]->val1; if (sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 3) @@ -4801,6 +4824,10 @@ static int status_calc_batk(struct block_list *bl, struct status_change *sc, int /* some statuses that are hidden in the status window */ if(sc->data[SC_PLUSATTACKPOWER]) batk += sc->data[SC_PLUSATTACKPOWER]->val1; + if (sc->data[SC_POPECOOKIE] != NULL) + batk += batk * sc->data[SC_POPECOOKIE]->val1 / 100; + if (sc->data[SC_VITALIZE_POTION] != NULL) + batk += batk * sc->data[SC_VITALIZE_POTION]->val1 / 100; return cap_value(batk, battle_config.batk_min, battle_config.batk_max); } #ifndef RENEWAL @@ -4880,6 +4907,10 @@ static int status_calc_batk(struct block_list *bl, struct status_change *sc, int batk += batk * sc->data[SC_2011RWC]->val2 / 100; if (sc->data[SC_STEAMPACK]) batk += sc->data[SC_STEAMPACK]->val1; + if (sc->data[SC_SKF_ATK] != NULL) + batk += sc->data[SC_SKF_ATK]->val1; + if (sc->data[SC_ALMIGHTY] != NULL) + batk += sc->data[SC_ALMIGHTY]->val1; if (sc->data[SC_SHRIMP]) batk += batk * sc->data[SC_SHRIMP]->val2 / 100; @@ -5020,6 +5051,10 @@ static int status_calc_matk(struct block_list *bl, struct status_change *sc, int /* some statuses that are hidden in the status window */ if (sc->data[SC_MINDBREAKER]) matk += matk * sc->data[SC_MINDBREAKER]->val2 / 100; + if (sc->data[SC_POPECOOKIE] != NULL) + matk += matk * sc->data[SC_POPECOOKIE]->val2 / 100; + if (sc->data[SC_VITALIZE_POTION] != NULL) + matk += matk * sc->data[SC_VITALIZE_POTION]->val2 / 100; return cap_value(matk, battle_config.matk_min, battle_config.matk_max); } @@ -5077,6 +5112,10 @@ static int status_calc_matk(struct block_list *bl, struct status_change *sc, int matk += matk * sc->data[SC_2011RWC]->val2 / 100; if (sc->data[SC_MAGIC_CANDY]) matk += sc->data[SC_MAGIC_CANDY]->val1; + if (sc->data[SC_SKF_MATK] != NULL) + matk += sc->data[SC_SKF_MATK]->val1; + if (sc->data[SC_ALMIGHTY] != NULL) + matk += sc->data[SC_ALMIGHTY]->val2; return cap_value(matk, battle_config.matk_min, battle_config.matk_max); } @@ -5901,6 +5940,8 @@ static short status_calc_aspd(struct block_list *bl, struct status_change *sc, s bonus += sc->data[SC_BATTLESCROLL]->val1; if (sc->data[SC_STEAMPACK]) bonus += sc->data[SC_STEAMPACK]->val2; + if (sc->data[SC_SKF_ASPD] != NULL) + bonus += sc->data[SC_SKF_ASPD]->val1; } return (bonus + pots); @@ -6068,6 +6109,8 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * aspd_rate += sc->data[SC_BATTLESCROLL]->val1 * 10; if (sc->data[SC_STEAMPACK]) aspd_rate += sc->data[SC_STEAMPACK]->val2 * 10; + if (sc->data[SC_SKF_ASPD] != NULL) + aspd_rate -= sc->data[SC_SKF_ASPD]->val1 * 10; return (short)cap_value(aspd_rate,0,SHRT_MAX); } diff --git a/src/map/status.h b/src/map/status.h index ada18bc0a..d5cb3da75 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -854,6 +854,13 @@ typedef enum sc_type { SC_RESIST_PROPERTY_WIND, SC_CLIENT_ONLY_EQUIP_ARROW, SC_MADOGEAR, + SC_POPECOOKIE, + SC_VITALIZE_POTION, + SC_SKF_MATK, + SC_SKF_ATK, + SC_SKF_ASPD, + SC_SKF_CAST, + SC_ALMIGHTY, #ifndef SC_MAX SC_MAX, //Automatically updated max, used in for's to check we are within bounds. #endif diff --git a/src/map/unit.c b/src/map/unit.c index a879a125f..d484056f9 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -96,6 +96,8 @@ static struct unit_data *unit_bl2ud(struct block_list *bl) return &BL_UCAST(BL_MER, bl)->ud; case BL_ELEM: return &BL_UCAST(BL_ELEM, bl)->ud; + case BL_SKILL: // No assertion to not spam the server console when attacking a skill type unit such as Ice Wall. + return NULL; default: Assert_retr(NULL, false); } @@ -128,6 +130,8 @@ static const struct unit_data *unit_cbl2ud(const struct block_list *bl) return &BL_UCCAST(BL_MER, bl)->ud; case BL_ELEM: return &BL_UCCAST(BL_ELEM, bl)->ud; + case BL_SKILL: // No assertion to not spam the server console when attacking a skill type unit such as Ice Wall. + return NULL; default: Assert_retr(NULL, false); } @@ -326,7 +330,7 @@ static int unit_warpto_master(struct block_list *master_bl, struct block_list *s static int unit_walk_toxy_timer(int tid, int64 tick, int id, intptr_t data) { struct block_list *bl = map->id2bl(id); - if (bl == NULL || bl->prev == NULL) // Stop moved because it is missing from the block_list + if (bl == NULL) return 1; struct unit_data *ud = unit->bl2ud(bl); if (ud == NULL) @@ -336,8 +340,12 @@ static int unit_walk_toxy_timer(int tid, int64 tick, int id, intptr_t data) ShowError("unit_walk_timer mismatch %d != %d\n",ud->walktimer,tid); return 1; } + ud->walktimer = INVALID_TIMER; + if (bl->prev == NULL) // Stop moved because it is missing from the block_list. + return 1; + if (ud->walkpath.path_pos >= ud->walkpath.path_len) return 1; @@ -898,7 +906,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; @@ -1148,8 +1156,10 @@ static int unit_skilluse_id(struct block_list *src, int target_id, uint16 skill_ int ret = unit->skilluse_id2(src, target_id, skill_id, skill_lv, casttime, castcancel); struct map_session_data *sd = BL_CAST(BL_PC, src); - if (sd != NULL && (ret == 0 || !skill->is_item_skill(sd, skill_id, skill_lv))) - pc->itemskill_clear(sd); + if (sd != NULL && ret == 0) + pc->autocast_clear(sd); // Error in unit_skilluse_id2(). + else if (sd != NULL && ret != 0 && skill_id != SA_ABRACADABRA && skill_id != WM_RANDOMIZESPELL) + skill->validate_autocast_data(sd, skill_id, skill_lv); return ret; } @@ -1708,7 +1718,7 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill if (!ud->state.running) //need TK_RUN or WUGDASH handler to be done before that, see bugreport:6026 unit->stop_walking(src, STOPWALKING_FLAG_FIXPOS);// even though this is not how official works but this will do the trick. bugreport:6829 - if (sd != NULL && sd->state.itemskill_no_casttime == 1 && skill->is_item_skill(sd, skill_id, skill_lv)) + if (sd != NULL && sd->autocast.itemskill_instant_cast && sd->autocast.type == AUTOCAST_ITEM) casttime = 0; // in official this is triggered even if no cast time. @@ -1746,7 +1756,7 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill if( casttime <= 0 ) ud->state.skillcastcancel = 0; - if( !sd || sd->skillitem != skill_id || skill->get_cast(skill_id,skill_lv) ) + if (sd == NULL || sd->autocast.type < AUTOCAST_ABRA || skill->get_cast(skill_id, skill_lv) != 0) ud->canact_tick = tick + casttime + 100; if( sd ) { @@ -1785,8 +1795,10 @@ static int unit_skilluse_pos(struct block_list *src, short skill_x, short skill_ int ret = unit->skilluse_pos2(src, skill_x, skill_y, skill_id, skill_lv, casttime, castcancel); struct map_session_data *sd = BL_CAST(BL_PC, src); - if (sd != NULL && (ret == 0 || !skill->is_item_skill(sd, skill_id, skill_lv))) - pc->itemskill_clear(sd); + if (sd != NULL && ret == 0) + pc->autocast_clear(sd); // Error in unit_skilluse_pos2(). + else if (sd != NULL && ret != 0 && skill_id != SA_ABRACADABRA && skill_id != WM_RANDOMIZESPELL) + skill->validate_autocast_data(sd, skill_id, skill_lv); return ret; } @@ -1883,7 +1895,7 @@ static int unit_skilluse_pos2(struct block_list *src, short skill_x, short skill } ud->state.skillcastcancel = castcancel&&casttime>0?1:0; - if( !sd || sd->skillitem != skill_id || skill->get_cast(skill_id,skill_lv) ) + if (sd == NULL || sd->autocast.type < AUTOCAST_ABRA || skill->get_cast(skill_id, skill_lv) != 0) ud->canact_tick = tick + casttime + 100; #if 0 if (sd) { @@ -1914,7 +1926,7 @@ static int unit_skilluse_pos2(struct block_list *src, short skill_x, short skill unit->stop_walking(src, STOPWALKING_FLAG_FIXPOS); - if (sd != NULL && sd->state.itemskill_no_casttime == 1 && skill->is_item_skill(sd, skill_id, skill_lv)) + if (sd != NULL && sd->autocast.itemskill_instant_cast && sd->autocast.type == AUTOCAST_ITEM) casttime = 0; // in official this is triggered even if no cast time. @@ -2718,7 +2730,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); @@ -2932,7 +2944,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. diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc index f01d0250d..b8aa5ae61 100644 --- a/src/plugins/HPMHooking/HPMHooking.Defs.inc +++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc @@ -6188,8 +6188,8 @@ typedef int (*HPMHOOK_pre_pc_checkitem) (struct map_session_data **sd); typedef int (*HPMHOOK_post_pc_checkitem) (int retVal___, struct map_session_data *sd); typedef int (*HPMHOOK_pre_pc_useitem) (struct map_session_data **sd, int *n); typedef int (*HPMHOOK_post_pc_useitem) (int retVal___, struct map_session_data *sd, int n); -typedef int (*HPMHOOK_pre_pc_itemskill_clear) (struct map_session_data **sd); -typedef int (*HPMHOOK_post_pc_itemskill_clear) (int retVal___, struct map_session_data *sd); +typedef int (*HPMHOOK_pre_pc_autocast_clear) (struct map_session_data **sd); +typedef int (*HPMHOOK_post_pc_autocast_clear) (int retVal___, struct map_session_data *sd); typedef int (*HPMHOOK_pre_pc_skillatk_bonus) (struct map_session_data **sd, uint16 *skill_id); typedef int (*HPMHOOK_post_pc_skillatk_bonus) (int retVal___, struct map_session_data *sd, uint16 skill_id); typedef int (*HPMHOOK_pre_pc_skillheal_bonus) (struct map_session_data **sd, uint16 *skill_id); @@ -6500,6 +6500,8 @@ typedef int (*HPMHOOK_pre_pet_final) (void); typedef int (*HPMHOOK_post_pet_final) (int retVal___); typedef int (*HPMHOOK_pre_pet_hungry_val) (struct pet_data **pd); typedef int (*HPMHOOK_post_pet_hungry_val) (int retVal___, struct pet_data *pd); +typedef void (*HPMHOOK_pre_pet_set_hunger) (struct pet_data **pd, int *value); +typedef void (*HPMHOOK_post_pet_set_hunger) (struct pet_data *pd, int value); typedef void (*HPMHOOK_pre_pet_set_intimate) (struct pet_data **pd, int *value); typedef void (*HPMHOOK_post_pet_set_intimate) (struct pet_data *pd, int value); typedef int (*HPMHOOK_pre_pet_create_egg) (struct map_session_data **sd, int *item_id); @@ -7336,8 +7338,6 @@ typedef int (*HPMHOOK_pre_skill_vf_cast_fix) (struct block_list **bl, double *ti typedef int (*HPMHOOK_post_skill_vf_cast_fix) (int retVal___, struct block_list *bl, double time, uint16 skill_id, uint16 skill_lv); typedef int (*HPMHOOK_pre_skill_delay_fix) (struct block_list **bl, uint16 *skill_id, uint16 *skill_lv); typedef int (*HPMHOOK_post_skill_delay_fix) (int retVal___, struct block_list *bl, uint16 skill_id, uint16 skill_lv); -typedef bool (*HPMHOOK_pre_skill_is_item_skill) (struct map_session_data **sd, int *skill_id, int *skill_lv); -typedef bool (*HPMHOOK_post_skill_is_item_skill) (bool retVal___, struct map_session_data *sd, int skill_id, int skill_lv); typedef int (*HPMHOOK_pre_skill_check_condition_castbegin) (struct map_session_data **sd, uint16 *skill_id, uint16 *skill_lv); typedef int (*HPMHOOK_post_skill_check_condition_castbegin) (int retVal___, struct map_session_data *sd, uint16 skill_id, uint16 skill_lv); typedef int (*HPMHOOK_pre_skill_check_condition_castend) (struct map_session_data **sd, uint16 *skill_id, uint16 *skill_lv); @@ -7388,6 +7388,8 @@ typedef int (*HPMHOOK_pre_skill_not_ok_hom_unknown) (uint16 *skill_id, struct ho typedef int (*HPMHOOK_post_skill_not_ok_hom_unknown) (int retVal___, uint16 skill_id, struct homun_data *hd); typedef int (*HPMHOOK_pre_skill_not_ok_mercenary) (uint16 *skill_id, struct mercenary_data **md); typedef int (*HPMHOOK_post_skill_not_ok_mercenary) (int retVal___, uint16 skill_id, struct mercenary_data *md); +typedef void (*HPMHOOK_pre_skill_validate_autocast_data) (struct map_session_data **sd, int *skill_id, int *skill_lv); +typedef void (*HPMHOOK_post_skill_validate_autocast_data) (struct map_session_data *sd, int skill_id, int skill_lv); typedef int (*HPMHOOK_pre_skill_chastle_mob_changetarget) (struct block_list **bl, va_list ap); typedef int (*HPMHOOK_post_skill_chastle_mob_changetarget) (int retVal___, struct block_list *bl, va_list ap); typedef int (*HPMHOOK_pre_skill_can_produce_mix) (struct map_session_data **sd, int *nameid, int *trigger, int *qty); diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc index 24635d7e3..109c30885 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc @@ -4768,8 +4768,8 @@ struct { struct HPMHookPoint *HP_pc_checkitem_post; struct HPMHookPoint *HP_pc_useitem_pre; struct HPMHookPoint *HP_pc_useitem_post; - struct HPMHookPoint *HP_pc_itemskill_clear_pre; - struct HPMHookPoint *HP_pc_itemskill_clear_post; + struct HPMHookPoint *HP_pc_autocast_clear_pre; + struct HPMHookPoint *HP_pc_autocast_clear_post; struct HPMHookPoint *HP_pc_skillatk_bonus_pre; struct HPMHookPoint *HP_pc_skillatk_bonus_post; struct HPMHookPoint *HP_pc_skillheal_bonus_pre; @@ -5076,6 +5076,8 @@ struct { struct HPMHookPoint *HP_pet_final_post; struct HPMHookPoint *HP_pet_hungry_val_pre; struct HPMHookPoint *HP_pet_hungry_val_post; + struct HPMHookPoint *HP_pet_set_hunger_pre; + struct HPMHookPoint *HP_pet_set_hunger_post; struct HPMHookPoint *HP_pet_set_intimate_pre; struct HPMHookPoint *HP_pet_set_intimate_post; struct HPMHookPoint *HP_pet_create_egg_pre; @@ -5860,8 +5862,6 @@ struct { struct HPMHookPoint *HP_skill_vf_cast_fix_post; struct HPMHookPoint *HP_skill_delay_fix_pre; struct HPMHookPoint *HP_skill_delay_fix_post; - struct HPMHookPoint *HP_skill_is_item_skill_pre; - struct HPMHookPoint *HP_skill_is_item_skill_post; struct HPMHookPoint *HP_skill_check_condition_castbegin_pre; struct HPMHookPoint *HP_skill_check_condition_castbegin_post; struct HPMHookPoint *HP_skill_check_condition_castend_pre; @@ -5912,6 +5912,8 @@ struct { struct HPMHookPoint *HP_skill_not_ok_hom_unknown_post; struct HPMHookPoint *HP_skill_not_ok_mercenary_pre; struct HPMHookPoint *HP_skill_not_ok_mercenary_post; + struct HPMHookPoint *HP_skill_validate_autocast_data_pre; + struct HPMHookPoint *HP_skill_validate_autocast_data_post; struct HPMHookPoint *HP_skill_chastle_mob_changetarget_pre; struct HPMHookPoint *HP_skill_chastle_mob_changetarget_post; struct HPMHookPoint *HP_skill_can_produce_mix_pre; @@ -11647,8 +11649,8 @@ struct { int HP_pc_checkitem_post; int HP_pc_useitem_pre; int HP_pc_useitem_post; - int HP_pc_itemskill_clear_pre; - int HP_pc_itemskill_clear_post; + int HP_pc_autocast_clear_pre; + int HP_pc_autocast_clear_post; int HP_pc_skillatk_bonus_pre; int HP_pc_skillatk_bonus_post; int HP_pc_skillheal_bonus_pre; @@ -11955,6 +11957,8 @@ struct { int HP_pet_final_post; int HP_pet_hungry_val_pre; int HP_pet_hungry_val_post; + int HP_pet_set_hunger_pre; + int HP_pet_set_hunger_post; int HP_pet_set_intimate_pre; int HP_pet_set_intimate_post; int HP_pet_create_egg_pre; @@ -12739,8 +12743,6 @@ struct { int HP_skill_vf_cast_fix_post; int HP_skill_delay_fix_pre; int HP_skill_delay_fix_post; - int HP_skill_is_item_skill_pre; - int HP_skill_is_item_skill_post; int HP_skill_check_condition_castbegin_pre; int HP_skill_check_condition_castbegin_post; int HP_skill_check_condition_castend_pre; @@ -12791,6 +12793,8 @@ struct { int HP_skill_not_ok_hom_unknown_post; int HP_skill_not_ok_mercenary_pre; int HP_skill_not_ok_mercenary_post; + int HP_skill_validate_autocast_data_pre; + int HP_skill_validate_autocast_data_post; int HP_skill_chastle_mob_changetarget_pre; int HP_skill_chastle_mob_changetarget_post; int HP_skill_can_produce_mix_pre; diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc index cc8d59844..ac30b97d4 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc @@ -2442,7 +2442,7 @@ struct HookingPointData HookingPoints[] = { { HP_POP(pc->unequipitem_pos, HP_pc_unequipitem_pos) }, { HP_POP(pc->checkitem, HP_pc_checkitem) }, { HP_POP(pc->useitem, HP_pc_useitem) }, - { HP_POP(pc->itemskill_clear, HP_pc_itemskill_clear) }, + { HP_POP(pc->autocast_clear, HP_pc_autocast_clear) }, { HP_POP(pc->skillatk_bonus, HP_pc_skillatk_bonus) }, { HP_POP(pc->skillheal_bonus, HP_pc_skillheal_bonus) }, { HP_POP(pc->skillheal2_bonus, HP_pc_skillheal2_bonus) }, @@ -2598,6 +2598,7 @@ struct HookingPointData HookingPoints[] = { { HP_POP(pet->init, HP_pet_init) }, { HP_POP(pet->final, HP_pet_final) }, { HP_POP(pet->hungry_val, HP_pet_hungry_val) }, + { HP_POP(pet->set_hunger, HP_pet_set_hunger) }, { HP_POP(pet->set_intimate, HP_pet_set_intimate) }, { HP_POP(pet->create_egg, HP_pet_create_egg) }, { HP_POP(pet->unlocktarget, HP_pet_unlocktarget) }, @@ -2999,7 +3000,6 @@ struct HookingPointData HookingPoints[] = { { HP_POP(skill->cast_fix_sc, HP_skill_cast_fix_sc) }, { HP_POP(skill->vf_cast_fix, HP_skill_vf_cast_fix) }, { HP_POP(skill->delay_fix, HP_skill_delay_fix) }, - { HP_POP(skill->is_item_skill, HP_skill_is_item_skill) }, { HP_POP(skill->check_condition_castbegin, HP_skill_check_condition_castbegin) }, { HP_POP(skill->check_condition_castend, HP_skill_check_condition_castend) }, { HP_POP(skill->consume_requirement, HP_skill_consume_requirement) }, @@ -3025,6 +3025,7 @@ struct HookingPointData HookingPoints[] = { { HP_POP(skill->not_ok_hom, HP_skill_not_ok_hom) }, { HP_POP(skill->not_ok_hom_unknown, HP_skill_not_ok_hom_unknown) }, { HP_POP(skill->not_ok_mercenary, HP_skill_not_ok_mercenary) }, + { HP_POP(skill->validate_autocast_data, HP_skill_validate_autocast_data) }, { HP_POP(skill->chastle_mob_changetarget, HP_skill_chastle_mob_changetarget) }, { HP_POP(skill->can_produce_mix, HP_skill_can_produce_mix) }, { HP_POP(skill->produce_mix, HP_skill_produce_mix) }, diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc index a9ed12c31..940f96ca2 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc @@ -63411,14 +63411,14 @@ int HP_pc_useitem(struct map_session_data *sd, int n) { } return retVal___; } -int HP_pc_itemskill_clear(struct map_session_data *sd) { +int HP_pc_autocast_clear(struct map_session_data *sd) { int hIndex = 0; int retVal___ = 0; - if (HPMHooks.count.HP_pc_itemskill_clear_pre > 0) { + if (HPMHooks.count.HP_pc_autocast_clear_pre > 0) { int (*preHookFunc) (struct map_session_data **sd); *HPMforce_return = false; - for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_itemskill_clear_pre; hIndex++) { - preHookFunc = HPMHooks.list.HP_pc_itemskill_clear_pre[hIndex].func; + for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_autocast_clear_pre; hIndex++) { + preHookFunc = HPMHooks.list.HP_pc_autocast_clear_pre[hIndex].func; retVal___ = preHookFunc(&sd); } if (*HPMforce_return) { @@ -63427,12 +63427,12 @@ int HP_pc_itemskill_clear(struct map_session_data *sd) { } } { - retVal___ = HPMHooks.source.pc.itemskill_clear(sd); + retVal___ = HPMHooks.source.pc.autocast_clear(sd); } - if (HPMHooks.count.HP_pc_itemskill_clear_post > 0) { + if (HPMHooks.count.HP_pc_autocast_clear_post > 0) { int (*postHookFunc) (int retVal___, struct map_session_data *sd); - for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_itemskill_clear_post; hIndex++) { - postHookFunc = HPMHooks.list.HP_pc_itemskill_clear_post[hIndex].func; + for (hIndex = 0; hIndex < HPMHooks.count.HP_pc_autocast_clear_post; hIndex++) { + postHookFunc = HPMHooks.list.HP_pc_autocast_clear_post[hIndex].func; retVal___ = postHookFunc(retVal___, sd); } } @@ -67561,6 +67561,32 @@ int HP_pet_hungry_val(struct pet_data *pd) { } return retVal___; } +void HP_pet_set_hunger(struct pet_data *pd, int value) { + int hIndex = 0; + if (HPMHooks.count.HP_pet_set_hunger_pre > 0) { + void (*preHookFunc) (struct pet_data **pd, int *value); + *HPMforce_return = false; + for (hIndex = 0; hIndex < HPMHooks.count.HP_pet_set_hunger_pre; hIndex++) { + preHookFunc = HPMHooks.list.HP_pet_set_hunger_pre[hIndex].func; + preHookFunc(&pd, &value); + } + if (*HPMforce_return) { + *HPMforce_return = false; + return; + } + } + { + HPMHooks.source.pet.set_hunger(pd, value); + } + if (HPMHooks.count.HP_pet_set_hunger_post > 0) { + void (*postHookFunc) (struct pet_data *pd, int value); + for (hIndex = 0; hIndex < HPMHooks.count.HP_pet_set_hunger_post; hIndex++) { + postHookFunc = HPMHooks.list.HP_pet_set_hunger_post[hIndex].func; + postHookFunc(pd, value); + } + } + return; +} void HP_pet_set_intimate(struct pet_data *pd, int value) { int hIndex = 0; if (HPMHooks.count.HP_pet_set_intimate_pre > 0) { @@ -78215,33 +78241,6 @@ int HP_skill_delay_fix(struct block_list *bl, uint16 skill_id, uint16 skill_lv) } return retVal___; } -bool HP_skill_is_item_skill(struct map_session_data *sd, int skill_id, int skill_lv) { - int hIndex = 0; - bool retVal___ = false; - if (HPMHooks.count.HP_skill_is_item_skill_pre > 0) { - bool (*preHookFunc) (struct map_session_data **sd, int *skill_id, int *skill_lv); - *HPMforce_return = false; - for (hIndex = 0; hIndex < HPMHooks.count.HP_skill_is_item_skill_pre; hIndex++) { - preHookFunc = HPMHooks.list.HP_skill_is_item_skill_pre[hIndex].func; - retVal___ = preHookFunc(&sd, &skill_id, &skill_lv); - } - if (*HPMforce_return) { - *HPMforce_return = false; - return retVal___; - } - } - { - retVal___ = HPMHooks.source.skill.is_item_skill(sd, skill_id, skill_lv); - } - if (HPMHooks.count.HP_skill_is_item_skill_post > 0) { - bool (*postHookFunc) (bool retVal___, struct map_session_data *sd, int skill_id, int skill_lv); - for (hIndex = 0; hIndex < HPMHooks.count.HP_skill_is_item_skill_post; hIndex++) { - postHookFunc = HPMHooks.list.HP_skill_is_item_skill_post[hIndex].func; - retVal___ = postHookFunc(retVal___, sd, skill_id, skill_lv); - } - } - return retVal___; -} int HP_skill_check_condition_castbegin(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv) { int hIndex = 0; int retVal___ = 0; @@ -78919,6 +78918,32 @@ int HP_skill_not_ok_mercenary(uint16 skill_id, struct mercenary_data *md) { } return retVal___; } +void HP_skill_validate_autocast_data(struct map_session_data *sd, int skill_id, int skill_lv) { + int hIndex = 0; + if (HPMHooks.count.HP_skill_validate_autocast_data_pre > 0) { + void (*preHookFunc) (struct map_session_data **sd, int *skill_id, int *skill_lv); + *HPMforce_return = false; + for (hIndex = 0; hIndex < HPMHooks.count.HP_skill_validate_autocast_data_pre; hIndex++) { + preHookFunc = HPMHooks.list.HP_skill_validate_autocast_data_pre[hIndex].func; + preHookFunc(&sd, &skill_id, &skill_lv); + } + if (*HPMforce_return) { + *HPMforce_return = false; + return; + } + } + { + HPMHooks.source.skill.validate_autocast_data(sd, skill_id, skill_lv); + } + if (HPMHooks.count.HP_skill_validate_autocast_data_post > 0) { + void (*postHookFunc) (struct map_session_data *sd, int skill_id, int skill_lv); + for (hIndex = 0; hIndex < HPMHooks.count.HP_skill_validate_autocast_data_post; hIndex++) { + postHookFunc = HPMHooks.list.HP_skill_validate_autocast_data_post[hIndex].func; + postHookFunc(sd, skill_id, skill_lv); + } + } + return; +} int HP_skill_chastle_mob_changetarget(struct block_list *bl, va_list ap) { int hIndex = 0; int retVal___ = 0; diff --git a/src/plugins/Makefile.in b/src/plugins/Makefile.in index 5527ceb2f..e44412bfa 100644 --- a/src/plugins/Makefile.in +++ b/src/plugins/Makefile.in @@ -103,7 +103,7 @@ Makefile: Makefile.in ../../plugins/%@DLLEXT@: %.c $(ALL_H) $$(shell ls %/* 2>/dev/null) @echo " CC $<" - @$(CC) $(COMMON_INCLUDE) $(THIRDPARTY_INCLUDE) @PLUGINSTATIC@ @DEFS@ @CFLAGS@ @CPPFLAGS@ @LDFLAGS@ @SOFLAGS@ -o $@ $< + @$(CC) $(COMMON_INCLUDE) $(THIRDPARTY_INCLUDE) @PLUGINSTATIC@ @DEFS@ @CFLAGS@ @CPPFLAGS@ @LDFLAGS@ @SOFLAGS@ @LIBS@ @MYSQL_LIBS@ -o $@ $< ../../plugins/HPMHooking_login@DLLEXT@: HPMHOOKINGTYPE = LOGIN ../../plugins/HPMHooking_char@DLLEXT@: HPMHOOKINGTYPE = CHAR |