diff --git a/src/map/battle.cpp b/src/map/battle.cpp index 522d3713824..2a5340d5aac 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -4817,18 +4817,6 @@ static int32 battle_calc_attack_skill_ratio(struct Damage* wd, block_list *src,b #endif skillratio += 35 * skill_lv; break; - case AM_DEMONSTRATION: - skillratio += 20 * skill_lv; - break; - case AM_ACIDTERROR: -#ifdef RENEWAL - skillratio += -100 + 200 * skill_lv; - if (sd && pc_checkskill(sd, AM_LEARNINGPOTION)) - skillratio += 100; // !TODO: What's this bonus increase? -#else - skillratio += -50 + 50 * skill_lv; -#endif - break; case MO_FINGEROFFENSIVE: #ifdef RENEWAL skillratio += 500 + skill_lv * 200; diff --git a/src/map/map-server-generator.vcxproj b/src/map/map-server-generator.vcxproj index d4abc2a9bc2..430404129a4 100644 --- a/src/map/map-server-generator.vcxproj +++ b/src/map/map-server-generator.vcxproj @@ -334,8 +334,15 @@ + + + + + + + @@ -345,8 +352,17 @@ + + + + + + + + + @@ -540,8 +556,15 @@ + + + + + + + @@ -551,8 +574,17 @@ + + + + + + + + + diff --git a/src/map/map-server-generator.vcxproj.filters b/src/map/map-server-generator.vcxproj.filters index 3c55ace6d37..b7a1849bbc1 100644 --- a/src/map/map-server-generator.vcxproj.filters +++ b/src/map/map-server-generator.vcxproj.filters @@ -651,12 +651,33 @@ Header Files\Skills\Mercenary + + Header Files\Skills\Merchant + Header Files\Skills\Merchant Header Files\Skills\Merchant + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + Header Files\Skills\Merchant @@ -684,12 +705,39 @@ Header Files\Skills\Merchant + + Header Files\Skills\Merchant + Header Files\Skills\Merchant Header Files\Skills\Merchant + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + Header Files\Skills\Merchant @@ -1127,12 +1175,33 @@ Source Files\Skills\Mercenary + + Source Files\Skills\Merchant + Source Files\Skills\Merchant Source Files\Skills\Merchant + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + Source Files\Skills\Merchant @@ -1160,12 +1229,39 @@ Source Files\Skills\Merchant + + Source Files\Skills\Merchant + Source Files\Skills\Merchant Source Files\Skills\Merchant + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + Source Files\Skills\Merchant diff --git a/src/map/map-server.vcxproj b/src/map/map-server.vcxproj index 91ce78ef0c2..d6760d3723c 100644 --- a/src/map/map-server.vcxproj +++ b/src/map/map-server.vcxproj @@ -334,8 +334,15 @@ + + + + + + + @@ -345,8 +352,17 @@ + + + + + + + + + @@ -540,8 +556,15 @@ + + + + + + + @@ -551,8 +574,17 @@ + + + + + + + + + diff --git a/src/map/map-server.vcxproj.filters b/src/map/map-server.vcxproj.filters index 3c55ace6d37..b7a1849bbc1 100644 --- a/src/map/map-server.vcxproj.filters +++ b/src/map/map-server.vcxproj.filters @@ -651,12 +651,33 @@ Header Files\Skills\Mercenary + + Header Files\Skills\Merchant + Header Files\Skills\Merchant Header Files\Skills\Merchant + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + Header Files\Skills\Merchant @@ -684,12 +705,39 @@ Header Files\Skills\Merchant + + Header Files\Skills\Merchant + Header Files\Skills\Merchant Header Files\Skills\Merchant + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + + + Header Files\Skills\Merchant + Header Files\Skills\Merchant @@ -1127,12 +1175,33 @@ Source Files\Skills\Mercenary + + Source Files\Skills\Merchant + Source Files\Skills\Merchant Source Files\Skills\Merchant + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + Source Files\Skills\Merchant @@ -1160,12 +1229,39 @@ Source Files\Skills\Merchant + + Source Files\Skills\Merchant + Source Files\Skills\Merchant Source Files\Skills\Merchant + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + + + Source Files\Skills\Merchant + Source Files\Skills\Merchant diff --git a/src/map/skill.cpp b/src/map/skill.cpp index c97fbde8291..64e717d6ef7 100755 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -1466,24 +1466,6 @@ int32 skill_additional_effect( block_list* src, block_list *bl, uint16 skill_id, sc_start(src,bl,SC_BLIND,100,skill_lv,skill_get_time2(skill_id,skill_lv)); break; - case AM_ACIDTERROR: - sc_start2(src,bl,SC_BLEEDING,(skill_lv*3),skill_lv,src->id,skill_get_time2(skill_id,skill_lv)); -#ifdef RENEWAL - if (skill_break_equip(src,bl, EQP_ARMOR, (1000 * skill_lv + 500) - 1000, BCT_ENEMY)) -#else - if (skill_break_equip(src,bl, EQP_ARMOR, 100*skill_get_time(skill_id,skill_lv), BCT_ENEMY)) -#endif - clif_emotion( *bl, ET_HUK ); - break; - - case AM_DEMONSTRATION: -#ifdef RENEWAL - skill_break_equip(src,bl, EQP_WEAPON, 300 * skill_lv, BCT_ENEMY); -#else - skill_break_equip(src,bl, EQP_WEAPON, 100*skill_lv, BCT_ENEMY); -#endif - break; - case CR_SHIELDCHARGE: sc_start(src,bl,SC_STUN,(15+skill_lv*5),skill_lv,skill_get_time2(skill_id,skill_lv)); break; @@ -8375,13 +8357,6 @@ int32 skill_castend_nodamage_id (block_list *src, block_list *bl, uint16 skill_i clif_skill_nodamage(src,*bl,skill_id,skill_lv,i != 0); break; - case AM_PHARMACY: - if(sd) { - clif_skill_produce_mix_list( *sd, skill_id, 22 ); - clif_skill_nodamage(src,*bl,skill_id,skill_lv); - } - break; - case SA_CREATECON: if( sd != nullptr ){ clif_elementalconverter_list( *sd ); @@ -8998,191 +8973,6 @@ int32 skill_castend_nodamage_id (block_list *src, block_list *bl, uint16 skill_i break; } - case AM_BERSERKPITCHER: - case AM_POTIONPITCHER: - { - int32 j,hp = 0,sp = 0; - if( dstmd && dstmd->mob_id == MOBID_EMPERIUM ) { - return 1; - } - if( sd ) { - int32 x,bonus=100; - struct s_skill_condition require = skill_get_requirement(sd, skill_id, skill_lv); - x = skill_lv%11 - 1; - j = pc_search_inventory(sd, require.itemid[x]); - if (j < 0 || require.itemid[x] <= 0) { - clif_skill_fail( *sd, skill_id ); - return 1; - } - if (sd->inventory_data[j] == nullptr || sd->inventory.u.items_inventory[j].amount < require.amount[x]) { - clif_skill_fail( *sd, skill_id ); - return 1; - } - if( skill_id == AM_BERSERKPITCHER ) { - if( dstsd && dstsd->status.base_level < (uint32)sd->inventory_data[j]->elv ) { - clif_skill_fail( *sd, skill_id ); - return 1; - } - } - potion_flag = 1; - potion_hp = potion_sp = potion_per_hp = potion_per_sp = 0; - potion_target = bl->id; - run_script(sd->inventory_data[j]->script,0,sd->id,0); - potion_flag = potion_target = 0; - if( sd->sc.getSCE(SC_SPIRIT) && sd->sc.getSCE(SC_SPIRIT)->val2 == SL_ALCHEMIST ) - bonus += sd->status.base_level; - if( potion_per_hp > 0 || potion_per_sp > 0 ) { - hp = tstatus->max_hp * potion_per_hp / 100; - hp = hp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; - if( dstsd ) { - sp = dstsd->status.max_sp * potion_per_sp / 100; - sp = sp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; - } - } else { - if( potion_hp > 0 ) { - hp = potion_hp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; - hp = hp * (100 + (tstatus->vit * 2)) / 100; - if( dstsd ) - hp = hp * (100 + pc_checkskill(dstsd,SM_RECOVERY)*10) / 100; - } - if( potion_sp > 0 ) { - sp = potion_sp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; - sp = sp * (100 + (tstatus->int_ * 2)) / 100; - if( dstsd ) - sp = sp * (100 + pc_checkskill(dstsd,MG_SRECOVERY)*10) / 100; - } - } - - if ((bonus = pc_get_itemgroup_bonus_group(sd, IG_POTION, sd->itemgrouphealrate))) { - hp += hp * bonus / 100; - } - - if( ( bonus = pc_get_itemgroup_bonus_group( sd, IG_POTION, sd->itemgroupsphealrate ) ) ){ - sp += sp * bonus / 100; - } - - if( (j = pc_skillheal_bonus(sd, skill_id)) ) { - hp += hp * j / 100; - sp += sp * j / 100; - } - } else { - //Maybe replace with potion_hp, but I'm unsure how that works [Playtester] - switch (skill_lv) { - case 1: hp = 45; break; - case 2: hp = 105; break; - case 3: hp = 175; break; - default: hp = 325; break; - } - hp = (hp + rnd()%(skill_lv*20+1)) * (150 + skill_lv*10) / 100; - hp = hp * (100 + (tstatus->vit * 2)) / 100; - if( dstsd ) - hp = hp * (100 + pc_checkskill(dstsd,SM_RECOVERY)*10) / 100; - } - if( dstsd && (j = pc_skillheal2_bonus(dstsd, skill_id)) ) { - hp += hp * j / 100; - sp += sp * j / 100; - } - // Final heal increased by HPlus. - // Is this the right place for this??? [Rytech] - // Can HPlus also affect SP recovery??? - if (sd && sstatus->hplus > 0) { - hp += hp * sstatus->hplus / 100; - sp += sp * sstatus->hplus / 100; - } - if (tsc != nullptr && !tsc->empty()) { - uint8 penalty = 0; - - if (tsc->getSCE(SC_WATER_INSIGNIA) && tsc->getSCE(SC_WATER_INSIGNIA)->val1 == 2) { - hp += hp / 10; - sp += sp / 10; - } - if (tsc->getSCE(SC_CRITICALWOUND)) - penalty += tsc->getSCE(SC_CRITICALWOUND)->val2; - if (tsc->getSCE(SC_DEATHHURT) && tsc->getSCE(SC_DEATHHURT)->val3) - penalty += 20; - if (tsc->getSCE(SC_NORECOVER_STATE)) - penalty = 100; - if (penalty > 0) { - hp -= hp * penalty / 100; - sp -= sp * penalty / 100; - } - } - -#ifdef RENEWAL - if (bl->type == BL_HOM) - hp *= 3; // Heal effectiveness is 3x for Homunculus -#endif - - clif_skill_nodamage(src,*bl,skill_id,skill_lv); - if( hp > 0 || (skill_id == AM_POTIONPITCHER && sp <= 0) ) - clif_skill_nodamage(nullptr,*bl,AL_HEAL,hp,1); - if( sp > 0 ) - clif_skill_nodamage(nullptr,*bl,MG_SRECOVERY,sp); - if (tsc) { -#ifdef RENEWAL - if (tsc->getSCE(SC_EXTREMITYFIST)) - sp = 0; -#endif - if (tsc->getSCE(SC_NORECOVER_STATE)) { - hp = 0; - sp = 0; - } - } - status_heal(bl,hp,sp,0); - } - break; - case AM_CP_WEAPON: - case AM_CP_SHIELD: - case AM_CP_ARMOR: - case AM_CP_HELM: - { - uint32 equip[] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HEAD_TOP}; - - if( sd && ( bl->type != BL_PC || ( dstsd && pc_checkequip(dstsd,equip[skill_id - AM_CP_WEAPON]) < 0 ) ) ){ - clif_skill_fail( *sd, skill_id ); - return 0; - } - clif_skill_nodamage(src,*bl,skill_id,skill_lv, - sc_start(src,bl,type,100,skill_lv,skill_get_time(skill_id,skill_lv))); - } - break; - case AM_TWILIGHT1: - if (sd) { - clif_skill_nodamage(src,*bl,skill_id,skill_lv); - //Prepare 200 White Potions. - if (!skill_produce_mix(sd, skill_id, ITEMID_WHITE_POTION, 0, 0, 0, 200, -1)) - clif_skill_fail( *sd, skill_id ); - } - break; - case AM_TWILIGHT2: - if (sd) { - clif_skill_nodamage(src,*bl,skill_id,skill_lv); - //Prepare 200 Slim White Potions. - if (!skill_produce_mix(sd, skill_id, ITEMID_WHITE_SLIM_POTION, 0, 0, 0, 200, -1)) - clif_skill_fail( *sd, skill_id ); - } - break; - case AM_TWILIGHT3: - if (sd) { - int32 ebottle = pc_search_inventory(sd,ITEMID_EMPTY_BOTTLE); - int16 alcohol_idx = -1, acid_idx = -1, fire_idx = -1; - if( ebottle >= 0 ) - ebottle = sd->inventory.u.items_inventory[ebottle].amount; - //check if you can produce all three, if not, then fail: - if (!(alcohol_idx = skill_can_produce_mix(sd,ITEMID_ALCOHOL,-1, 100)) //100 Alcohol - || !(acid_idx = skill_can_produce_mix(sd,ITEMID_ACID_BOTTLE,-1, 50)) //50 Acid Bottle - || !(fire_idx = skill_can_produce_mix(sd,ITEMID_FIRE_BOTTLE,-1, 50)) //50 Flame Bottle - || ebottle < 200 //200 empty bottle are required at total. - ) { - clif_skill_fail( *sd, skill_id ); - break; - } - clif_skill_nodamage(src,*bl,skill_id,skill_lv); - skill_produce_mix(sd, skill_id, ITEMID_ALCOHOL, 0, 0, 0, 100, alcohol_idx-1); - skill_produce_mix(sd, skill_id, ITEMID_ACID_BOTTLE, 0, 0, 0, 50, acid_idx-1); - skill_produce_mix(sd, skill_id, ITEMID_FIRE_BOTTLE, 0, 0, 0, 50, fire_idx-1); - } - break; case SA_DISPELL: if (flag&1 || (i = skill_get_splash(skill_id, skill_lv)) < 1) { if (sd && dstsd && !map_flag_vs(sd->m) && (!sd->duel_group || sd->duel_group != dstsd->duel_group) && (!sd->status.party_id || sd->status.party_id != dstsd->status.party_id)) @@ -10104,24 +9894,6 @@ int32 skill_castend_nodamage_id (block_list *src, block_list *bl, uint16 skill_i clif_skill_nodamage(src, *bl, skill_id, skill_lv); break; - case AM_CALLHOMUN: //[orn] - if (sd && !hom_call(sd)) - clif_skill_fail( *sd, skill_id ); -#ifdef RENEWAL - else if (sd && hom_is_active(sd->hd)) - skill_area_temp[0] = 1; // Already passed pre-cast checks -#endif - break; - - case AM_REST: - if (sd) { - if (hom_vaporize(sd,HOM_ST_REST)) - clif_skill_nodamage(src, *bl, skill_id, skill_lv); - else - clif_skill_fail( *sd, skill_id ); - } - break; - case HAMI_CASTLE: //[orn] if (src != bl && rnd_chance(20 * skill_lv, 100)) { // Get one of the monsters targeting the player and set the homunculus as its new target @@ -13502,7 +13274,6 @@ int32 skill_castend_pos2(block_list* src, int32 x, int32 y, uint16 skill_id, uin case MA_SANDMAN: case MA_FREEZINGTRAP: case AS_VENOMDUST: - case AM_DEMONSTRATION: case PF_FOGWALL: case PF_SPIDERWEB: case WE_CALLPARTNER: @@ -13731,26 +13502,6 @@ int32 skill_castend_pos2(block_list* src, int32 x, int32 y, uint16 skill_id, uin clif_blown(src); status_change_end(src, SC_HIDING); break; - case AM_SPHEREMINE: - case AM_CANNIBALIZE: - { - int32 summons[5] = { MOBID_G_MANDRAGORA, MOBID_G_HYDRA, MOBID_G_FLORA, MOBID_G_PARASITE, MOBID_G_GEOGRAPHER }; - int32 class_ = skill_id==AM_SPHEREMINE?MOBID_MARINE_SPHERE:summons[skill_lv-1]; - enum mob_ai ai = (skill_id == AM_SPHEREMINE) ? AI_SPHERE : AI_FLORA; - mob_data *md; - - // Correct info, don't change any of this! [celest] - md = mob_once_spawn_sub(src, src->m, x, y, status_get_name(*src), class_, "", SZ_SMALL, ai); - if (md) { - md->master_id = src->id; - md->special_state.ai = ai; - if( md->deletetimer != INVALID_TIMER ) - delete_timer(md->deletetimer, mob_timer_delete); - md->deletetimer = add_timer (gettick() + skill_get_time(skill_id,skill_lv), mob_timer_delete, md->id, 0); - mob_spawn (md); //Now it is ready for spawning. - } - } - break; // Slim Pitcher [Celest] case CR_SLIMPITCHER: diff --git a/src/map/skills/merchant/acidterror.cpp b/src/map/skills/merchant/acidterror.cpp new file mode 100644 index 00000000000..ffd5aebbe41 --- /dev/null +++ b/src/map/skills/merchant/acidterror.cpp @@ -0,0 +1,35 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "acidterror.hpp" + +#include + +#include "map/clif.hpp" +#include "map/pc.hpp" +#include "map/status.hpp" + +SkillAcidTerror::SkillAcidTerror() : WeaponSkillImpl(AM_ACIDTERROR) { +} + +void SkillAcidTerror::calculateSkillRatio(const Damage* wd, const block_list* src, const block_list* target, uint16 skill_lv, int32& base_skillratio, int32 mflag) const { +#ifdef RENEWAL + const map_session_data* sd = BL_CAST(BL_PC, src); + + base_skillratio += -100 + 200 * skill_lv; + if (sd && pc_checkskill(sd, AM_LEARNINGPOTION)) + base_skillratio += 100; // !TODO: What's this bonus increase? +#else + base_skillratio += -50 + 50 * skill_lv; +#endif +} + +void SkillAcidTerror::applyAdditionalEffects(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32 attack_type, enum damage_lv dmg_lv) const { + sc_start2(src,target,SC_BLEEDING,(skill_lv*3),skill_lv,src->id,skill_get_time2(getSkillId(),skill_lv)); +#ifdef RENEWAL + if (skill_break_equip(src,target, EQP_ARMOR, (1000 * skill_lv + 500) - 1000, BCT_ENEMY)) +#else + if (skill_break_equip(src,target, EQP_ARMOR, 100*skill_get_time(getSkillId(),skill_lv), BCT_ENEMY)) +#endif + clif_emotion( *target, ET_HUK ); +} diff --git a/src/map/skills/merchant/acidterror.hpp b/src/map/skills/merchant/acidterror.hpp new file mode 100644 index 00000000000..ebd0eed2433 --- /dev/null +++ b/src/map/skills/merchant/acidterror.hpp @@ -0,0 +1,14 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../weapon_skill_impl.hpp" + +class SkillAcidTerror : public WeaponSkillImpl { +public: + SkillAcidTerror(); + + void calculateSkillRatio(const Damage* wd, const block_list* src, const block_list* target, uint16 skill_lv, int32& base_skillratio, int32 mflag) const override; + void applyAdditionalEffects(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32 attack_type, enum damage_lv dmg_lv) const override; +}; diff --git a/src/map/skills/merchant/aidberserkpotion.cpp b/src/map/skills/merchant/aidberserkpotion.cpp new file mode 100644 index 00000000000..d8c2a833d44 --- /dev/null +++ b/src/map/skills/merchant/aidberserkpotion.cpp @@ -0,0 +1,154 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "aidberserkpotion.hpp" + +#include + +#include "map/clif.hpp" +#include "map/mob.hpp" +#include "map/pc.hpp" +#include "map/status.hpp" + +SkillAidBerserkPotion::SkillAidBerserkPotion() : SkillImpl(AM_BERSERKPITCHER) { +} + +void SkillAidBerserkPotion::castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const { + map_session_data* sd = BL_CAST(BL_PC, src); + status_data* sstatus = status_get_status_data(*src); + map_session_data* dstsd = BL_CAST(BL_PC, target); + mob_data* dstmd = BL_CAST(BL_MOB, target); + status_data* tstatus = status_get_status_data(*target); + status_change* tsc = status_get_sc(target); + + int32 j,hp = 0,sp = 0; + if( dstmd && dstmd->mob_id == MOBID_EMPERIUM ) { + flag |= SKILL_NOCONSUME_REQ; + return; + } + if( sd ) { + int32 x,bonus=100; + struct s_skill_condition require = skill_get_requirement(sd, getSkillId(), skill_lv); + x = skill_lv%11 - 1; + j = pc_search_inventory(sd, require.itemid[x]); + if (j < 0 || require.itemid[x] <= 0) { + clif_skill_fail( *sd, getSkillId() ); + flag |= SKILL_NOCONSUME_REQ; + return; + } + if (sd->inventory_data[j] == nullptr || sd->inventory.u.items_inventory[j].amount < require.amount[x]) { + clif_skill_fail( *sd, getSkillId() ); + flag |= SKILL_NOCONSUME_REQ; + return; + } + if( dstsd && dstsd->status.base_level < (uint32)sd->inventory_data[j]->elv ) { + clif_skill_fail( *sd, getSkillId() ); + flag |= SKILL_NOCONSUME_REQ; + return; + } + potion_flag = 1; + potion_hp = potion_sp = potion_per_hp = potion_per_sp = 0; + potion_target = target->id; + run_script(sd->inventory_data[j]->script,0,sd->id,0); + potion_flag = potion_target = 0; + if( sd->sc.getSCE(SC_SPIRIT) && sd->sc.getSCE(SC_SPIRIT)->val2 == SL_ALCHEMIST ) + bonus += sd->status.base_level; + if( potion_per_hp > 0 || potion_per_sp > 0 ) { + hp = tstatus->max_hp * potion_per_hp / 100; + hp = hp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; + if( dstsd ) { + sp = dstsd->status.max_sp * potion_per_sp / 100; + sp = sp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; + } + } else { + if( potion_hp > 0 ) { + hp = potion_hp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; + hp = hp * (100 + (tstatus->vit * 2)) / 100; + if( dstsd ) + hp = hp * (100 + pc_checkskill(dstsd,SM_RECOVERY)*10) / 100; + } + if( potion_sp > 0 ) { + sp = potion_sp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; + sp = sp * (100 + (tstatus->int_ * 2)) / 100; + if( dstsd ) + sp = sp * (100 + pc_checkskill(dstsd,MG_SRECOVERY)*10) / 100; + } + } + + if ((bonus = pc_get_itemgroup_bonus_group(sd, IG_POTION, sd->itemgrouphealrate))) { + hp += hp * bonus / 100; + } + + if( ( bonus = pc_get_itemgroup_bonus_group( sd, IG_POTION, sd->itemgroupsphealrate ) ) ){ + sp += sp * bonus / 100; + } + + if( (j = pc_skillheal_bonus(sd, getSkillId())) ) { + hp += hp * j / 100; + sp += sp * j / 100; + } + } else { + //Maybe replace with potion_hp, but I'm unsure how that works [Playtester] + switch (skill_lv) { + case 1: hp = 45; break; + case 2: hp = 105; break; + case 3: hp = 175; break; + default: hp = 325; break; + } + hp = (hp + rnd()%(skill_lv*20+1)) * (150 + skill_lv*10) / 100; + hp = hp * (100 + (tstatus->vit * 2)) / 100; + if( dstsd ) + hp = hp * (100 + pc_checkskill(dstsd,SM_RECOVERY)*10) / 100; + } + if( dstsd && (j = pc_skillheal2_bonus(dstsd, getSkillId())) ) { + hp += hp * j / 100; + sp += sp * j / 100; + } + // Final heal increased by HPlus. + // Is this the right place for this??? [Rytech] + // Can HPlus also affect SP recovery??? + if (sd && sstatus->hplus > 0) { + hp += hp * sstatus->hplus / 100; + sp += sp * sstatus->hplus / 100; + } + if (tsc != nullptr && !tsc->empty()) { + uint8 penalty = 0; + + if (tsc->getSCE(SC_WATER_INSIGNIA) && tsc->getSCE(SC_WATER_INSIGNIA)->val1 == 2) { + hp += hp / 10; + sp += sp / 10; + } + if (tsc->getSCE(SC_CRITICALWOUND)) + penalty += tsc->getSCE(SC_CRITICALWOUND)->val2; + if (tsc->getSCE(SC_DEATHHURT) && tsc->getSCE(SC_DEATHHURT)->val3) + penalty += 20; + if (tsc->getSCE(SC_NORECOVER_STATE)) + penalty = 100; + if (penalty > 0) { + hp -= hp * penalty / 100; + sp -= sp * penalty / 100; + } + } + +#ifdef RENEWAL + if (target->type == BL_HOM) + hp *= 3; // Heal effectiveness is 3x for Homunculus +#endif + + clif_skill_nodamage(src,*target,getSkillId(),skill_lv); + if( hp > 0 ) + clif_skill_nodamage(nullptr,*target,AL_HEAL,hp,1); + if( sp > 0 ) + clif_skill_nodamage(nullptr,*target,MG_SRECOVERY,sp); + if (tsc) { +#ifdef RENEWAL + if (tsc->getSCE(SC_EXTREMITYFIST)) + sp = 0; +#endif + if (tsc->getSCE(SC_NORECOVER_STATE)) { + hp = 0; + sp = 0; + } + } + status_heal(target,hp,sp,0); +} diff --git a/src/map/skills/merchant/aidberserkpotion.hpp b/src/map/skills/merchant/aidberserkpotion.hpp new file mode 100644 index 00000000000..37e84ef74a9 --- /dev/null +++ b/src/map/skills/merchant/aidberserkpotion.hpp @@ -0,0 +1,13 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillAidBerserkPotion : public SkillImpl { +public: + SkillAidBerserkPotion(); + + void castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const override; +}; diff --git a/src/map/skills/merchant/aidpotion.cpp b/src/map/skills/merchant/aidpotion.cpp new file mode 100644 index 00000000000..088797e6f03 --- /dev/null +++ b/src/map/skills/merchant/aidpotion.cpp @@ -0,0 +1,149 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "aidpotion.hpp" + +#include + +#include "map/clif.hpp" +#include "map/mob.hpp" +#include "map/pc.hpp" +#include "map/status.hpp" + +SkillAidPotion::SkillAidPotion() : SkillImpl(AM_POTIONPITCHER) { +} + +void SkillAidPotion::castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const { + map_session_data* sd = BL_CAST(BL_PC, src); + status_data* sstatus = status_get_status_data(*src); + map_session_data* dstsd = BL_CAST(BL_PC, target); + mob_data* dstmd = BL_CAST(BL_MOB, target); + status_data* tstatus = status_get_status_data(*target); + status_change* tsc = status_get_sc(target); + + int32 j,hp = 0,sp = 0; + if( dstmd && dstmd->mob_id == MOBID_EMPERIUM ) { + flag |= SKILL_NOCONSUME_REQ; + return; + } + if( sd ) { + int32 x,bonus=100; + struct s_skill_condition require = skill_get_requirement(sd, getSkillId(), skill_lv); + x = skill_lv%11 - 1; + j = pc_search_inventory(sd, require.itemid[x]); + if (j < 0 || require.itemid[x] <= 0) { + clif_skill_fail( *sd, getSkillId() ); + flag |= SKILL_NOCONSUME_REQ; + return; + } + if (sd->inventory_data[j] == nullptr || sd->inventory.u.items_inventory[j].amount < require.amount[x]) { + clif_skill_fail( *sd, getSkillId() ); + flag |= SKILL_NOCONSUME_REQ; + return; + } + potion_flag = 1; + potion_hp = potion_sp = potion_per_hp = potion_per_sp = 0; + potion_target = target->id; + run_script(sd->inventory_data[j]->script,0,sd->id,0); + potion_flag = potion_target = 0; + if( sd->sc.getSCE(SC_SPIRIT) && sd->sc.getSCE(SC_SPIRIT)->val2 == SL_ALCHEMIST ) + bonus += sd->status.base_level; + if( potion_per_hp > 0 || potion_per_sp > 0 ) { + hp = tstatus->max_hp * potion_per_hp / 100; + hp = hp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; + if( dstsd ) { + sp = dstsd->status.max_sp * potion_per_sp / 100; + sp = sp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; + } + } else { + if( potion_hp > 0 ) { + hp = potion_hp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; + hp = hp * (100 + (tstatus->vit * 2)) / 100; + if( dstsd ) + hp = hp * (100 + pc_checkskill(dstsd,SM_RECOVERY)*10) / 100; + } + if( potion_sp > 0 ) { + sp = potion_sp * (100 + pc_checkskill(sd,AM_POTIONPITCHER)*10 + pc_checkskill(sd,AM_LEARNINGPOTION)*5)*bonus/10000; + sp = sp * (100 + (tstatus->int_ * 2)) / 100; + if( dstsd ) + sp = sp * (100 + pc_checkskill(dstsd,MG_SRECOVERY)*10) / 100; + } + } + + if ((bonus = pc_get_itemgroup_bonus_group(sd, IG_POTION, sd->itemgrouphealrate))) { + hp += hp * bonus / 100; + } + + if( ( bonus = pc_get_itemgroup_bonus_group( sd, IG_POTION, sd->itemgroupsphealrate ) ) ){ + sp += sp * bonus / 100; + } + + if( (j = pc_skillheal_bonus(sd, getSkillId())) ) { + hp += hp * j / 100; + sp += sp * j / 100; + } + } else { + //Maybe replace with potion_hp, but I'm unsure how that works [Playtester] + switch (skill_lv) { + case 1: hp = 45; break; + case 2: hp = 105; break; + case 3: hp = 175; break; + default: hp = 325; break; + } + hp = (hp + rnd()%(skill_lv*20+1)) * (150 + skill_lv*10) / 100; + hp = hp * (100 + (tstatus->vit * 2)) / 100; + if( dstsd ) + hp = hp * (100 + pc_checkskill(dstsd,SM_RECOVERY)*10) / 100; + } + if( dstsd && (j = pc_skillheal2_bonus(dstsd, getSkillId())) ) { + hp += hp * j / 100; + sp += sp * j / 100; + } + // Final heal increased by HPlus. + // Is this the right place for this??? [Rytech] + // Can HPlus also affect SP recovery??? + if (sd && sstatus->hplus > 0) { + hp += hp * sstatus->hplus / 100; + sp += sp * sstatus->hplus / 100; + } + if (tsc != nullptr && !tsc->empty()) { + uint8 penalty = 0; + + if (tsc->getSCE(SC_WATER_INSIGNIA) && tsc->getSCE(SC_WATER_INSIGNIA)->val1 == 2) { + hp += hp / 10; + sp += sp / 10; + } + if (tsc->getSCE(SC_CRITICALWOUND)) + penalty += tsc->getSCE(SC_CRITICALWOUND)->val2; + if (tsc->getSCE(SC_DEATHHURT) && tsc->getSCE(SC_DEATHHURT)->val3) + penalty += 20; + if (tsc->getSCE(SC_NORECOVER_STATE)) + penalty = 100; + if (penalty > 0) { + hp -= hp * penalty / 100; + sp -= sp * penalty / 100; + } + } + +#ifdef RENEWAL + if (target->type == BL_HOM) + hp *= 3; // Heal effectiveness is 3x for Homunculus +#endif + + clif_skill_nodamage(src,*target,getSkillId(),skill_lv); + if( hp > 0 || sp <= 0 ) + clif_skill_nodamage(nullptr,*target,AL_HEAL,hp,1); + if( sp > 0 ) + clif_skill_nodamage(nullptr,*target,MG_SRECOVERY,sp); + if (tsc) { +#ifdef RENEWAL + if (tsc->getSCE(SC_EXTREMITYFIST)) + sp = 0; +#endif + if (tsc->getSCE(SC_NORECOVER_STATE)) { + hp = 0; + sp = 0; + } + } + status_heal(target,hp,sp,0); +} diff --git a/src/map/skills/merchant/aidpotion.hpp b/src/map/skills/merchant/aidpotion.hpp new file mode 100644 index 00000000000..6e16ee8db23 --- /dev/null +++ b/src/map/skills/merchant/aidpotion.hpp @@ -0,0 +1,13 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillAidPotion : public SkillImpl { +public: + SkillAidPotion(); + + void castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const override; +}; diff --git a/src/map/skills/merchant/alchemicalweapon.cpp b/src/map/skills/merchant/alchemicalweapon.cpp new file mode 100644 index 00000000000..53368951eae --- /dev/null +++ b/src/map/skills/merchant/alchemicalweapon.cpp @@ -0,0 +1,24 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "alchemicalweapon.hpp" + +#include "map/clif.hpp" +#include "map/pc.hpp" +#include "map/status.hpp" + +SkillAlchemicalWeapon::SkillAlchemicalWeapon() : SkillImpl(AM_CP_WEAPON) { +} + +void SkillAlchemicalWeapon::castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const { + map_session_data* sd = BL_CAST(BL_PC, src); + map_session_data* dstsd = BL_CAST(BL_PC, target); + + if( sd && ( target->type != BL_PC || ( dstsd && pc_checkequip(dstsd,EQP_WEAPON) < 0 ) ) ){ + clif_skill_fail( *sd, getSkillId() ); + flag |= SKILL_NOCONSUME_REQ; + return; + } + clif_skill_nodamage(src,*target,getSkillId(),skill_lv, + sc_start(src,target,skill_get_sc(getSkillId()), 100, skill_lv, skill_get_time(getSkillId(), skill_lv))); +} diff --git a/src/map/skills/merchant/alchemicalweapon.hpp b/src/map/skills/merchant/alchemicalweapon.hpp new file mode 100644 index 00000000000..8f52350efdb --- /dev/null +++ b/src/map/skills/merchant/alchemicalweapon.hpp @@ -0,0 +1,13 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillAlchemicalWeapon : public SkillImpl { +public: + SkillAlchemicalWeapon(); + + void castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const override; +}; diff --git a/src/map/skills/merchant/biochemicalhelm.cpp b/src/map/skills/merchant/biochemicalhelm.cpp new file mode 100644 index 00000000000..84689768243 --- /dev/null +++ b/src/map/skills/merchant/biochemicalhelm.cpp @@ -0,0 +1,24 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "biochemicalhelm.hpp" + +#include "map/clif.hpp" +#include "map/pc.hpp" +#include "map/status.hpp" + +SkillBiochemicalHelm::SkillBiochemicalHelm() : SkillImpl(AM_CP_HELM) { +} + +void SkillBiochemicalHelm::castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const { + map_session_data* sd = BL_CAST(BL_PC, src); + map_session_data* dstsd = BL_CAST(BL_PC, target); + + if( sd && ( target->type != BL_PC || ( dstsd && pc_checkequip(dstsd,EQP_HEAD_TOP) < 0 ) ) ){ + clif_skill_fail( *sd, getSkillId() ); + flag |= SKILL_NOCONSUME_REQ; + return; + } + clif_skill_nodamage(src,*target,getSkillId(),skill_lv, + sc_start(src,target,skill_get_sc(getSkillId()), 100, skill_lv, skill_get_time(getSkillId(), skill_lv))); +} diff --git a/src/map/skills/merchant/biochemicalhelm.hpp b/src/map/skills/merchant/biochemicalhelm.hpp new file mode 100644 index 00000000000..79a85c0fa28 --- /dev/null +++ b/src/map/skills/merchant/biochemicalhelm.hpp @@ -0,0 +1,13 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillBiochemicalHelm : public SkillImpl { +public: + SkillBiochemicalHelm(); + + void castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const override; +}; diff --git a/src/map/skills/merchant/bomb.cpp b/src/map/skills/merchant/bomb.cpp new file mode 100644 index 00000000000..b3e814d581b --- /dev/null +++ b/src/map/skills/merchant/bomb.cpp @@ -0,0 +1,30 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "bomb.hpp" + +#include + +#include "map/pc.hpp" + +SkillBomb::SkillBomb() : SkillImpl(AM_DEMONSTRATION) { +} + +void SkillBomb::castendPos2(block_list* src, int32 x, int32 y, uint16 skill_lv, t_tick tick, int32& flag) const { + //Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete). + flag|=1; + + skill_unitsetting(src,getSkillId(),skill_lv,x,y,0); +} + +void SkillBomb::calculateSkillRatio(const Damage* wd, const block_list* src, const block_list* target, uint16 skill_lv, int32& base_skillratio, int32 mflag) const { + base_skillratio += 20 * skill_lv; +} + +void SkillBomb::applyAdditionalEffects(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32 attack_type, enum damage_lv dmg_lv) const { +#ifdef RENEWAL + skill_break_equip(src,target, EQP_WEAPON, 300 * skill_lv, BCT_ENEMY); +#else + skill_break_equip(src,target, EQP_WEAPON, 100*skill_lv, BCT_ENEMY); +#endif +} diff --git a/src/map/skills/merchant/bomb.hpp b/src/map/skills/merchant/bomb.hpp new file mode 100644 index 00000000000..ac1987f97d2 --- /dev/null +++ b/src/map/skills/merchant/bomb.hpp @@ -0,0 +1,15 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillBomb : public SkillImpl { +public: + SkillBomb(); + + void castendPos2(block_list* src, int32 x, int32 y, uint16 skill_lv, t_tick tick, int32& flag) const override; + void calculateSkillRatio(const Damage* wd, const block_list* src, const block_list* target, uint16 skill_lv, int32& base_skillratio, int32 mflag) const override; + void applyAdditionalEffects(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32 attack_type, enum damage_lv dmg_lv) const override; +}; diff --git a/src/map/skills/merchant/callhomunculus.cpp b/src/map/skills/merchant/callhomunculus.cpp new file mode 100644 index 00000000000..97f95133c2f --- /dev/null +++ b/src/map/skills/merchant/callhomunculus.cpp @@ -0,0 +1,24 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "callhomunculus.hpp" + +#include + +#include "map/clif.hpp" +#include "map/homunculus.hpp" +#include "map/pc.hpp" + +SkillCallHomunculus::SkillCallHomunculus() : SkillImpl(AM_CALLHOMUN) { +} + +void SkillCallHomunculus::castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const { + map_session_data* sd = BL_CAST(BL_PC, src); + + if (sd && !hom_call(sd)) + clif_skill_fail( *sd, getSkillId() ); +#ifdef RENEWAL + else if (sd && hom_is_active(sd->hd)) + skill_area_temp[0] = 1; // Already passed pre-cast checks +#endif +} diff --git a/src/map/skills/merchant/callhomunculus.hpp b/src/map/skills/merchant/callhomunculus.hpp new file mode 100644 index 00000000000..42dfa934866 --- /dev/null +++ b/src/map/skills/merchant/callhomunculus.hpp @@ -0,0 +1,13 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillCallHomunculus : public SkillImpl { +public: + SkillCallHomunculus(); + + void castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const override; +}; diff --git a/src/map/skills/merchant/preparepotion.cpp b/src/map/skills/merchant/preparepotion.cpp new file mode 100644 index 00000000000..923a246f9e4 --- /dev/null +++ b/src/map/skills/merchant/preparepotion.cpp @@ -0,0 +1,19 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "preparepotion.hpp" + +#include "map/clif.hpp" +#include "map/pc.hpp" + +SkillPreparePotion::SkillPreparePotion() : SkillImpl(AM_PHARMACY) { +} + +void SkillPreparePotion::castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const { + map_session_data* sd = BL_CAST(BL_PC, src); + + if(sd) { + clif_skill_produce_mix_list( *sd, getSkillId(), 22); + clif_skill_nodamage(src,*target,getSkillId(),skill_lv); + } +} diff --git a/src/map/skills/merchant/preparepotion.hpp b/src/map/skills/merchant/preparepotion.hpp new file mode 100644 index 00000000000..00c037d2ba3 --- /dev/null +++ b/src/map/skills/merchant/preparepotion.hpp @@ -0,0 +1,13 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillPreparePotion : public SkillImpl { +public: + SkillPreparePotion(); + + void castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const override; +}; diff --git a/src/map/skills/merchant/skill_factory_merchant.cpp b/src/map/skills/merchant/skill_factory_merchant.cpp index cae55b576f7..1039064a30c 100644 --- a/src/map/skills/merchant/skill_factory_merchant.cpp +++ b/src/map/skills/merchant/skill_factory_merchant.cpp @@ -8,8 +8,15 @@ #include "../status_skill_impl.hpp" #include "../weapon_skill_impl.hpp" +#include "acidterror.hpp" #include "adrenalinerush.hpp" #include "advancedadrenalinerush.hpp" +#include "aidberserkpotion.hpp" +#include "aidpotion.hpp" +#include "alchemicalweapon.hpp" +#include "biochemicalhelm.hpp" +#include "bomb.hpp" +#include "callhomunculus.hpp" #include "decoratecart.hpp" #include "cartrevolution.hpp" #include "changecart.hpp" @@ -19,14 +26,53 @@ #include "crazyuproar.hpp" #include "mammonite.hpp" #include "powerthrust.hpp" +#include "preparepotion.hpp" #include "skill_vending.hpp" +#include "summonflora.hpp" +#include "summonmarinesphere.hpp" +#include "synthesizedshield.hpp" +#include "syntheticarmor.hpp" +#include "twilightalchemy1.hpp" +#include "twilightalchemy2.hpp" +#include "twilightalchemy3.hpp" +#include "vaporize.hpp" #include "weaponperfection.hpp" #include "weaponrepair.hpp" std::unique_ptr SkillFactoryMerchant::create(const e_skill skill_id) const { switch (skill_id) { case AM_ACIDTERROR: - return std::make_unique(skill_id); + return std::make_unique(); + case AM_BERSERKPITCHER: + return std::make_unique(); + case AM_CALLHOMUN: + return std::make_unique(); + case AM_CANNIBALIZE: + return std::make_unique(); + case AM_CP_ARMOR: + return std::make_unique(); + case AM_CP_HELM: + return std::make_unique(); + case AM_CP_SHIELD: + return std::make_unique(); + case AM_CP_WEAPON: + return std::make_unique(); + case AM_DEMONSTRATION: + return std::make_unique(); + case AM_PHARMACY: + return std::make_unique(); + case AM_POTIONPITCHER: + return std::make_unique(); + case AM_REST: + return std::make_unique(); + case AM_SPHEREMINE: + return std::make_unique(); + case AM_TWILIGHT1: + return std::make_unique(); + case AM_TWILIGHT2: + return std::make_unique(); + case AM_TWILIGHT3: + return std::make_unique(); case BO_ACIDIFIED_ZONE_WATER_ATK: return std::make_unique(skill_id); case BO_ACIDIFIED_ZONE_GROUND_ATK: diff --git a/src/map/skills/merchant/summonflora.cpp b/src/map/skills/merchant/summonflora.cpp new file mode 100644 index 00000000000..6585cb86e7b --- /dev/null +++ b/src/map/skills/merchant/summonflora.cpp @@ -0,0 +1,27 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "summonflora.hpp" + +#include "map/mob.hpp" + +SkillSummonFlora::SkillSummonFlora() : SkillImpl(AM_CANNIBALIZE) { +} + +void SkillSummonFlora::castendPos2(block_list* src, int32 x, int32 y, uint16 skill_lv, t_tick tick, int32& flag) const { + int32 summons[5] = { MOBID_G_MANDRAGORA, MOBID_G_HYDRA, MOBID_G_FLORA, MOBID_G_PARASITE, MOBID_G_GEOGRAPHER }; + int32 class_ = summons[skill_lv-1]; + enum mob_ai ai = AI_FLORA; + mob_data *md; + + // Correct info, don't change any of this! [celest] + md = mob_once_spawn_sub(src, src->m, x, y, status_get_name(*src), class_, "", SZ_SMALL, ai); + if (md) { + md->master_id = src->id; + md->special_state.ai = ai; + if( md->deletetimer != INVALID_TIMER ) + delete_timer(md->deletetimer, mob_timer_delete); + md->deletetimer = add_timer (gettick() + skill_get_time(getSkillId(),skill_lv), mob_timer_delete, md->id, 0); + mob_spawn (md); //Now it is ready for spawning. + } +} diff --git a/src/map/skills/merchant/summonflora.hpp b/src/map/skills/merchant/summonflora.hpp new file mode 100644 index 00000000000..c96d388b78c --- /dev/null +++ b/src/map/skills/merchant/summonflora.hpp @@ -0,0 +1,13 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillSummonFlora : public SkillImpl { +public: + SkillSummonFlora(); + + void castendPos2(block_list* src, int32 x, int32 y, uint16 skill_lv, t_tick tick, int32& flag) const override; +}; diff --git a/src/map/skills/merchant/summonmarinesphere.cpp b/src/map/skills/merchant/summonmarinesphere.cpp new file mode 100644 index 00000000000..7fa792f158b --- /dev/null +++ b/src/map/skills/merchant/summonmarinesphere.cpp @@ -0,0 +1,26 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "summonmarinesphere.hpp" + +#include "map/mob.hpp" + +SkillSummonMarineSphere::SkillSummonMarineSphere() : SkillImpl(AM_SPHEREMINE) { +} + +void SkillSummonMarineSphere::castendPos2(block_list* src, int32 x, int32 y, uint16 skill_lv, t_tick tick, int32& flag) const { + int32 class_ = MOBID_MARINE_SPHERE; + enum mob_ai ai = AI_SPHERE; + mob_data *md; + + // Correct info, don't change any of this! [celest] + md = mob_once_spawn_sub(src, src->m, x, y, status_get_name(*src), class_, "", SZ_SMALL, ai); + if (md) { + md->master_id = src->id; + md->special_state.ai = ai; + if( md->deletetimer != INVALID_TIMER ) + delete_timer(md->deletetimer, mob_timer_delete); + md->deletetimer = add_timer (gettick() + skill_get_time(getSkillId(),skill_lv), mob_timer_delete, md->id, 0); + mob_spawn (md); //Now it is ready for spawning. + } +} diff --git a/src/map/skills/merchant/summonmarinesphere.hpp b/src/map/skills/merchant/summonmarinesphere.hpp new file mode 100644 index 00000000000..85a1d1a731a --- /dev/null +++ b/src/map/skills/merchant/summonmarinesphere.hpp @@ -0,0 +1,13 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillSummonMarineSphere : public SkillImpl { +public: + SkillSummonMarineSphere(); + + void castendPos2(block_list* src, int32 x, int32 y, uint16 skill_lv, t_tick tick, int32& flag) const override; +}; diff --git a/src/map/skills/merchant/synthesizedshield.cpp b/src/map/skills/merchant/synthesizedshield.cpp new file mode 100644 index 00000000000..0e001c5afe7 --- /dev/null +++ b/src/map/skills/merchant/synthesizedshield.cpp @@ -0,0 +1,24 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "synthesizedshield.hpp" + +#include "map/clif.hpp" +#include "map/pc.hpp" +#include "map/status.hpp" + +SkillSynthesizedShield::SkillSynthesizedShield() : SkillImpl(AM_CP_SHIELD) { +} + +void SkillSynthesizedShield::castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const { + map_session_data* sd = BL_CAST(BL_PC, src); + map_session_data* dstsd = BL_CAST(BL_PC, target); + + if( sd && ( target->type != BL_PC || ( dstsd && pc_checkequip(dstsd,EQP_SHIELD) < 0 ) ) ){ + clif_skill_fail( *sd, getSkillId() ); + flag |= SKILL_NOCONSUME_REQ; + return; + } + clif_skill_nodamage(src,*target,getSkillId(),skill_lv, + sc_start(src,target,skill_get_sc(getSkillId()), 100, skill_lv, skill_get_time(getSkillId(), skill_lv))); +} diff --git a/src/map/skills/merchant/synthesizedshield.hpp b/src/map/skills/merchant/synthesizedshield.hpp new file mode 100644 index 00000000000..95267d67c7a --- /dev/null +++ b/src/map/skills/merchant/synthesizedshield.hpp @@ -0,0 +1,13 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillSynthesizedShield : public SkillImpl { +public: + SkillSynthesizedShield(); + + void castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const override; +}; diff --git a/src/map/skills/merchant/syntheticarmor.cpp b/src/map/skills/merchant/syntheticarmor.cpp new file mode 100644 index 00000000000..106130d3d3b --- /dev/null +++ b/src/map/skills/merchant/syntheticarmor.cpp @@ -0,0 +1,24 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "syntheticarmor.hpp" + +#include "map/clif.hpp" +#include "map/pc.hpp" +#include "map/status.hpp" + +SkillSyntheticArmor::SkillSyntheticArmor() : SkillImpl(AM_CP_ARMOR) { +} + +void SkillSyntheticArmor::castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const { + map_session_data* sd = BL_CAST(BL_PC, src); + map_session_data* dstsd = BL_CAST(BL_PC, target); + + if( sd && ( target->type != BL_PC || ( dstsd && pc_checkequip(dstsd,EQP_ARMOR) < 0 ) ) ){ + clif_skill_fail( *sd, getSkillId() ); + flag |= SKILL_NOCONSUME_REQ; + return; + } + clif_skill_nodamage(src,*target,getSkillId(),skill_lv, + sc_start(src,target,skill_get_sc(getSkillId()), 100, skill_lv, skill_get_time(getSkillId(), skill_lv))); +} diff --git a/src/map/skills/merchant/syntheticarmor.hpp b/src/map/skills/merchant/syntheticarmor.hpp new file mode 100644 index 00000000000..b0fd99be993 --- /dev/null +++ b/src/map/skills/merchant/syntheticarmor.hpp @@ -0,0 +1,13 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillSyntheticArmor : public SkillImpl { +public: + SkillSyntheticArmor(); + + void castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const override; +}; diff --git a/src/map/skills/merchant/twilightalchemy1.cpp b/src/map/skills/merchant/twilightalchemy1.cpp new file mode 100644 index 00000000000..f022a0eb2a6 --- /dev/null +++ b/src/map/skills/merchant/twilightalchemy1.cpp @@ -0,0 +1,22 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "twilightalchemy1.hpp" + +#include "map/clif.hpp" +#include "map/itemdb.hpp" +#include "map/pc.hpp" + +SkillTwilightAlchemy1::SkillTwilightAlchemy1() : SkillImpl(AM_TWILIGHT1) { +} + +void SkillTwilightAlchemy1::castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const { + map_session_data* sd = BL_CAST(BL_PC, src); + + if (sd) { + clif_skill_nodamage(src,*target,getSkillId(),skill_lv); + //Prepare 200 White Potions. + if (!skill_produce_mix(sd, getSkillId(), ITEMID_WHITE_POTION, 0, 0, 0, 200, -1)) + clif_skill_fail( *sd, getSkillId() ); + } +} diff --git a/src/map/skills/merchant/twilightalchemy1.hpp b/src/map/skills/merchant/twilightalchemy1.hpp new file mode 100644 index 00000000000..840e490c47d --- /dev/null +++ b/src/map/skills/merchant/twilightalchemy1.hpp @@ -0,0 +1,13 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillTwilightAlchemy1 : public SkillImpl { +public: + SkillTwilightAlchemy1(); + + void castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const override; +}; diff --git a/src/map/skills/merchant/twilightalchemy2.cpp b/src/map/skills/merchant/twilightalchemy2.cpp new file mode 100644 index 00000000000..ba9e648e96e --- /dev/null +++ b/src/map/skills/merchant/twilightalchemy2.cpp @@ -0,0 +1,22 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "twilightalchemy2.hpp" + +#include "map/clif.hpp" +#include "map/itemdb.hpp" +#include "map/pc.hpp" + +SkillTwilightAlchemy2::SkillTwilightAlchemy2() : SkillImpl(AM_TWILIGHT2) { +} + +void SkillTwilightAlchemy2::castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const { + map_session_data* sd = BL_CAST(BL_PC, src); + + if (sd) { + clif_skill_nodamage(src,*target,getSkillId(),skill_lv); + //Prepare 200 Slim White Potions. + if (!skill_produce_mix(sd, getSkillId(), ITEMID_WHITE_SLIM_POTION, 0, 0, 0, 200, -1)) + clif_skill_fail( *sd, getSkillId() ); + } +} diff --git a/src/map/skills/merchant/twilightalchemy2.hpp b/src/map/skills/merchant/twilightalchemy2.hpp new file mode 100644 index 00000000000..f4d1934d3b3 --- /dev/null +++ b/src/map/skills/merchant/twilightalchemy2.hpp @@ -0,0 +1,13 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillTwilightAlchemy2 : public SkillImpl { +public: + SkillTwilightAlchemy2(); + + void castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const override; +}; diff --git a/src/map/skills/merchant/twilightalchemy3.cpp b/src/map/skills/merchant/twilightalchemy3.cpp new file mode 100644 index 00000000000..8e5b61de98d --- /dev/null +++ b/src/map/skills/merchant/twilightalchemy3.cpp @@ -0,0 +1,35 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "twilightalchemy3.hpp" + +#include "map/clif.hpp" +#include "map/itemdb.hpp" +#include "map/pc.hpp" + +SkillTwilightAlchemy3::SkillTwilightAlchemy3() : SkillImpl(AM_TWILIGHT3) { +} + +void SkillTwilightAlchemy3::castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const { + map_session_data* sd = BL_CAST(BL_PC, src); + + if (sd) { + int32 ebottle = pc_search_inventory(sd,ITEMID_EMPTY_BOTTLE); + int16 alcohol_idx = -1, acid_idx = -1, fire_idx = -1; + if( ebottle >= 0 ) + ebottle = sd->inventory.u.items_inventory[ebottle].amount; + //check if you can produce all three, if not, then fail: + if (!(alcohol_idx = skill_can_produce_mix(sd,ITEMID_ALCOHOL,-1, 100)) //100 Alcohol + || !(acid_idx = skill_can_produce_mix(sd,ITEMID_ACID_BOTTLE,-1, 50)) //50 Acid Bottle + || !(fire_idx = skill_can_produce_mix(sd,ITEMID_FIRE_BOTTLE,-1, 50)) //50 Flame Bottle + || ebottle < 200 //200 empty bottle are required at total. + ) { + clif_skill_fail( *sd, getSkillId() ); + return; + } + clif_skill_nodamage(src,*target,getSkillId(),skill_lv); + skill_produce_mix(sd, getSkillId(), ITEMID_ALCOHOL, 0, 0, 0, 100, alcohol_idx-1); + skill_produce_mix(sd, getSkillId(), ITEMID_ACID_BOTTLE, 0, 0, 0, 50, acid_idx-1); + skill_produce_mix(sd, getSkillId(), ITEMID_FIRE_BOTTLE, 0, 0, 0, 50, fire_idx-1); + } +} diff --git a/src/map/skills/merchant/twilightalchemy3.hpp b/src/map/skills/merchant/twilightalchemy3.hpp new file mode 100644 index 00000000000..19611392e82 --- /dev/null +++ b/src/map/skills/merchant/twilightalchemy3.hpp @@ -0,0 +1,13 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillTwilightAlchemy3 : public SkillImpl { +public: + SkillTwilightAlchemy3(); + + void castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const override; +}; diff --git a/src/map/skills/merchant/vaporize.cpp b/src/map/skills/merchant/vaporize.cpp new file mode 100644 index 00000000000..dc993e00570 --- /dev/null +++ b/src/map/skills/merchant/vaporize.cpp @@ -0,0 +1,22 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "vaporize.hpp" + +#include "map/clif.hpp" +#include "map/homunculus.hpp" +#include "map/pc.hpp" + +SkillVaporize::SkillVaporize() : SkillImpl(AM_REST) { +} + +void SkillVaporize::castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const { + map_session_data* sd = BL_CAST(BL_PC, src); + + if (sd) { + if (hom_vaporize(sd,HOM_ST_REST)) + clif_skill_nodamage(src, *target, getSkillId(), skill_lv); + else + clif_skill_fail( *sd, getSkillId() ); + } +} diff --git a/src/map/skills/merchant/vaporize.hpp b/src/map/skills/merchant/vaporize.hpp new file mode 100644 index 00000000000..4951c62af56 --- /dev/null +++ b/src/map/skills/merchant/vaporize.hpp @@ -0,0 +1,13 @@ +// Copyright (c) rAthena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#pragma once + +#include "../skill_impl.hpp" + +class SkillVaporize : public SkillImpl { +public: + SkillVaporize(); + + void castendNoDamageId(block_list* src, block_list* target, uint16 skill_lv, t_tick tick, int32& flag) const override; +};