diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/map/battle.c | 70 | ||||
-rw-r--r-- | src/map/map.c | 67 | ||||
-rw-r--r-- | src/map/map.h | 1 | ||||
-rw-r--r-- | src/map/skill.c | 322 | ||||
-rw-r--r-- | src/map/status.c | 70 | ||||
-rw-r--r-- | src/map/unit.c | 4 |
6 files changed, 441 insertions, 93 deletions
diff --git a/src/map/battle.c b/src/map/battle.c index 3292f55ee..3ca8480b4 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -2119,6 +2119,52 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo case LG_HESPERUSLIT: skillratio += 120 * skill_lv - 100; break; + case SR_DRAGONCOMBO: + skillratio += 40 * skill_lv; + break; + case SR_SKYNETBLOW: + skillratio += 80 * skill_lv - 100 + ( sstatus->agi * 4 ); + break; + case SR_EARTHSHAKER: + skillratio += 50 * skill_lv - 50;// Need to code a check to make the ratio 3x when hitting a hidden player. [Rytech] + break; + case SR_FALLENEMPIRE: + skillratio += 150 * skill_lv; // Need official on how much enemy players weight affects damage. [Rytech] + //if( tsd && tsd->weight ) + // skillratio = (100 + 150 * skill_lv) * tsd->weight / 10000; + //else + // skillratio = (100 + 150 * skill_lv) * 600 / 100; + break; + case SR_TIGERCANNON: + skillratio = 2000 + ( sstatus->hp * ( 10 + 2 * skill_lv ) / 100 ); + break; + case SR_RAMPAGEBLASTER: + if( sc && sc->data[SC_EXPLOSIONSPIRITS] ) + skillratio += 40 * skill_lv * (sd?sd->spiritball_old:5) - 100; + else + skillratio += 20 * skill_lv * (sd?sd->spiritball_old:5) - 100; + break; + case SR_KNUCKLEARROW: + if( wflag&4 ) + skillratio = 150 * skill_lv; //+Knockback Damage (Must check and test. [Rytech]) + else + skillratio += 400 + (100 * skill_lv); + break; + case SR_WINDMILL: + skillratio += 150; + break; + case SR_GATEOFHELL: + skillratio += 500 * skill_lv -100; + break; + case SR_GENTLETOUCH_QUIET: + skillratio += 100 * skill_lv - 100 + sstatus->dex; + break; + case SR_HOWLINGOFLION: + skillratio += 300 * skill_lv - 100; + break; + case SR_RIDEINLIGHTNING: + skillratio += 200 * skill_lv -100; + break; } ATK_RATE(skillratio); @@ -2147,24 +2193,21 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo case NJ_SYURIKEN: ATK_ADD(4*skill_lv); break; - /** - * Ranger - **/ case RA_WUGDASH: case RA_WUGSTRIKE: case RA_WUGBITE: if(sd) ATK_ADD(30*pc_checkskill(sd, RA_TOOTHOFWUG)); break; - /** - * Royal Guard - **/ case LG_RAYOFGENESIS: if( sc && sc->data[SC_BANDING] ) {// Increase only if the RG is under Banding. short lv = (short)skill_lv; ATK_ADDRATE( 190 * ((sd) ? skill_check_pc_partner(sd,(short)skill_num,&lv,skill_get_splash(skill_num,skill_lv),0) : 1)); } break; + case SR_GATEOFHELL: + ATK_ADD (sstatus->max_hp - status_get_hp(src));//Will have to add the consumed SP part to the formula in the future. [Rytech] + break; } } //Div fix. @@ -2205,6 +2248,14 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo if( (sstatus->rhw.ele) == ELE_WIND || (sstatus->lhw.ele) == ELE_WIND ) ATK_ADDRATE(50); break; + case SR_EARTHSHAKER: + if( tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || tsc->data[SC_CHASEWALK] || tsc->data[SC_CLOAKINGEXCEED]) ) + ATK_ADDRATE(150+150*skill_lv); + break; + case SR_RIDEINLIGHTNING: + if( (sstatus->rhw.ele) == ELE_WIND || (sstatus->lhw.ele) == ELE_WIND ) + ATK_ADDRATE(skill_lv*5); + break; } if( sd ) @@ -3969,6 +4020,13 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t if( src != target )// Don't reflect your own damage (Grand Cross) map_foreachinshootrange(battle_damage_area,target,skill_get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,tick,target,wd.amotion,wd.dmotion,rdamage,tstatus->race,0); } else { + if( tsc && tsc->data[SC_CRESCENTELBOW] ) { // Deal rdamage to src and 10% damage back to target. + clif_skill_nodamage(target,target,SR_CRESCENTELBOW_AUTOSPELL,tsc->data[SC_CRESCENTELBOW]->val1,1); + skill_blown(target,src,skill_get_blewcount(SR_CRESCENTELBOW_AUTOSPELL,tsc->data[SC_CRESCENTELBOW]->val1),unit_getdir(src),0); + status_damage(NULL,target,rdamage/10,0,0,1); + clif_damage(target, target, tick, wd.amotion, wd.dmotion, rdamage/10, wd.div_ , wd.type, wd.damage2); + status_change_end(target, SC_CRESCENTELBOW, INVALID_TIMER); + } rdelay = clif_damage(src, src, tick, wd.amotion, sstatus->dmotion, rdamage, 1, 4, 0); //Use Reflect Shield to signal this kind of skill trigger. [Skotlex] skill_additional_effect(target,src,CR_REFLECTSHIELD,1,BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick); diff --git a/src/map/map.c b/src/map/map.c index b1fa2d132..0ae05d3f4 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -692,7 +692,74 @@ int map_foreachinarea(int (*func)(struct block_list*,va_list), int m, int x0, in bl_list_count = blockcount; return returnCount; //[Skotlex] } +/*========================================== + * Adapted from forcountinarea for an easier invocation. [pakpil] + *------------------------------------------*/ +int map_forcountinrange(int (*func)(struct block_list*,va_list), struct block_list* center, int range, int count, int type, ...) +{ + int bx,by,m; + int returnCount =0; //total sum of returned values of func() [Skotlex] + struct block_list *bl; + int blockcount=bl_list_count,i; + int x0,x1,y0,y1; + + m = center->m; + x0 = max(center->x-range, 0); + y0 = max(center->y-range, 0); + x1 = min(center->x+range, map[m].xs-1); + y1 = min(center->y+range, map[m].ys-1); + + if (type&~BL_MOB) + for (by = y0 / BLOCK_SIZE; by <= y1 / BLOCK_SIZE; by++) { + for(bx = x0 / BLOCK_SIZE; bx <= x1 / BLOCK_SIZE; bx++) { + for( bl = map[m].block[bx+by*map[m].bxs] ; bl != NULL ; bl = bl->next ) + { + if( bl->type&type + && bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1 +#ifdef CIRCULAR_AREA + && check_distance_bl(center, bl, range) +#endif + && bl_list_count<BL_LIST_MAX) + bl_list[bl_list_count++]=bl; + } + } + } + if(type&BL_MOB) + for(by=y0/BLOCK_SIZE;by<=y1/BLOCK_SIZE;by++){ + for(bx=x0/BLOCK_SIZE;bx<=x1/BLOCK_SIZE;bx++){ + for( bl = map[m].block_mob[bx+by*map[m].bxs] ; bl != NULL ; bl = bl->next ) + { + if( bl->x>=x0 && bl->x<=x1 && bl->y>=y0 && bl->y<=y1 +#ifdef CIRCULAR_AREA + && check_distance_bl(center, bl, range) +#endif + && bl_list_count<BL_LIST_MAX) + bl_list[bl_list_count++]=bl; + } + } + } + + if(bl_list_count>=BL_LIST_MAX) + ShowWarning("map_forcountinrange: block count too many!\n"); + + map_freeblock_lock(); // メモリからの解放を禁止する + for(i=blockcount;i<bl_list_count;i++) + if(bl_list[i]->prev) // 有?かどうかチェック + { + va_list ap; + va_start(ap, type); + returnCount += func(bl_list[i], ap); + va_end(ap); + if( count && returnCount >= count ) + break; + } + + map_freeblock_unlock(); // 解放を許可する + + bl_list_count = blockcount; + return returnCount; //[Skotlex] +} int map_forcountinarea(int (*func)(struct block_list*,va_list), int m, int x0, int y0, int x1, int y1, int count, int type, ...) { int bx,by; diff --git a/src/map/map.h b/src/map/map.h index 98833fe85..f55140847 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -591,6 +591,7 @@ int map_moveblock(struct block_list *, int, int, unsigned int); int map_foreachinrange(int (*func)(struct block_list*,va_list), struct block_list* center, int range, int type, ...); int map_foreachinshootrange(int (*func)(struct block_list*,va_list), struct block_list* center, int range, int type, ...); int map_foreachinarea(int (*func)(struct block_list*,va_list), int m, int x0, int y0, int x1, int y1, int type, ...); +int map_forcountinrange(int (*func)(struct block_list*,va_list), struct block_list* center, int range, int count, int type, ...); int map_forcountinarea(int (*func)(struct block_list*,va_list), int m, int x0, int y0, int x1, int y1, int count, int type, ...); int map_foreachinmovearea(int (*func)(struct block_list*,va_list), struct block_list* center, int range, int dx, int dy, int type, ...); int map_foreachincell(int (*func)(struct block_list*,va_list), int m, int x, int y, int type, ...); diff --git a/src/map/skill.c b/src/map/skill.c index 31b4045ea..cac203aba 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -1214,6 +1214,27 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int skill_break_equip(src, EQP_SHIELD, 500, BCT_SELF); sc_start(bl, SC_EARTHDRIVE, 100, skilllv, skill_get_time(skillid, skilllv)); break; + case SR_DRAGONCOMBO: + sc_start(bl, SC_STUN, 1 + 1 * skilllv, skilllv, skill_get_time(skillid, skilllv)); + break; + case SR_FALLENEMPIRE: + sc_start(bl, SC_STOP, 100, skilllv, skill_get_time(skillid, skilllv)); + break; + case SR_TIGERCANNON: + status_percent_damage(src, bl, 0, 5+1*skilllv, false); // The hell is this? [Rytech] + break; + case SR_WINDMILL: + if( dstsd ) + skill_addtimerskill(src,tick+status_get_amotion(src),bl->id,0,0,skillid,skilllv,BF_WEAPON,0); + else if( dstmd && !is_boss(bl) ) + sc_start(bl, SC_STUN, 100, skilllv, 1000 + 1000 * (rand()%3)); + break; + case SR_GENTLETOUCH_QUIET: + sc_start(bl, SC_SILENCE, 2 * skilllv, skilllv, skill_get_time(skillid, skilllv)); + break; + case SR_HOWLINGOFLION: + sc_start(bl, SC_FEAR, 5 + 5 * skilllv, skilllv, skill_get_time(skillid, skilllv)); + break; } if (md && battle_config.summons_trigger_autospells && md->master_id && md->special_state.ai) @@ -2105,7 +2126,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds switch(skillid) { case MO_TRIPLEATTACK: - if (pc_checkskill(sd, MO_CHAINCOMBO) > 0) + if (pc_checkskill(sd, MO_CHAINCOMBO) > 0 || pc_checkskill(sd, SR_DRAGONCOMBO) > 0) flag=1; break; case MO_CHAINCOMBO: @@ -2148,10 +2169,21 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds //Can't attack nor use items until skill's delay expires. [Skotlex] sd->ud.attackabletime = sd->canuseitem_tick = sd->ud.canact_tick; break; + case SR_DRAGONCOMBO: + if( pc_checkskill(sd, SR_FALLENEMPIRE) > 0 ) + flag = 1; + break; + case SR_FALLENEMPIRE: + if( pc_checkskill(sd, SR_TIGERCANNON) > 0 || pc_checkskill(sd, SR_GATEOFHELL) > 0 ) + flag = 1; + break; } //Switch End if (flag) { //Possible to chain flag = DIFF_TICK(sd->ud.canact_tick, tick); if (flag < 1) flag = 1; + // Dragon Combo must change into self skill and auto-select target when used as combo skill. + if( skillid == MO_TRIPLEATTACK && pc_checkskill(sd, SR_DRAGONCOMBO) > 0 ) + clif_skillinfo(sd,SR_DRAGONCOMBO,INF_SELF_SKILL); sc_start2(src,SC_COMBO,100,skillid,bl->id,flag); clif_combo_delay(src, flag); } @@ -2183,10 +2215,8 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds else // the central target doesn't display an animation dmg.dmotion = clif_skill_damage(dsrc,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skillid, -2, 5); // needs -2(!) as skill level break; - /** - * Warlock - **/ case WL_HELLINFERNO: + case SR_EARTHSHAKER: dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,1,skillid,-2,6); break; case WL_SOULEXPANSION: @@ -2202,9 +2232,6 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds case WL_TETRAVORTEX_GROUND: dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,1,WL_TETRAVORTEX_FIRE,-2,type); break; - /** - * Royal Guard - **/ case LG_OVERBRAND_BRANDISH: case LG_OVERBRAND_PLUSATK: dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,skillid,-1,5); @@ -2332,12 +2359,13 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds if (dmg.blewcount > 0 && bl!=dsrc && !status_isdead(bl)) { int direction = -1; // default - switch(skillid) { + switch(skillid) {//direction case MG_FIREWALL: case WZ_STORMGUST: case PR_SANCTUARY: case SC_TRIANGLESHOT: case LG_OVERBRAND: + case SR_KNUCKLEARROW: direction = unit_getdir(bl);// backwards break; case WL_CRIMSONROCK: @@ -2345,17 +2373,31 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds break; } - if( skillid == LG_OVERBRAND ) { - if( skill_blown(dsrc,bl,dmg.blewcount,direction,0) ) { - short dir_x, dir_y; - dir_x = dirx[(direction+4)%8]; - dir_y = diry[(direction+4)%8]; - if( map_getcell(bl->m, bl->x+dir_x, bl->y+dir_y, CELL_CHKNOPASS) != 0 ) + //blown-specific handling + switch( skillid ) { + case LG_OVERBRAND: + if( skill_blown(dsrc,bl,dmg.blewcount,direction,0) ) { + short dir_x, dir_y; + dir_x = dirx[(direction+4)%8]; + dir_y = diry[(direction+4)%8]; + if( map_getcell(bl->m, bl->x+dir_x, bl->y+dir_y, CELL_CHKNOPASS) != 0 ) + skill_addtimerskill(src, tick + status_get_amotion(src), bl->id, 0, 0, LG_OVERBRAND_PLUSATK, skilllv, BF_WEAPON, flag ); + } else skill_addtimerskill(src, tick + status_get_amotion(src), bl->id, 0, 0, LG_OVERBRAND_PLUSATK, skilllv, BF_WEAPON, flag ); - } else - skill_addtimerskill(src, tick + status_get_amotion(src), bl->id, 0, 0, LG_OVERBRAND_PLUSATK, skilllv, BF_WEAPON, flag ); - } else - skill_blown(dsrc,bl,dmg.blewcount,direction,0); + break; + case SR_KNUCKLEARROW: + if( skill_blown(dsrc,bl,dmg.blewcount,direction,0) && !(flag&4) ) { + short dir_x, dir_y; + dir_x = dirx[(direction+4)%8]; + dir_y = diry[(direction+4)%8]; + if( map_getcell(bl->m, bl->x+dir_x, bl->y+dir_y, CELL_CHKNOPASS) != 0 ) + skill_addtimerskill(src, tick + 300 * ((flag&2) ? 1 : 2), bl->id, 0, 0, skillid, skilllv, BF_WEAPON, flag|4); + } + break; + default: + skill_blown(dsrc,bl,dmg.blewcount,direction,0); + break; + } } //Delayed damage must be dealt after the knockback (it needs to know actual position of target) @@ -2901,6 +2943,7 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) } break; case LG_MOONSLASHER: + case SR_WINDMILL: if( target->type == BL_PC ) { struct map_session_data *tsd = NULL; if( (tsd = ((TBL_PC*)target)) && !pc_issit(tsd) ) { @@ -2912,6 +2955,7 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data) break; case LG_OVERBRAND_BRANDISH: case LG_OVERBRAND_PLUSATK: + case SR_KNUCKLEARROW: skill_attack(BF_WEAPON, src, src, target, skl->skill_id, skl->skill_lv, tick, skl->flag|SD_LEVEL); break; default: @@ -3161,6 +3205,11 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int case LG_RAGEBURST: case LG_RAYOFGENESIS: case LG_HESPERUSLIT: + case SR_SKYNETBLOW: + case SR_FALLENEMPIRE: + case SR_CRESCENTELBOW_AUTOSPELL: + case SR_GATEOFHELL: + case SR_GENTLETOUCH_QUIET: skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); break; @@ -3365,40 +3414,23 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int case NPC_PULSESTRIKE: case NPC_HELLJUDGEMENT: case NPC_VAMPIRE_GIFT: - /** - * Rune Knight - **/ case RK_IGNITIONBREAK: - /** - * Arch Bishop - **/ case AB_JUDEX: - /** - * Warlock - **/ case WL_SOULEXPANSION: case WL_CRIMSONROCK: case WL_COMET: - /** - * Ranger - **/ case RA_ARROWSTORM: case RA_WUGDASH: - /** - * Mechanic - **/ case NC_SELFDESTRUCTION: case NC_AXETORNADO: - /** - * Guilotine Cross - **/ case GC_ROLLINGCUTTER: case GC_COUNTERSLASH: - /** - * Royal Guard - **/ case LG_MOONSLASHER: case LG_EARTHDRIVE: + case SR_TIGERCANNON: + case SR_RAMPAGEBLASTER: + case SR_WINDMILL: + case SR_RIDEINLIGHTNING: if( flag&1 ) { //Recursive invocation // skill_area_temp[0] holds number of targets in area @@ -3715,9 +3747,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int status_change_end(src, SC_HIDING, INVALID_TIMER); skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); break; - /** - * Rune Knight - **/ case RK_PHANTOMTHRUST: unit_setdir(src,map_calc_dir(src, bl->x, bl->y)); clif_skill_nodamage(src,bl,skillid,skilllv,1); @@ -3737,9 +3766,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int } else //non-sd support skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); break; - /** - * Guilotinne Cross - **/ case GC_DARKILLUSION: { short x, y; @@ -3789,9 +3815,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); } break; - /** - * Warlock - **/ case WL_CHAINLIGHTNING: clif_skill_nodamage(src,bl,skillid,skilllv,1); skill_addtimerskill(src,tick + 150,bl->id,3,0,WL_CHAINLIGHTNING_ATK,skilllv,4+skilllv,flag); @@ -3975,9 +3998,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int skill_attack(skill_get_type(skillid), src, src, bl, skillid, skilllv, tick, flag); } break; - /** - * Ranger - **/ case RA_WUGSTRIKE: case RA_WUGBITE: if( path_search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKNOREACH) ) { @@ -4016,9 +4036,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int } } break; - /** - * Mechanic - **/ case NC_INFRAREDSCAN: if( flag&1 ) { //TODO: Need a confirmation if the other type of hidden status is included to be scanned. [Jobbie] @@ -4054,9 +4071,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int clif_skill_damage(src,src,tick,status_get_amotion(src),0,-30000,1,skillid,skilllv,6); } break; - /** - * Royal Guard - **/ case LG_PINPOINTATTACK: if( !map_flag_gvg(src->m) && !map[src->m].flag.battleground && unit_movepos(src, bl->x, bl->y, 1, 1) ) clif_slide(src,bl->x,bl->y); @@ -4075,6 +4089,59 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int case LG_OVERBRAND_BRANDISH: skill_addtimerskill(src, tick + status_get_amotion(src)*8/10, bl->id, 0, 0, skillid, skilllv, BF_WEAPON, flag|SD_LEVEL); break; + case SR_DRAGONCOMBO: + if( sd ) // Dragon Combo must back to target-selectable skill after use it as combo. + clif_skillinfo(sd,SR_DRAGONCOMBO,0); + skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag); + break; + + case SR_KNUCKLEARROW: + if( !map_flag_gvg(src->m) && !map[src->m].flag.battleground && unit_movepos(src, bl->x, bl->y, 1, 1) ) { + clif_slide(src,bl->x,bl->y); + clif_fixpos(src); // Aegis send this packet too. + } + + if( flag&1 ) + skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick, flag|SD_LEVEL); + else + skill_addtimerskill(src, tick + 300, bl->id, 0, 0, skillid, skilllv, BF_WEAPON, flag|SD_LEVEL|2); + break; + + case SR_HOWLINGOFLION: + status_change_end(bl, SC_SWINGDANCE, -1); + status_change_end(bl, SC_SYMPHONYOFLOVER, -1); + status_change_end(bl, SC_MOONLITSERENADE, -1); + status_change_end(bl, SC_RUSHWINDMILL, -1); + status_change_end(bl, SC_ECHOSONG, -1); + status_change_end(bl, SC_HARMONIZE, -1); + status_change_end(bl, SC_SIRCLEOFNATURE, -1); + status_change_end(bl, SC_SATURDAYNIGHTFEVER, -1); + status_change_end(bl, SC_DANCEWITHWUG, -1); + status_change_end(bl, SC_LERADSDEW, -1); + status_change_end(bl, SC_MELODYOFSINK, -1); + status_change_end(bl, SC_BEYONDOFWARCRY, -1); + status_change_end(bl, SC_UNLIMITEDHUMMINGVOICE, -1); + skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick, flag); + break; + + case SR_EARTHSHAKER: + if( flag&1 ) { + struct status_change *tsc = status_get_sc(bl); + if( tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CHASEWALK] || tsc->data[SC_CLOAKING] || tsc->data[SC_CLOAKINGEXCEED]) ) { + 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); + sc_start(bl,SC_STUN, 25 + 5 * skilllv,skilllv,skill_get_time(skillid,skilllv));//Does it apply the stun chance to targets knocked out of hiding, or it applys allways? [Rytech] + skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick, flag); + } else + skill_attack(BF_WEAPON, src, src, bl, skillid, skilllv, tick, flag); + } + else + map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id); + clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6); + break; + case 0: if(sd) { @@ -4718,6 +4785,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case SC_DEADLYINFECT: case LG_EXEEDBREAK: case LG_PRESTIGE: + case SR_CRESCENTELBOW: + case SR_LIGHTNINGWALK: + case SR_GENTLETOUCH_ENERGYGAIN: + case SR_GENTLETOUCH_CHANGE: + case SR_GENTLETOUCH_REVITALIZE: clif_skill_nodamage(src,bl,skillid,skilllv, sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); break; @@ -5004,18 +5076,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case ASC_METEORASSAULT: case GS_SPREADATTACK: - /** - * Rune Knight - **/ case RK_STORMBLAST: - /** - * Mechanic - **/ case NC_AXETORNADO: - /** - * Guilotine Cross - **/ case GC_COUNTERSLASH: + case SR_SKYNETBLOW: + case SR_RAMPAGEBLASTER: + case SR_HOWLINGOFLION: skill_area_temp[1] = 0; clif_skill_nodamage(src,bl,skillid,skilllv,1); i = map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src), @@ -5029,6 +5095,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in status_change_end(src,SC_OVERHEAT_LIMITPOINT,-1); status_change_end(src,SC_OVERHEAT,-1); break; + case SR_EARTHSHAKER: + case SR_WINDMILL: case NC_INFRAREDSCAN: case NPC_EARTHQUAKE: case NPC_VAMPIRE_GIFT: @@ -7607,6 +7675,83 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in clif_skill_nodamage(bl,src,skillid,skilllv, sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv))); break; + case SR_CURSEDCIRCLE: + if( flag&1 ) { + if( is_boss(bl) ) break; + if( sc_start2(bl, type, 100, skilllv, src->id, skill_get_time(skillid, skilllv))) { + unit_stop_attack(bl); + clif_bladestop(src, bl->id, 1); + map_freeblock_unlock(); + return 1; + } + } else { + int count = 0; + clif_skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6); + count = map_forcountinrange(skill_area_sub, src, skill_get_splash(skillid,skilllv), (sd)?sd->spiritball_old:15, // Assume 15 spiritballs in non-charactors + BL_CHAR, src, skillid, skilllv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id); + if( sd ) pc_delspiritball(sd, count, 0); + clif_skill_nodamage(src, src, skillid, skilllv, + sc_start2(src, SC_CURSEDCIRCLE_ATKER, 100, skilllv, count, skill_get_time(skillid,skilllv))); + } + break; + + case SR_RAISINGDRAGON: + if( sd ) { + short max = 5 + skilllv; + sc_start(bl, SC_EXPLOSIONSPIRITS, 100, skilllv, skill_get_time(skillid, skilllv)); + for( i = 0; i < max; i++ ) // Don't call more than max available spheres. + pc_addspiritball(sd, skill_get_time(skillid, skilllv), max); + clif_skill_nodamage(src, bl, skillid, skilllv, sc_start(bl, type, 100, skilllv,skill_get_time(skillid, skilllv))); + } + break; + + case SR_ASSIMILATEPOWER: + if( flag&1 ) { + i = 0; + if( dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER ) + { + i = dstsd->spiritball; //1%sp per spiritball. + pc_delspiritball(dstsd, dstsd->spiritball, 0); + } + if( i ) status_percent_heal(src, 0, i); + clif_skill_nodamage(src, bl, skillid, skilllv, i ? 1:0); + } else { + clif_skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6); + map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|BCT_SELF|SD_SPLASH|1, skill_castend_nodamage_id); + } + break; + + case SR_POWERVELOCITY: + if( !dstsd ) + break; + if( sd && dstsd->spiritball <= 5 ) { + for(i = 0; i <= 5; i++) { + pc_addspiritball(dstsd, skill_get_time(MO_CALLSPIRITS, pc_checkskill(sd,MO_CALLSPIRITS)), i); + pc_delspiritball(sd, sd->spiritball, 0); + } + } + clif_skill_nodamage(src, bl, skillid, skilllv, 1); + break; + + case SR_GENTLETOUCH_CURE: + if( status_isimmune(bl) ) { + clif_skill_nodamage(src,bl,skillid,skilllv,0); + break; + } + if( (tsc && tsc->opt1) && rand()%100 < 5 * skilllv ) { + status_change_end(bl, SC_STONE, -1 ); + status_change_end(bl, SC_FREEZE, -1 ); + status_change_end(bl, SC_STUN, -1 ); + status_change_end(bl, SC_POISON, -1 ); + status_change_end(bl, SC_SILENCE, -1 ); + status_change_end(bl, SC_BLIND, -1 ); + status_change_end(bl, SC_HALLUCINATION, -1 ); + status_change_end(bl, SC_BURNING, -1 ); + status_change_end(bl, SC_FREEZING, -1 ); + skill_castend_nodamage_id(src, bl, AL_HEAL, skilllv, tick, flag); + } + clif_skill_nodamage(src,bl,skillid,skilllv,1); + break; case RETURN_TO_ELDICASTES: case ALL_GUARDIAN_RECALL: @@ -7778,7 +7923,8 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data) inf2 = skill_get_inf2(ud->skillid); if(inf&INF_ATTACK_SKILL || - (inf&INF_SELF_SKILL && inf2&INF2_NO_TARGET_SELF)) //Combo skills + (inf&INF_SELF_SKILL && inf2&INF2_NO_TARGET_SELF) || //Combo skills + (ud->skillid == SR_DRAGONCOMBO && src == target) ) // Casted through combo. inf = BCT_ENEMY; //Offensive skill. else if(inf2&INF2_NO_ENEMY) inf = BCT_NOENEMY; @@ -8184,6 +8330,12 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk src->m, x-i, y-i, x+i,y+i,BL_SKILL); break; + case SR_RIDEINLIGHTNING: + i = skill_get_splash(skillid, skilllv); + map_foreachinarea(skill_area_sub, src->m, x-i, y-i, x+i, y+i, BL_CHAR, + src, skillid, skilllv, tick, flag|BCT_ENEMY|1, skill_castend_damage_id); + break; + case SA_VOLCANO: case SA_DELUGE: case SA_VIOLENTGALE: @@ -10563,6 +10715,8 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh break; case MO_FINGEROFFENSIVE: case GS_FLING: + case SR_RAMPAGEBLASTER: + case SR_RIDEINLIGHTNING: if( sd->spiritball > 0 && sd->spiritball < require.spiritball ) sd->spiritball_old = require.spiritball = sd->spiritball; else @@ -10967,6 +11121,28 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh return 0; } break; + case SR_FALLENEMPIRE: + if( !(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_DRAGONCOMBO) ) + return 0; + break; + case SR_CRESCENTELBOW: + if( sc && sc->data[SC_CRESCENTELBOW] ) { + clif_skill_fail(sd,skill,0,0); + return 0; + } + break; + case SR_CURSEDCIRCLE: + if( sd->spiritball > 0 ) + sd->spiritball_old = require.spiritball = sd->spiritball; + else { + clif_skill_fail(sd,skill,0,0); + return 0; + } + break; + case SR_GATEOFHELL: + if( sd->spiritball > 0 ) + sd->spiritball_old = require.spiritball; + break; case SC_MANHOLE: case SC_DIMENSIONDOOR: if( sc && sc->data[SC_MAGNETICFIELD] ) { @@ -11519,6 +11695,13 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, short } } break; + case SR_RAMPAGEBLASTER: + req.spiritball = sd->spiritball?sd->spiritball:15; + break; + case SR_GATEOFHELL: + if( sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == SR_FALLENEMPIRE ) + req.sp -= req.sp * 10 / 100; + break; } return req; @@ -11638,13 +11821,14 @@ int skill_delayfix (struct block_list *bl, int skill_id, int skill_lv) time = -time + status_get_amotion(bl); // If set to <0, add to attack motion. // Delay reductions - switch (skill_id) - { //Monk combo skills have their delay reduced by agi/dex. + switch (skill_id) { //Monk combo skills have their delay reduced by agi/dex. case MO_TRIPLEATTACK: case MO_CHAINCOMBO: case MO_COMBOFINISH: case CH_TIGERFIST: case CH_CHAINCRUSH: + case SR_DRAGONCOMBO: + case SR_FALLENEMPIRE: time -= 4*status_get_agi(bl) - 2*status_get_dex(bl); break; case HP_BASILICA: diff --git a/src/map/status.c b/src/map/status.c index 39634ad09..dc0d8fdb2 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -555,18 +555,18 @@ void initChangeTables(void) set_sc( SC_MANHOLE , SC__MANHOLE , SI_MANHOLE , SCB_NONE ); add_sc( SC_CHAOSPANIC , SC_CHAOS ); set_sc( SC_BLOODYLUST , SC__BLOODYLUST , SI_BLOODYLUST , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); - ///** - // * Sura - // **/ - //add_sc( SR_DRAGONCOMBO , SC_STUN ); - //add_sc( SR_EARTHSHAKER , SC_STUN ); - //set_sc( SR_CRESCENTELBOW , SC_CRESCENTELBOW , SI_CRESCENTELBOW , SCB_NONE ); - //set_sc( SR_CURSEDCIRCLE , SC_CURSEDCIRCLE_TARGET, SI_CURSEDCIRCLE_TARGET , SCB_NONE ); - //set_sc( SR_LIGHTNINGWALK , SC_LIGHTNINGWALK , SI_LIGHTNINGWALK , SCB_NONE ); - //set_sc( SR_RAISINGDRAGON , SC_RAISINGDRAGON , SI_RAISINGDRAGON , SCB_REGEN|SCB_MAXHP|SCB_MAXSP/*|SCB_ASPD*/ ); - //set_sc( SR_GENTLETOUCH_ENERGYGAIN, SC_GT_ENERGYGAIN , SI_GENTLETOUCH_ENERGYGAIN, SCB_NONE ); - //set_sc( SR_GENTLETOUCH_CHANGE , SC_GT_CHANGE , SI_GENTLETOUCH_CHANGE , SCB_BATK|SCB_ASPD|SCB_DEF|SCB_MDEF ); - //set_sc( SR_GENTLETOUCH_REVITALIZE, SC_GT_REVITALIZE , SI_GENTLETOUCH_REVITALIZE, SCB_MAXHP|SCB_DEF2|SCB_REGEN|SCB_ASPD|SCB_SPEED ); + /** + * Sura + **/ + add_sc( SR_DRAGONCOMBO , SC_STUN ); + add_sc( SR_EARTHSHAKER , SC_STUN ); + set_sc( SR_CRESCENTELBOW , SC_CRESCENTELBOW , SI_CRESCENTELBOW , SCB_NONE ); + set_sc( SR_CURSEDCIRCLE , SC_CURSEDCIRCLE_TARGET, SI_CURSEDCIRCLE_TARGET , SCB_NONE ); + set_sc( SR_LIGHTNINGWALK , SC_LIGHTNINGWALK , SI_LIGHTNINGWALK , SCB_NONE ); + set_sc( SR_RAISINGDRAGON , SC_RAISINGDRAGON , SI_RAISINGDRAGON , SCB_REGEN|SCB_MAXHP|SCB_MAXSP/*|SCB_ASPD*/ ); + set_sc( SR_GENTLETOUCH_ENERGYGAIN, SC_GT_ENERGYGAIN , SI_GENTLETOUCH_ENERGYGAIN, SCB_NONE ); + set_sc( SR_GENTLETOUCH_CHANGE , SC_GT_CHANGE , SI_GENTLETOUCH_CHANGE , SCB_BATK|SCB_ASPD|SCB_DEF|SCB_MDEF ); + set_sc( SR_GENTLETOUCH_REVITALIZE, SC_GT_REVITALIZE , SI_GENTLETOUCH_REVITALIZE, SCB_MAXHP|SCB_DEF2|SCB_REGEN|SCB_ASPD|SCB_SPEED ); ///** // * Wanderer / Mistrel // **/ @@ -1013,6 +1013,8 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s sc_start4(target,SC_PROVOKE,100,10,1,0,0,0); if (sc->data[SC_BERSERK] && status->hp <= 100) status_change_end(target, SC_BERSERK, INVALID_TIMER); + if( sc->data[SC_RAISINGDRAGON] && status->hp <= 1000 ) + status_change_end(target, SC_RAISINGDRAGON, -1); } switch (target->type) @@ -1411,7 +1413,8 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, int sc->data[SC_WHITEIMPRISON] || (sc->data[SC_STASIS] && skill_stasis_check(src, sc->data[SC_STASIS]->val2, skill_num)) || sc->data[SC__INVISIBILITY] || - sc->data[SC__IGNORANCE] + sc->data[SC__IGNORANCE] || + sc->data[SC_CURSEDCIRCLE_TARGET] )) return 0; @@ -3093,6 +3096,8 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str || sc->data[SC_BERSERK] || sc->data[SC_TRICKDEAD] || sc->data[SC_BLEEDING] + || sc->data[SC_MAGICMUSHROOM] + || sc->data[SC_RAISINGDRAGON] ) //No regen regen->flag = 0; @@ -3918,6 +3923,8 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan batk -= batk * sc->data[SC__ENERVATION]->val2 / 100; if(sc->data[SC__BLOODYLUST]) batk += batk * 32 / 100; + if(sc->data[SC_GT_CHANGE]) + batk += batk * sc->data[SC_GT_CHANGE]->val3 / 100; #if RE_EDP /** * in RE EDP increases your base atk by atk x Skill Level. @@ -4483,7 +4490,8 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha val = max( val, 75 ); if( sc->data[SC_CLOAKINGEXCEED] ) val = max( val, sc->data[SC_CLOAKINGEXCEED]->val3); - + if( sc->data[SC_GT_REVITALIZE] ) + val = max( val, sc->data[SC_GT_REVITALIZE]->val2 ); //FIXME: official items use a single bonus for this [ultramage] if( sc->data[SC_SPEEDUP0] ) // temporary item-based speedup val = max( val, 25 ); @@ -4709,6 +4717,12 @@ static unsigned int status_calc_maxhp(struct block_list *bl, struct status_chang maxhp -= maxhp * sc->data[SC__WEAKNESS]->val2 / 100; if(sc->data[SC_FORCEOFVANGUARD]) maxhp += maxhp * 3 * sc->data[SC_FORCEOFVANGUARD]->val1 / 100; + if(sc->data[SC_RAISINGDRAGON]) + maxhp += maxhp * (2 + sc->data[SC_RAISINGDRAGON]->val1) / 100; + if(sc->data[SC_GT_CHANGE]) + maxhp -= maxhp * (2 * sc->data[SC_GT_CHANGE]->val1) / 100; + if(sc->data[SC_GT_REVITALIZE]) + maxhp += maxhp * (3 * sc->data[SC_GT_REVITALIZE]->val1) / 100; if(sc->data[SC_INSPIRATION]) //Custom value. maxhp += maxhp * 3 * sc->data[SC_INSPIRATION]->val1 / 100; @@ -4727,6 +4741,8 @@ static unsigned int status_calc_maxsp(struct block_list *bl, struct status_chang maxsp += maxsp * sc->data[SC_SERVICE4U]->val2/100; if(sc->data[SC_MERC_SPUP]) maxsp += maxsp * sc->data[SC_MERC_SPUP]->val2/100; + if(sc->data[SC_RAISINGDRAGON]) + maxsp += maxsp * (2 + sc->data[SC_RAISINGDRAGON]->val1) / 100; return cap_value(maxsp,1,UINT_MAX); } @@ -6003,6 +6019,16 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if( type != SC_SHIELDSPELL_REF ) status_change_end(bl, SC_SHIELDSPELL_REF, INVALID_TIMER); break; + case SC_GT_ENERGYGAIN: + case SC_GT_CHANGE: + case SC_GT_REVITALIZE: + if( type != SC_GT_REVITALIZE ) + status_change_end(bl, SC_GT_REVITALIZE, INVALID_TIMER); + if( type != SC_GT_ENERGYGAIN ) + status_change_end(bl, SC_GT_ENERGYGAIN, INVALID_TIMER); + if( type != SC_GT_CHANGE ) + status_change_end(bl, SC_GT_CHANGE, INVALID_TIMER); + break; } //Check for overlapping fails @@ -7461,6 +7487,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val case SC_BITE: case SC__MANHOLE: case SC_CHAOS: + case SC_CURSEDCIRCLE_ATKER: + case SC_CURSEDCIRCLE_TARGET: unit_stop_walking(bl,1); break; case SC_HIDING: @@ -7742,6 +7770,9 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val clif_skillinfo(sd,TK_JUMPKICK, INF_SELF_SKILL); break; } + case SC_RAISINGDRAGON: + sce->val2 = status->max_hp / 100;// Officially tested its 1%hp drain. [Jobbie] + break; } if( opt_flag&2 && sd && sd->touching_id ) @@ -8258,7 +8289,6 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const } } break; - /* case SC_CURSEDCIRCLE_ATKER: if( sce->val3 ) map_foreachinrange(status_change_timer_sub, bl, skill_get_splash(SR_CURSEDCIRCLE, sce->val1),BL_CHAR, bl, sce, SC_CURSEDCIRCLE_TARGET, gettick()); @@ -8276,7 +8306,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const --i; } } - break;*/ + break; } opt_flag = 1; @@ -9341,6 +9371,12 @@ int status_change_timer_sub(struct block_list* bl, va_list ap) status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER); } break; + case SC_CURSEDCIRCLE_TARGET: + if( tsc && tsc->data[SC_CURSEDCIRCLE_TARGET] && tsc->data[SC_CURSEDCIRCLE_TARGET]->val2 == src->id ) { + status_change_end(bl, type, -1); + clif_bladestop(src, bl->id, 0); + } + break; } return 0; } @@ -9415,6 +9451,8 @@ int status_change_clear_buffs (struct block_list* bl, int type) case SC_VITALITYACTIVATION: case SC_FIGHTINGSPIRIT: case SC_ABUNDANCE: + case SC_CURSEDCIRCLE_ATKER: + case SC_CURSEDCIRCLE_TARGET: continue; //Debuffs that can be removed. diff --git a/src/map/unit.c b/src/map/unit.c index 9df208e11..56deae9c7 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1035,8 +1035,8 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh sc = NULL; //Unneeded //temp: used to signal combo-skills right now. - if (sc && sc->data[SC_COMBO] && (sc->data[SC_COMBO]->val1 == skill_num || skill_num == MO_EXTREMITYFIST)) - { + if (sc && sc->data[SC_COMBO] && (sc->data[SC_COMBO]->val1 == skill_num || + skill_num == MO_EXTREMITYFIST || skill_num == SR_DRAGONCOMBO )) { if (sc->data[SC_COMBO]->val2) target_id = sc->data[SC_COMBO]->val2; else |