From c1d7d16b0e4010b27591f37ee93a1ca8d1137ecb Mon Sep 17 00:00:00 2001 From: Inkfish Date: Fri, 19 Jun 2009 13:26:50 +0000 Subject: * Implemented script command "areamobuseskill" and skill NPC_INVINCIBLE and NPC_INVINCIBLEOFF. (topic:217330) * Using items no longer cancels invincibility(but using target and ground skills through items does). (bugreport:3259) * Fixed Butterfly Wings not working during GVG. (bugreport:3264) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@13897 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/battle.c | 22 +++++++++++------ src/map/battle.h | 1 + src/map/clif.c | 4 +-- src/map/mob.c | 2 -- src/map/mob.h | 3 +++ src/map/script.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/map/skill.c | 15 ++++++++---- src/map/skill.h | 5 +--- src/map/status.c | 13 +++++++++- src/map/status.h | 4 ++- 10 files changed, 122 insertions(+), 22 deletions(-) (limited to 'src/map') diff --git a/src/map/battle.c b/src/map/battle.c index 0f943c5c4..17f052bb0 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -294,12 +294,15 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag if(!damage) return 0; } - - if (skill_num == PA_PRESSURE) - return damage; //This skill bypass everything else. sc = status_get_sc(bl); + if( sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) + return 0; + + if (skill_num == PA_PRESSURE) + return damage; //This skill bypass everything else. + if( sc && sc->count ) { //First, sc_*'s that reduce damage to 0. @@ -482,12 +485,16 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag status_heal(src, damage*sce->val4/100, 0, 3); } - //SC effects from caster side. Currently none. -/* + + //SC effects from caster side. sc = status_get_sc(src); - if (sc && sc->count) { + + if (sc && sc->count) + { + if( sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) + damage += damage * 75 / 100; } -*/ + if (battle_config.pk_mode && sd && bl->type == BL_PC && damage) { if (flag & BF_SKILL) { //Skills get a different reduction than non-skills. [Skotlex] @@ -3820,6 +3827,7 @@ static const struct _battle_data { { "display_status_timers", &battle_config.display_status_timers, 1, 0, 1, }, { "skill_add_heal_rate", &battle_config.skill_add_heal_rate, 7, 0, INT_MAX, }, { "eq_single_target_reflectable", &battle_config.eq_single_target_reflectable, 1, 0, 1, }, + { "invincible.nodamage", &battle_config.invincible_nodamage, 0, 0, 1, }, // BattleGround Settings { "bg_update_interval", &battle_config.bg_update_interval, 1000, 100, INT_MAX, }, { "bg_short_attack_damage_rate", &battle_config.bg_short_damage_rate, 80, 0, INT_MAX, }, diff --git a/src/map/battle.h b/src/map/battle.h index c559c0ba5..8e262cc5e 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -466,6 +466,7 @@ extern struct Battle_Config int display_status_timers; //Show or hide skill buff/delay timers in recent clients [Sara] int skill_add_heal_rate; //skills that bHealPower has effect on [Inkfish] int eq_single_target_reflectable; + int invincible_nodamage; // [BattleGround Settings] int bg_update_interval; diff --git a/src/map/clif.c b/src/map/clif.c index ddb0fcca8..7a16ab73b 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -8940,8 +8940,6 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd) } else if (pc_istrading(sd)) return; - - pc_delinvincibletimer(sd); //Whether the item is used or not is irrelevant, the char ain't idle. [Skotlex] sd->idletime = last_tick; @@ -9510,6 +9508,8 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) { if( skilllv != sd->skillitemlv ) skilllv = sd->skillitemlv; + if( !(skill_get_inf(skillnum)&INF_SELF_SKILL) ) + pc_delinvincibletimer(sd); // Target skills thru items cancel invincibility. [Inkfish] unit_skilluse_id(&sd->bl, target_id, skillnum, skilllv); return; } diff --git a/src/map/mob.c b/src/map/mob.c index 834d44220..367d2ff7d 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -50,8 +50,6 @@ #define MOB_MAX_DELAY (24*3600*1000) #define MAX_MINCHASE 30 //Max minimum chase value to use for mobs. #define RUDE_ATTACKED_COUNT 2 //After how many rude-attacks should the skill be used? -//Used to determine default enemy type of mobs (for use in eachinrange calls) -#define DEFAULT_ENEMY_TYPE(md) (md->special_state.ai?BL_CHAR:BL_PC|BL_HOM|BL_MER) //Dynamic mob database, allows saving of memory when there's big gaps in the mob_db [Skotlex] struct mob_db *mob_db_data[MAX_MOB_DB+1]; diff --git a/src/map/mob.h b/src/map/mob.h index b0a7a11e9..360c69e06 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -35,6 +35,9 @@ #define MOB_CLONE_START (MAX_MOB_DB-999) #define MOB_CLONE_END MAX_MOB_DB +//Used to determine default enemy type of mobs (for use in eachinrange calls) +#define DEFAULT_ENEMY_TYPE(md) (md->special_state.ai?BL_CHAR:BL_PC|BL_HOM|BL_MER) + //Mob skill states. enum MobSkillState { MSS_ANY = -1, diff --git a/src/map/script.c b/src/map/script.c index f09b24a5c..28cea9ed1 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -13655,6 +13655,80 @@ BUILDIN_FUNC(setfont) return 0; } +static int buildin_mobuseskill_sub(struct block_list *bl,va_list ap) +{ + TBL_MOB* md = (TBL_MOB*)bl; + struct block_list *tbl; + int mobid = va_arg(ap,int); + int skillid = va_arg(ap,int); + int skilllv = va_arg(ap,int); + int casttime = va_arg(ap,int); + int cancel = va_arg(ap,bool); + int emotion = va_arg(ap,int); + int target = va_arg(ap,int); + + if( md->class_ != mobid ) + return 0; + + if( md->ud.skilltimer != -1 ) // Cancel the casting skill. + unit_skillcastcancel(bl,0); + + // 0:self, 1:target, 2:master, default:random + switch( target ) + { + case 0: tbl = map_id2bl(md->bl.id); break; + case 1: tbl = map_id2bl(md->target_id); break; + case 2: tbl = map_id2bl(md->master_id); break; + default:tbl = battle_getenemy(&md->bl, DEFAULT_ENEMY_TYPE(md),skill_get_range2(&md->bl, skillid, skilllv)); break; + } + + if( !tbl ) + return 0; + + if( skill_get_casttype(skillid) == CAST_GROUND ) + unit_skilluse_pos2(&md->bl, tbl->x, tbl->y, skillid, skilllv, casttime, cancel); + else + unit_skilluse_id2(&md->bl, tbl->id, skillid, skilllv, casttime, cancel); + + clif_emotion(&md->bl, emotion); + + return 0; +} +/*========================================== + * areamobuseskill "Map Name",,,,,,"Skill Name"/,,,,,; + *------------------------------------------*/ +BUILDIN_FUNC(areamobuseskill) +{ + int m,x1,y1,x2,y2,mobid,skillid,skilllv,casttime,emotion,target; + bool cancel; + + if( m = map_mapname2mapid(script_getstr(st,2)) < 0 ) + { + ShowError("areamobuseskill: invalid map name.\n"); + return 0; + } + + skillid = ( script_isstring(st,8) ? skill_name2id(script_getstr(st,8)) : script_getnum(st,8) ); + + skilllv = script_getnum(st,9); + if( skilllv > battle_config.mob_max_skilllvl ) + skilllv = battle_config.mob_max_skilllvl; + + x1 = script_getnum(st,3); + y1 = script_getnum(st,4); + x2 = script_getnum(st,5); + y2 = script_getnum(st,6); + + mobid = script_getnum(st,7); + casttime = script_getnum(st,10); + cancel = script_getnum(st,11); + emotion = script_getnum(st,12); + target = script_getnum(st,13); + + map_foreachinarea(buildin_mobuseskill_sub, m, x1, y1, x2, y2, BL_MOB, mobid,skillid,skilllv,casttime,cancel,emotion,target); + return 0; +} + // declarations that were supposed to be exported from npc_chat.c #ifdef PCRE_SUPPORT BUILDIN_FUNC(defpattern); @@ -14014,6 +14088,7 @@ struct script_function buildin_func[] = { BUILDIN_DEF(mercenary_set_faith,"ii"), BUILDIN_DEF(readbook,"ii"), BUILDIN_DEF(setfont,"i"), + BUILDIN_DEF(areamobuseskill,"siiiiiviiiii"), // WoE SE BUILDIN_DEF(agitstart2,""), BUILDIN_DEF(agitend2,""), diff --git a/src/map/skill.c b/src/map/skill.c index f33b7bb59..ef3b65dac 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -360,7 +360,10 @@ int skillnotok (int skillid, struct map_session_data *sd) return 1; // invalid skill id if (battle_config.gm_skilluncond && pc_isGM(sd) >= battle_config.gm_skilluncond) - return 0; // GMs can do any damn thing they want + return 0; // GMs can do any damn thing they want + + if( skillid == AL_TELEPORT && sd->skillitem == skillid && sd->skillitemlv > 2 ) + return 0; // Teleport lv 3 bypasses this check.[Inkfish] if (sd->blockskill[i] > 0) return 1; @@ -385,10 +388,10 @@ int skillnotok (int skillid, struct map_session_data *sd) } return 0; case AL_TELEPORT: - // if(map[m].flag.noteleport) { - // clif_skill_teleportmessage(sd,0); - // return 1; - // } + if(map[m].flag.noteleport) { + clif_skill_teleportmessage(sd,0); + return 1; + } return 0; // gonna be checked in 'skill_castend_nodamage_id' case WE_CALLPARTNER: case WE_CALLPARENT: @@ -3662,6 +3665,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case NPC_DEFENDER: case NPC_MAGICMIRROR: case ST_PRESERVE: + case NPC_INVINCIBLE: + case NPC_INVINCIBLEOFF: clif_skill_nodamage(src,bl,skillid,skilllv, sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv))); break; diff --git a/src/map/skill.h b/src/map/skill.h index 795cdf65b..02a9a760a 100644 --- a/src/map/skill.h +++ b/src/map/skill.h @@ -972,15 +972,12 @@ enum e_skill { NPC_WIDESOULDRAIN, ALL_INCCARRY = 681, - //NPC_TALK = 682, NPC_HELLPOWER = 683, NPC_WIDEHELLDIGNITY, - /* NPC_INVINCIBLE, NPC_INVINCIBLEOFF, - */ - NPC_ALLHEAL = 687, + NPC_ALLHEAL, //GM_SANDMAN = 688, CASH_BLESSING = 689, CASH_INCAGI, diff --git a/src/map/status.c b/src/map/status.c index 54d019a48..467626106 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -388,6 +388,8 @@ void initChangeTables(void) set_sc( NPC_HELLPOWER , SC_HELLPOWER , SI_HELLPOWER , SCB_NONE ); set_sc( NPC_WIDEHELLDIGNITY , SC_HELLPOWER , SI_HELLPOWER , SCB_NONE ); + set_sc( NPC_INVINCIBLE , SC_INVINCIBLE , SI_INVINCIBLE , SCB_SPEED ); + set_sc( NPC_INVINCIBLEOFF , SC_INVINCIBLEOFF , SI_BLANK , SCB_SPEED ); set_sc( CASH_BLESSING , SC_BLESSING , SI_BLESSING , SCB_STR|SCB_INT|SCB_DEX ); set_sc( CASH_INCAGI , SC_INCREASEAGI , SI_INCREASEAGI , SCB_AGI|SCB_SPEED ); @@ -665,6 +667,13 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s sc = status_get_sc(target); + if( battle_config.invincible_nodamage && src && sc && sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) + { + if( !sp ) + return 0; + hp = 0; + } + if( hp && !(flag&1) ) { if( sc ) { struct status_change_entry *sce; @@ -3798,6 +3807,8 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha val = max( val, 55 ); if( sc->data[SC_AVOID] ) val = max( val, 10 * sc->data[SC_AVOID]->val1 ); + if( sc->data[SC_INVINCIBLE] && !sc->data[SC_INVINCIBLEOFF] ) + val = max( val, 75 ); //FIXME: official items use a single bonus for this [ultramage] if( sc->data[SC_SPEEDUP0] ) // temporary item-based speedup @@ -3822,7 +3833,7 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha speed = 200; if( sc->data[SC_DEFENDER] ) speed = max(speed, 200); - if( sc->data[SC_WALKSPEED] ) // ChangeSpeed + if( sc->data[SC_WALKSPEED] && sc->data[SC_WALKSPEED]->val1 > 0 ) // ChangeSpeed speed = speed * 100 / sc->data[SC_WALKSPEED]->val1; } diff --git a/src/map/status.h b/src/map/status.h index 389817a65..2d45b2626 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -315,6 +315,8 @@ typedef enum sc_type { SC_JEXPBOOST, SC_IGNOREDEF, SC_HELLPOWER, + SC_INVINCIBLE, //295 + SC_INVINCIBLEOFF, SC_MAX, //Automatically updated max, used in for's to check we are within bounds. } sc_type; @@ -633,7 +635,7 @@ enum si_type { // SI_REUSE_LIMIT_D = 308, // SI_REUSE_LIMIT_E = 309, // SI_REUSE_LIMIT_F = 310, -// SI_INVINCIBLE = 311, + SI_INVINCIBLE = 311, SI_CASH_PLUSONLYJOBEXP = 312, // SI_PARTYFLEE = 313, // SI_ANGEL_PROTECT = 314, -- cgit v1.2.3-60-g2f50