Commit 82ca400a0f21a21261624cc386a51526a401af81

Authored by dg
1 parent 2712603b

fix


git-svn-id: http://svn.net-core.org/repos/t-engine4@2888 51575b47-30f0-44d4-a5cc-537603b46e54
... ... @@ -195,12 +195,14 @@ function _M:act()
195 195 if x and y then self:move(x, y) end
196 196 if act then self.src:projectDoAct(self.project.def.typ, self.project.def.tg, self.project.def.damtype, self.project.def.dam, self.project.def.particles, self.x, self.y, self.tmp_proj) end
197 197 if stop then
198   - -- Correct the explosion source position if we exploded on terrain
199   - local radius_x, radius_y
  198 + local block, hit, hit_radius = false, true, true
200 199 if self.project.def.typ.block_path then
201   - _, radius_x, radius_y = self.project.def.typ:block_path(self.x, self.y)
  200 + block, hit, hit_radius = self.project.def.typ:block_path(self.x, self.y)
202 201 end
203   - if not radius_x then
  202 + local radius_x, radius_y
  203 + if hit_radius then
  204 + radius_x, radius_y = self.x, self.y
  205 + else
204 206 radius_x, radius_y = self.old_x, self.old_y
205 207 end
206 208 game.level:removeEntity(self)
... ...
... ... @@ -75,44 +75,46 @@ function _M:display(dispx, dispy)
75 75 local lx, ly = l()
76 76 local initial_dir = lx and coord_to_dir[lx - self.source_actor.x][ly - self.source_actor.y] or 5
77 77 local stop_x, stop_y = self.source_actor.x, self.source_actor.y
78   - local stop_radius_x, stop_radius_y = stopx, stopy
79   - local blocked = false
  78 + local stop_radius_x, stop_radius_y = self.source_actor.x, self.source_actor.y
  79 + local stopped = false
80 80 while lx and ly do
81   - if s == self.sb then
82   - stop_radius_x, stop_radius_y = stop_x, stop_y
  81 + local block, hit, hit_radius = false, true, true
  82 + if self.target_type.block_path then
  83 + block, hit, hit_radius = self.target_type:block_path(lx, ly)
  84 + end
  85 +
  86 + -- Update coordinates and set color
  87 + if hit and not stopped then
83 88 stop_x, stop_y = lx, ly
  89 + else
  90 + s = self.sr
  91 + end
  92 + if hit_radius and not stopped then
  93 + stop_radius_x, stop_radius_y = lx, ly
84 94 end
85   - if self.target_type.min_range then
  95 + if self.target_type.min_range and not stopped then
86 96 -- Check if we should be "red"
87 97 if core.fov.distance(self.source_actor.x, self.source_actor.y, lx, ly) < self.target_type.min_range then
88 98 s = self.sr
89 99 -- Check if we were only "red" because of minimum distance
90   - elseif s == self.sr and not blocked then
  100 + elseif s == self.sr then
91 101 s = self.sb
92 102 end
93 103 end
94 104 s:toScreen(self.display_x + (lx - game.level.map.mx) * self.tile_w * Map.zoom, self.display_y + (ly - game.level.map.my) * self.tile_h * Map.zoom, self.tile_w * Map.zoom, self.tile_h * Map.zoom)
95   - if self.target_type.block_path and self.target_type:block_path(lx, ly) then
  105 + if block then
96 106 s = self.sr
97   - blocked = true
  107 + stopped = true
98 108 end
  109 +
99 110 lx, ly = l()
100 111 end
101 112 self.cursor:toScreen(self.display_x + (self.target.x - game.level.map.mx) * self.tile_w * Map.zoom, self.display_y + (self.target.y - game.level.map.my) * self.tile_h * Map.zoom, self.tile_w * Map.zoom, self.tile_h * Map.zoom)
102 113
103   - -- Correct the explosion source position if we exploded on terrain
104   - local radius_x, radius_y
105   - if self.target_type.block_path and self.target_type.radius and self.target_type.radius > 0 then
106   - _, radius_x, radius_y = self.target_type:block_path(stop_x, stop_y)
107   - end
108   - if not radius_x then
109   - radius_x, radius_y = stop_radius_x, stop_radius_y
110   - end
111   -
112 114 if self.target_type.ball and self.target_type.ball > 0 then
113 115 core.fov.calc_circle(
114   - radius_x,
115   - radius_y,
  116 + stop_radius_x,
  117 + stop_radius_y,
116 118 game.level.map.w,
117 119 game.level.map.h,
118 120 self.target_type.ball,
... ... @@ -128,8 +130,8 @@ function _M:display(dispx, dispy)
128 130 nil)
129 131 elseif self.target_type.cone and self.target_type.cone > 0 then
130 132 core.fov.calc_beam(
131   - radius_x,
132   - radius_y,
  133 + stop_radius_x,
  134 + stop_radius_y,
133 135 game.level.map.w,
134 136 game.level.map.h,
135 137 self.target_type.cone,
... ... @@ -164,7 +166,7 @@ end
164 166 -- @param t.stop_block Boolean that stops the target on the first tile that has an entity that blocks move.
165 167 -- @param t.range The range the target can be from the origin.
166 168 -- @param t.pass_terrain Boolean that allows the target to pass through terrain to remembered tiles on the other side.
167   --- @param t.block_path(typ, lx, ly) Function called on each tile to determine if the targeting is blocked. Automatically set when using t.typ, but the user can provide their own if they know what they are doing.
  169 +-- @param t.block_path(typ, lx, ly) Function called on each tile to determine if the targeting is blocked. Automatically set when using t.typ, but the user can provide their own if they know what they are doing. It should return three arguments: block, hit, hit_radius
168 170 -- @param t.block_radius(typ, lx, ly) Function called on each tile when projecting the radius to determine if the radius projection is blocked. Automatically set when using t.typ, but the user can provide their own if they know what they are doing.
169 171 function _M:getType(t)
170 172 if not t then return {} end
... ... @@ -177,14 +179,27 @@ function _M:getType(t)
177 179 friendlyfire=true,
178 180 block_path = function(typ, lx, ly)
179 181 if not typ.no_restrict then
180   - if typ.requires_knowledge and not game.level.map.remembers(lx, ly) and not game.level.map.seens(lx, ly) then return true end
181   - if not typ.pass_terrain and game.level.map:checkEntity(lx, ly, engine.Map.TERRAIN, "block_move") then return true
  182 + if typ.range and typ.source_actor and typ.source_actor.x then
  183 + local dist = core.fov.distance(typ.source_actor.x, typ.source_actor.y, lx, ly)
  184 + -- Need to handle range 1 separately to allow diagonal hits
  185 + if typ.range == 1 then
  186 + if math.floor(dist) > 1 then return true, false, false end
  187 + else
  188 + if dist > typ.range then return true, false, false end
  189 + end
  190 + end
  191 + if typ.requires_knowledge and not game.level.map.remembers(lx, ly) and not game.level.map.seens(lx, ly) then
  192 + return true, false, false
  193 + end
  194 + if not typ.pass_terrain and game.level.map:checkEntity(lx, ly, engine.Map.TERRAIN, "block_move") then
  195 + return true, true, false
182 196 -- If we explode due to something other than terrain, then we should explode ON the tile, not before it
183   - elseif typ.stop_block and game.level.map:checkAllEntities(lx, ly, "block_move") then return true, lx, ly end
184   - if typ.range and typ.source_actor and typ.source_actor.x and core.fov.distance(typ.source_actor.x, typ.source_actor.y, lx, ly) > typ.range then return true end
  197 + elseif typ.stop_block and game.level.map:checkAllEntities(lx, ly, "block_move") then
  198 + return true, true, true
  199 + end
185 200 end
186 201 -- If we don't block the path, then the explode point should be here
187   - return false, lx, ly
  202 + return false, true, true
188 203 end,
189 204 block_radius=function(typ, lx, ly)
190 205 return not typ.no_restrict and game.level.map:checkEntity(lx, ly, engine.Map.TERRAIN, "block_move")
... ...
... ... @@ -60,42 +60,60 @@ function _M:project(t, x, y, damtype, dam, particles)
60 60 lx, ly = l()
61 61 local initial_dir = lx and coord_to_dir[lx - srcx][ly - srcy] or 5
62 62 while lx and ly do
63   - stop_radius_x, stop_radius_y = stop_x, stop_y
64   - stop_x, stop_y = lx, ly
65   -
66   - -- Deal damage: beam
67   - if typ.line then addGrid(lx, ly) end
68   -
69   - -- Call the on project of the target grid if possible
70   - if not t.bypass and game.level.map:checkAllEntities(lx, ly, "on_project", self, t, lx, ly, damtype, dam, particles) then
71   - return
  63 + local block, hit, hit_radius = false, true, true
  64 + if typ.block_path then
  65 + block, hit, hit_radius = typ:block_path(lx, ly)
  66 + end
  67 + if hit then
  68 + stop_x, stop_y = lx, ly
  69 + -- Deal damage: beam
  70 + if typ.line then addGrid(lx, ly) end
  71 + -- WHAT DOES THIS DO AGAIN?
  72 + -- Call the on project of the target grid if possible
  73 + if not t.bypass and game.level.map:checkAllEntities(lx, ly, "on_project", self, t, lx, ly, damtype, dam, particles) then
  74 + return
  75 + end
  76 + end
  77 + if hit_radius then
  78 + stop_radius_x, stop_radius_y = lx, ly
72 79 end
73 80
74   - if typ.block_path and typ:block_path(lx, ly) then break end
  81 + if block then break end
75 82 lx, ly = l()
76 83 end
77 84
78   - -- Correct the explosion source position if we exploded on terrain
79   - local radius_x, radius_y
80   - if typ.block_path then
81   - _, radius_x, radius_y = typ:block_path(stop_x, stop_y)
82   - end
83   - if not radius_x then
84   - radius_x, radius_y = stop_radius_x, stop_radius_y
85   - end
86 85 if typ.ball and typ.ball > 0 then
87   - core.fov.calc_circle(radius_x, radius_y, game.level.map.w, game.level.map.h, typ.ball, function(_, px, py)
88   - -- Deal damage: ball
89   - addGrid(px, py)
90   - if typ.block_radius and typ:block_radius(px, py) then return true end
91   - end, function()end, nil)
  86 + core.fov.calc_circle(
  87 + stop_radius_x,
  88 + stop_radius_y,
  89 + game.level.map.w,
  90 + game.level.map.h,
  91 + typ.ball,
  92 + function(_, px, py)
  93 + if typ.block_radius and typ:block_radius(px, py) then return true end
  94 + end,
  95 + function(_, px, py)
  96 + -- Deal damage: ball
  97 + addGrid(px, py)
  98 + end,
  99 + nil)
92 100 addGrid(stop_x, stop_y)
93 101 elseif typ.cone and typ.cone > 0 then
94   - core.fov.calc_beam(radius_x, radius_y, game.level.map.w, game.level.map.h, typ.cone, initial_dir, typ.cone_angle, function(_, px, py)
95   - -- Deal damage: cone
96   - addGrid(px, py)
97   - if typ.block_radius and typ:block_radius(px, py) then return true end
98   - end, function()end, nil)
  102 + core.fov.calc_beam(
  103 + stop_radius_x,
  104 + stop_radius_y,
  105 + game.level.map.w,
  106 + game.level.map.h,
  107 + typ.cone,
  108 + initial_dir,
  109 + typ.cone_angle,
  110 + function(_, px, py)
  111 + if typ.block_radius and typ:block_radius(px, py) then return true end
  112 + end,
  113 + function(_, px, py)
  114 + addGrid(px, py)
  115 + end,
  116 + nil)
99 117 addGrid(stop_x, stop_y)
100 118 else
101 119 -- Deal damage: single
... ... @@ -154,19 +172,19 @@ function _M:canProject(t, x, y)
154 172 local l = line.new(self.x, self.y, x, y)
155 173 lx, ly = l()
156 174 while lx and ly do
157   - stop_radius_x, stop_radius_y = stop_x, stop_y
158   - stop_x, stop_y = lx, ly
159   - if typ.block_path and typ:block_path(lx, ly) then break end
160   - lx, ly = l()
161   - end
  175 + local block, hit, hit_radius = false, true, true
  176 + if typ.block_path then
  177 + block, hit, hit_radius = typ:block_path(lx, ly)
  178 + end
  179 + if hit then
  180 + stop_x, stop_y = lx, ly
  181 + end
  182 + if hit_radius then
  183 + stop_radius_x, stop_radius_y = lx, ly
  184 + end
162 185
163   - -- Correct the explosion source position if we exploded on terrain
164   - local radius_x, radius_y
165   - if typ.block_path then
166   - _, radius_x, radius_y = typ:block_path(stop_x, stop_y)
167   - end
168   - if not radius_x then
169   - radius_x, radius_y = stop_radius_x, stop_radius_y
  186 + if block then break end
  187 + lx, ly = l()
170 188 end
171 189
172 190 -- Check for minimum range
... ... @@ -175,7 +193,7 @@ function _M:canProject(t, x, y)
175 193 end
176 194
177 195 if stop_x == x and stop_y == y then return true, stop_x, stop_y, stop_x, stop_y end
178   - return false, stop_x, stop_y, radius_x, radius_y
  196 + return false, stop_x, stop_y, stop_radius_x, stop_radius_y
179 197 end
180 198
181 199 --- Project damage to a distance using a moving projectile
... ... @@ -196,6 +214,13 @@ function _M:projectile(t, x, y, damtype, dam, particles)
196 214 game.zone:addEntity(game.level, proj, "projectile", self.x, self.y)
197 215 end
198 216
  217 +-- @param typ a target type table
  218 +-- @param tgtx the target's x-coordinate
  219 +-- @param tgty the target's y-coordinate
  220 +-- @param x the projectile's x-coordinate
  221 +-- @param y the projectile's x-coordinate
  222 +-- @param srcx the sources's x-coordinate
  223 +-- @param srcx the source's x-coordinate
199 224 -- @return lx x-coordinate the projectile travels to next
200 225 -- @return ly y-coordinate the projectile travels to next
201 226 -- @return act should we call projectDoAct (usually only for beam)
... ... @@ -210,10 +235,24 @@ function _M:projectDoMove(typ, tgtx, tgty, x, y, srcx, srcy)
210 235 if lx and ly then lx, ly = l() end
211 236
212 237 if lx and ly then
213   - if typ.block_path and typ:block_path(lx, ly) then return lx, ly, false, true end
  238 + local block, hit, hit_radius = false, true, true
  239 + if typ.block_path then
  240 + block, hit, hit_radius = typ:block_path(lx, ly)
  241 + end
  242 +
  243 + if block then
  244 + if hit then
  245 + return lx, ly, false, true
  246 + -- If we don't hit the tile, pass back nils to stop on the current spot
  247 + else
  248 + return nil, nil, false, true
  249 + end
  250 + end
214 251
215 252 -- End of the map
216   - if lx < 0 or lx >= game.level.map.w or ly < 0 or ly >= game.level.map.h then return lx, ly, false, true end
  253 + if lx < 0 or lx >= game.level.map.w or ly < 0 or ly >= game.level.map.h then
  254 + return nil, nil, false, true
  255 + end
217 256
218 257 -- Deal damage: beam
219 258 if typ.line and (lx ~= tgtx or ly ~= tgty) then return lx, ly, true, false end
... ... @@ -251,19 +290,39 @@ function _M:projectDoStop(typ, tg, damtype, dam, particles, lx, ly, tmp, rx, ry)
251 290 end
252 291
253 292 if typ.ball and typ.ball > 0 then
254   - core.fov.calc_circle(rx, ry, game.level.map.w, game.level.map.h, typ.ball, function(_, px, py)
255   - -- Deal damage: ball
256   - addGrid(px, py)
257   - if typ.block_radius and typ:block_radius(px, py) then return true end
258   - end, function()end, nil)
  293 + core.fov.calc_circle(
  294 + rx,
  295 + ry,
  296 + game.level.map.w,
  297 + game.level.map.h,
  298 + typ.ball,
  299 + function(_, px, py)
  300 + if typ.block_radius and typ:block_radius(px, py) then return true end
  301 + end,
  302 + function(_, px, py)
  303 + -- Deal damage: ball
  304 + addGrid(px, py)
  305 + end,
  306 + nil)
259 307 addGrid(rx, ry)
260 308 elseif typ.cone and typ.cone > 0 then
261 309 local initial_dir = lx and util.getDir(lx, ly, x, y) or 5
262   - core.fov.calc_beam(rx, ry, game.level.map.w, game.level.map.h, typ.cone, initial_dir, typ.cone_angle, function(_, px, py)
263   - -- Deal damage: cone
264   - addGrid(px, py)
265   - if typ.block_radius and typ:block_radius(px, py) then return true end
266   - end, function()end, nil)
  310 + core.fov.calc_beam(
  311 + rx,
  312 + ry,
  313 + game.level.map.w,
  314 + game.level.map.h,
  315 + typ.cone,
  316 + initial_dir,
  317 + typ.cone_angle,
  318 + function(_, px, py)
  319 + if typ.block_radius and typ:block_radius(px, py) then return true end
  320 + end,
  321 + function(_, px, py)
  322 + -- Deal damage: cone
  323 + addGrid(px, py)
  324 + end,
  325 + nil)
267 326 addGrid(rx, ry)
268 327 else
269 328 -- Deal damage: single
... ...
... ... @@ -103,17 +103,26 @@ function _M:generateList()
103 103
104 104 -- Talents
105 105 if game.zone and not game.zone.wilderness then
  106 + local canHit = function(tg, x, y)
  107 + local hit = false
  108 + player:project(tg, x, y, function(px, py)
  109 + if px == x and py == y then
  110 + hit = true
  111 + end
  112 + end)
  113 + return hit
  114 + end
106 115 local tals = {}
107 116 for tid, _ in pairs(player.talents) do
108 117 local t = player:getTalentFromId(tid)
109 118 local t_avail = false
110 119 local tg = player:getTalentTarget(t)
111   - local default_tg = {type=util.getval(t.direct_hit, player, t) and "hit" or "bolt"}
112   - local total_dist = (player:getTalentRange(t) + player:getTalentRadius(t))
  120 + local total_range = player:getTalentRange(t) + player:getTalentRadius(t)
  121 + local default_tg = {type=util.getval(t.direct_hit, player, t) and "hit" or "bolt", range=total_range}
113 122 if t.mode == "activated" and not player:isTalentCoolingDown(t) and
114 123 player:preUseTalent(t, true, true) and
115 124 (not player:getTalentRequiresTarget(t) or
116   - player:canProject(tg or default_tg, self.tmx, self.tmy))
  125 + canHit(tg or default_tg, self.tmx, self.tmy))
117 126 then
118 127 t_avail = true
119 128 elseif t.mode == "sustained" and not t.no_npc_use and
... ...