From 81e3b03ace4e7facc898f782d4c1c6f14d32bd04 Mon Sep 17 00:00:00 2001 From: akinari1087 Date: Tue, 9 Jul 2013 06:02:39 +0000 Subject: [PATCH] Poison React now activates when character is damaged only - Fixes bugreport:109 Cloaking fixed to official behaviour (Thanks helvetica for the hour of testing) - Concerning bugreport:171 Fixed instancing long map names causing crashes - Cannot save or memo on instance maps (Lemongrass) - Map channels are no longer activated on instance maps (Lemongrass) - Fixed a character save issue with instance maps (Lemongrass) - Map local channels are disabled by default, this is custom (Lemongrass) - Just thank Lemongrass overall, I gave him a hard time with this issue ~ Hercules Merge ~ Update Bloody Lust and Maelstrom to official behaviour (Credits: malufett) git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@17408 54d463be-8e91-2dee-dedb-b68131a5f0ec --- conf/channels.conf | 2 +- conf/msg_conf/map_msg.conf | 4 +- db/re/skill_db.txt | 2 +- src/map/atcommand.c | 8 ++- src/map/battle.c | 8 ++- src/map/chrif.c | 17 +++++- src/map/clif.c | 27 ++++++++-- src/map/clif.h | 2 +- src/map/instance.c | 15 ++++-- src/map/map.c | 14 +++-- src/map/pc.c | 28 +++++----- src/map/pc.h | 1 - src/map/script.c | 11 ++-- src/map/skill.c | 103 +++++++++++++++++++++++-------------- src/map/skill.h | 1 + src/map/status.c | 69 +++++++++++-------------- src/map/unit.c | 8 ++- 17 files changed, 196 insertions(+), 124 deletions(-) diff --git a/conf/channels.conf b/conf/channels.conf index c0a76fd506..5930531c0d 100644 --- a/conf/channels.conf +++ b/conf/channels.conf @@ -30,7 +30,7 @@ chsys: ( allow_user_channel_creation: true /* "map_local_channel" is an instanced channel unique to each map. */ - map_local_channel: true + map_local_channel: false map_local_channel_name: "map" map_local_channel_color: "Yellow" map_local_channel_autojoin: true /* Disable autojoin in specific maps through mapflag 'nomapchannelautojoin'. */ diff --git a/conf/msg_conf/map_msg.conf b/conf/msg_conf/map_msg.conf index 7c1c6ae26b..8f3de8027c 100644 --- a/conf/msg_conf/map_msg.conf +++ b/conf/msg_conf/map_msg.conf @@ -399,7 +399,9 @@ 380: Item Failed. [%s] is cooling down. Wait %d seconds. 381: Skill Failed. [%s] requires %dx %s. 382: You're too close to a stone or emperium to use this skill. -//383-389 free +383: You cannot create a savepoint in an instance. +384: You cannot create a memo in an instance. +//385-389 free //NoAsk 390: Autorejecting is activated. 391: Autorejecting is deactivated. diff --git a/db/re/skill_db.txt b/db/re/skill_db.txt index 28ff64ddd4..292f6ba962 100644 --- a/db/re/skill_db.txt +++ b/db/re/skill_db.txt @@ -874,7 +874,7 @@ 2300,7,6,2,0,0x1,0,3,1,yes,0,0,1,none,0, SC_DIMENSIONDOOR,Dimension Door 2301,7,6,2,0,0x1,0,3,1,yes,0,0,0,none,0, SC_CHAOSPANIC,Chaos Panic 2302,7,6,2,0,0x1,0,3,1,yes,0,0,0,none,0, SC_MAELSTROM,Maelstrom -2303,7,6,2,0,0x1,0,3,1,yes,0,0,0,none,0, SC_BLOODYLUST,Bloody Lust +2303,7,6,2,0,0x1,3,3,1,yes,0,0,1,none,0, SC_BLOODYLUST,Bloody Lust 2304,0,6,4,-1,0,0,3,1,no,0,0,0,weapon,0, SC_FEINTBOMB,Feint Bomb //**** diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 0d5602aa59..85045eb4fb 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -729,6 +729,11 @@ ACMD_FUNC(save) { nullpo_retr(-1, sd); + if( map[sd->bl.m].instance_id ) { + clif_displaymessage(fd, msg_txt(sd,383)); // You cannot create a savepoint in an instance. + return 1; + } + pc_setsavepoint(sd, sd->mapindex, sd->bl.x, sd->bl.y); if (sd->status.pet_id > 0 && sd->pd) intif_save_petdata(sd->status.account_id, &sd->pd->pet); @@ -2221,8 +2226,7 @@ ACMD_FUNC(memo) return -1; } - pc_memo(sd, position); - return 0; + return !pc_memo( sd, position ); } /*========================================== diff --git a/src/map/battle.c b/src/map/battle.c index 26ad11d1ca..11d5fc0dd2 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -745,6 +745,10 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag if( battle_config.ksprotection && mob_ksprotected(src, bl) ) return 0; + if( map_getcell(bl->m, bl->x, bl->y, CELL_CHKMAELSTROM) && skill_get_type(skill_id) != BF_MISC + && skill_get_casttype(skill_id) == CAST_GROUND ) + return 0; + if (bl->type == BL_PC) { sd=(struct map_session_data *)bl; //Special no damage states @@ -2739,7 +2743,7 @@ static int battle_calc_attack_skill_ratio(struct Damage wd, struct block_list *s skillratio += sc->data[SC_OVERTHRUST]->val3; if(sc->data[SC_MAXOVERTHRUST]) skillratio += sc->data[SC_MAXOVERTHRUST]->val2; - if (sc->data[SC_BERSERK] || sc->data[SC_SATURDAYNIGHTFEVER] || sc->data[SC__BLOODYLUST]) + if (sc->data[SC_BERSERK] || sc->data[SC_SATURDAYNIGHTFEVER]) skillratio += 100; if(sc->data[SC_ZENKAI] && sstatus->rhw.ele == sc->data[SC_ZENKAI]->val2 ) skillratio += sc->data[SC_ZENKAI]->val1 * 2; @@ -6008,7 +6012,7 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t } if (tsc) { - if (tsc->data[SC_POISONREACT] && + if (damage > 0 && tsc->data[SC_POISONREACT] && (rnd()%100 < tsc->data[SC_POISONREACT]->val3 || sstatus->def_ele == ELE_POISON) && // check_distance_bl(src, target, tstatus->rhw.range+1) && Doesn't checks range! o.O; diff --git a/src/map/chrif.c b/src/map/chrif.c index 8dc4390791..6ad62e2b92 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -304,7 +304,22 @@ int chrif_save(struct map_session_data *sd, int flag) { WFIFOL(char_fd,4) = sd->status.account_id; WFIFOL(char_fd,8) = sd->status.char_id; WFIFOB(char_fd,12) = (flag==1)?1:0; //Flag to tell char-server this character is quitting. - memcpy(WFIFOP(char_fd,13), &sd->status, sizeof(sd->status)); + + // If the user is on a instance map, we have to fake his current position + if( map[sd->bl.m].instance_id ){ + struct mmo_charstatus status; + + // Copy the whole status + memcpy( &status, &sd->status, sizeof( struct mmo_charstatus ) ); + // Change his current position to his savepoint + memcpy( &status.last_point, &status.save_point, sizeof( struct point ) ); + // Copy the copied status into the packet + memcpy( WFIFOP( char_fd, 13 ), &status, sizeof( struct mmo_charstatus ) ); + } else { + // Copy the whole status into the packet + memcpy( WFIFOP( char_fd, 13 ), &sd->status, sizeof( struct mmo_charstatus ) ); + } + WFIFOSET(char_fd, WFIFOW(char_fd,2)); if( sd->status.pet_id > 0 && sd->pd ) diff --git a/src/map/clif.c b/src/map/clif.c index bcbe8ebf2d..4aeabfcd21 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -1660,7 +1660,7 @@ void clif_quitsave(int fd,struct map_session_data *sd) { /// Notifies the client of a position change to coordinates on given map (ZC_NPCACK_MAPMOVE). /// 0091 .16B .W .W -void clif_changemap(struct map_session_data *sd, short map, int x, int y) +void clif_changemap(struct map_session_data *sd, short m, int x, int y) { int fd; nullpo_retv(sd); @@ -1668,7 +1668,18 @@ void clif_changemap(struct map_session_data *sd, short map, int x, int y) WFIFOHEAD(fd,packet_len(0x91)); WFIFOW(fd,0) = 0x91; - mapindex_getmapname_ext(mapindex_id2name(map), (char*)WFIFOP(fd,2)); + if(map[m].instance_id) { // Instance map check to send client source map name so we don't crash player + struct instance_data *im = &instance_data[map[m].instance_id]; + int i; + if(!im) // This shouldn't happen but if it does give them the map we intended to give + mapindex_getmapname_ext(map[m].name, (char*)WFIFOP(fd,2)); + for(i = 0; i < MAX_MAP_PER_INSTANCE; i++) // Loop to find the src map we want + if(im->map[i].m == m) { + mapindex_getmapname_ext(map[im->map[i].src_m].name, (char*)WFIFOP(fd,2)); + break; + } + } else + mapindex_getmapname_ext(map[m].name, (char*)WFIFOP(fd,2)); WFIFOW(fd,18) = x; WFIFOW(fd,20) = y; WFIFOSET(fd,packet_len(0x91)); @@ -8286,7 +8297,7 @@ void clif_refresh(struct map_session_data *sd) int i; nullpo_retv(sd); - clif_changemap(sd,sd->mapindex,sd->bl.x,sd->bl.y); + clif_changemap(sd,sd->bl.m,sd->bl.x,sd->bl.y); clif_inventorylist(sd); if(pc_iscarton(sd)) { clif_cartlist(sd); @@ -9139,7 +9150,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) if (sd->state.rewarp) { //Rewarp player. sd->state.rewarp = 0; - clif_changemap(sd, sd->mapindex, sd->bl.x, sd->bl.y); + clif_changemap(sd, sd->bl.m, sd->bl.x, sd->bl.y); return; } @@ -9379,7 +9390,8 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) status_calc_pc(sd, false); // Some conditions are map-dependent so we must recalculate sd->state.changemap = false; - if( Channel_Config.map_enable && Channel_Config.map_autojoin && !map[sd->bl.m].flag.chmautojoin) { + // Instances do not need their own channels + if( Channel_Config.map_enable && Channel_Config.map_autojoin && !map[sd->bl.m].flag.chmautojoin && !map[sd->bl.m].instance_id ) { channel_mjoin(sd); //join new map } } @@ -9567,6 +9579,11 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd) if(sd->sc.data[SC_RUN] || sd->sc.data[SC_WUGDASH]) return; + // Cloaking wall check is actually updated when you click to process next movement + // not when you move each cell. This is official behaviour. + if (sd->sc.data[SC_CLOAKING]) + skill_check_cloaking(&sd->bl, sd->sc.data[SC_CLOAKING]); + pc_delinvincibletimer(sd); RFIFOPOS(fd, packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0], &x, &y, NULL); diff --git a/src/map/clif.h b/src/map/clif.h index a818d9c1c7..177afc54f8 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -345,7 +345,7 @@ void clif_clearunit_delayed(struct block_list* bl, clr_type type, unsigned int t int clif_spawn(struct block_list *bl); //area void clif_walkok(struct map_session_data *sd); // self void clif_move(struct unit_data *ud); //area -void clif_changemap(struct map_session_data *sd, short map, int x, int y); //self +void clif_changemap(struct map_session_data *sd, short m, int x, int y); //self void clif_changemapserver(struct map_session_data* sd, unsigned short map_index, int x, int y, uint32 ip, uint16 port); //self void clif_blown(struct block_list *bl); // area void clif_slide(struct block_list *bl, int x, int y); // area diff --git a/src/map/instance.c b/src/map/instance.c index ec21a75e71..3813251a79 100644 --- a/src/map/instance.c +++ b/src/map/instance.c @@ -369,7 +369,7 @@ int instance_mapname2mapid(const char *name, short instance_id) { struct instance_data *im; int m = map_mapname2mapid(name); - char iname[12]; + char iname[MAP_NAME_LENGTH]; int i; if(m < 0) { @@ -377,6 +377,8 @@ int instance_mapname2mapid(const char *name, short instance_id) return m; } + strcpy(iname,name); + if(instance_id <= 0 || instance_id > MAX_INSTANCE_DATA) return m; @@ -386,8 +388,13 @@ int instance_mapname2mapid(const char *name, short instance_id) for(i = 0; i < MAX_MAP_PER_INSTANCE; i++) if(im->map[i].src_m == m) { - snprintf(iname, sizeof(iname), ((strchr(name,'@') == NULL)?"%.3d#%s":"%.3d%s"), instance_id, name); - return mapindex_name2id(iname); + char alt_name[MAP_NAME_LENGTH]; + if((strchr(iname,'@') == NULL) && strlen(iname) > 8) { + memmove(iname, iname+(strlen(iname)-9), strlen(iname)); + snprintf(alt_name, sizeof(alt_name),"%d#%s", instance_id, iname); + } else + snprintf(alt_name, sizeof(alt_name),"%.3d%s", instance_id, iname); + return map_mapname2mapid(alt_name); } return m; @@ -515,7 +522,7 @@ int instance_enter(struct map_session_data *sd, const char *name) if((m = instance_mapname2mapid(db->enter.mapname, p->instance_id)) < 0) return 3; - if(pc_setpos(sd, m, db->enter.x, db->enter.y, 0)) + if(pc_setpos(sd, map_id2index(m), db->enter.x, db->enter.y, 0)) return 3; // If there was an idle timer, let's stop it diff --git a/src/map/map.c b/src/map/map.c index ab754f82dd..afd166cf96 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -425,8 +425,6 @@ int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick) if (sc->data[SC_DANCING]) skill_unit_move_unit_group(skill_id2group(sc->data[SC_DANCING]->val2), bl->m, x1-x0, y1-y0); else { - if (sc->data[SC_CLOAKING]) - skill_check_cloaking(bl, sc->data[SC_CLOAKING]); if (sc->data[SC_WARM]) skill_unit_move_unit_group(skill_id2group(sc->data[SC_WARM]->val4), bl->m, x1-x0, y1-y0); if (sc->data[SC_BANDING]) @@ -2181,6 +2179,7 @@ int map_addinstancemap(const char *name, int id) { int src_m = map_mapname2mapid(name); int dst_m = -1, i; + char iname[MAP_NAME_LENGTH]; size_t size; if(src_m < 0) @@ -2209,8 +2208,16 @@ int map_addinstancemap(const char *name, int id) // Copy the map memcpy(&map[dst_m], &map[src_m], sizeof(struct map_data)); + strcpy(iname,name); + // Alter the name - snprintf(map[dst_m].name, sizeof(map[dst_m].name), ((strchr(name,'@') == NULL)?"%.3d#%s":"%.3d%s"), id, name); + // Due to this being custom we only worry about preserving as many characters as necessary for accurate map distinguishing + // This also allows us to maintain complete independence with main map functions + if((strchr(iname,'@') == NULL) && strlen(iname) > 8) { + memmove(iname, iname+(strlen(iname)-9), strlen(iname)); + snprintf(map[dst_m].name, sizeof(map[dst_m].name),"%d#%s", id, iname); + } else + snprintf(map[dst_m].name, sizeof(map[dst_m].name),"%.3d%s", id, iname); map[dst_m].name[MAP_NAME_LENGTH-1] = '\0'; map[dst_m].m = dst_m; @@ -2225,6 +2232,7 @@ int map_addinstancemap(const char *name, int id) map[dst_m].block_mob = (struct block_list **)aCalloc(1,size); map[dst_m].index = mapindex_addmap(-1, map[dst_m].name); + map[dst_m].channel = NULL; map_addmap2db(&map[dst_m]); diff --git a/src/map/pc.c b/src/map/pc.c index d9897cebc2..5e64d2892e 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1091,7 +1091,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim /** * Fixes login-without-aura glitch (the screen won't blink at this point, don't worry :P) **/ - clif_changemap(sd,sd->mapindex,sd->bl.x,sd->bl.y); + clif_changemap(sd,sd->bl.m,sd->bl.x,sd->bl.y); } /** @@ -4211,7 +4211,7 @@ int pc_isUseitem(struct map_session_data *sd,int n) case 12243: // Mercenary's Berserk Potion if( sd->md == NULL || sd->md->db == NULL ) return 0; - if (sd->md->sc.data[SC_BERSERK] || sd->md->sc.data[SC_SATURDAYNIGHTFEVER] || sd->md->sc.data[SC__BLOODYLUST]) + if (sd->md->sc.data[SC_BERSERK] || sd->md->sc.data[SC_SATURDAYNIGHTFEVER]) return 0; if( nameid == 12242 && sd->md->db->lv < 40 ) return 0; @@ -4308,7 +4308,7 @@ int pc_useitem(struct map_session_data *sd,int n) return 0; if (sd->sc.count && ( - sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || sd->sc.data[SC_SATURDAYNIGHTFEVER] || + sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAYNIGHTFEVER] || (sd->sc.data[SC_GRAVITATION] && sd->sc.data[SC_GRAVITATION]->val3 == BCT_SELF) || sd->sc.data[SC_TRICKDEAD] || sd->sc.data[SC_HIDING] || @@ -4879,7 +4879,7 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y if(sd->bl.prev != NULL){ unit_remove_map_pc(sd,clrtype); - clif_changemap(sd,map[m].index,x,y); // [MouseJstr] + clif_changemap(sd,m,x,y); // [MouseJstr] } else if(sd->state.active) //Tag player for rewarping after map-loading is done. [Skotlex] sd->state.rewarp = 1; @@ -4992,6 +4992,11 @@ int pc_memo(struct map_session_data* sd, int pos) pos = 0; } + if( map[sd->bl.m].instance_id ) { + clif_displaymessage( sd->fd, msg_txt(sd,384) ); // You cannot create a memo in an instance. + return 0; + } + sd->status.memo_point[pos].map = map_id2index(sd->bl.m); sd->status.memo_point[pos].x = sd->bl.x; sd->status.memo_point[pos].y = sd->bl.y; @@ -8553,8 +8558,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) return 0; } - if( DIFF_TICK(sd->canequip_tick,gettick()) > 0 ) - { + if( DIFF_TICK(sd->canequip_tick,gettick()) > 0 ) { clif_equipitemack(sd,n,0,0); return 0; } @@ -8570,8 +8574,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) return 0; } - if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAYNIGHTFEVER] || sd->sc.data[SC__BLOODYLUST]) - { + if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_SATURDAYNIGHTFEVER]) { clif_equipitemack(sd,n,0,0); // fail return 0; } @@ -8582,15 +8585,14 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) pos = sd->equip_index[EQI_ACC_R] >= 0 ? EQP_ACC_L : EQP_ACC_R; } - if(pos == EQP_ARMS && id->equip == EQP_HAND_R) - { //Dual wield capable weapon. + if(pos == EQP_ARMS && id->equip == EQP_HAND_R) { //Dual wield capable weapon. pos = (req_pos&EQP_ARMS); if (pos == EQP_ARMS) //User specified both slots, pick one for them. pos = sd->equip_index[EQI_HAND_R] >= 0 ? EQP_HAND_L : EQP_HAND_R; } - if (pos&EQP_HAND_R && battle_config.use_weapon_skill_range&BL_PC) - { //Update skill-block range database when weapon range changes. [Skotlex] + if (pos&EQP_HAND_R && battle_config.use_weapon_skill_range&BL_PC) { + //Update skill-block range database when weapon range changes. [Skotlex] i = sd->equip_index[EQI_HAND_R]; if (i < 0 || !sd->inventory_data[i]) //No data, or no weapon equipped flag = 1; @@ -8607,7 +8609,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos) } } - if(pos==EQP_AMMO){ + if(pos==EQP_AMMO) { clif_arrowequip(sd,n); clif_arrow_fail(sd,3); } diff --git a/src/map/pc.h b/src/map/pc.h index e277df6cdf..b83f12393f 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -250,7 +250,6 @@ struct map_session_data { unsigned int canskill_tick; // used to prevent abuse from no-delay ACT files unsigned int cansendmail_tick; // [Mail System Flood Protection] unsigned int ks_floodprotect_tick; // [Kill Steal Protection] - unsigned int bloodylust_tick; // bloodylust player timer [out/in re full-heal protection] struct { short nameid; diff --git a/src/map/script.c b/src/map/script.c index b0ea6731d3..378c7cddb5 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -16561,21 +16561,18 @@ BUILDIN_FUNC(instance_npcname) BUILDIN_FUNC(instance_mapname) { const char *str; - char iname[12]; int16 m; short instance_id = 0; str = script_getstr(st,2); + if( script_hasdata(st,3) ) instance_id = script_getnum(st,3); else instance_id = script_instancegetid(st); - // Build the instance mapname - snprintf(iname, sizeof(iname), ((strchr(str,'@') == NULL)?"%.3d#%s":"%.3d%s"), instance_id, str); - // Check that instance mapname is a valid map - if( !instance_id || (m = map_mapname2mapid(iname)) < 0 ) + if(!instance_id || (m = instance_mapname2mapid(str,instance_id)) < 0) script_pushconststr(st, ""); else script_pushconststr(st, map[m].name); @@ -16616,7 +16613,6 @@ BUILDIN_FUNC(instance_warpall) short instance_id; const char *mapn; int x, y; - unsigned short mapindex; mapn = script_getstr(st,2); x = script_getnum(st,3); @@ -16632,9 +16628,8 @@ BUILDIN_FUNC(instance_warpall) if( !(p = party_search(instance_data[instance_id].party_id)) ) return 0; - mapindex = map_id2index(m); for( i = 0; i < MAX_PARTY; i++ ) - if( (pl_sd = p->data[i].sd) && map[pl_sd->bl.m].instance_id == instance_id ) pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT); + if( (pl_sd = p->data[i].sd) && map[pl_sd->bl.m].instance_id == instance_id ) pc_setpos(pl_sd,map_id2index(m),x,y,CLR_TELEPORT); return 0; } diff --git a/src/map/skill.c b/src/map/skill.c index 0a2330e71f..b73c5fcffa 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -5028,7 +5028,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui dstsd = sd; } } - else if (tsc->data[SC_BERSERK] || tsc->data[SC_SATURDAYNIGHTFEVER] || tsc->data[SC__BLOODYLUST]) + else if (tsc->data[SC_BERSERK] || tsc->data[SC_SATURDAYNIGHTFEVER]) heal = 0; //Needed so that it actually displays 0 when healing. } clif_skill_nodamage (src, bl, skill_id, heal, 1); @@ -10081,6 +10081,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui case SC_DIMENSIONDOOR: case SC_CHAOSPANIC: case SC_MAELSTROM: + case SC_BLOODYLUST: case WM_REVERBERATION: case WM_SEVERE_RAINSTORM: case WM_POEMOFNETHERWORLD: @@ -10565,11 +10566,6 @@ int skill_castend_pos2(struct block_list* src, int x, int y, uint16 skill_id, ui sc_start2(src,src, type, 100, skill_id, skill_lv, skill_get_time(skill_id, skill_lv))); break; - case SC_BLOODYLUST: //set in another group so instance will move if recasted - flag |= 33; - skill_unitsetting(src, skill_id, skill_lv, x, y, 0); - break; - case KO_MAKIBISHI: for( i = 0; i < (skill_lv+2); i++ ) { x = src->x - 1 + rnd()%3; @@ -10629,7 +10625,7 @@ int skill_castend_map (struct map_session_data *sd, uint16 skill_id, const char sd->sc.data[SC_AUTOCOUNTER] || sd->sc.data[SC_STEELBODY] || (sd->sc.data[SC_DANCING] && skill_id < RK_ENCHANTBLADE && !pc_checkskill(sd, WM_LESSON)) || - sd->sc.data[SC_BERSERK] || sd->sc.data[SC__BLOODYLUST] || + sd->sc.data[SC_BERSERK] || sd->sc.data[SC_BASILICA] || sd->sc.data[SC_MARIONETTE] || sd->sc.data[SC_WHITEIMPRISON] || @@ -11163,9 +11159,6 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill case SO_VACUUM_EXTREME: range++; - break; - case SC_BLOODYLUST: - skill_clear_group(src, 32); break; case GN_WALLOFTHORN: if( flag&1 ) @@ -11299,6 +11292,9 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, uint16 skill if (unit_flag&UF_RANGEDSINGLEUNIT && i == (layout->count / 2)) val2 |= UF_RANGEDSINGLEUNIT; // center. + if( sd && map_getcell(src->m, ux, uy, CELL_CHKMAELSTROM) ) //Does not recover SP from monster skills + map_foreachincell(skill_maelstrom_suction,src->m,ux,uy,BL_SKILL,skill_id,skill_lv); + if( range <= 0 ) map_foreachincell(skill_cell_overlap,src->m,ux,uy,BL_SKILL,skill_id, &alive, src); if( !alive ) @@ -11360,7 +11356,8 @@ static int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, un nullpo_ret(sg=src->group); nullpo_ret(ss=map_id2bl(sg->src_id)); - if( skill_get_type(sg->skill_id) == BF_MAGIC && map_getcell(bl->m, bl->x, bl->y, CELL_CHKLANDPROTECTOR) && sg->skill_id != SA_LANDPROTECTOR ) + if( (skill_get_type(sg->skill_id) == BF_MAGIC && map_getcell(bl->m, bl->x, bl->y, CELL_CHKLANDPROTECTOR) && sg->skill_id != SA_LANDPROTECTOR) || + map_getcell(bl->m, bl->x, bl->y, CELL_CHKMAELSTROM) ) return 0; //AoE skills are ineffective. [Skotlex] if( skill_get_inf2(sg->skill_id)&(INF2_SONG_DANCE|INF2_ENSEMBLE_SKILL) && map_getcell(bl->m, bl->x, bl->y, CELL_CHKBASILICA) ) @@ -11400,26 +11397,17 @@ static int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, un sc_start4(ss, bl,type,100,sg->skill_lv,sg->skill_id,sg->group_id,0,sg->limit); break; - case UNT_PNEUMA: - case UNT_CHAOSPANIC: - case UNT_MAELSTROM: - if (!sce) - sc_start4(ss, bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit); - break; case UNT_BLOODYLUST: if (sg->src_id == bl->id) break; //Does not affect the caster. - if (!sce) { - TBL_PC *sd = BL_CAST(BL_PC, bl); //prevent fullheal exploit - if (sd && sd->bloodylust_tick && DIFF_TICK(gettick(), sd->bloodylust_tick) < skill_get_time2(SC_BLOODYLUST, 1)) - clif_skill_nodamage(&src->bl,bl,sg->skill_id,sg->skill_lv, - sc_start4(ss, bl, type, 100, sg->skill_lv, 1, 0, 0, skill_get_time(LK_BERSERK, sg->skill_lv))); - else { - if (sd) sd->bloodylust_tick = gettick(); - clif_skill_nodamage(&src->bl,bl,sg->skill_id,sg->skill_lv, - sc_start4(ss, bl, type, 100, sg->skill_lv, 0, 0, 0, skill_get_time(LK_BERSERK, sg->skill_lv))); - } - } + if( !sce && sc_start4(ss, bl,type,100,sg->skill_lv,0,SC__BLOODYLUST,0,sg->limit) ) + sc_start(ss, bl,SC__BLOODYLUST,100,sg->skill_lv,sg->limit); + break; + + case UNT_PNEUMA: + case UNT_CHAOSPANIC: + if (!sce) + sc_start4(ss, bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit); break; case UNT_WARP_WAITING: { @@ -12413,15 +12401,10 @@ int skill_unit_onleft (uint16 skill_id, struct block_list *bl, unsigned int tick case SO_WATER_INSIGNIA: case SO_WIND_INSIGNIA: case SO_EARTH_INSIGNIA: + case SC_BLOODYLUST: if (sce) status_change_end(bl, type, INVALID_TIMER); break; - case SC_BLOODYLUST: - if (sce) { - status_change_end(bl, type, INVALID_TIMER); - status_set_sp(bl, 0, 0); //set sp to 0 when quitting zone - } - break; case BA_DISSONANCE: case DC_UGLYDANCE: //Used for updating song timers in overlap instances { @@ -12908,6 +12891,22 @@ int skill_check_condition_castbegin(struct map_session_data* sd, uint16 skill_id return 0; } break; + case AS_CLOAKING: + { + static int dx[] = { 0, 1, 0, -1, -1, 1, 1, -1}; + static int dy[] = {-1, 0, 1, 0, -1, -1, 1, 1}; + + if( (sd->bl.type == BL_PC && battle_config.pc_cloak_check_type&1) + || (sd->bl.type != BL_PC && battle_config.monster_cloak_check_type&1) ) { //Check for walls. + int i; + ARR_FIND( 0, 8, i, map_getcell(sd->bl.m, sd->bl.x+dx[i], sd->bl.y+dy[i], CELL_CHKNOPASS) != 0 ); + if( i == 8 ) { + clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + return 0; + } + } + break; + } case AL_WARP: if(!battle_config.duel_allow_teleport && sd->duel_group) { // duel restriction [LuzZza] char output[128]; sprintf(output, msg_txt(sd,365), skill_get_name(AL_WARP)); @@ -15002,10 +15001,6 @@ int skill_clear_group (struct block_list *bl, int flag) if( flag&8 ) group[count++]= ud->skillunit[i]; break; - case SC_BLOODYLUST: - if (flag & 32) - group[count++] = ud->skillunit[i]; - break; default: if (flag&2 && skill_get_inf2(ud->skillunit[i]->skill_id)&INF2_TRAP) group[count++]= ud->skillunit[i]; @@ -15036,7 +15031,6 @@ struct skill_unit_group *skill_locate_element_field(struct block_list *bl) case SA_LANDPROTECTOR: case NJ_SUITON: case SO_WARMER: - case SC_BLOODYLUST: return ud->skillunit[i]; } } @@ -15317,6 +15311,34 @@ static int skill_trap_splash (struct block_list *bl, va_list ap) return 1; } +int skill_maelstrom_suction(struct block_list *bl, va_list ap) +{ + uint16 skill_id, skill_lv; + struct skill_unit *unit; + + skill_id = va_arg(ap,int); + skill_lv = va_arg(ap,int); + unit = (struct skill_unit *)bl; + + if( unit == NULL || unit->group == NULL ) + return 0; + + if( skill_get_inf2(skill_id)&INF2_TRAP ) + return 0; + + if( unit->group->skill_id == SC_MAELSTROM ){ + struct block_list *src; + if( (src = map_id2bl(unit->group->src_id)) ){ + int sp = unit->group->skill_lv * skill_lv; + if( src->type == BL_PC ) + sp += ((TBL_PC*)src)->status.job_level / 5; + status_heal(src, 0, sp/2, 1); + } + } + + return 0; +} + /*========================================== * *------------------------------------------*/ @@ -15405,6 +15427,9 @@ struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int nullpo_retr(NULL, group->unit); // crash-protection against poor coding nullpo_retr(NULL, unit=&group->unit[idx]); + if( map_getcell(map_id2bl(group->src_id)->m, x, y, CELL_CHKMAELSTROM) ) + return unit; + if(!unit->alive) group->alive_count++; diff --git a/src/map/skill.h b/src/map/skill.h index ccb35c23ad..bf583caf98 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -1865,6 +1865,7 @@ struct s_skill_magicmushroom_db { uint16 skill_id; }; extern struct s_skill_magicmushroom_db skill_magicmushroom_db[MAX_SKILL_MAGICMUSHROOM_DB]; +int skill_maelstrom_suction(struct block_list *bl, va_list ap); /** * Ranger **/ diff --git a/src/map/status.c b/src/map/status.c index c017497d58..04ee8ead17 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -496,10 +496,10 @@ void initChangeTables(void) { set_sc(MH_PAIN_KILLER , SC_PAIN_KILLER , SI_PAIN_KILLER , SCB_ASPD ); add_sc(MH_STYLE_CHANGE , SC_STYLE_CHANGE ); - set_sc(MH_TINDER_BREAKER , SC_TINDER_BREAKER2 , SI_TINDER_BREAKER, SCB_FLEE ); - set_sc(MH_TINDER_BREAKER , SC_TINDER_BREAKER , SI_TINDER_BREAKER_POSTDELAY, SCB_FLEE ); - set_sc(MH_CBC , SC_CBC, SI_CBC , SCB_FLEE ); - set_sc(MH_EQC , SC_EQC, SI_EQC , SCB_DEF2|SCB_BATK|SCB_MAXHP ); + set_sc(MH_TINDER_BREAKER , SC_TINDER_BREAKER2 , SI_TINDER_BREAKER , SCB_FLEE ); + set_sc(MH_TINDER_BREAKER , SC_TINDER_BREAKER , SI_TINDER_BREAKER_POSTDELAY , SCB_FLEE ); + set_sc(MH_CBC , SC_CBC , SI_CBC , SCB_FLEE ); + set_sc(MH_EQC , SC_EQC , SI_EQC , SCB_DEF2|SCB_BATK|SCB_MAXHP ); add_sc( MER_CRASH , SC_STUN ); set_sc( MER_PROVOKE , SC_PROVOKE , SI_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK ); @@ -635,7 +635,7 @@ void initChangeTables(void) { set_sc( SC_STRIPACCESSARY , SC__STRIPACCESSORY , SI_STRIPACCESSARY , SCB_DEX|SCB_INT|SCB_LUK ); set_sc_with_vfx( SC_MANHOLE , SC__MANHOLE , SI_MANHOLE , SCB_NONE ); add_sc( SC_CHAOSPANIC , SC_CONFUSION ); - set_sc_with_vfx( SC_BLOODYLUST , SC__BLOODYLUST , SI_BERSERK , SCB_DEF | SCB_DEF2 | SCB_MDEF | SCB_MDEF2 | SCB_FLEE | SCB_SPEED | SCB_ASPD | SCB_MAXHP | SCB_REGEN ); + add_sc( SC_BLOODYLUST , SC_BERSERK ); /** * Sura **/ @@ -1048,7 +1048,6 @@ void initChangeTables(void) { StatusChangeStateTable[SC_BERSERK] |= SCS_NOCHAT; StatusChangeStateTable[SC_SATURDAYNIGHTFEVER] |= SCS_NOCHAT; StatusChangeStateTable[SC_DEEPSLEEP] |= SCS_NOCHAT; - StatusChangeStateTable[SC__BLOODYLUST] |= SCS_NOCHAT; StatusChangeStateTable[SC_NOCHAT] |= SCS_NOCHAT|SCS_NOCHATCOND; } @@ -1233,8 +1232,6 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s status_change_end(target, SC_RAISINGDRAGON, INVALID_TIMER); if (sc->data[SC_SATURDAYNIGHTFEVER] && status->hp <= 100) status_change_end(target, SC_SATURDAYNIGHTFEVER, INVALID_TIMER); - if (sc->data[SC__BLOODYLUST] && status->hp <= 100) - status_change_end(target, SC__BLOODYLUST, INVALID_TIMER); } switch (target->type) { @@ -1367,7 +1364,7 @@ int status_heal(struct block_list *bl,int hp,int sp, int flag) } if(hp) { - if( sc && (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) ) { + if( sc && (sc->data[SC_BERSERK]) ) { if( flag&1 ) flag &= ~2; else @@ -3488,7 +3485,7 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str if ( (sc->data[SC_POISON] && !sc->data[SC_SLOWPOISON]) || (sc->data[SC_DPOISON] && !sc->data[SC_SLOWPOISON]) - || sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST] + || sc->data[SC_BERSERK] || sc->data[SC_TRICKDEAD] || sc->data[SC_BLEEDING] || sc->data[SC_MAGICMUSHROOM] @@ -4910,7 +4907,7 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change flee += flee * sc->data[SC_INCFLEERATE]->val1/100; if(sc->data[SC_SPIDERWEB] && sc->data[SC_SPIDERWEB]->val1) flee -= flee * 50/100; - if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) + if(sc->data[SC_BERSERK]) flee -= flee * 50/100; if(sc->data[SC_BLIND]) flee -= flee * 25/100; @@ -4957,7 +4954,7 @@ static defType status_calc_def(struct block_list *bl, struct status_change *sc, if(!sc || !sc->count) return (defType)cap_value(def,DEFTYPE_MIN,DEFTYPE_MAX); - if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) + if(sc->data[SC_BERSERK]) return 0; if(sc->data[SC_SKA]) return sc->data[SC_SKA]->val3; @@ -5037,7 +5034,7 @@ static signed short status_calc_def2(struct block_list *bl, struct status_change return (short)cap_value(def2,1,SHRT_MAX); #endif - if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) + if(sc->data[SC_BERSERK]) return 0; if(sc->data[SC_ETERNALCHAOS]) return 0; @@ -5095,7 +5092,7 @@ static defType status_calc_mdef(struct block_list *bl, struct status_change *sc, if(!sc || !sc->count) return (defType)cap_value(mdef,DEFTYPE_MIN,DEFTYPE_MAX); - if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) + if(sc->data[SC_BERSERK]) return 0; if(sc->data[SC_BARRIER]) return 100; @@ -5145,7 +5142,7 @@ static signed short status_calc_mdef2(struct block_list *bl, struct status_chang #endif - if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) + if(sc->data[SC_BERSERK]) return 0; if(sc->data[SC_SKA]) return 90; @@ -5290,7 +5287,7 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha val = max( val, 1 * pc_checkskill(sd,TF_MISS) ); if( sc->data[SC_CLOAKING] && (sc->data[SC_CLOAKING]->val4&1) == 1 ) val = max( val, sc->data[SC_CLOAKING]->val1 >= 10 ? 25 : 3 * sc->data[SC_CLOAKING]->val1 - 3 ); - if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) + if( sc->data[SC_BERSERK] ) val = max( val, 25 ); if( sc->data[SC_RUN] ) val = max( val, 55 ); @@ -5405,7 +5402,7 @@ static short status_calc_aspd(struct block_list *bl, struct status_change *sc, s } } - if((sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) && skills1 < 15) + if(sc->data[SC_BERSERK] && skills1 < 15) skills1 = 15; else if(sc->data[SC_MADNESSCANCEL] && skills1 < 15) // needs more info skills1 = 15; @@ -5550,7 +5547,7 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change * } aspd_rate -= max; - if((sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST])) + if(sc->data[SC_BERSERK]) aspd_rate -= 300; else if(sc->data[SC_MADNESSCANCEL]) aspd_rate -= 200; @@ -5652,7 +5649,7 @@ static unsigned int status_calc_maxhp(struct block_list *bl, struct status_chang maxhp += maxhp * sc->data[SC_APPLEIDUN]->val2/100; if(sc->data[SC_DELUGE]) maxhp += maxhp * sc->data[SC_DELUGE]->val2/100; - if (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST]) + if(sc->data[SC_BERSERK]) maxhp += maxhp * 2; if(sc->data[SC_MARIONETTE]) maxhp -= 1000; @@ -6310,7 +6307,6 @@ int status_get_sc_def(struct block_list *src, struct block_list *bl, enum sc_typ case SC__LAZINESS: case SC__UNLUCKY: case SC__WEAKNESS: - case SC__BLOODYLUST: return 0; } @@ -6690,12 +6686,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty break; //There all like berserk, do not everlap each other - case SC__BLOODYLUST: - if(!sd) return 0; //should only affect player case SC_BERSERK: - if (((type == SC_BERSERK) && (sc->data[SC_SATURDAYNIGHTFEVER] || sc->data[SC__BLOODYLUST])) - || ((type == SC__BLOODYLUST) && (sc->data[SC_SATURDAYNIGHTFEVER] || sc->data[SC_BERSERK])) - ) + if(sc->data[SC_SATURDAYNIGHTFEVER] || sc->data[SC__BLOODYLUST]) return 0; break; @@ -6946,7 +6938,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty } break; case SC_SATURDAYNIGHTFEVER: - if (sc->data[SC_BERSERK] || sc->data[SC_INSPIRATION] || sc->data[SC__BLOODYLUST]) + if (sc->data[SC_BERSERK] || sc->data[SC_INSPIRATION]) return 0; break; } @@ -7067,8 +7059,9 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty status_change_end(bl, SC_CLOSECONFINE, INVALID_TIMER); status_change_end(bl, SC_CLOSECONFINE2, INVALID_TIMER); break; - case SC__BLOODYLUST: case SC_BERSERK: + if( val3 == SC__BLOODYLUST ) + break; if(battle_config.berserk_cancels_buffs) { status_change_end(bl, SC_ONEHAND, INVALID_TIMER); status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER); @@ -7324,7 +7317,7 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty val4 = sce->val4; break; case SC_LERADSDEW: - if (sc && (sc->data[SC_BERSERK] || sc->data[SC__BLOODYLUST])) + if (sc && sc->data[SC_BERSERK]) return 0; case SC_SHAPESHIFT: case SC_PROPERTYWALK: @@ -7785,9 +7778,10 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty break; case SC_BERSERK: - if (!sc->data[SC_ENDURE] || !sc->data[SC_ENDURE]->val4) + if( val3 == SC__BLOODYLUST ) + sc_start(src,bl,(sc_type)val3,100,val1,tick); + if (!val3 && !(sc->data[SC_ENDURE] && sc->data[SC_ENDURE]->val4)) sc_start4(src,bl, SC_ENDURE, 100,10,0,0,2, tick); - case SC__BLOODYLUST: //HP healing is performing after the calc_status call. //Val2 holds HP penalty if (!val4) val4 = skill_get_time2(status_sc2skill(type),val1); @@ -8962,7 +8956,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty break; case SC_BERSERK: opt_flag = 0; -// case SC__BLOODYLUST: sc->opt3 |= OPT3_BERSERK; break; // case ???: // doesn't seem to do anything @@ -9101,7 +9094,6 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty pet_sc_check(sd, type); //Skotlex: Pet Status Effect Healing switch (type) { - case SC__BLOODYLUST: case SC_BERSERK: if (!(sce->val2)) { //don't heal if already set status_heal(bl, status->max_hp, 0, 1); //Do not use percent_heal as this healing must override BERSERK's block. @@ -9580,15 +9572,15 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const case SC_BERSERK: case SC_SATURDAYNIGHTFEVER: - //If val2 is removed, no HP penalty (dispelled?) [Skotlex] - if (status->hp > 100 && sce->val2) + if(status->hp > 200 && sc && sc->data[SC__BLOODYLUST]) { + status_percent_heal(bl, 100, 0); + status_change_end(bl, SC__BLOODYLUST, INVALID_TIMER); + } else if (status->hp > 100 && sce->val2) //If val2 is removed, no HP penalty (dispelled?) [Skotlex] status_set_hp(bl, 100, 0); - if(sc->data[SC_ENDURE] && sc->data[SC_ENDURE]->val4 == 2) - { + if(sc->data[SC_ENDURE] && sc->data[SC_ENDURE]->val4 == 2) { sc->data[SC_ENDURE]->val4 = 0; status_change_end(bl, SC_ENDURE, INVALID_TIMER); } - case SC__BLOODYLUST: sc_start4(bl, bl, SC_REGENERATION, 100, 10,0,0,(RGN_HP|RGN_SP), skill_get_time(LK_BERSERK, sce->val1)); if( type == SC_SATURDAYNIGHTFEVER ) //Sit down force of Saturday Night Fever has the duration of only 3 seconds. sc_start(bl, bl,SC_SITDOWN_FORCE,100,sce->val1,skill_get_time2(WM_SATURDAY_NIGHT_FEVER,sce->val1)); @@ -9875,7 +9867,6 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const break; case SC_BERSERK: opt_flag = 0; -// case SC__BLOODYLUST: sc->opt3 &= ~OPT3_BERSERK; break; // case ???: // doesn't seem to do anything @@ -10257,7 +10248,6 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data) return 0; } break; - case SC__BLOODYLUST: case SC_BERSERK: // 5% every 10 seconds [DracoRPG] if( --( sce->val3 ) > 0 && status_charge(bl, sce->val2, 0) && status->hp > 100 ) @@ -11015,7 +11005,6 @@ int status_change_clear_buffs (struct block_list* bl, int type) continue; break; //The rest are buffs that can be removed. - case SC__BLOODYLUST: case SC_BERSERK: case SC_SATURDAYNIGHTFEVER: if (!(type&1)) diff --git a/src/map/unit.c b/src/map/unit.c index ba67b9319e..889d925c4e 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -987,8 +987,7 @@ int unit_can_move(struct block_list *bl) { (sc->data[SC_DANCING]->val1&0xFFFF) == CG_MOONLIT || (sc->data[SC_DANCING]->val1&0xFFFF) == CG_HERMODE ) ) - || (sc->data[SC_CLOAKING] && //Need wall at level 1-2 - sc->data[SC_CLOAKING]->val1 < 3 && !(sc->data[SC_CLOAKING]->val4&1)) + || (sc->data[SC_CLOAKING] && sc->data[SC_CLOAKING]->val1 < 3) // Can't move at level less than 3 ) return 0; @@ -1475,6 +1474,11 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, ui } } + if( (skill_id >= SC_MANHOLE && skill_id <= SC_FEINTBOMB) && map_getcell(src->m, skill_x, skill_y, CELL_CHKMAELSTROM) ) { + clif_skill_fail(sd,skill_id,USESKILL_FAIL_LEVEL,0); + return 0; + } + if (!status_check_skilluse(src, NULL, skill_id, 0)) return 0;