From ed39c7518c82ede371b9b74f6eca8deb66a73e31 Mon Sep 17 00:00:00 2001 From: Jesusaves Date: Sun, 11 Apr 2021 08:38:20 -0300 Subject: Fix bugs, prepare to implement the *real* skill loop --- npc/magic/config.txt | 4 +- npc/magic/final.txt | 464 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 466 insertions(+), 2 deletions(-) create mode 100644 npc/magic/final.txt (limited to 'npc/magic') diff --git a/npc/magic/config.txt b/npc/magic/config.txt index 608b2223..1cde0148 100644 --- a/npc/magic/config.txt +++ b/npc/magic/config.txt @@ -379,9 +379,9 @@ function script poolskill { // unpoolskill(skill) function script unpoolskill { - .@f=getpoolskillFID(getarg(0); + .@f=getpoolskillFID(getarg(0)); if (FOCUSING & .@f) - FOCUSING=FOCUSING ^ .@f); + FOCUSING=FOCUSING ^ .@f; return; } diff --git a/npc/magic/final.txt b/npc/magic/final.txt new file mode 100644 index 00000000..c64c9c95 --- /dev/null +++ b/npc/magic/final.txt @@ -0,0 +1,464 @@ +// TMW2 scripts. +// Authors: +// Jesusalva +// TMW Org. +// Description: +// HUB functions (Magic) +// HUB_SkillInvoke ( ) +function script HUB_SkillInvoke { + // Something is... wrong + if (!@skillId) { + Exception("ILLEGAL SKILL PASSED TO HUB. It has been compromised, Jim.", RB_DEBUGMES|RB_IRCBROADCAST); + debugmes "Legal Caster: %s", strcharinfo(0); + debugmes "Effective Caster: %d", @skillCaster; + return; + } + + /* *********************************************************************** */ + // TODO: Detect what was script-cast and what was player-case. Then, readd RB_IRCBROADCAST + // If you can't do this: You can't do this + if (getskilllv(@skillId) < @skillLv && @skillId != BS_GREED) + Exception("System ERROR, HSI."+@skillId+" INVALID CAST (got "+@skillLv+" expected "+getskilllv(@skillId)+", sub-LC."+(getcharid(3)-2000000)+")", RB_DEBUGMES|RB_ISFATAL); + // You are AFK for over 3 minutes, that's crazy, disregard + if (checkidle() > 180) + return; + + // Record to database + skillInvoke[@skillId] = skillInvoke[@skillId] + 1; + + // Script-based skills + /* *********************************************************************** */ + switch (@skillId) { + case TMW2_FAKESKILL: + charcommand("@refresh"); // Possibly broken on too up-to-date Herc + break; + case EVOL_AREA_PROVOKE: + if (@skillTargetX && @skillTargetY) + massprovoke(1+@skillLv, getmap(), @skillTargetX, @skillTargetY); + else + massprovoke(1+@skillLv); + // SC_PROVOKE ? + GetManaExp(@skillId, rand2(1,3)); + break; + //////////////////////////////// + // XXX: Healing Class + case TMW2_FIRSTAID: + .@PW=90+(10*@skillLv); + // First aid only works on you, so + .@heal=max(AdjustSpellpower(.@PW), AdjustAttackpower(.@PW)); + heal .@heal, 0; + GetManaExp(TMW2_HEALING, 1); + break; + case TMW2_HEALING: + .@PW=130+(20*@skillLv); + harm(@skillTarget, -AdjustSpellpower(.@PW), HARM_MISC); + GetManaExp(TMW2_HEALING, 2); + break; + case TMW2_MAGNUSHEAL: + // Area healing + .@PW=200+(20*@skillLv); + .@RG=4+(@skillLv/5); + areaharm(@skillTarget, .@RG, -AdjustSpellpower(.@PW), HARM_MISC, "filter_friendly"); + GetManaExp(TMW2_HEALING, 3); + break; + //////////////////////////////// + // XXX: Fire Class + // (May burn targets for damage over time) + case TMW2_FIREARROW: + .@PW=140+(10*@skillLv); + // 4% chance, 2.5s + harm(@skillTarget, AdjustSpellpower(.@PW), HARM_MAGI, Ele_Fire); + sc_start SC_BLOODING, 4500, 1, 400, SCFLAG_NONE, @skillTarget; + GetManaExp(TMW2_FIREBALL, 1); + break; + case TMW2_FIREBALL: + .@PW=140+(10*@skillLv); + .@RG=2+(@skillLv/5); + // 22% chance, 2.5s + areaharm(@skillTarget, .@RG, AdjustSpellpower(.@PW), HARM_MAGI, Ele_Fire); + sc_start SC_BLOODING, 2500, 1, 4200, SCFLAG_NONE, @skillTarget; + GetManaExp(TMW2_FIREBALL, 2); + break; + case TMW2_ARMAGEDDON: + .@PW=140+(10*@skillLv); + .@RG=5+(@skillLv/5); + // 18% chance, 3s, 3x3 radius + areaharm(@skillTarget, .@RG, AdjustSpellpower(.@PW), HARM_MAGI, Ele_Fire); + areasc(.@RG, 6000, SC_BLOODING, BL_MOB|BL_PC|BL_HOM|BL_MER, 1, "filter_hostile", @skillTarget, 1800); + GetManaExp(TMW2_FIREBALL, 3); + break; + //////////////////////////////// + // XXX: Holy Class + // (Single DPS + AOE) + case TMW2_NAPALMBEAT: + .@PW=35+(5*@skillLv); + .@dmg=AdjustSpellpower(.@PW); + .@RG=2+(@skillLv/3); + harm(@skillTarget, .@dmg/10, HARM_MAGI, Ele_Holy); + areaharm(@skillTarget, .@RG, .@dmg, HARM_MAGI, Ele_Holy); + GetManaExp(TMW2_HOLYLIGHT, 1); + break; + case TMW2_HOLYLIGHT: + .@PW=125+(25*@skillLv); + .@dmg=AdjustSpellpower(.@PW); + harm(@skillTarget, .@dmg, HARM_MAGI, Ele_Holy); + areaharm(@skillTarget, 1, .@dmg/5, HARM_MAGI, Ele_Holy); + GetManaExp(TMW2_HOLYLIGHT, 2); + break; + case TMW2_JUDGMENT: + .@PW=250+(50*@skillLv); + .@SPW=60+(15*@skillLv); + .@dmg=AdjustSpellpower(.@PW); + .@dsub=AdjustSpellpower(.@SPW); + .@RG=3+(@skillLv/5); + harm(@skillTarget, .@dmg, HARM_MAGI, Ele_Holy); + areaharm(@skillTarget, .@RG, .@dsub, HARM_MAGI, Ele_Holy); + GetManaExp(TMW2_HOLYLIGHT, 3); + break; + //////////////////////////////// + // XXX: Wind Class + // (Smaller cooldown than others) + case TMW2_MAGICSTRIKE: + .@PW=125+(25*@skillLv); + .@dmg=AdjustSpellpower(.@PW); + harm(@skillTarget, .@dmg, HARM_MAGI, Ele_Wind); + GetManaExp(TMW2_LIGHTNINGBOLT, 1); + break; + case TMW2_LIGHTNINGBOLT: + .@PW=150+(50*@skillLv); + .@dmg=AdjustSpellpower(.@PW); + harm(@skillTarget, .@dmg, HARM_MAGI, Ele_Wind); + GetManaExp(TMW2_LIGHTNINGBOLT, 2); + break; + case TMW2_TEMPEST: + .@PW=125+(25*@skillLv); + .@dmg=AdjustSpellpower(.@PW); + .@RG=2+(@skillLv/5); + areaharm(@skillTarget, .@RG, .@dmg, HARM_MAGI, Ele_Wind); + GetManaExp(TMW2_LIGHTNINGBOLT, 3); + break; + //////////////////////////////// + // XXX: Ice Class + // (May freeze the targets) + case TMW2_FROSTDIVER: + .@PW=80+(10*@skillLv); + // 22% chance, 2.5s + harm(@skillTarget, AdjustSpellpower(.@PW), HARM_MAGI, Ele_Water); + sc_start SC_FREEZE, 2500, 1, 2200, SCFLAG_NONE, @skillTarget; + GetManaExp(TMW2_NILFHEIM, 1); + break; + case TMW2_FROSTNOVA: + .@PW=80+(10*@skillLv); + .@RG=2+(@skillLv/5); + // 18% chance, 3s, 3x3 radius + areaharm(@skillTarget, .@RG, AdjustSpellpower(.@PW), HARM_MAGI, Ele_Water); + areasc(.@RG, 3000, SC_FREEZE, BL_MOB|BL_PC|BL_HOM|BL_MER, 1, "filter_hostile", @skillTarget, 1800); + GetManaExp(TMW2_NILFHEIM, 2); + break; + case TMW2_NILFHEIM: + // Nilfheim cast on self? + .@PW=80+(10*@skillLv); + .@RG=4+(@skillLv/5); + areaharm(getcharid(3), .@RG*3/2, AdjustSpellpower(.@PW), HARM_MAGI, Ele_Water); + areasc(.@RG, 15000, SC_FREEZE, BL_PC | BL_MOB | BL_MER | BL_HOM, 1, "filter_hostile"); + // Maybe filter_notme() would work better, indeed + GetManaExp(TMW2_NILFHEIM, 3); + break; + //////////////////////////////// + // XXX: Earth Class + // DEF Effects at Gaia Break, more expensive + case TMW2_METEORSTRIKE: + .@PW=130+(20*@skillLv); + .@dmg=AdjustSpellpower(.@PW); + .@TM=1200+(@skillLv*300); + harm(@skillTarget, .@dmg, HARM_MAGI, Ele_Earth); + sc_start SC_STUN, .@TM, 1, 800, SCFLAG_NONE, @skillTarget; + GetManaExp(TMW2_METEORSTRIKE, 1); + break; + case TMW2_METEORSHOWER: + .@PW=130+(15*@skillLv); + .@dmg=AdjustSpellpower(.@PW); + .@RG=3+(@skillLv/5); + .@TM=800+(@skillLv*200); + areaharm(@skillTarget, .@RG, .@dmg, HARM_MAGI, Ele_Earth); + areasc(.@RG, .@TM, SC_STUN, BL_MOB | BL_PC | BL_HOM | BL_MER, 1, "filter_hostile", @skillTarget, 800); + GetManaExp(TMW2_METEORSTRIKE, 2); + break; + case TMW2_GAIABREAK: + .@PWA=170+(30*@skillLv); + .@PWB=110+(10*@skillLv); + .@dmg=AdjustSpellpower(.@PWA); + .@dsub=AdjustSpellpower(.@PWB); + harm(@skillTarget, .@dmg, HARM_MAGI, Ele_Earth); + rectharm(@skillTarget, 2, 5, .@dsub, HARM_MAGI, Ele_Earth); + areasc(2, 5000, SC_INCDEFRATE, BL_PC, 10, "filter_friendly"); + GetManaExp(TMW2_METEORSTRIKE, 3); + break; + //////////////////////////////// + // XXX: Physical Class (Regular) + case TMW2_FALKONSTRIKE: + .@PW=100+(25*@skillLv); + .@ST=0+(10*@skillLv); + .@TM=100+(90*@skillLv); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral); + sc_start SC_STUN, .@TM, 1, .@ST, SCFLAG_NONE, @skillTarget; + GetManaExp(@skillId, rand2(1,3)); + break; + case TMW2_GROUNDSTRIKE: + .@PW=50+(40*@skillLv); + .@dmg=AdjustAttackpower(.@PW); + .@RG=2+(@skillLv/5); + .@TM=100+(@skillLv*200); + .@ST=500+(100*@skillLv); + .@EF=any(SC_STUN, SC_BLIND, SC_BLOODING, SC_BLIND, SC_BLOODING); + areaharm(@skillTarget, .@RG, .@dmg, HARM_PHYS, Ele_Neutral); + areasc(.@RG, .@TM, .@EF, BL_MOB | BL_PC | BL_HOM | BL_MER, 1, "filter_hostile", @skillTarget, .@ST); + GetManaExp(@skillId, rand2(1,3)); + break; + case TMW2_SUPREMEATTACK: + .@PW=100+(50*@skillLv); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral); + GetManaExp(@skillId, rand2(1,3)); + break; + //////////////////////////////// + // XXX: Physical Class (Archery) + case TMW2_CHARGEDARROW: + .@PW=100+(50*@skillLv); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral); + GetManaExp(@skillId, rand2(1,3)); + break; + case TMW2_ARROWSHOWER: + .@PW=150+(10*@skillLv); + .@dmg=AdjustAttackpower(.@PW); + .@RG=1+(@skillLv/3); + areaharm(@skillTarget, .@RG, .@dmg, HARM_PHYS, Ele_Neutral); + GetManaExp(@skillId, rand2(1,3)); + break; + //////////////////////////////// + // XXX: Brawling Class + case TMW2_BRAWLING: + // 75x3 = 225 + .@PW=70+(5*@skillLv); + // Using a shield, so power is halved + if (getequipid(EQI_HAND_L) > 0) + .@PW=.@PW/2; + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral); + sleep2(10); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral); + sleep2(10); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral); + break; + case TMW2_BEARSTRIKE: + // 60x5 = 300 + .@PW=55+(5*@skillLv); + // Using a shield, so power is halved + if (getequipid(EQI_HAND_L) > 0) + .@PW=.@PW/2; + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral); + sleep2(10); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral); + sleep2(10); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral); + sleep2(10); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral); + sleep2(10); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral); + break; + case TMW2_ALLINONE: + // 45x8 = 360 + .@PW=40+(5*@skillLv); + // Using a shield, so power is halved + if (getequipid(EQI_HAND_L) > 0) + .@PW=.@PW/2; + //harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Neutral); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Fire); + sleep2(10); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Water); + sleep2(10); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Earth); + sleep2(10); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Wind); + sleep2(10); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Holy); + sleep2(10); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Shadow); + sleep2(10); + harm(@skillTarget, AdjustAttackpower(.@PW), HARM_PHYS, Ele_Ghost); + sleep2(10); + // The main elemental-less blast hits all in same square, + // and also hits behind (and on your square) + rectharm(@skillTarget, 0, 1, AdjustAttackpower(.@PW/2), HARM_PHYS, Ele_Neutral); + break; + + //////////////////////////////// + // CLASS_OTHER + case TMW2_PARUM: + SK_parum(); + break; + case TMW2_DEMURE: + SK_Demure(); + break; + case TMW2_DRAGOKIN: + SK_Dragokin(); + break; + // Summons which never fail + case TMW2_ZARKOR: + alignment_cansummon(); + SummonMagic(@skillId, CaveMaggot, 2, @skillLv); + GetManaExp(@skillId, 1); + break; + // Summons which may fail + case TMW2_KALWULF: + SK_summon(Wolvern, 4, any(3,4)); + break; + case TMW2_KALBOO: + SK_summon(Mouboo, 4, any(2,3)); + break; + case TMW2_KALSPIKE: + SK_summon(PoisonSpikyMushroom, 4, any(2,3)); + break; + case TMW2_CUTEHEART: + SK_summon(Fluffy, 4, any(2,3)); + break; + // Slightly more complex summons + case TMW2_LIMERIZER: + SK_summon(any(GreenSlime,AzulSlime,RedSlime,AngryYellowSlime), 2, any(3,4)); + break; + case TMW2_FAIRYKINGDOM: + SK_summon(any(FireFairy, EarthFairy, WaterFairy, WindFairy, PoisonFairy), 4, any(3,4)); + break; + case TMW2_FAIRYEMPIRE: + SK_summon(any(VanityPixie, HolyPixie, ShadowPixie, NulityPixie), 5, any(4,5)); + break; + // More complex summons + case TMW2_KALMURK: + .@mobId=Maggot; + if (abizit() > 4 && + GHMEMO[GHQ_GetQuestIDByMonsterID(Maggot)] >= 10000 && + MAGIC_LVL >= 3) + { + .@mobId=any(Maggot, Maggot, Maggot, Maggot, GiantMaggot); + } + SK_summon(.@mobId, (.@mobId == Maggot ? 2 : 4), any(1,2)); + break; + case TMW2_HALHISS: + .@mobId=Snake; + if (abizit() > 3 && + GHMEMO[GHQ_GetQuestIDByMonsterID(MountainSnake)] >= 10000 && + rand2(1,3) == 2) + { + .@mobId=MountainSnake; + } + SK_summon(.@mobId, 4, any(3,4)); + break; + case TMW2_FROZENHEART: + .@mobId=Moggun; + if (rand2(6,12) < (abizit()*2)+1) + { + .@mobId=Yeti; + } + SK_summon(.@mobId, 4, any(3,4)); + break; + case TMW2_STONEHEART: + .@mobId=Terranite; + if (rand2(9,12) < (abizit()*2)+1 && + BaseLevel > 80) + { + .@mobId=TerraniteProtector; + } + SK_summon(.@mobId, 4, any(4,5)); + break; + case TMW2_DUCKY: + .@mobId=Duck; + .@q=getq(LilitQuest_PiratesOfSARAH); + if (!alignment_cansummon()) + break; + if (abizit() > 4 && + .@q > 2 && + MAGIC_LVL >= 3) + { + // GHQ Complete: 33% chances + // Otherwise: 8% chances + if (GHMEMO[GHQ_GetQuestIDByMonsterID(Duck)] >= 10000) + .@mobId=any(Duck, Duck, EliteDuck); + else + .@mobId=any(Duck, Duck, Duck, Duck, + Duck, Duck, Duck, Duck, + Duck, Duck, Duck, EliteDuck); + } + SummonMagic(@skillId, .@mobId, 2); + GetManaExp(@skillId, 1); + break; + + // Experience only + case KN_AUTOCOUNTER: + case SN_SHARPSHOOTING: + case HW_MAGICPOWER: + case SM_PROVOKE: + case SN_WINDWALK: + case SO_FIREWALK: + case TF_BACKSLIDING: + case MG_FIREWALL: + case ALL_FULL_THROTTLE: + case GC_DARKILLUSION: + case NV_TRICKDEAD: + GetManaExp(@skillId, rand2(1,3)); + break; + } + + // Debug + if ($@GM_OVERRIDE) + debugmes "Cast skill %d on level %d - Target %d", + @skillId, @skillLv, @skillTarget; + + // Cleanup (double-safe) + @skillTarget = 0; + return; + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// HUB_PCBonus () +function script HUB_PCBonus { + /* Passive Skills */ + if (FOCUSING & FSKILL_ASTRAL_SOUL) { + bonus bMatk, 25*getskilllv(SKILL_ASTRAL_SOUL); + } + if (FOCUSING & FSKILL_RAGING) { + bonus bCritical, 5*getskilllv(SKILL_RAGING); + } + if (FOCUSING & FSKILL_SPEED) { + bonus bAspd, 5*getskilllv(SKILL_SPEED); + } + // MALLARD EYE handled by C code + // SKILL_BRAWLING SKILL_RESIST_POISON + return; +} + -- cgit v1.2.3-60-g2f50