diff --git a/design/skills.py b/design/skills.py index b8cdc2d..909ab12 100644 --- a/design/skills.py +++ b/design/skills.py @@ -221,6 +221,7 @@ skills={ "cooldown":60000, "target":"monster", "hostile":True, + "use_range":True, }, "tangle":{ "type":"skill", @@ -232,6 +233,8 @@ skills={ "cooldown":60000, "target":True, "hostile":True, + "use_range":True, + "range_multiplier":2, }, "rspeed":{ "type":"skill", @@ -606,6 +609,9 @@ skills={ "cooldown":10000, "target":True, "hostile":True, + "range_multiplier":3, + "range_bonus":20, + "use_range": True }, "pcoat":{ "type":"skill", @@ -644,6 +650,7 @@ skills={ "warning":"Highly unbalanced skill, could get nerfed or modified", "hostile":True, "projectile":"mentalburst", + "use_range":True, }, "quickpunch":{ "type":"skill", @@ -748,6 +755,7 @@ skills={ "pierces_immunity":True, "damage_type":"physical", "procs":True, + "use_range":True, }, "3shot":{ "type":"skill", @@ -810,6 +818,7 @@ skills={ "name":"Curse", "explanation":"Cursed opponents receive 20% more damage, deal 20% less damage and they slow down by 20.", "mp":400, + "range":200, "duration":5000, "cooldown":5000, "condition":"cursed", diff --git a/node/server.js b/node/server.js index 360f3c7..23be148 100644 --- a/node/server.js +++ b/node/server.js @@ -2886,9 +2886,6 @@ function commence_attack(attacker, target, atype) { } else if (atype == "cburst") { var mp_cutoff = attacker.next_mp; var mp = attacker.next_mp; - if (atype == "cburst") { - mp = mp_cutoff = attacker.next_mp; - } if (attacker.mp < mp_cutoff) { attacker.socket.emit("game_response", { response: "no_mp" }); return { failed: true, reason: "no_mp", place: atype, id: target.id }; @@ -8259,7 +8256,8 @@ function init_io() { } // Range check - if (target && (gSkill.range || gSkill.use_range)) { + const isTargetTooFar = (target) => { + // Use the range of the skill, falling back to the player range if it isn't set let range = gSkill.range || player.range; if (gSkill.range_multiplier) { range *= gSkill.range_multiplier; @@ -8274,12 +8272,16 @@ function init_io() { const dist = distance(player, target); if (dist > range + player.xrange) { - return fail_response("too_far", data.name, { dist: dist, id: target.id }); + return true; } if (dist > range) { // xrange was used, reduce it by however much we used player.xrange -= dist - range; } + return false; + }; + if (target && isTargetTooFar(target)) { + return fail_response("too_far", data.name, { dist: dist, id: target.id }); } // Consume item check @@ -8573,37 +8575,41 @@ function init_io() { resend(target, "u+cid"); } } else if (data.name == "cburst") { - var hit = {}; - var times = 0; + var targeted = {}; var attack = null; var c_resolve = null; consume_mp(player, gSkill.mp); player.first_burst = true; player.halt = true; if (is_array(data.targets)) { - data.targets.forEach(function (t) { - // console.log(id); - var id = t[0]; - var mp = max(0, parseInt(t[1]) || 0); - if (player.mp < 20 || times > 16 || !mp) { - return; + // Only look at the first 16 targets in the array if more are provided + for (const t of data.targets.slice(0, 16)) { + const id = t[0]; + + // Prevent attacking the same entity twice + if (targeted[id]) { + continue; } - times += 1; - var target = instances[player.in].monsters[id]; + targeted[id] = true; + + const mp = max(0, parseInt(t[1]) || 0); + if (mp <= 0) { + continue; + } + let target = instances[player.in].monsters[id]; if (!target) { target = instances[player.in].players[id]; } if (!target || is_invinc(target) || target.name == player.name) { - return; + continue; } - if (hit[id]) { - return; + if (isTargetTooFar(target)) { + continue; } - hit[id] = true; player.next_mp = mp; attack = commence_attack(player, target, "cburst"); if (!attack || !attack.projectile) { - return; + continue; } if (!c_resolve) { c_resolve = attack; @@ -8613,14 +8619,12 @@ function init_io() { c_resolve.pids.push(attack.pid); c_resolve.targets.push(attack.target); } - }); + } } player.halt = false; player.to_resend = "u+cid"; if (!c_resolve) { - if (attack) { - reject = attack; - } + reject = { failed: true, place: data.name, reason: "no_target" }; disappearing_text(player.socket, player, "NO HITS"); } else { resolve = c_resolve; @@ -8662,40 +8666,34 @@ function init_io() { xy_emit(player, "ui", { type: data.name }); } else if (data.name == "3shot" || data.name == "5shot") { player.halt = true; - var times = 0; - var hit = {}; - var reftarget = null; - var targets = 3; - var attack = null; - var c_resolve = null; - if (data.name == "5shot") { - targets = 5; - } + const targeted = {}; + let c_resolve = null; //console.log(data.ids); if (is_array(data.ids)) { - data.ids.forEach(function (id) { - if (times >= targets) { - return; + // Only look at the first Xshot targets in the array if more are provided + for (const id of data.ids.slice(0, data.name === "5shot" ? 5 : 3)) { + // Prevent attacking the same entity twice + if (targeted[id]) { + continue; } - times += 1; - var target = instances[player.in].monsters[id]; + targeted[id] = true; + + target = instances[player.in].monsters[id]; if (!target) { target = instances[player.in].players[id]; } + if (!target || is_invinc(target) || target.name == player.name) { - attack = { failed: true, place: data.name, reason: "no_target" }; - return; + continue; } - if (hit[id]) { - return; + if (isTargetTooFar(target)) { + continue; } - hit[id] = true; - attack = commence_attack(player, target, data.name); + const attack = commence_attack(player, target, data.name); if (!attack || !attack.projectile) { - return; + continue; } if (!c_resolve) { - reftarget = target; c_resolve = attack; attack.pids = [attack.pid]; attack.targets = [attack.target]; @@ -8703,16 +8701,13 @@ function init_io() { c_resolve.pids.push(attack.pid); c_resolve.targets.push(attack.target); } - // if(times==1 && attack==null) times=40; - }); + } } - consume_mp(player, gSkill.mp, reftarget); player.halt = false; player.to_resend = "u+cid"; + consume_mp(player, gSkill.mp, target); if (!c_resolve) { - if (attack) { - reject = attack; - } + reject = { failed: true, place: data.name, reason: "no_target" }; disappearing_text(player.socket, player, "NO HITS"); } else { resolve = c_resolve;