/
position.lua
106 lines (93 loc) · 2.99 KB
/
position.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
local mt = rawgetmetatable("Position")
function mt.__add(lhs, rhs)
local stackpos = lhs.stackpos or rhs.stackpos
return Position(lhs.x + (rhs.x or 0), lhs.y + (rhs.y or 0), lhs.z + (rhs.z or 0), stackpos)
end
function mt.__sub(lhs, rhs)
local stackpos = lhs.stackpos or rhs.stackpos
return Position(lhs.x - (rhs.x or 0), lhs.y - (rhs.y or 0), lhs.z - (rhs.z or 0), stackpos)
end
function mt.__concat(lhs, rhs) return tostring(lhs) .. tostring(rhs) end
function mt.__eq(lhs, rhs) return lhs.x == rhs.x and lhs.y == rhs.y and lhs.z == rhs.z end
function mt.__tostring(self) return string.format("Position(%d, %d, %d)", self.x, self.y, self.z) end
Position.directionOffset = {
[DIRECTION_NORTH] = {x = 0, y = -1},
[DIRECTION_EAST] = {x = 1, y = 0},
[DIRECTION_SOUTH] = {x = 0, y = 1},
[DIRECTION_WEST] = {x = -1, y = 0},
[DIRECTION_SOUTHWEST] = {x = -1, y = 1},
[DIRECTION_SOUTHEAST] = {x = 1, y = 1},
[DIRECTION_NORTHWEST] = {x = -1, y = -1},
[DIRECTION_NORTHEAST] = {x = 1, y = -1}
}
local abs, max = math.abs, math.max
function Position:getDistance(positionEx)
local dx = abs(self.x - positionEx.x)
local dy = abs(self.y - positionEx.y)
local dz = abs(self.z - positionEx.z)
return max(dx, dy, dz)
end
function Position:getNextPosition(direction, steps)
local offset = Position.directionOffset[direction]
if offset then
steps = steps or 1
self.x = self.x + offset.x * steps
self.y = self.y + offset.y * steps
end
end
function Position:moveUpstairs()
local swap = function(lhs, rhs)
lhs.x, rhs.x = rhs.x, lhs.x
lhs.y, rhs.y = rhs.y, lhs.y
lhs.z, rhs.z = rhs.z, lhs.z
end
self.z = self.z - 1
local defaultPosition = self + Position.directionOffset[DIRECTION_SOUTH]
local toTile = Tile(defaultPosition)
if not toTile or not toTile:isWalkable() then
for direction = DIRECTION_NORTH, DIRECTION_NORTHEAST do
if direction == DIRECTION_SOUTH then
direction = DIRECTION_WEST
end
local position = Position(self)
position:getNextPosition(direction)
toTile = Tile(position)
if toTile and toTile:isWalkable() then
swap(self, position)
return self
end
end
end
swap(self, defaultPosition)
return self
end
function Position:isInRange(from, to)
-- No matter what corner from and to is, we want to make
-- life easier by calculating north-west and south-east
local zone = {
nW = {
x = (from.x < to.x and from.x or to.x),
y = (from.y < to.y and from.y or to.y),
z = (from.z < to.z and from.z or to.z)
},
sE = {
x = (to.x > from.x and to.x or from.x),
y = (to.y > from.y and to.y or from.y),
z = (to.z > from.z and to.z or from.z)
}
}
if self.x >= zone.nW.x and self.x <= zone.sE.x
and self.y >= zone.nW.y and self.y <= zone.sE.y
and self.z >= zone.nW.z and self.z <= zone.sE.z then
return true
end
return false
end
function Position:notifySummonAppear(summon)
local spectators = Game.getSpectators(self)
for _, spectator in ipairs(spectators) do
if spectator:isMonster() and spectator ~= summon then
spectator:addTarget(summon)
end
end
end