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;
+};