Praytic / youtd2

Classic community-driven session-based Tower Defense game with RPG elements.
https://youtd2.com/
MIT License
97 stars 17 forks source link

Tower attack ranges should calculate from tower edge, not center #437

Closed Kvel2D closed 6 months ago

Kvel2D commented 6 months ago

The difference is 72 and comes from original youtd/wc3 engine.

Proof below.

Icy skulls is a tower with 700 attack range. Each tile is 128 wide.

At 6 tile distance, creeps are in 700 attack range. At 6.5 tile distances, creeps are out of 700 attack range.

6 * 128 = 768 and 768 > 700 6.5 * 128 = 832 and 832 > 700 With +72 range extension: 768 < 772

2024-05-22 21_36_42-title_screen tscn - YouTD 2 - Godot Engine 2024-05-22 21_37_34-title_screen tscn - YouTD 2 - Godot Engine

Note that this also affects tower-tower abilities and this is already implemented in Utils.get_units_in_range(). BUT this doesn't affect tower-creep auras. Proof below.

Icy Core has aura with range of 800.

At 6 tile distance, creeps are in 800 aura range. At 6.5 tile distances, creeps are out of 800 aura range.

6 * 128 = 768 and 768 < 800 6.5 * 128 = 832 and 832 > 800 If there was an extension of 72 applied to tower-creep aura, then aura would reach the creep at 6.5 tiles because 832 < 872.

2024-05-22 22_23_12-Warcraft III 2024-05-22 22_24_37-game_scene tscn - YouTD 2 - Godot Engine

Note that even after implementing the extension, youtd2 ranges might not behave exactly like original youtd because in youtd2 the creep paths are centered while in original youtd, the creep paths are slightly closer to tower areas.

In terms of game code, the way it works is that Iterate does range checks with an extra bonus based on "unit radius". This unit radius is 72 for towers and 8 for creeps. The radius is added only from target, not from tower.

function unit_is_in_range takes unit j5,real x,real y,real R5 returns boolean
    return u8(x,y,b8(j5),B8(j5))<=R5+get_unit_radius(j5)
endfunction

function get_unit_radius takes unit u returns real
//  This means "if unit is tower"
    if(GetUnitPointValue((u))<90000)then
        return 8.
    endif
    return 72.
endfunction

But attack ranges are special because they use built-in wc3 range checking instead of Iterate, so the radius is added both from target(creep) and from attacker (tower).