summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--db/constants.conf5
-rw-r--r--npc/functions/main.txt5
-rw-r--r--npc/magic/config.txt264
-rw-r--r--npc/scripts.conf3
4 files changed, 276 insertions, 1 deletions
diff --git a/db/constants.conf b/db/constants.conf
index a339559a..c108a981 100644
--- a/db/constants.conf
+++ b/db/constants.conf
@@ -712,6 +712,11 @@ more than one separator can be used in a row (so 12_3___456 is illegal).
Ele_Undead: 7 // 9
Ele_All: 255
+ comment__: "Attack Types"
+ HARM_PHYS: 1
+ HARM_MAGI: 2
+ HARM_MISC: 4
+
comment__: "Races"
RC_Formless: 0
RC_Undead: 1
diff --git a/npc/functions/main.txt b/npc/functions/main.txt
index eac02526..8dd7c95f 100644
--- a/npc/functions/main.txt
+++ b/npc/functions/main.txt
@@ -613,3 +613,8 @@ function script iscollision {
return checknpccell(getarg(0), getarg(1), getarg(2), cell_chkpass);
}
+function script readparam2 {
+ readbattleparam(getcharid(3), getarg(0));
+ return;
+}
+
diff --git a/npc/magic/config.txt b/npc/magic/config.txt
new file mode 100644
index 00000000..0ea9d3b7
--- /dev/null
+++ b/npc/magic/config.txt
@@ -0,0 +1,264 @@
+// TMW2 script
+// Author: Jesusalva <admin@tmw2.org>
+//
+// Magic Script Core Functions
+//
+// Used for our pseudo-magic.
+// These are only helpers, you can add more restrictions and effects freely.
+// FIXME
+function script abizit {
+ return 0;
+}
+
+// AdjustSpellpower(power=100, {target=@skillTarget{, type=HARM_MAGI}})
+function script AdjustSpellpower {
+ .@power=getarg(0, 100);
+ .@target=getarg(1, @skillTarget);
+ .@type=getarg(2, HARM_MAGI);
+ .@src=getcharid(3);
+
+ // Prevents a possible glitch
+ if (.@target < 1 || .@target == getcharid(3))
+ .@target=0;
+
+ // Calculation FIX
+ if (.@type == HARM_MAGI) {
+ .@power+=(readparam2(bInt)/2);
+ .@dmg=rand2(
+ getunitdata(getcharid(3), UDT_MATKMIN),
+ getunitdata(getcharid(3), UDT_MATKMAX));
+ // Apply defense
+ if (.@target)
+ .@dmg=max(0, .@dmg-getunitdata(.@target, UDT_MDEF));
+ } else if (.@type == HARM_PHYS) {
+ .@power+=(readparam2(bStr)/2);
+ .@dmg=rand2(
+ getunitdata(getcharid(3), UDT_ATKMIN),
+ getunitdata(getcharid(3), UDT_ATKMAX));
+ // Apply defense
+ if (.@target)
+ .@dmg=max(0, .@dmg-getunitdata(.@target, UDT_DEF));
+ } else {
+ .@dmg = .@power; .@power = 100;
+ }
+ // Abizit Influence (80%~130% at best, worst shot at perfect ctrl is 105%)
+ .@dmg = .@dmg * (80 + abizit() * rand2(5,10)) / 100;
+ .@dmg = .@dmg * .@power / 100;
+ return .@dmg;
+}
+
+// An alias for simplification
+// AdjustAttackpower(power=100, {target=@skillTarget{, type=HARM_PHYS}})
+function script AdjustAttackpower {
+ .@power=getarg(0, 100);
+ .@target=getarg(1, @skillTarget);
+ .@type=getarg(2, HARM_PHYS);
+ return AdjustSpellpower(.@power, .@target, .@type);
+}
+
+
+// SkillID, EXP Points
+function script GetManaExp {
+ // FIXME
+ .@sk=getarg(0);
+ .@pt=getarg(1);
+ .@bonus=rand2(0,getskilllv(TMW2_SAGE)*3/2);
+ if (LAST_SKILL == .@sk) {
+ .@pt=limit(0, (.@pt+.@bonus)/3, 1);
+ .@bonus=0;
+ } else {
+ // Update skill memory
+ LAST_SKILL[4]=LAST_SKILL[3];
+ LAST_SKILL[3]=LAST_SKILL[2];
+ LAST_SKILL[2]=LAST_SKILL[1];
+ LAST_SKILL[1]=LAST_SKILL[0];
+ LAST_SKILL[0]=.@sk;
+ MAGIC_RP+=1;
+ // Magic RP is gained by switching skills often
+ }
+
+ // Update Magic EXP
+ MAGIC_EXP=MAGIC_EXP+.@pt+.@bonus;
+ return;
+}
+
+
+// SkillID, MobID{, SkillLevelPerMob=2{, Level Override}}
+function script SummonMagic {
+ .@sk=getarg(0);
+ .@id=getarg(1);
+ .@adj=getarg(2,2);
+ .@lv=getarg(3,getskilllv(.@sk));
+
+ if (.@adj < 1) {
+ debugmes "\033[31mInvalid MobPerSkillLevel for SummonMagic (.@adj): "+.@adj+"\033[0m";
+ dispbottom l("Invalid parameter specified, blame saulc.");
+ end;
+ }
+
+ // Cause effect
+ // Summoned monsters live from 45 to 60 seconds, and each skill levels grants 10s extra life
+ // The 35~50 is not a defect, remember skill starts at level 1...
+ // PS. Abizit makes a variation from 80% to 130% of official values
+ for (.@i = 0; .@i < (.@lv+(.@adj-1))/.@adj; .@i++) {
+ .@lifetime=rand2(35,50)+.@lv*10;
+ // Abizit makes lifetime vary (like AdjustSpellpower)
+ .@lifetime = .@lifetime * (80 + abizit() * rand2(5,10)) / 100;
+ // Unfortunately this version does not returns the summoned monster GID
+ summon("Summoned Monster", .@id, .@lifetime);
+ /*
+ .@mids=summon("Summoned Monster", .@id, .@lifetime);
+ .@bhp=getunitdata(.@mids, UDT_MAXHP);
+ // Each skill level raises HP in 5%
+ .@lvx=.@bhp + max(0, (.@lv-1)*.@bhp/20);
+ // Abizit makes bonus HP vary (like AdjustSpellpower)
+ .@lvx = .@lvx * (80 + abizit() * rand2(5,10)) / 100;
+ setunitdata(.@mids, UDT_MAXHP, .@lvx);
+ setunitdata(.@mids, UDT_HP, .@lvx);
+ // Reconfigure monster modes
+ .@opt=getunitdata(.@mids, UDT_MODE);
+ // Disable looting
+ if (.@opt & MD_LOOTER)
+ .@opt=.@opt^MD_LOOTER;
+ // All summons can suffer knockback
+ if (.@opt & MD_NOKNOCKBACK)
+ .@opt=.@opt^MD_NOKNOCKBACK;
+ // Strip summons from BOSS mode and immunity
+ if (.@opt & MD_BOSS)
+ .@opt=.@opt^MD_BOSS;
+ // Save new options
+ setunitdata(.@mids, UDT_MODE, .@opt);
+ */
+ }
+ dispbottom l("All monsters summoned!");
+ return;
+}
+
+// areaharm(target, range, DMG, {type, element, filter, bl})
+// Defaults to HARM_MISC, Ele_Neutral, filter filter_hostile and all BLs
+// Valid BL: BL_MOB | BL_PC | BL_HOM | BL_MER
+// Do not use: NPC, PET, ELEM
+// Range centers on caster (player), implement and use areaharm2 elsewhere
+function script areaharm {
+ .@t=getarg(0);
+ .@r=getarg(1);
+ .@d=getarg(2);
+ .@h=getarg(3, HARM_MISC);
+ .@e=getarg(4, Ele_Neutral);
+ .@f$=getarg(5, "filter_hostile");
+ .@b=getarg(6, BL_PC | BL_MOB | BL_MER | BL_HOM);
+
+ getmapxy(.@m$, .@x, .@y, getunittype(.@t), .@t);
+
+ .@c=getunits(.@b, .@mbs, false, .@m$, .@x-.@r, .@y-.@r, .@x+.@r, .@y+.@r);
+ for (.@i = 0; .@i < .@c; .@i++) {
+ // Filtering
+ if (!callfunc(.@f$, .@mbs[.@i]))
+ continue;
+ harm(.@mbs[.@i], .@d, .@t, .@e);
+ specialeffect(FX_ATTACK, AREA, .@mbs[.@i]);
+ // TODO: Handle MobPt to don't overload timer system?
+ }
+ return;
+}
+
+
+// rectharm(target, x, y, DMG, {type, element, filter, bl})
+// Same as areaharm() but causes a rectangle in (x,y) size, instead of a square
+function script rectharm {
+ .@t=getarg(0);
+ .@rx=getarg(1);
+ .@ry=getarg(2);
+ .@d=getarg(3);
+ .@h=getarg(4, HARM_MISC);
+ .@e=getarg(5, Ele_Neutral);
+ .@f$=getarg(6, "filter_hostile");
+ .@b=getarg(7, BL_PC | BL_MOB | BL_MER | BL_HOM);
+
+ getmapxy(.@m$, .@x, .@y, getunittype(.@t), .@t);
+
+ .@c=getunits(.@b, .@mbs, false, .@m$, .@x-.@rx, .@y-.@ry, .@x+.@rx, .@y+.@ry);
+ for (.@i = 0; .@i < .@c; .@i++) {
+ // Filtering
+ if (!callfunc(.@f$, .@mbs[.@i]))
+ continue;
+ harm(.@mbs[.@i], .@d, .@t, .@e);
+ specialeffect(FX_ATTACK, AREA, .@mbs[.@i]);
+ // TODO: Handle MobPt to don't overload timer system?
+ }
+ return;
+}
+
+
+// mescordialog(text, color, {dialog=1})
+function script mescordialog {
+ if (getarg(2, true))
+ mesc getarg(0), getarg(1);
+ else
+ dispbottom col(getarg(0), getarg(1));
+ return;
+}
+
+// ShowAbizit({dialog=1})
+function script ShowAbizit {
+ .@dial=getarg(0, true);
+ if (.@dial)
+ mesn l("Current Magic Control");
+
+ // FIXME
+ .@val=MAGIC_EXP+rand(-MAGIC_LVL*5, MAGIC_LVL*5);
+ .@base=((MAGIC_LVL*2)**3);
+ if (.@val > .@base*5)
+ mescordialog l("You are perfectly in control of your magic."), 3, .@dial;
+ else if (.@val > .@base*4)
+ mescordialog l("You are mostly in control of your magic."), 2, .@dial;
+ else if (.@val > .@base*3)
+ mescordialog l("You are somewhat in control of your magic."), 4, .@dial;
+ else if (.@val > .@base*2)
+ mescordialog l("Your magic is more powerful than you, but you can control."), 7, .@dial;
+ else if (.@val > .@base)
+ mescordialog l("You still are overwhelmed by your magic."), 6, .@dial;
+ else
+ mescordialog l("You are completly overwhelmed by your magic."), 1, .@dial;
+ return;
+}
+
+
+// SK_summon(ID, amount, mexp)
+function script SK_summon {
+ .@mob=getarg(0);
+ .@amt=getarg(1);
+ .@mex=getarg(2);
+ if ($@GM_OVERRIDE || debug) debugmes "Skill "+@skillId+" Lv "+@skillLv;
+
+ if (rand2(5) < abizit()) {
+ // Summon Magic (with magic level bonus)
+ SummonMagic(@skillId, .@mob, .@amt, MAGIC_LVL+@skillLv-1, @skillLv);
+ } else if (rand2(5) < abizit()) {
+ // Re-roll
+ dispbottom l("You cannot complete the casting correctly!");
+ SummonMagic(@skillId, .@mob, 1, 1, 1);
+ } else if (abizit() <= 1 && any(true, false, false)) {
+ // Spell overwhelms you, causing it to be spawned as aggro vs you. (33%)
+ dispbottom l("The spell takes a mind of its own backfires!");
+ getmapxy(.@m$, .@x, .@y, 0);
+ .@opo=monster(.@m$, .@x, .@y, "Failed summon", .@mob, 1);
+ unitattack(.@opo, getcharid(3));
+ } else {
+ dispbottom l("The spell fails!");
+ }
+
+ // Get a single mana experience point (FIXME)
+ GetManaExp(@skillId, .@mex);
+ return;
+}
+
+- script Magic Load NPC_HIDDEN,{
+OnInit:
+ end;
+OnSkillInvoke:
+ end;
+OnPCBonusEvent:
+ end;
+}
+
diff --git a/npc/scripts.conf b/npc/scripts.conf
index 7c1520e0..beed5f75 100644
--- a/npc/scripts.conf
+++ b/npc/scripts.conf
@@ -62,7 +62,8 @@
"npc/items/mirror.txt",
"npc/items/rubber_bat.txt",
-//@include "npc/magic/_import.txt",
+//Magic
+"npc/magic/config.txt",
// Commands
"npc/commands/debug-quest.txt",