summaryrefslogtreecommitdiff
path: root/src/map/skill.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/skill.c')
-rw-r--r--src/map/skill.c416
1 files changed, 299 insertions, 117 deletions
diff --git a/src/map/skill.c b/src/map/skill.c
index cdf70d82f..a88927335 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -75,6 +75,9 @@ struct s_skill_db skill_db[MAX_SKILL_DB];
struct s_skill_produce_db skill_produce_db[MAX_SKILL_PRODUCE_DB];
struct s_skill_arrow_db skill_arrow_db[MAX_SKILL_ARROW_DB];
struct s_skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB];
+
+bool skill_reproduce_db[MAX_SKILL_DB];
+
//Warlock
struct s_skill_spellbook_db {
int nameid;
@@ -422,6 +425,13 @@ int can_copy (struct map_session_data *sd, int skillid, struct block_list* bl)
skillid == MER_INCAGI || skillid == MER_BLESSING))
return 0;
+ // Couldn't preserve 3rd Class skills except only when using Reproduce skill. [Jobbie]
+ if( !(sd->sc.data[SC__REPRODUCE]) && (skillid >= RK_ENCHANTBLADE && skillid <= SR_RIDEINLIGHTNING) )
+ return 0;
+ // Reproduce will only copy skills according on the list. [Jobbie]
+ else if( sd->sc.data[SC__REPRODUCE] && !skill_reproduce_db[skillid] )
+ return 0;
+
return 1;
}
@@ -485,6 +495,8 @@ int skillnotok (int skillid, struct map_session_data *sd)
}
return 0;
case AL_TELEPORT:
+ case SC_FATALMENACE:
+ case SC_DIMENSIONDOOR:
if(map[m].flag.noteleport) {
clif_skill_teleportmessage(sd,0);
return 1;
@@ -1802,9 +1814,9 @@ int skill_break_equip (struct block_list *bl, unsigned short where, int rate, in
int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int lv, int time)
{
struct status_change *sc;
- const int pos[4] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HELM};
- const enum sc_type sc_atk[4] = {SC_STRIPWEAPON, SC_STRIPSHIELD, SC_STRIPARMOR, SC_STRIPHELM};
- const enum sc_type sc_def[4] = {SC_CP_WEAPON, SC_CP_SHIELD, SC_CP_ARMOR, SC_CP_HELM};
+ const int pos[5] = {EQP_WEAPON, EQP_SHIELD, EQP_ARMOR, EQP_HELM, EQP_ACC};
+ const enum sc_type sc_atk[5] = {SC_STRIPWEAPON, SC_STRIPSHIELD, SC_STRIPARMOR, SC_STRIPHELM, SC__STRIPACCESSORY};
+ const enum sc_type sc_def[5] = {SC_CP_WEAPON, SC_CP_SHIELD, SC_CP_ARMOR, SC_CP_HELM, 0};
int i;
if (rnd()%100 >= rate)
@@ -2238,25 +2250,46 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
if ((tsd->status.skill[copy_skill].id == 0 || tsd->status.skill[copy_skill].flag == SKILL_FLAG_PLAGIARIZED) &&
can_copy(tsd,copy_skill,bl)) // Split all the check into their own function [Aru]
{
- int lv = skilllv;
- if (tsd->cloneskill_id && tsd->status.skill[tsd->cloneskill_id].flag == SKILL_FLAG_PLAGIARIZED){
- tsd->status.skill[tsd->cloneskill_id].id = 0;
- tsd->status.skill[tsd->cloneskill_id].lv = 0;
- tsd->status.skill[tsd->cloneskill_id].flag = 0;
- clif_deleteskill(tsd,tsd->cloneskill_id);
- }
+ int lv;
+ if( sc && sc->data[SC__REPRODUCE] && (lv = sc->data[SC__REPRODUCE]->val1) ) {
+ //Level dependent and limitation.
+ lv = min(lv,skill_get_max(copy_skill));
+ if( tsd->reproduceskill_id && tsd->status.skill[tsd->reproduceskill_id].flag == 13 ) {
+ tsd->status.skill[tsd->reproduceskill_id].id = 0;
+ tsd->status.skill[tsd->reproduceskill_id].lv = 0;
+ tsd->status.skill[tsd->reproduceskill_id].flag = 0;
+ clif_deleteskill(tsd,tsd->reproduceskill_id);
+ }
+
+ tsd->reproduceskill_id = copy_skill;
+ pc_setglobalreg(tsd, "REPRODUCE_SKILL", copy_skill);
+ pc_setglobalreg(tsd, "REPRODUCE_SKILL_LV", lv);
+
+ tsd->status.skill[copy_skill].id = copy_skill;
+ tsd->status.skill[copy_skill].lv = lv;
+ tsd->status.skill[copy_skill].flag = 13;
+ clif_addskill(tsd,copy_skill);
+ } else {
+ lv = skilllv;
+ if (tsd->cloneskill_id && tsd->status.skill[tsd->cloneskill_id].flag == SKILL_FLAG_PLAGIARIZED){
+ tsd->status.skill[tsd->cloneskill_id].id = 0;
+ tsd->status.skill[tsd->cloneskill_id].lv = 0;
+ tsd->status.skill[tsd->cloneskill_id].flag = 0;
+ clif_deleteskill(tsd,tsd->cloneskill_id);
+ }
- if ((type = pc_checkskill(tsd,RG_PLAGIARISM)) < lv)
- lv = type;
+ if ((type = pc_checkskill(tsd,RG_PLAGIARISM)) < lv)
+ lv = type;
- tsd->cloneskill_id = copy_skill;
- pc_setglobalreg(tsd, "CLONE_SKILL", copy_skill);
- pc_setglobalreg(tsd, "CLONE_SKILL_LV", lv);
+ tsd->cloneskill_id = copy_skill;
+ pc_setglobalreg(tsd, "CLONE_SKILL", copy_skill);
+ pc_setglobalreg(tsd, "CLONE_SKILL_LV", lv);
- tsd->status.skill[skillid].id = copy_skill;
- tsd->status.skill[skillid].lv = lv;
- tsd->status.skill[skillid].flag = SKILL_FLAG_PLAGIARIZED;
- clif_addskill(tsd,skillid);
+ tsd->status.skill[skillid].id = copy_skill;
+ tsd->status.skill[skillid].lv = lv;
+ tsd->status.skill[skillid].flag = SKILL_FLAG_PLAGIARIZED;
+ clif_addskill(tsd,skillid);
+ }
}
}
if( skillid != WZ_SIGHTRASHER &&
@@ -2303,6 +2336,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
case MG_FIREWALL:
case WZ_STORMGUST:
case PR_SANCTUARY:
+ case SC_TRIANGLESHOT:
case LG_OVERBRAND:
direction = unit_getdir(bl);// backwards
break;
@@ -2348,11 +2382,14 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
}
}
- if(skillid == RG_INTIMIDATE && damage > 0 && !(tstatus->mode&MD_BOSS)) {
- int rate = 50 + skilllv * 5;
- rate = rate + (status_get_lv(src) - status_get_lv(bl));
- if(rnd()%100 < rate)
- skill_addtimerskill(src,tick + 800,bl->id,0,0,skillid,skilllv,0,flag);
+ if(damage > 0 && !(tstatus->mode&MD_BOSS)) {
+ if( skillid == RG_INTIMIDATE ) {
+ int rate = 50 + skilllv * 5;
+ rate = rate + (status_get_lv(src) - status_get_lv(bl));
+ if(rnd()%100 < rate)
+ skill_addtimerskill(src,tick + 800,bl->id,0,0,skillid,skilllv,0,flag);
+ } else if( skillid == SC_FATALMENACE )
+ skill_addtimerskill(src,tick + 800,bl->id,skill_area_temp[4],skill_area_temp[5],skillid,skilllv,0,flag);
}
if(skillid == CR_GRANDCROSS || skillid == NPC_GRANDDARKNESS)
@@ -2468,11 +2505,11 @@ static int skill_check_unit_range_sub (struct block_list *bl, va_list ap)
skillid = va_arg(ap,int);
g_skillid = unit->group->skill_id;
- switch (skillid)
- {
+ switch (skillid) {
case MG_SAFETYWALL:
case AL_PNEUMA:
- if(g_skillid != MG_SAFETYWALL && g_skillid != AL_PNEUMA)
+ case SC_MAELSTROM:
+ if(g_skillid != MG_SAFETYWALL && g_skillid != AL_PNEUMA && g_skillid != SC_MAELSTROM)
return 0;
break;
case AL_WARP:
@@ -2491,9 +2528,6 @@ static int skill_check_unit_range_sub (struct block_list *bl, va_list ap)
case HT_CLAYMORETRAP:
case HT_TALKIEBOX:
case HP_BASILICA:
- /**
- * Ranger
- **/
case RA_ELECTRICSHOCKER:
case RA_CLUSTERBOMB:
case RA_MAGENTATRAP:
@@ -2502,6 +2536,7 @@ static int skill_check_unit_range_sub (struct block_list *bl, va_list ap)
case RA_VERDURETRAP:
case RA_FIRINGTRAP:
case RA_ICEBOUNDTRAP:
+ case SC_DIMENSIONDOOR:
//Non stackable on themselves and traps (including venom dust which does not has the trap inf2 set)
if (skillid != g_skillid && !(skill_get_inf2(g_skillid)&INF2_TRAP) && g_skillid != AS_VENOMDUST)
return 0;
@@ -2749,7 +2784,7 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data)
break;
if(skl->target_id) {
target = map_id2bl(skl->target_id);
- if( skl->skill_id == RG_INTIMIDATE && (!target || target->prev == NULL || !check_distance_bl(src,target,AREA_SIZE)) )
+ if( ( skl->skill_id == RG_INTIMIDATE || skl->skill_id == SC_FATALMENACE ) && (!target || target->prev == NULL || !check_distance_bl(src,target,AREA_SIZE)) )
target = src; //Required since it has to warp.
if(target == NULL)
break;
@@ -2856,6 +2891,15 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data)
}
}
break;
+ case SC_FATALMENACE:
+ if( src == target ) // Casters Part
+ unit_warp(src, -1, skl->x, skl->y, 3);
+ else { // Target's Part
+ short x = skl->x, y = skl->y;
+ map_search_freecell(NULL, target->m, &x, &y, 2, 2, 1);
+ unit_warp(target,-1,x,y,3);
+ }
+ break;
case LG_MOONSLASHER:
if( target->type == BL_PC ) {
struct map_session_data *tsd = NULL;
@@ -3101,33 +3145,17 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
case NPC_BLEEDING:
case NPC_CRITICALWOUND:
case NPC_HELLPOWER:
- /**
- * Rune Knight
- **/
case RK_SONICWAVE:
case RK_HUNDREDSPEAR:
case RK_WINDCUTTER:
- /**
- * Arch Bishop
- **/
case AB_DUPLELIGHT_MELEE:
- /**
- * Ranger
- **/
case RA_AIMEDBOLT:
- /**
- * Mechanic
- **/
case NC_AXEBOOMERANG:
case NC_POWERSWING:
- /**
- * Guilotinne Cross
- **/
case GC_CROSSIMPACT:
case GC_VENOMPRESSURE:
- /**
- * Royal Guard
- **/
+ case SC_TRIANGLESHOT:
+ case SC_FEINTBOMB:
case LG_BANISHINGPOINT:
case LG_SHIELDPRESS:
case LG_RAGEBURST:
@@ -4011,6 +4039,21 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
case NC_MAGNETICFIELD:
sc_start2(bl,SC_MAGNETICFIELD,100,skilllv,src->id,skill_get_time(skillid,skilllv));
break;
+ case SC_FATALMENACE:
+ if( flag&1 )
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ else
+ {
+ short x, y;
+ map_search_freecell(src, 0, &x, &y, -1, -1, 0);
+ // Destination area
+ skill_area_temp[4] = x;
+ skill_area_temp[5] = y;
+ map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|1, skill_castend_damage_id);
+ skill_addtimerskill(src,tick + 800,src->id,x,y,skillid,skilllv,0,flag); // To teleport Self
+ clif_skill_damage(src,src,tick,status_get_amotion(src),0,-30000,1,skillid,skilllv,6);
+ }
+ break;
/**
* Royal Guard
**/
@@ -4662,34 +4705,17 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case ST_PRESERVE:
case NPC_INVINCIBLE:
case NPC_INVINCIBLEOFF:
- /**
- * Rune Knight
- **/
case RK_DEATHBOUND:
- /**
- * Arch Bishop
- **/
case AB_RENOVATIO:
case AB_EXPIATIO:
case AB_DUPLELIGHT:
case AB_SECRAMENT:
- /**
- * Mechanic
- **/
case NC_ACCELERATION:
case NC_HOVERING:
case NC_SHAPESHIFT:
- /**
- * Warlock
- **/
case WL_RECOGNIZEDSPELL:
- /**
- * Guillotine Cross
- **/
case GC_VENOMIMPRESS:
- /**
- * Royal Guard
- **/
+ case SC_DEADLYINFECT:
case LG_EXEEDBREAK:
case LG_PRESTIGE:
clif_skill_nodamage(src,bl,skillid,skilllv,
@@ -5169,16 +5195,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
break;
case AS_CLOAKING:
case RA_CAMOUFLAGE:
- /**
- * Guilotine Cross
- **/
case GC_CLOAKINGEXCEED:
- /**
- * Royal Guard
- **/
case LG_FORCEOFVANGUARD:
- if (tsce)
- {
+ case SC_REPRODUCE:
+ case SC_INVISIBILITY:
+ if (tsce) {
i = status_change_end(bl, type, INVALID_TIMER);
if( i )
clif_skill_nodamage(src,bl,skillid,( skillid == LG_FORCEOFVANGUARD ) ? skilllv : -1,i);
@@ -5499,16 +5520,19 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case RG_STRIPHELM:
case ST_FULLSTRIP:
case GC_WEAPONCRUSH:
- {
+ case SC_STRIPACCESSARY: {
unsigned short location = 0;
int d = 0;
//Rate in percent
if ( skillid == ST_FULLSTRIP ) {
i = 5 + 2*skilllv + (sstatus->dex - tstatus->dex)/5;
+ } else if( skillid == SC_STRIPACCESSARY ) {
+ i = 12 + 2 * skilllv + (sstatus->dex - tstatus->dex)/5;
} else {
i = 5 + 5*skilllv + (sstatus->dex - tstatus->dex)/5;
}
+
if (i < 5) i = 5; //Minimum rate 5%
//Duration in ms
@@ -5532,6 +5556,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case ST_FULLSTRIP:
location = EQP_WEAPON|EQP_SHIELD|EQP_ARMOR|EQP_HELM;
break;
+ case SC_STRIPACCESSARY:
+ location = EQP_ACC;
+ break;
}
//Special message when trying to use strip on FCP [Jobbie]
@@ -5548,8 +5575,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
//Nothing stripped.
if( sd && !i )
clif_skill_fail(sd,skillid,USESKILL_FAIL_LEVEL,0);
- }
break;
+ }
case AM_BERSERKPITCHER:
case AM_POTIONPITCHER:
@@ -5752,7 +5779,13 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case SC_FOOD_AGI_CASH: case SC_FOOD_VIT_CASH: case SC_FOOD_DEX_CASH:
case SC_FOOD_INT_CASH: case SC_FOOD_LUK_CASH: case SC_SEVENWIND:
case SC_MIRACLE: case SC_S_LIFEPOTION: case SC_L_LIFEPOTION:
- case SC_INCHEALRATE:
+ case SC_INCHEALRATE: case SC_ELECTRICSHOCKER: case SC__STRIPACCESSORY:
+ //case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD: case SC_MINOR_BBQ:
+ //case SC_SIROMA_ICE_TEA: case SC_DROCERA_HERB_STEAMED: case SC_PUTTI_TAILS_NOODLES:
+ case SC_NEUTRALBARRIER_MASTER: case SC_NEUTRALBARRIER: case SC_STEALTHFIELD_MASTER:
+ case SC_STEALTHFIELD: case SC_GIANTGROWTH: case SC_MILLENNIUMSHIELD:
+ case SC_REFRESH: case SC_STONEHARDSKIN: case SC_VITALITYACTIVATION:
+ case SC_FIGHTINGSPIRIT: case SC_ABUNDANCE: case SC__SHADOWFORM:
continue;
/**
* bugreport:4888 these songs may only be dispelled if you're not in their song area anymore
@@ -7067,14 +7100,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case SC_HUMMING: case SC_DONTFORGETME: case SC_FORTUNE:
case SC_SERVICE4U: case SC_FOOD_STR_CASH: case SC_FOOD_AGI_CASH:
case SC_FOOD_VIT_CASH: case SC_FOOD_DEX_CASH: case SC_FOOD_INT_CASH:
- case SC_FOOD_LUK_CASH: /* case SC_ELECTRICSHOCKER: case SC_BITE:
+ case SC_FOOD_LUK_CASH: case SC_ELECTRICSHOCKER: case SC_BITE:
case SC__STRIPACCESSORY: case SC__ENERVATION: case SC__GROOMY:
case SC__IGNORANCE: case SC__LAZINESS: case SC__UNLUCKY:
- case SC__WEAKNESS: case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD:
- case SC_MAGNETICFIELD:case SC_MINOR_BBQ: case SC_SIROMA_ICE_TEA:
- case SC_DROCERA_HERB_STEAMED: case SC_PUTTI_TAILS_NOODLES:
+ case SC__WEAKNESS: //case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD:
+ case SC_MAGNETICFIELD://case SC_MINOR_BBQ: case SC_SIROMA_ICE_TEA:
+ //case SC_DROCERA_HERB_STEAMED: case SC_PUTTI_TAILS_NOODLES:
case SC_NEUTRALBARRIER_MASTER: case SC_NEUTRALBARRIER:
- case SC_STEALTHFIELD_MASTER: case SC_STEALTHFIELD: */
+ case SC_STEALTHFIELD_MASTER: case SC_STEALTHFIELD:
continue;
case SC_ASSUMPTIO:
if( bl->type == BL_MOB )
@@ -7357,9 +7390,79 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
clif_skill_nodamage(src, bl, skillid, skilllv, 1);
}
break;
- /**
- * Royal Guard
- **/
+ case SC_AUTOSHADOWSPELL:
+ if( sd ) {
+ if( sd->status.skill[sd->reproduceskill_id].id || sd->status.skill[sd->cloneskill_id].id ) {
+ sc_start(src,SC_STOP,100,skilllv,-1);// The skilllv is stored in val1 used in skill_select_menu to determine the used skill lvl [Xazax]
+ clif_autoshadowspell_list(sd);
+ clif_skill_nodamage(src,bl,skillid,1,1);
+ }
+ else
+ clif_skill_fail(sd,skillid,0x15,0);
+ }
+ break;
+
+ case SC_SHADOWFORM:
+ if( sd && dstsd && src != bl && !dstsd->shadowform_id ) {
+ if( clif_skill_nodamage(src,bl,skillid,skilllv,sc_start4(src,type,100,skilllv,bl->id,4+skilllv,0,skill_get_time(skillid, skilllv))) )
+ dstsd->shadowform_id = src->id;
+ }
+ else if( sd )
+ clif_skill_fail(sd, skillid, 0, 0);
+ break;
+
+ case SC_BODYPAINT:
+ if( flag&1 ) {
+ if( tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] ||
+ tsc->data[SC_CHASEWALK] || tsc->data[SC_CLOAKINGEXCEED] ||
+ tsc->data[SC__INVISIBILITY]) ) {
+ status_change_end(bl, SC_HIDING, -1);
+ status_change_end(bl, SC_CLOAKING, -1);
+ status_change_end(bl, SC_CHASEWALK, -1);
+ status_change_end(bl, SC_CLOAKINGEXCEED, -1);
+ status_change_end(bl, SC__INVISIBILITY, -1);
+
+ sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv));
+ sc_start(bl,SC_BLIND,53 + 2 * skilllv,skilllv,skill_get_time(skillid,skilllv));
+ }
+ } else {
+ clif_skill_nodamage(src, bl, skillid, 0, 1);
+ map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), BL_CHAR,
+ src, skillid, skilllv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id);
+ }
+ break;
+
+ case SC_ENERVATION:
+ case SC_GROOMY:
+ case SC_LAZINESS:
+ case SC_UNLUCKY:
+ case SC_WEAKNESS:
+ if( !(tsc && tsc->data[type]) ) {
+ //((rand(myDEX / 12, myDEX / 4) + myJobLevel + 10 * skLevel) + myLevel / 10) - (targetLevel / 10 + targetLUK / 10 + (targetMaxWeight - targetWeight) / 1000 + rand(targetAGI / 6, targetAGI / 3))
+ int rate = rnd_value(sstatus->dex/12,sstatus->dex/4) + 10*skilllv + (sd?sd->status.job_level:0) + status_get_lv(src)/10
+ - status_get_lv(bl)/10 - tstatus->luk/10 - (dstsd?(dstsd->max_weight-dstsd->weight)/10000:0) - rnd_value(tstatus->agi/6,tstatus->agi/3);
+ rate = cap_value(rate, skilllv+sstatus->dex/20, 100);
+ clif_skill_nodamage(src,bl,skillid,0,sc_start(bl,type,rate,skilllv,skill_get_time(skillid,skilllv)));
+ } else if( sd )
+ clif_skill_fail(sd,skillid,0,0);
+ break;
+
+ case SC_IGNORANCE:
+ if( !(tsc && tsc->data[type]) ) {
+ int rate = rnd_value(sstatus->dex/12,sstatus->dex/4) + 10*skilllv + (sd?sd->status.job_level:0) + status_get_lv(src)/10
+ - status_get_lv(bl)/10 - tstatus->luk/10 - (dstsd?(dstsd->max_weight-dstsd->weight)/10000:0) - rnd_value(tstatus->agi/6,tstatus->agi/3);
+ rate = cap_value(rate, skilllv+sstatus->dex/20, 100);
+ if (clif_skill_nodamage(src,bl,skillid,0,sc_start(bl,type,rate,skilllv,skill_get_time(skillid,skilllv)))) {
+ int sp = 200 * skilllv;
+ if( dstmd ) sp = dstmd->level * 2;
+ if( status_zap(bl,0,sp) )
+ status_heal(src,0,sp/2,3);
+ }
+ else if( sd ) clif_skill_fail(sd,skillid,0,0);
+ } else if( sd )
+ clif_skill_fail(sd,skillid,0,0);
+ break;
+
case LG_TRAMPLE:
clif_skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6);
map_foreachinrange(skill_destroy_trap,bl,skill_get_splash(skillid,skilllv),BL_SKILL,tick);
@@ -8165,9 +8268,6 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
case NJ_RAIGEKISAI:
case NJ_KAMAITACHI:
case NPC_EVILLAND:
- /**
- * Ranger
- **/
case RA_ELECTRICSHOCKER:
case RA_CLUSTERBOMB:
case RA_MAGENTATRAP:
@@ -8176,6 +8276,11 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
case RA_VERDURETRAP:
case RA_FIRINGTRAP:
case RA_ICEBOUNDTRAP:
+ case SC_MANHOLE:
+ case SC_DIMENSIONDOOR:
+ case SC_CHAOSPANIC:
+ case SC_BLOODYLUST:
+ case SC_MAELSTROM:
flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete).
case GS_GROUNDDRIFT: //Ammo should be deleted right away.
skill_unitsetting(src,skillid,skilllv,x,y,0);
@@ -8535,9 +8640,13 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
case NC_MAGICDECOY:
if( sd ) clif_magicdecoy_list(sd,skilllv,x,y);
break;
- /**
- * Royal Guard
- **/
+
+ case SC_FEINTBOMB:
+ clif_skill_nodamage(src,src,skillid,skilllv,1);
+ skill_unitsetting(src,skillid,skilllv,x,y,0); // Set bomb on current Position
+ skill_blown(src,src,6,unit_getdir(src),0);
+ break;
+
case LG_OVERBRAND:
{
int width;//according to data from irowiki it actually is a square
@@ -8622,15 +8731,10 @@ int skill_castend_map (struct map_session_data *sd, short skill_num, const char
sd->sc.data[SC_BERSERK] ||
sd->sc.data[SC_BASILICA] ||
sd->sc.data[SC_MARIONETTE] ||
- /**
- * Warlock
- **/
sd->sc.data[SC_WHITEIMPRISON] ||
(sd->sc.data[SC_STASIS] && skill_stasis_check(&sd->bl, sd->sc.data[SC_STASIS]->val2, skill_num)) ||
- /**
- * Guillotine Cross
- **/
- sd->sc.data[SC_OBLIVIONCURSE]
+ sd->sc.data[SC_OBLIVIONCURSE] ||
+ sd->sc.data[SC__MANHOLE]
)) {
skill_failed(sd);
return 0;
@@ -9302,6 +9406,8 @@ static int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, un
break;
case UNT_PNEUMA:
+ case UNT_CHAOSPANIC:
+ case UNT_MAELSTROM:
if (!sce)
sc_start4(bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit);
break;
@@ -9461,6 +9567,8 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
switch (sg->unit_id) {
case UNT_ANKLESNARE: //These happen when a trap is splash-triggered by multiple targets on the same cell.
case UNT_FIREPILLAR_ACTIVE:
+ case UNT_ELECTRICSHOCKER:
+ case UNT_MANHOLE:
return 0;
default:
ShowError("skill_unit_onplace_timer: interval error (unit id %x)\n", sg->unit_id);
@@ -9623,19 +9731,17 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
break;
case UNT_ANKLESNARE:
- if( sg->val2 == 0 && tsc )
- {
+ case UNT_MANHOLE:
+ if( sg->val2 == 0 && tsc && (sg->unit_id == UNT_ANKLESNARE || bl->id != sg->src_id) ) {
int sec = skill_get_time2(sg->skill_id,sg->skill_lv);
- if( status_change_start(bl,type,10000,sg->skill_lv,sg->group_id,0,0,sec, 8) )
- {
+ if( status_change_start(bl,type,10000,sg->skill_lv,sg->group_id,0,0,sec, 8) ) {
const struct TimerData* td = tsc->data[type]?get_timer(tsc->data[type]->timer):NULL;
if( td )
sec = DIFF_TICK(td->tick, tick);
unit_movepos(bl, src->bl.x, src->bl.y, 0, 0);
clif_fixpos(bl);
sg->val2 = bl->id;
- }
- else
+ } else
sec = 3000; //Couldn't trap it?
clif_skillunit_update(&src->bl);
@@ -10046,6 +10152,8 @@ static int skill_unit_onleft (int skill_id, struct block_list *bl, unsigned int
case CG_HERMODE:
case HW_GRAVITATION:
case NJ_SUITON:
+ case SC_MAELSTROM:
+ case SC_BLOODYLUST:
if (sce)
status_change_end(bl, type, INVALID_TIMER);
break;
@@ -10411,6 +10519,9 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh
return 0;
}
+ if( sc && ( sc->data[SC__SHADOWFORM] || sc->data[SC__IGNORANCE] ) )
+ return 0;
+
switch( skill )
{ // Turn off check.
case BS_MAXIMIZE: case NV_TRICKDEAD: case TF_HIDING: case AS_CLOAKING: case CR_AUTOGUARD:
@@ -10802,7 +10913,7 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh
}
break;
case RA_WUGMASTERY:
- if( pc_isfalcon(sd) || pc_isridingwug(sd) ) {
+ if( pc_isfalcon(sd) || pc_isridingwug(sd) || sd->sc.data[SC__GROOMY]) {
clif_skill_fail(sd,skill,USESKILL_FAIL_LEVEL,0);
return 0;
}
@@ -10856,6 +10967,13 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh
return 0;
}
break;
+ case SC_MANHOLE:
+ case SC_DIMENSIONDOOR:
+ if( sc && sc->data[SC_MAGNETICFIELD] ) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
}
switch(require.state) {
@@ -11270,8 +11388,18 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, short
if( sd->dsprate!=100 )
req.sp = req.sp * sd->dsprate / 100;
+ if( sc ) {
+ if( sc->data[SC__LAZINESS] )
+ req.sp += req.sp + sc->data[SC__LAZINESS]->val1 * 10;
+ if( sc->data[SC_RECOGNIZEDSPELL] )
+ req.sp += req.sp / 4;
+ }
+
req.zeny = skill_db[j].zeny[lv-1];
+ if( sc && sc->data[SC__UNLUCKY] )
+ req.zeny += sc->data[SC__UNLUCKY]->val1 * 500;
+
req.spiritball = skill_db[j].spiritball[lv-1];
req.state = skill_db[j].state;
@@ -11466,6 +11594,8 @@ int skill_castfix_sc (struct block_list *bl, int time, int skill_id, int skill_l
if (sc->data[SC_POEMBRAGI])
time -= time * sc->data[SC_POEMBRAGI]->val2 / 100;
#if RECASTING
+ if( sc->data[SC__LAZINESS] )
+ fixed += fixed * sc->data[SC__LAZINESS]->val2 / 100;
/**
* AB Sacrament reduces fixed cast time by (10 x Level)% (up to 50%)
**/
@@ -12559,15 +12689,8 @@ struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int
case HP_BASILICA:
skill_unitsetmapcell(unit,HP_BASILICA,group->skill_lv,CELL_BASILICA,true);
break;
- /**
- * Ranger
- **/
- case RA_ELECTRICSHOCKER:
- {
- struct block_list* target = map_id2bl(group->val2);
- if( target )
- status_change_end(target, SC_ELECTRICSHOCKER, -1);
- }
+ case SC_MAELSTROM:
+ skill_unitsetmapcell(unit,SC_MAELSTROM,group->skill_lv,CELL_MAELSTROM,true);
break;
default:
if (group->state.song_dance&0x1) //Check for dissonance.
@@ -12620,6 +12743,22 @@ int skill_delunit (struct skill_unit* unit)
case HP_BASILICA:
skill_unitsetmapcell(unit,HP_BASILICA,group->skill_lv,CELL_BASILICA,false);
break;
+ case RA_ELECTRICSHOCKER: {
+ struct block_list* target = map_id2bl(group->val2);
+ if( target )
+ status_change_end(target, SC_ELECTRICSHOCKER, -1);
+ break;
+ }
+ case SC_MAELSTROM:
+ skill_unitsetmapcell(unit,SC_MAELSTROM,group->skill_lv,CELL_MAELSTROM,false);
+ break;
+ case SC_MANHOLE: // Note : Removing the unit don't remove the status (official info)
+ if( group->val2 ) { // Someone Traped
+ struct status_change *tsc = status_get_sc( map_id2bl(group->val2));
+ if( tsc && tsc->data[SC__MANHOLE] )
+ tsc->data[SC__MANHOLE]->val4 = 0; // Remove the Unit ID
+ }
+ break;
}
clif_skill_delunit(unit);
@@ -13033,6 +13172,14 @@ static int skill_unit_timer_sub (DBKey key, void* data, va_list ap)
}
break;
+ case UNT_FEINTBOMB: {
+ struct block_list *src = map_id2bl(group->src_id);
+ if( src )
+ map_foreachinrange(skill_area_sub, &group->unit->bl, unit->range, splash_target(src), src, SC_FEINTBOMB, group->skill_lv, tick, BCT_ENEMY|1, skill_castend_damage_id);
+ skill_delunit(unit);
+ break;
+ }
+
default:
skill_delunit(unit);
}
@@ -13973,6 +14120,27 @@ int skill_spellbook (struct map_session_data *sd, int nameid) {
return 1;
}
+int skill_select_menu(struct map_session_data *sd,int flag,int skill_id) {
+ int id, lv, prob, aslvl = 0;
+ nullpo_ret(sd);
+
+ if (sd->sc.data[SC_STOP]) {
+ aslvl = sd->sc.data[SC_STOP]->val1;
+ status_change_end(&sd->bl,SC_STOP,-1);
+ }
+
+ if( (id = sd->status.skill[skill_id].id) == 0 || sd->status.skill[skill_id].flag != 13 ||
+ skill_id >= GS_GLITTERING || skill_get_type(skill_id) != BF_MAGIC ) {
+ clif_skill_fail(sd,SC_AUTOSHADOWSPELL,0,0);
+ return 0;
+ }
+
+ lv = (aslvl + 1) / 2; // The level the skill will be autocasted
+ lv = min(lv,sd->status.skill[skill_id].lv);
+ prob = (aslvl == 10) ? 15 : (32 - 2 * aslvl); // Probability at level 10 was increased to 15.
+ sc_start4(&sd->bl,SC__AUTOSHADOWSPELL,100,id,lv,prob,0,skill_get_time(SC_AUTOSHADOWSPELL,aslvl));
+ return 0;
+}
/**
* for Royal Guard's LG_TRAMPLE
**/
@@ -14489,8 +14657,7 @@ void skill_init_unit_layout (void)
}
// Stasis skill usage check. [LimitLine/3CeAM]
-int skill_stasis_check(struct block_list *bl, int src_id, int skillid)
-{
+int skill_stasis_check(struct block_list *bl, int src_id, int skillid) {
int inf = 0;
if( !bl || skillid < 1 )
return 0; // Can do it
@@ -14880,6 +15047,18 @@ static bool skill_parse_row_magicmushroomdb(char* split[], int column, int curre
return true;
}
+static bool skill_parse_row_reproducedb(char* split[], int column, int current) {
+ int skillid = atoi(split[0]);
+
+ skillid = skill_get_index(skillid);
+ if( !skillid )
+ return false;
+
+ skill_reproduce_db[skillid] = true;
+
+ return true;
+}
+
static bool skill_parse_row_abradb(char* split[], int columns, int current)
{// SkillID,DummyName,RequiredHocusPocusLevel,Rate
@@ -14912,6 +15091,8 @@ static void skill_readdb(void)
memset(skill_abra_db,0,sizeof(skill_abra_db));
memset(skill_spellbook_db,0,sizeof(skill_spellbook_db));
memset(skill_magicmushroom_db,0,sizeof(skill_magicmushroom_db));
+ memset(skill_reproduce_db,0,sizeof(skill_reproduce_db));
+
// load skill databases
safestrncpy(skill_db[0].name, "UNKNOWN_SKILL", sizeof(skill_db[0].name));
safestrncpy(skill_db[0].desc, "Unknown Skill", sizeof(skill_db[0].desc));
@@ -14939,6 +15120,7 @@ static void skill_readdb(void)
sv_readdb(db_path, "spellbook_db.txt" , ',', 3, 3, MAX_SKILL_SPELLBOOK_DB, skill_parse_row_spellbookdb);
//Guillotine Cross
sv_readdb(db_path, "magicmushroom_db.txt" , ',', 1, 1, MAX_SKILL_MAGICMUSHROOM_DB, skill_parse_row_magicmushroomdb);
+ sv_readdb(db_path, "skill_reproduce_db.txt", ',', 1, 1, MAX_SKILL_DB, skill_parse_row_reproducedb);
}