# Special-purpose globals obscure_chance = 95 min_casttime = 200 # Schools of magic CONST MAGIC = 340 CONST LIFE = 341 CONST WAR = 342 CONST TRANSMUTE = 343 CONST NATURE = 344 CONST ASTRAL = 345 # Elements CONST ELT_NEUTRAL = 0 CONST ELT_WATER = 1 CONST ELT_EARTH = 2 CONST ELT_FIRE = 3 CONST ELT_WIND = 4 CONST ELT_POISON = 5 CONST ELT_SHADOW = 6 CONST ELT_HOLY = 7 CONST ELT_GHOST = 8 CONST ELT_UNDEAD = 9 # Schools of magic CONST SC_HALT_REGENERATE = 195 CONST SC_FLYING_BACKPACK = 196 CONST SC_MBARRIER = 197 CONST SC_HASTE = 198 CONST SC_PHYS_SHIELD = 199 CONST SFX_TELEPORT = 24 # Increase spellpower by school and general magic skill PROCEDURE adjust_spellpower(school) = spellpower = spellpower + (skill(caster, MAGIC) + skill(caster, school)) * 10; IF ((school = LIFE) && (target = partner(caster))) THEN spellpower = spellpower + 200; # Do something for wedding rings, too? PROCEDURE heal(target, max_heal) = sfx(caster, 4, 0); IF caster <> target THEN sfx(target, 4, 0); power = spellpower + vit(caster); power = min(max_heal, (max_heal * power) / 250); itemheal(target, power, 0); # Goes through instaheal instead of itemheal PROCEDURE quickheal(target, power) = sfx(caster, 4, 0); IF caster <> target THEN sfx(target, 4, 0); instaheal(target, power, 0); # Can attack the target? Imports attack_range from dynamic environment PROCEDURE attack_check(target) = IF (not (line_of_sight(location(caster), location(target)))) THEN ABORT; IF (not (rdistance(location(caster), location(target)) <= attack_range)) THEN ABORT; # Cause elemental damage. bonus_elt grants an attack bonus, malus_elt reduces the attack. `effect' is the sfx ID. PROCEDURE elt_damage(target, damage, dmgplus, bonus_elt, malus_elt, effect) = d = damage + random(dmgplus); IF (element(target) = malus_elt) THEN d = d / 3; IF (element(target) = bonus_elt) THEN d = (d * (4 + element_level(target))) / 4; #message(caster, "bonus=" + (element(target) = bonus_elt) + " malus=" + (element(target) = malus_elt) + " damage=" + damage + " + r(" + dmgplus + ") -> " + d); sfx(target, effect, 0); injure(caster, target, d, 0); PROCEDURE melee_damage(target, damage, dmgplus) = CALL attack_check(target); d = damage + random(dmgplus); injure(caster, target, d, 0); PROCEDURE install_attack_spell(charges, base_delay, range, attack_animation) = sfx(caster, 5, 0); attack_range = range; override_attack(caster, charges, ((200 - agi(caster)) * base_delay) / 200, range, 0, attack_animation); PROCEDURE install_melee_spell(charges, base_delay, attack_animation) = CALL install_attack_spell(charges, base_delay, 1, attack_animation); PROCEDURE summon_spell(mob_id, count, delay, lifetime, control_level) = sfx(caster, 2, 0); sfx(location, 21, 0); WAIT delay; sfx(location, 22, 0); spawn(rbox(location, 2), caster, mob_id, if_then_else(skill(caster, ASTRAL) >= control_level, 2, 1), # pets when level is high enough count, lifetime); #-------------------------------------------------------------------------------- # Level 0 spells #-------------------------------------------------------------------------------- #SPELL reset : "#reset" = # EFFECT { skill 340, 0; # skill 341, 0; # skill 342, 0; # skill 343, 0; # skill 344, 0; # skill 345, 0; # } SPELL lesser-heal (target : STRING) : "#imx" = LET level = 0 school = LIFE IN (MANA 5, CASTTIME 400, REQUIRE skill(caster, MAGIC) > level, REQUIRE if_then_else(failed(pc(target)), 1, rdistance(location(caster), location(pc(target))) < 2 + (spellpower / 50)), (COMPONENTS ["MaggotSlime"] OR COMPONENTS ["BugLeg"])) => EFFECT CALL adjust_spellpower(school); IF failed(pc(target)) THEN target = caster; # quest handling goes here ELSE target = pc(target); CALL heal(target, 200); SPELL flare-dart : "#fla" = LET level = 0 school = WAR IN (MANA 15, CASTTIME 500, REQUIRE skill(caster, MAGIC) > level, (REQUIRE skill(caster, school) > 2 OR COMPONENTS ["SulphurPowder"])) => EFFECT CALL adjust_spellpower(school); sfx(caster, 5, 0); damage = min(40 + skill(caster, school) * 20, 10 + spellpower); damage_bonus = 5 + level(caster) / 3; CALL install_attack_spell(3 + spellpower / 30, 1200, 4, 31); ATTRIGGER CALL attack_check(target); CALL elt_damage (target, damage, damage_bonus, ELT_WATER, ELT_FIRE, 15); SPELL magic-blade : "#mbl" = LET level = 0 school = WAR IN (MANA 12, CASTTIME 500, REQUIRE skill(caster, MAGIC) > level) => ( COMPONENTS ["SharpKnife"] => EFFECT CALL adjust_spellpower(WAR); sfx(caster, 5, 0); CALL install_melee_spell(10 + spellpower / 10, 900, 30); ATTRIGGER CALL melee_damage(target, 60 + spellpower / 20, 5 + str(caster)); | COMPONENTS ["Knife"] => EFFECT CALL adjust_spellpower(WAR); sfx(caster, 5, 0); CALL install_melee_spell(10 + spellpower / 10, 900, 30); ATTRIGGER CALL melee_damage(target, 40 + spellpower / 20, 5 + str(caster)); ) SPELL aggravate : "#qaw" = LET level = 0 school = NATURE IN (MANA 5, CASTTIME 300, REQUIRE skill(caster, MAGIC) > level) => EFFECT CALL adjust_spellpower(school); sfx(caster, 2, 0); FOREACH MOB target IN rbox(location(caster), 1 + spellpower / 20) DO (sfx(target, 2, 0); aggravate(target, 0, caster);) LOCAL SPELL summon-maggots : "#kbm" = LET level = 0 school = ASTRAL IN (MANA 20, CASTTIME 3000, REQUIRE skill(caster, MAGIC) > level, COMPONENTS ["MaggotSlime"]) => EFFECT CALL adjust_spellpower(school); CALL summon_spell(1002, 3 + spellpower / 15, 5000 - (spellpower * 10), spellpower * 500, 1); #-------------------------------------------------------------------------------- # Level 1 spells #-------------------------------------------------------------------------------- SPELL make-arrows : "#mkarrows" = LET level = 1 school = TRANSMUTE IN (MANA 20, CASTTIME 2000, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, COMPONENTS ["RawLog"]) => EFFECT CALL adjust_spellpower(school); sfx(caster, 2, 0); create_item(caster, "Arrow", 1 + spellpower / 15); SPELL make-shirt : "#mkshirt" = LET level = 1 school = TRANSMUTE IN (MANA 20, CASTTIME 2000, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, COMPONENTS [5 * "CottonCloth"]) => EFFECT CALL adjust_spellpower(school); sfx(caster, 2, 0); create_item(caster, "CottonShirt", 1); SPELL make-tanktop : "#mktanktop" = LET level = 1 school = TRANSMUTE IN (MANA 20, CASTTIME 2000, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, COMPONENTS [4 * "CottonCloth"]) => EFFECT CALL adjust_spellpower(school); sfx(caster, 2, 0); create_item(caster, "TanktopWhite", 1); SPELL make-short-tanktop : "#mkshorttanktop" = LET level = 1 school = TRANSMUTE IN (MANA 20, CASTTIME 2000, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, COMPONENTS [3 * "CottonCloth"]) => EFFECT CALL adjust_spellpower(school); sfx(caster, 2, 0); create_item(caster, "ShortTanktopWhite", 1); SPELL lightning-strike : "#kig" = LET level = 1 school = WAR IN (MANA 25, CASTTIME 1000, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["IronPowder"])) => EFFECT CALL adjust_spellpower(school); damage = min(100 + skill(caster, school) * 50, 50 + spellpower * 2); damage_bonus = level(caster) + spellpower; CALL install_attack_spell(1 + spellpower / 60, 3000, 8, 31); ATTRIGGER CALL attack_check(target); CALL elt_damage (target, damage, damage_bonus, ELT_EARTH, ELT_WIND, 17 + random(3)); SPELL fire-ball : "#pof" = LET level = 1 school = WAR IN (MANA 30, CASTTIME 1000, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["PileOfAsh"])) => EFFECT CALL adjust_spellpower(school); damage = min(50 + skill(caster, school) * 40, 30 + ((spellpower * 3) / 2)); damage_bonus = level(caster) + spellpower * 2; radius = 2 + spellpower / 50; CALL install_attack_spell(1 + spellpower / 60, 5000, 10, 31); ATTRIGGER CALL attack_check(target); loc = location(target); #WAIT 500; sfx(loc, 16, 0); FOREACH TARGET target IN rbox(loc, radius) DO IF line_of_sight(loc, location(target)) THEN (divisor = (3 + rdistance(loc, location(target))); CALL elt_damage (target, (damage * 3) / divisor, (damage_bonus * 3) / divisor, ELT_WATER, ELT_FIRE, 15); ) SPELL magic-knuckles (target : PC) : "#iom" = LET level = 1 school = WAR IN (MANA 20, CASTTIME 500, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["Beer"])) => EFFECT CALL adjust_spellpower(WAR); str = str(target); CALL install_melee_spell(10 + spellpower / 12, 1000, 0); ATTRIGGER CALL melee_damage(target, 40 + (str / 2) + spellpower / 20, 5 + str); SPELL flying-backpack (target : PC) : "#uuy" = LET level = 1 school = NATURE IN (MANA 12, CASTTIME 1000, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30) => EFFECT CALL adjust_spellpower(school); sfx(target, 3, 0); IF (caster <> target) THEN sfx(caster, 2, 0); status_change(target, SC_FLYING_BACKPACK, 0, 0, 0, 0, 5000 + (spellpower * 500)); message (target, "Your backpack is lifted by a mystical force; you no longer feel it pressing on your back."); ATEND message (target, "Your backpack is no longer levitating."); sfx(target, 2, 0); SPELL protect (target : PC) : "#ism" = LET level = 1 school = NATURE IN (MANA 18, CASTTIME 1000, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["HardSpike"]), REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30) => EFFECT CALL adjust_spellpower(school); sfx(target, 11, 0); IF (caster <> target) THEN sfx(caster, 2, 0); status_change(target, SC_PHYS_SHIELD, 5 + max(15, spellpower / 12), 0, 0, 0, 5000 + (spellpower * 500)); message (target, "You feel more protected."); ATEND message (target, "You feel less protected."); sfx(target, 111, 0); LOCAL SPELL rain : "#flosh" = LET level = 1 school = NATURE IN (MANA 20, CASTTIME 3000, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["BottleOfWater"])) => EFFECT CALL adjust_spellpower(school); sfx(caster, 2, 0); area = rbox(location(caster), 3 + spellpower / 30); FOR i = 0 TO spellpower DO ( FOR j = 0 TO spellpower / 100 DO ( location = random_location(area); sfx(location, 25, 0); FOREACH TARGET target IN rbox(location, 1) DO IF element(target) = ELT_FIRE THEN injure(caster, target, 5 + random(5 + spellpower / 10), 0); ) WAIT 300 - min(spellpower, 200) + random(100); ); SPELL happy-curse (target : PC) : "#happy" = LET level = 1 school = NATURE IN (MANA 10, CASTTIME 1000, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["WhiteFur"]), REQUIRE rdistance(location(target), location(caster)) < 1 + spellpower / 100) => EFFECT CALL adjust_spellpower(school); FOR i = 0 TO (spellpower / 10) DO (emote(target, 3); WAIT 500;); SPELL barrier (target : PC) : "#iso" = LET level = 1 school = NATURE IN (MANA 18, CASTTIME 1000, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, (REQUIRE skill(caster, school) > 3 OR COMPONENTS ["HardSpike"]), REQUIRE rdistance(location(target), location(caster)) < 2 + spellpower / 30) => EFFECT CALL adjust_spellpower(school); sfx(target, 3, 0); IF (caster <> target) THEN sfx(caster, 2, 0); status_change(target, SC_MBARRIER, 30 + max(30, spellpower / 8), 0, 0, 0, 2000 + (spellpower * 200)); message (target, "You are surrounded by a magical barrier."); ATEND message (target, "Your magical barrier disspiates."); sfx(target, 2, 0); LOCAL SPELL summon-scorps : "#kbms" = LET level = 1 school = ASTRAL IN (MANA 25, CASTTIME 3000, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, COMPONENTS ["ScorpionStinger"]) => EFFECT CALL adjust_spellpower(school); sfx(target, 2, 0); CALL summon_spell(1003, 1 + spellpower / 30, 5000 - (spellpower * 9), spellpower * 400, 2); LOCAL SPELL summon-red-scorps : "#kbmq" = LET level = 1 school = ASTRAL IN (MANA 30, CASTTIME 3000, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, COMPONENTS ["RedScorpionStinger"]) => EFFECT CALL adjust_spellpower(school); sfx(target, 2, 0); CALL summon_spell(1004, 1 + spellpower / 40, 5000 - (spellpower * 8), spellpower * 350, 3); SPELL detect-players : "#ewm" = LET level = 1 school = MAGIC IN (MANA 10, CASTTIME 300, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level) => EFFECT CALL adjust_spellpower(school); sfx(target, 2, 0); message = ""; FOREACH PC target IN rbox(location(caster), spellpower / 2) DO IF target <> caster THEN (IF message <> "" THEN message = message + ", "; message = message + name_of (target); IF spellpower > 99 THEN message = message + "(" + level(target) + ")"; ) IF message = "" THEN message(caster, "You sense no-one else nearby."); ELSE message(caster, "You sense the following: " + message); SPELL lay-on-hands (target : STRING) : "#loh" = LET level = 1 school = LIFE IN (MANA 8, CASTTIME 400, REQUIRE hp(caster) > max_hp(caster) / 20, REQUIRE skill(caster, MAGIC) > level, REQUIRE if_then_else(failed(pc(target)), 1, (rdistance(location(caster), location(pc(target))) < 2 + (spellpower / 50)) && not (running_status_update(pc(target), SC_HALT_REGENERATE)) )) => EFFECT CALL adjust_spellpower(school); IF failed(pc(target)) THEN target = caster; # quest handling goes here ELSE target = pc(target); needed = max_hp(target) - hp(target); pay_fraction = max(80, 200 - (vit(caster) + (spellpower / 10))); # Pay at least 40% payment = (needed * pay_fraction) / 200; available = hp(caster) - (max_hp(caster) / 20); IF payment < available THEN power = needed; ELSE (payment = available; power = (available * 200) / pay_fraction; ) instaheal(caster, 0 - payment, 0); CALL quickheal(target, power); status_change(caster, SC_HALT_REGENERATE, 0, 0, 0, 0, 10000); #-------------------------------------------------------------------------------- # Level 2 spells #-------------------------------------------------------------------------------- SPELL summon-partner : "#aid" = LET level = 2 school = ASTRAL IN (MANA 30, CASTTIME 2000, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level, REQUIRE is_married(caster)) => EFFECT CALL adjust_spellpower(school); sfx(caster, 2, 0); IF (failed (partner (caster))) THEN message (caster, "You call out for your partner, but there is no response."); ELSE (message (caster, "You call out for " + (name_of (partner (caster))) + "."); message (partner(caster), name_of(caster) + " is calling for your aid!"); sfx(partner(caster), 2, 0); WAIT (max (5000, 30000 - (spellpower * 60))); IF (failed (partner (caster))) THEN message (caster, "Your partner has abandoned you."); ELSE (sfx(location(partner(caster)), SFX_TELEPORT, 0); dest = awayfrom(location(caster), random_dir(1), 1); warp(partner(caster), dest); sfx(dest, SFX_TELEPORT, 0); ) ) #-------------------------------------------------------------------------------- # Level 4 spells #-------------------------------------------------------------------------------- SPELL shroud : "#aw" = LET level = 4 school = ASTRAL IN (MANA 40, CASTTIME 400, REQUIRE skill(caster, MAGIC) > level, REQUIRE skill(caster, school) > level) => EFFECT sfx(caster, 2, 0); shroud(caster, 0x04); #-------------------------------------------------------------------------------- # Special-purpose quasispells #-------------------------------------------------------------------------------- CONST MIN_MARRY_LEVEL = 32; SILENT SPELL marriage (target : PC) : "marry" = (REQUIRE is_in(location(caster), @("new_29-1.gat", 28,39) @+ (8, 6)))=> EFFECT IF target == caster # no valid target or tried to marry self? THEN ABORT; IF (level(caster) < MIN_MARRY_LEVEL) THEN (message(caster, "You must be level " + MIN_MARRY_LEVEL + " or higher to marry!"); ABORT;) IF (level(target) < MIN_MARRY_LEVEL) THEN (message(caster, "Your partner must be level " + MIN_MARRY_LEVEL + " or higher to marry!"); ABORT;) IF partner(caster) = target THEN (message(caster, "You and " + name_of(target) + " are already married."); ABORT;) IF is_married(caster) THEN (message(caster, "You are already married!"); ABORT;) IF is_married(target) THEN (message(caster, name_of(target) + " is already married."); ABORT;); IF distance(location(caster), location(target)) <> 1 THEN (message(caster, "You have to stand next to each other."); ABORT;); IF (count_item(caster, "WeddingRing") == 0 || count_item(target, "WeddingRing") == 0) THEN (message(caster, "You must both be wearing your wedding rings!"); ABORT;) script_target = target; { announce @caster_name$ + " is asking " + strcharinfo(0) + " for marriage.", 2; mes @caster_name$ + " wishes to marry you."; mes "Do you accept?"; next; menu "Yes, I do!", L_yes, "No.", -; close; L_yes: if marriage(@caster_name$) announce @caster_name$ + " and " + strcharinfo(0) + " are now married!", 0; } IF not (is_married(caster)) THEN message(caster, name_of(target) + " turned down your marriage offer."); SPELL change-hair-colour (colour : STRING) : "trapa" = (MANA 20) => EFFECT IF colour = "nworbl" THEN x = 0; # light brown ELSE IF colour = "der" THEN x = 1; # red ELSE IF colour = "neerg" THEN x = 2; # green ELSE IF colour = "elprup" THEN x = 3; # purple ELSE IF colour = "yerg" THEN x = 4; # grey ELSE IF colour = "wolley" THEN x = 5; # yellow ELSE IF colour = "eulb" THEN x = 6; # blue ELSE IF colour = "nwrob" THEN x = 7; # brown ELSE IF colour = "elpropl" THEN x = 8; # light purple ELSE IF colour = "elpropd" THEN x = 9; # dark purple ELSE x = random(10); sfx(caster, 2, 0); set_hair_colour(caster, x); SPELL trick-or-treat : "trick-or-treat" = (CASTTIME 30000, MANA 20, COMPONENTS [ "BugLeg" ]) => EFFECT IF (random(2)) THEN (sfx(caster, 2, 0); FOR i = 0 TO random(10) DO drop_item_for (random_location(rbox(location(caster), 5)), "Candy", 1, 10000 + random(10000), caster, 3000); FOR i = 0 TO random(10) DO drop_item_for (random_location(rbox(location(caster), 5)), "ChocolateBar", 1, 10000 + random(10000), caster, 3000); ) ELSE (sfx(caster, 5, 0); message(caster, "No treat for you!"); spawn(rbox(location(caster), 3), caster, 1010, 0, 1 + random(3), 10000 + random(20000)); FOREACH MOB target IN rbox(location(caster), 5) DO (sfx(target, 5, 0); aggravate(target, 0, caster);))