Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Anniversary Bash 21 Levels | Jazz2Online | Multiple | N/A |
namespace acSpells {
dictionary fullSpells = {
{"M", Spell("M", "Magic Arrow", SPELL_MAGIC_ARROW, SPELL_NONE, 1, 1, 1, 0, 10, 0, 0, false, "Fires an arrow that flies in a straight line, hitting all objects on its way and dealing ||{dmg} ||||damage on all enemies.")},
{"O", Spell("O", "Blood Lust", SPELL_BLOOD_LUST, SPELL_NONE, 1, 2, 0, 20, 10, 0, 0, false, "You gain a sugar rush and max fast fire for ||||{dur} ||seconds.")},
{"S", Spell("S", "Slow", SPELL_SLOW, SPELL_NONE, 1, 3, 0, 10, 10, 1, 4, false, "All enemies in range lose half of their movement speed for ||||{dur} ||seconds.")},
{"K", Spell("K", "Stone Skin", SPELL_STONE_SKIN, SPELL_DISRUPTING_RAY, 1, 4, 0, 20, 15, 0, 0, false, "You take |1 |||||damage less from enemy bullets for ||||||{dur} ||seconds. Counters Disrupting Ray.")},
{"B", Spell("B", "Bless", SPELL_BLESS, SPELL_WEAKNESS, 1, 5, 0, 20, 15, 0, 0, false, "Your bullets deal ||1 ||||damage more on all enemies for ||||||{dur} ||seconds. Counters Weakness.")},
{"D", Spell("D", "Dispel", SPELL_DISPEL, SPELL_NONE, 1, 6, 0, 0, 15, 1, 6, true, "Removes all effects from all players in range (including you).")},
{"R", Spell("R", "Disrupting Ray", SPELL_DISRUPTING_RAY, SPELL_STONE_SKIN, 2, 7, 0, 10, 20, 1.25, 5, false, "All enemies in range become vulnerable and take ||2 ||||damage more from bullets for ||||||{dur} ||seconds. Counters Stone Skin.")},
{"W", Spell("W", "Weakness", SPELL_WEAKNESS, SPELL_BLESS, 2, 8, 0, 10, 20, 1.25, 5, false, "All enemies in range become weak and their bullets deal |1 |||||damage less for ||||||{dur} ||seconds. Counters Bless.")},
{"E", Spell("E", "Ice Bolt", SPELL_ICE_BOLT, SPELL_NONE, 2, 9, 2, 0, 20, 0, 0, false, "Fires a bolt that flies in a straight line, hitting all objects on its way, dealing ||{dmg} ||||damage on all enemies and freezing them.")},
{"H", Spell("H", "Death Ripple", SPELL_DEATH_RIPPLE, SPELL_NONE, 2, 10, 1, 0, 25, 1.25, 6, true, "Deals ||{dmg} ||||damage to all living players in a range (undead are unaffected).")},
{"I", Spell("I", "Wall of Fire", SPELL_WALL_OF_FIRE, SPELL_NONE, 2, 11, 2, 10, 30, 1.25, 0, false, "Places a passable wall of fire that lasts ||||{dur} ||seconds. All players passing through it are dealt ||||{dmg} ||||damage.")}, //Should be Fire wall, but would be harder to distinguish from Fireball
{"G", Spell("G", "Forgetfulness", SPELL_FORGETFULNESS, SPELL_PRECISION, 3, 12, 0, 10, 35, 1.5, 7, false, "All enemies in range lose the ability to shoot bullets for ||||{dur} ||seconds. Counters Precision.")},
{"P", Spell("P", "Precision", SPELL_PRECISION, SPELL_FORGETFULNESS, 3, 13, 0, 20, 40, 0, 0, false, "Your bullets deal ||2 ||||damage more on all enemies for ||||||{dur} ||seconds. Counters Forgetfulness.")},
{"T", Spell("T", "Frost Ring", SPELL_FROST_RING, SPELL_NONE, 3, 14, 2, 0, 40, 1.5, 7, false, "Deals ||{dmg} ||||damage to all enemies in a range and freezes them (caster is unaffected).")},
{"F", Spell("F", "Fireball", SPELL_FIREBALL, SPELL_NONE, 3, 15, 3, 0, 40, 0, 7, false, "Fires a flaming bolt that flies in a straight line, exploding upon the first impact with a player or a solid wall, dealing ||{dmg} ||||damage in a large radius to all players.")},
{"U", Spell("U", "Cure", SPELL_CURE, SPELL_NONE, 4, 16, 0, 0, 50, 0, 0, false, "You regain full health (for a little pinch) and all negative effects are removed from you.")},
{"Y", Spell("Y", "Frenzy", SPELL_FRENZY, SPELL_NONE, 4, 17, 0, 20, 55, 0, 0, false, "Your bullets deal ||4 ||||damage more on all enemies, but you also take ||||4 ||||damage more from enemy bullets for ||||||{dur} ||seconds.")},
{"L", Spell("L", "Chain Lightning", SPELL_CHAIN_LIGHTNING, SPELL_NONE, 4, 18, 4, 0, 60, 1.75, 7, false, "All enemies in a large range are dealt ||{dmg} ||||damage. Players whom are in range of the primary targets take ||||half ||||the damage (including you).")},
{"A", Spell("A", "Armageddon", SPELL_ARMAGEDDON, SPELL_NONE, 5, 19, 5, 0, 70, 2, 8, true, "All players in a large range are dealt ||{dmg} ||||damage within a short delay (including you).")},
{"Q", Spell("Q", "Implosion", SPELL_IMPLOSION, SPELL_NONE, 5, 20, 7, 0, 80, 2, 3, false, "All enemies in a short range are dealt ||{dmg} ||||forced damage within a short delay (ignores blinking).")}
};
dictionary normalSpells = {
{"M", Spell("M", "Magic Arrow", SPELL_MAGIC_ARROW, SPELL_NONE, 1, 1, 1, 0, 10, 0, 0, false, "Fires an arrow that flies in a straight line, hitting all objects on its way and dealing ||{dmg} ||||damage on all enemies.")},
{"O", Spell("O", "Blood Lust", SPELL_BLOOD_LUST, SPELL_NONE, 1, 2, 0, 20, 10, 0, 0, false, "You gain a sugar rush and max fast fire for ||||{dur} ||seconds.")},
{"S", Spell("S", "Slow", SPELL_SLOW, SPELL_NONE, 1, 3, 0, 10, 10, 1, 4, false, "All enemies in range lose half of their movement speed for ||||{dur} ||seconds.")},
{"D", Spell("D", "Dispel", SPELL_DISPEL, SPELL_NONE, 1, 6, 0, 0, 15, 1, 6, true, "Removes all effects from all players in range (including you).")},
{"E", Spell("E", "Ice Bolt", SPELL_ICE_BOLT, SPELL_NONE, 2, 9, 2, 0, 20, 0, 0, false, "Fires a bolt that flies in a straight line, hitting all objects on its way, dealing ||{dmg} ||||damage on all enemies and freezing them.")},
{"H", Spell("H", "Death Ripple", SPELL_DEATH_RIPPLE, SPELL_NONE, 2, 10, 1, 0, 25, 1.25, 6, true, "Deals ||{dmg} ||||damage to all living players in a range (undead are unaffected).")},
{"I", Spell("I", "Wall of Fire", SPELL_WALL_OF_FIRE, SPELL_NONE, 2, 11, 2, 10, 30, 1.25, 0, false, "Places a passable wall of fire that lasts ||||{dur} ||seconds. All players passing through it are dealt ||||{dmg} ||||damage.")}, //Should be Fire wall, but would be harder to distinguish from Fireball
{"G", Spell("G", "Forgetfulness", SPELL_FORGETFULNESS, SPELL_PRECISION, 3, 12, 0, 10, 35, 1.5, 7, false, "All enemies in range lose the ability to shoot bullets for ||||{dur} ||seconds.")},
{"T", Spell("T", "Frost Ring", SPELL_FROST_RING, SPELL_NONE, 3, 14, 2, 0, 40, 1.5, 7, false, "Deals ||{dmg} ||||damage to all enemies in a range and freezes them (caster is unaffected).")},
{"F", Spell("F", "Fireball", SPELL_FIREBALL, SPELL_NONE, 3, 15, 3, 0, 40, 0, 7, false, "Fires a flaming bolt that flies in a straight line, exploding upon the first impact with a player or a solid wall, dealing ||{dmg} ||||damage in a large radius to all players.")},
{"U", Spell("U", "Cure", SPELL_CURE, SPELL_NONE, 4, 16, 0, 0, 50, 0, 0, false, "You regain full health (for a little pinch) and all negative effects are removed from you.")},
{"L", Spell("L", "Chain Lightning", SPELL_CHAIN_LIGHTNING, SPELL_NONE, 4, 18, 4, 0, 60, 1.75, 7, false, "All enemies in a large range are dealt ||{dmg} ||||damage. Players whom are in range of the primary targets take ||||half ||||the damage (including you).")},
{"A", Spell("A", "Armageddon", SPELL_ARMAGEDDON, SPELL_NONE, 5, 19, 5, 0, 70, 2, 8, true, "All players in a large range are dealt ||{dmg} ||||damage within a short delay (including you).")},
{"Q", Spell("Q", "Implosion", SPELL_IMPLOSION, SPELL_NONE, 5, 20, 7, 0, 80, 2, 3, false, "All enemies in a short range are dealt ||{dmg} ||||forced damage within a short delay (ignores blinking).")}
};
bool canCastSpell(Player@ asPlayer, SPELL spellEnum) {
string key = getSpellKeyByEnumValue(spellEnum);
Spell@ spell = cast<Spell@>(spells[key]);
return canCastSpell(asPlayer, spell);
}
bool canCastSpell(Player@ asPlayer, Spell@ spell) {
if (demoModeOn || (asPlayer.mana >= spell.baseManaCost && asPlayer.cooldown <= 0)) {
return true;
}
return false;
}
void castSpell(jjPLAYER@ play, string key) {
Spell@ spell = cast<Spell@>(spells[key]);
Player@ asPlayer = players[play.playerID];
asPlayer.unSetChanneledSpellKey();
numpadBuffer.removeRange(0, numpadBuffer.length);
acNetworking::sendChannelingStoppedPacket(play.playerID);
channelingStarted = false;
recovering = true;
if (!demoModeOn) {
asPlayer.cooldown = spell.tier * SECOND;
}
if (doSpell(key)) {
int index = ownSpells.find(key);
if (index >= 0 && !demoModeOn) {
asPlayer.mana -= spell.baseManaCost;
}
}
else {
if (key == "I") {
jjAlert("Can't cast wall of fire here. Try on a flat land on a more open area.");
}
else {
jjAlert("That spell affected no one!");
}
}
}
void changePlayerFur(uint8 effectID, int8 playerID) {
array<uint8> furArray;
jjPLAYER@ play = jjPlayers[playerID];
Player@ asPlayer = players[playerID];
bool change = true;
switch (effectID) {
case SPELL_STONE_SKIN:
{
furArray = FUR_STONE_SKIN;
}
break;
case SPELL_BLESS:
{
furArray = FUR_BLESS;
}
break;
case SPELL_SLOW:
{
furArray = FUR_SLOW;
}
break;
case SPELL_DISRUPTING_RAY:
{
furArray = FUR_DISRUPTING_RAY;
}
break;
case SPELL_WEAKNESS:
{
furArray = FUR_WEAKNESS;
}
break;
case SPELL_PRECISION:
{
furArray = FUR_PRECISION;
}
break;
case SPELL_FORGETFULNESS:
{
furArray = FUR_FORGETFULNESS;
}
break;
case SPELL_FRENZY:
{
furArray = FUR_FRENZY;
}
break;
case SPELL_UNDO:
{
if (asPlayer.activeEffects.length >= 1) { //If there are other active effects, change to the latest
Effect@ effect = asPlayer.activeEffects[asPlayer.activeEffects.length - 1];
changePlayerFur(effect.enumValue, playerID);
}
else {
play.fur = asPlayer.originalFur;
}
change = false;
}
break;
case SPELL_NONE:
default:
{
if (asPlayer.activeEffects.length >= 1) { //If there are any active effects, change to the original
play.fur = asPlayer.originalFur;
}
change = false;
}
break;
}
if (change) {
play.furSet(furArray[0], furArray[1], furArray[2], furArray[3]);
}
}
void channel(jjPLAYER@ play) {
string selectedSpellKey = players[play.playerID].selectedSpellKey;
if (channelingElapsed < cast<Spell@>(spells[selectedSpellKey]).channelingTime * SECOND) {
channelingElapsed++;
}
else {
channelingElapsed = 0;
castSpell(play, selectedSpellKey);
}
}
void doAOE(jjPLAYER@ caster, uint8 spellID, float xOrigin, float yOrigin) {
string spellKey = getSpellKeyByEnumValue(spellID);
Player@ asPlayer = players[caster.playerID];
Spell@ spell = cast<Spell@>(spells[spellKey]);
int damage = spell.baseDamage + asPlayer.spellDamageBonus;
switch (spellID) {
case SPELL_DEATH_RIPPLE:
{
jjSample(xOrigin, yOrigin, SOUND::COMMON_HEAD);
activeAreasOfEffect.insertLast(DeathRipple(
xOrigin, yOrigin, spell.radius, damage, 35, caster));
}
break;
case SPELL_FROST_RING:
{
jjSample(xOrigin, yOrigin, SOUND::COMMON_STEAM);
activeAreasOfEffect.insertLast(FrostRing(
xOrigin, yOrigin, spell.radius * 3.2, damage, 70, caster));
}
break;
case SPELL_FIREBALL:
{
jjSample(xOrigin, yOrigin, SOUND::COMMON_BENZIN1);
jjSample(xOrigin, yOrigin, SOUND::DEVILDEVAN_DRAGONFIRE);
activeAreasOfEffect.insertLast(FireballExplosion(
xOrigin, yOrigin, spell.radius, damage, 70, caster));
}
break;
case SPELL_ARMAGEDDON:
{
jjSample(xOrigin, yOrigin, SOUND::INTRO_BOEM1);
activeAreasOfEffect.insertLast(Armageddon(
xOrigin, yOrigin, spell.radius, damage, 70, caster));
}
break;
case SPELL_IMPLOSION:
{
activeAreasOfEffect.insertLast(Implosion(
xOrigin, yOrigin, spell.radius, damage, 70, caster));
}
break;
}
}
void doBullet(int bulletID) {
jjPLAYER@ play = jjLocalPlayers[0];
int originalAmmo = play.ammo[WEAPON::BLASTER];
play.ammo[WEAPON::BLASTER] = bulletID;
int id = play.fireBullet(WEAPON::BLASTER);
jjObjects[id].behave(BEHAVIOR::DEFAULT, false); //behave once to read bullet count
play.ammo[WEAPON::BLASTER] = originalAmmo;
}
array<ChainLightningTarget@> doChainLightning(int8 casterID, int8[] targets) {
Player@ asCaster = players[casterID];
Spell@ spell = cast<Spell@>(spells["L"]);
array<ChainLightningTarget@> chainLightningTargets;
for (uint i = 0; i < targets.length; i++) {
int8 targetPlayerID = targets[i];
chainLightningTargets.insertLast(ChainLightningTarget(
chainLightningCounter, targetPlayerID,
spell.baseDamage + asCaster.spellDamageBonus - players[targetPlayerID].magicResist,
CHAIN_LIGHTNING_DEFAULT_DURATION));
chainLightningCounter++;
}
for (uint i = 0; i < chainLightningTargets.length; i++) {
int8 targetPlayerID = chainLightningTargets[i].playerID;
float scaledRadius = acUtils::getScaledRadius(spell.radius, ANIM::FLARE, 5);
int8[] newTargets = acUtils::getTargets(jjPlayers[targetPlayerID], spell, scaledRadius);
for (uint j = 0; j < newTargets.length; j++) {
bool found = acUtils::findFromChainLightningTargets(chainLightningTargets, newTargets[j]);
if (!found) {
chainLightningTargets.insertLast(ChainLightningTarget(chainLightningCounter, newTargets[j],
int8((spell.baseDamage + asCaster.spellDamageBonus - players[newTargets[j]].magicResist) / 2),
CHAIN_LIGHTNING_DEFAULT_DURATION, chainLightningTargets[i].id));
chainLightningCounter++;
}
}
}
for (uint i = 0; i < chainLightningTargets.length; i++) {
if (acUtils::gameIsRunning()) {
jjPlayers[chainLightningTargets[i].playerID].hurt(chainLightningTargets[i].damage, false, jjPlayers[casterID]);
}
}
return chainLightningTargets;
}
void doEffect(uint8 effectID, int8 targetPlayerID, uint duration, bool multiplyDuration = true) {
jjPLAYER@ play = jjPlayers[targetPlayerID];
Player@ asPlayer = players[targetPlayerID];
if (multiplyDuration) duration *= SECOND;
Effect @effect;
bool affects = true;
switch (effectID) {
case SPELL_STONE_SKIN:
{
Spell@ spell = cast<Spell@>(spells["K"]);
@effect = StoneSkin(play, "Stone Skin", spell.enumValue, spell.counterSpell, duration);
jjSample(play.xPos, play.yPos, SOUND::ORANGE_BOEML);
jjSample(play.xPos, play.yPos, SOUND::ORANGE_BOEMR);
}
break;
case SPELL_BLESS:
{
Spell@ spell = cast<Spell@>(spells["B"]);
@effect = Bless(play, "Bless", spell.enumValue, spell.counterSpell, duration);
jjSample(play.xPos, play.yPos, SOUND::ORANGE_SWEEP0R);
}
break;
case SPELL_BLOOD_LUST:
{
Spell@ spell = cast<Spell@>(spells["O"]);
@effect = BloodLust(play, "Blood Lust", spell.enumValue, spell.counterSpell, duration, true);
}
break;
case SPELL_SLOW:
{
Spell@ spell = cast<Spell@>(spells["S"]);
@effect = Slow(play, "Slow", spell.enumValue, spell.counterSpell, duration,
true, true);
jjSample(play.xPos, play.yPos, SOUND::DEVILDEVAN_VANISH1);
}
break;
case SPELL_CURE:
{
if (asPlayer.activeEffects.length == 0) {
asPlayer.originalFur = play.fur; //This one works for storing the absolute original fur
}
asPlayer.removeNegativeEffects();
changePlayerFur(SPELL_UNDO, targetPlayerID);
affects = false;
jjSample(play.xPos, play.yPos, SOUND::ORANGE_SWEEP2L);
jjSample(play.xPos, play.yPos, SOUND::ORANGE_SWEEP2R);
}
break;
case SPELL_DISRUPTING_RAY:
{
Spell@ spell = cast<Spell@>(spells["R"]);
@effect = DisruptingRay(play, "Disrupting Ray", spell.enumValue, spell.counterSpell, duration,
false, true);
jjSample(play.xPos, play.yPos, SOUND::COMMON_ITEMTRE);
}
break;
case SPELL_WEAKNESS:
{
Spell@ spell = cast<Spell@>(spells["W"]);
@effect = Weakness(play, "Weakness", spell.enumValue, spell.counterSpell, duration,
false, true);
jjSample(play.xPos, play.yPos, SOUND::COMMON_HOLYFLUT);
}
break;
case SPELL_PRECISION:
{
Spell@ spell = cast<Spell@>(spells["P"]);
@effect = Precision(play, "Precision", spell.enumValue, spell.counterSpell, duration);
jjSample(play.xPos, play.yPos, SOUND::INTRO_RUN);
}
break;
case SPELL_FORGETFULNESS:
{
Spell@ spell = cast<Spell@>(spells["G"]);
@effect = Forgetfulness(play, "Forgetfulness", spell.enumValue, spell.counterSpell, duration,
true, true);
jjSample(play.xPos, play.yPos, SOUND::INTRO_GUNM0);
}
break;
case SPELL_FRENZY:
{
Spell@ spell = cast<Spell@>(spells["Y"]);
@effect = Frenzy(play, "Frenzy", spell.enumValue, spell.counterSpell, duration);
jjSample(play.xPos, play.yPos, SOUND::INTRO_MONSTER);
}
break;
}
if (affects) {
if (jjIsServer) {
if (asPlayer.activeEffects.length == 0) {
asPlayer.originalFur = play.fur; //This one works for storing the absolute original fur
}
changePlayerFur(effectID, targetPlayerID);
}
players[targetPlayerID].setNewActiveEffect(effect);
}
}
void doMassEffect(uint8 effectID, int8[] targets, uint duration) {
for (uint i = 0; i < targets.length; i++) {
int8 targetPlayerID = targets[i];
jjPLAYER@ play = jjPlayers[targetPlayerID];
Player@ asPlayer = players[targetPlayerID];
Effect @effect;
bool affects = true;
switch (effectID) {
case SPELL_SLOW:
{
Spell@ spell = cast<Spell@>(spells["S"]);
@effect = Slow(play, "Slow", spell.enumValue, spell.counterSpell, duration * SECOND,
true, true);
jjSample(play.xPos, play.yPos, SOUND::DEVILDEVAN_VANISH1);
}
break;
case SPELL_DISPEL:
{
unDoAllEffects(targetPlayerID);
affects = false;
jjSample(play.xPos, play.yPos, SOUND::WITCH_MAGIC);
}
break;
case SPELL_DISRUPTING_RAY:
{
Spell@ spell = cast<Spell@>(spells["R"]);
@effect = DisruptingRay(play, "Disrupting Ray", spell.enumValue, spell.counterSpell, duration * SECOND,
false, true);
jjSample(play.xPos, play.yPos, SOUND::COMMON_ITEMTRE);
}
break;
case SPELL_WEAKNESS:
{
Spell@ spell = cast<Spell@>(spells["W"]);
@effect = Weakness(play, "Weakness", spell.enumValue, spell.counterSpell, duration * SECOND,
false, true);
jjSample(play.xPos, play.yPos, SOUND::COMMON_HOLYFLUT);
}
break;
case SPELL_FORGETFULNESS:
{
Spell@ spell = cast<Spell@>(spells["G"]);
@effect = Forgetfulness(play, "Forgetfulness", spell.enumValue, spell.counterSpell, duration * SECOND,
true, true);
jjSample(play.xPos, play.yPos, SOUND::INTRO_GUNM0);
}
break;
}
if (affects) {
if (jjIsServer) {
if (asPlayer.activeEffects.length == 0) {
asPlayer.originalFur = play.fur; //This one works for storing the absolute original fur
}
changePlayerFur(effectID, targetPlayerID);
}
players[targetPlayerID].setNewActiveEffect(effect);
}
}
}
bool doSpell(string key) {
jjPLAYER@ caster = jjLocalPlayers[0];
Player@ asPlayer = players[caster.playerID];
int8 playerID = caster.playerID;
Spell@ spell = cast<Spell@>(spells[key]);
uint spellDuration = spell.baseDuration + asPlayer.spellDurationBonus;
switch (spell.enumValue) {
case SPELL_MAGIC_ARROW:
{
doBullet(BULLET_MAGIC_ARROW);
}
break;
case SPELL_STONE_SKIN:
{
acNetworking::sendEffectPacket(playerID, SPELL_STONE_SKIN, playerID, spellDuration);
if (jjIsServer) {
doEffect(SPELL_STONE_SKIN, playerID, spellDuration);
}
}
break;
case SPELL_BLESS:
{
acNetworking::sendEffectPacket(playerID, SPELL_BLESS, playerID, spellDuration);
if (jjIsServer) {
doEffect(SPELL_BLESS, playerID, spellDuration);
}
}
break;
case SPELL_BLOOD_LUST:
{
acNetworking::sendEffectPacket(playerID, SPELL_BLOOD_LUST, playerID, spellDuration);
if (jjIsServer) {
doEffect(SPELL_BLOOD_LUST, playerID, spellDuration);
}
jjPlayers[playerID].startSugarRush(spellDuration * 70);
}
break;
case SPELL_DISPEL:
{
float scaledRadius = acUtils::getScaledRadius(spell.radius, ANIM::FLARE, 5);
int8[] targets = acUtils::getTargets(caster, spell, scaledRadius);
if (targets.length == 0) return false;
acNetworking::sendMassEffectPacket(playerID, SPELL_DISPEL, targets, spellDuration);
if (jjIsServer) {
doMassEffect(SPELL_DISPEL, targets, spellDuration);
}
}
break;
case SPELL_SLOW:
{
float scaledRadius = acUtils::getScaledRadius(spell.radius, ANIM::FLARE, 5);
int8[] targets = acUtils::getTargets(caster, spell, scaledRadius);
if (targets.length == 0) return false;
acNetworking::sendMassEffectPacket(playerID, SPELL_SLOW, targets, spellDuration);
if (jjIsServer) {
doMassEffect(SPELL_SLOW, targets, spellDuration);
}
}
break;
case SPELL_CURE:
{
acNetworking::sendEffectPacket(playerID, SPELL_CURE, playerID, spellDuration);
if (jjIsServer) {
doEffect(SPELL_CURE, playerID, spellDuration);
}
if (caster.health < jjMaxHealth) {
int distance = caster.health - jjMaxHealth;
caster.hurt(distance, true);
}
}
break;
case SPELL_VISIONS:
{
acNetworking::sendEffectPacket(playerID, SPELL_VISIONS, playerID, spellDuration);
if (jjIsServer) {
doEffect(SPELL_VISIONS, playerID, spellDuration);
}
}
break;
case SPELL_DISRUPTING_RAY:
{
float scaledRadius = acUtils::getScaledRadius(spell.radius, ANIM::FLARE, 5);
int8[] targets = acUtils::getTargets(caster, spell, scaledRadius);
if (targets.length == 0) return false;
acNetworking::sendMassEffectPacket(playerID, SPELL_DISRUPTING_RAY, targets, spellDuration);
if (jjIsServer) {
doMassEffect(SPELL_DISRUPTING_RAY, targets, spellDuration);
}
}
break;
case SPELL_WEAKNESS:
{
float scaledRadius = acUtils::getScaledRadius(spell.radius, ANIM::FLARE, 5);
int8[] targets = acUtils::getTargets(caster, spell, scaledRadius);
if (targets.length == 0) return false;
acNetworking::sendMassEffectPacket(playerID, SPELL_WEAKNESS, targets, spellDuration);
if (jjIsServer) {
doMassEffect(SPELL_WEAKNESS, targets, spellDuration);
}
}
break;
case SPELL_ICE_BOLT:
{
doBullet(BULLET_ICE_BOLT);
}
break;
case SPELL_DEATH_RIPPLE:
{
float scaledRadius = acUtils::getScaledRadius(spell.radius, ANIM::FLARE, 5);
int8[] targets = acUtils::getTargets(caster, spell, scaledRadius);
if (targets.length == 0) return false;
acNetworking::sendAOEPacket(playerID, spell.enumValue);
if (jjIsServer) {
doAOE(caster, spell.enumValue, caster.xPos, caster.yPos);
}
}
break;
case SPELL_PRECISION:
{
acNetworking::sendEffectPacket(playerID, SPELL_PRECISION, playerID, spellDuration);
if (jjIsServer) {
doEffect(SPELL_PRECISION, playerID, spellDuration);
}
}
break;
case SPELL_WALL_OF_FIRE:
{
int direction = caster.direction;
float xOrigin = caster.xPos + direction * WALL_OF_FIRE_CASTING_RANGE;
float yOrigin = caster.yPos + 16;
int height = acUtils::getWallOfFireHeightInTiles(xOrigin, yOrigin);
if (height < 1) {
return false;
}
acNetworking::sendWallOfFirePacket(playerID, xOrigin, yOrigin, height);
if (jjIsServer) {
uint duration = (spell.baseDuration + asPlayer.spellDurationBonus) * SECOND;
doWallOfFire(caster, spell, xOrigin, yOrigin, height, duration);
}
}
break;
case SPELL_FORGETFULNESS:
{
float scaledRadius = acUtils::getScaledRadius(spell.radius, ANIM::FLARE, 5);
int8[] targets = acUtils::getTargets(caster, spell, scaledRadius);
if (targets.length == 0) return false;
acNetworking::sendMassEffectPacket(playerID, SPELL_FORGETFULNESS, targets, spellDuration);
if (jjIsServer) {
doMassEffect(SPELL_FORGETFULNESS, targets, spellDuration);
}
}
break;
case SPELL_FROST_RING:
{
float scaledRadius = acUtils::getScaledRadius(spell.radius, ANIM::FLARE, 5);
int8[] targets = acUtils::getTargets(caster, spell, scaledRadius);
if (targets.length == 0) return false;
acNetworking::sendAOEPacket(playerID, spell.enumValue);
if (jjIsServer) {
doAOE(caster, spell.enumValue, caster.xPos, caster.yPos);
}
}
break;
case SPELL_FIREBALL:
{
doBullet(BULLET_FIREBALL);
}
break;
case SPELL_FRENZY:
{
acNetworking::sendEffectPacket(playerID, SPELL_FRENZY, playerID, spellDuration);
if (jjIsServer) {
doEffect(SPELL_FRENZY, playerID, spellDuration);
}
}
break;
case SPELL_CHAIN_LIGHTNING:
{
float scaledRadius = acUtils::getScaledRadius(spell.radius, ANIM::FLARE, 5);
int8[] targets = acUtils::getTargets(caster, spell, scaledRadius);
if (targets.length == 0) return false;
acUtils::playLightningSound(caster.xPos, caster.yPos);
if (jjIsServer) {
array<ChainLightningTarget@> chainLightningTargets = doChainLightning(playerID, targets);
acNetworking::sendChainLightningPacketToClients(playerID, chainLightningTargets);
chainLightningTargetGroups.insertLast(chainLightningTargets);
} else {
acNetworking::sendChainLightningPacketToServer(playerID, targets);
}
}
break;
case SPELL_ARMAGEDDON:
{
float scaledRadius = acUtils::getScaledRadius(spell.radius, ANIM::FLARE, 5);
int8[] targets = acUtils::getTargets(caster, spell, scaledRadius);
if (targets.length == 0) return false;
acNetworking::sendAOEPacket(playerID, spell.enumValue);
if (jjIsServer) {
doAOE(caster, spell.enumValue, caster.xPos, caster.yPos);
}
}
break;
case SPELL_IMPLOSION:
{
float scaledRadius = acUtils::getScaledRadius(spell.radius, ANIM::FLARE, 5);
int8[] targets = acUtils::getTargets(caster, spell, scaledRadius);
if (targets.length == 0) return false;
acNetworking::sendAOEPacket(playerID, spell.enumValue);
if (jjIsServer) {
doAOE(caster, spell.enumValue, caster.xPos, caster.yPos);
}
}
break;
}
return true;
}
void doWallOfFire(jjPLAYER@ caster, Spell@ spell, float xOrigin, float yOrigin, int8 height, uint duration) {
Player@ asPlayer = players[caster.playerID];
removeWallOfFireByCaster(caster);
WallOfFire wallOfFire(xOrigin, yOrigin, height, spell.baseDamage + asPlayer.spellDamageBonus, duration, caster); //TODO: CHANGE TO VARIABLE
jjSample(caster.xPos, caster.yPos, SOUND::DEVILDEVAN_DRAGONFIRE);
activeWallsOfFire.insertLast(wallOfFire);
}
string getLongestSpellName() {
string longestName = "";
for (uint i = 0; i < ownSpells.length; i++) {
string spellName = cast<Spell@>(spells[ownSpells[i]]).name;
string fullName = ownSpells[i] + " " + spellName + " ";
if (fullName.length > longestName.length) longestName = fullName;
}
if (longestName.length == 0) longestName = EMPTY_SPELLBOOK;
return longestName;
}
int getSpellIndexByKey(string selectedSpellKey) {
if (selectedSpellKey == "" && ownSpells.length > 0) {
return -1;
}
for (uint i = 0; i < ownSpells.length; i++) {
Spell@ spell = cast<Spell@>(spells[ownSpells[i]]);
if (spell.key == selectedSpellKey) {
return int(i);
}
}
return -2;
}
string getSpellKeyByEnumValue(uint8 spellEnumValue) {
string spellKey = "";
array<string> spellKeys = spells.getKeys();
for (uint i = 0; i < spellKeys.length; i++) {
string key = spellKeys[i];
Spell@ spell = cast<Spell@>(spells[key]);
if (SPELL(spellEnumValue) == spell.enumValue) {
spellKey = key;
break;
}
}
return spellKey;
}
uint getTotalSpellCountByTier(uint tier) {
uint spellCount = 0;
array<string> spellKeys = spells.getKeys();
for (uint i = 0; i < spellKeys.length; i++) {
string key = spellKeys[i];
Spell@ spell = cast<Spell@>(spells[key]);
if (spell.tier == tier) spellCount++;
}
return spellCount;
}
Spell@ giveRandomSpellByTier(uint tierChance, uint minimumTier = 1) {
array<Spell@> spellsInRange;
array<string> spellKeys = spells.getKeys();
for (uint i = 0; i < spellKeys.length; i++) {
string key = spellKeys[i];
Spell@ spell = cast<Spell@>(spells[key]);
if (spell.tier <= tierChance && spell.tier >= minimumTier) {
spellsInRange.insertLast(spell);
}
}
return spellsInRange[jjRandom() % spellsInRange.length];
}
void removeSpells() {
ownSpells.removeRange(0, ownSpells.length);
}
void removeWallOfFireByCaster(jjPLAYER@ caster) {
int j = 0;
int activeWallsOfFireLength = activeWallsOfFire.length();
for (int i = 0; i < activeWallsOfFireLength; i++) {
WallOfFire@ wall = activeWallsOfFire[i];
if (@caster !is wall.caster) {
@activeWallsOfFire[j] = wall;
j++;
}
}
activeWallsOfFire.removeRange(j, activeWallsOfFireLength - j);
}
void unDoEffect(int8 targetPlayerID) {
if (jjIsServer) {
changePlayerFur(SPELL_UNDO, targetPlayerID);
}
}
void unDoAllEffects(int8 targetPlayerID) {
if (jjIsServer) changePlayerFur(SPELL_NONE, targetPlayerID);
players[targetPlayerID].removeAllActiveEffects();
}
void updateSpellDescriptions(array<string> spellKeys, Player@ asPlayer) {
for (uint i = 0; i < spellKeys.length; i++) {
string key = spellKeys[i];
Spell@ spell = cast<Spell@>(spells[key]);
string descriptionWithDmg = jjRegexReplace(spell.description, "\\{dmg\\}",
"" + (spell.baseDamage + asPlayer.spellDamageBonus));
spell.description = jjRegexReplace(descriptionWithDmg, "\\{dur\\}",
"" + (spell.baseDuration + asPlayer.spellDurationBonus));
}
}
}
Jazz2Online © 1999-INFINITY (Site Credits). We have a Privacy Policy. Jazz Jackrabbit, Jazz Jackrabbit 2, Jazz Jackrabbit Advance and all related trademarks and media are ™ and © Epic Games. Lori Jackrabbit is © Dean Dodrill. J2O development powered by Loops of Fury and Chemical Beats.
Eat your lima beans, Johnny.