Commit 94badf6aade63ed8359079a3c7f1f41463336daf

Authored by dg
1 parent 6f71a96d

Breaths and cone attacks can be targetted at any angle now


git-svn-id: http://svn.net-core.org/repos/t-engine4@2891 51575b47-30f0-44d4-a5cc-537603b46e54
... ... @@ -129,13 +129,14 @@ function _M:display(dispx, dispy)
129 129 end,
130 130 nil)
131 131 elseif self.target_type.cone and self.target_type.cone > 0 then
132   - core.fov.calc_beam(
  132 + local dir_angle = math.deg(math.atan2(self.target.y - self.source_actor.y, self.target.x - self.source_actor.x))
  133 + core.fov.calc_beam_any_angle(
133 134 stop_radius_x,
134 135 stop_radius_y,
135 136 game.level.map.w,
136 137 game.level.map.h,
137 138 self.target_type.cone,
138   - initial_dir,
  139 + dir_angle,
139 140 self.target_type.cone_angle,
140 141 function(_, px, py)
141 142 if self.target_type.block_radius and self.target_type:block_radius(px, py) then return true end
... ... @@ -181,12 +182,7 @@ function _M:getType(t)
181 182 if not typ.no_restrict then
182 183 if typ.range and typ.source_actor and typ.source_actor.x then
183 184 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
  185 + if math.floor(dist - typ.range + 0.5) > 0 then return true, false, false end
190 186 end
191 187 if typ.requires_knowledge and not game.level.map.remembers(lx, ly) and not game.level.map.seens(lx, ly) then
192 188 return true, false, false
... ...
... ... @@ -99,13 +99,14 @@ function _M:project(t, x, y, damtype, dam, particles)
99 99 nil)
100 100 addGrid(stop_x, stop_y)
101 101 elseif typ.cone and typ.cone > 0 then
102   - core.fov.calc_beam(
  102 + local dir_angle = math.deg(math.atan2(y - self.y, x - self.x))
  103 + core.fov.calc_beam_any_angle(
103 104 stop_radius_x,
104 105 stop_radius_y,
105 106 game.level.map.w,
106 107 game.level.map.h,
107 108 typ.cone,
108   - initial_dir,
  109 + dir_angle,
109 110 typ.cone_angle,
110 111 function(_, px, py)
111 112 if typ.block_radius and typ:block_radius(px, py) then return true end
... ... @@ -307,7 +308,8 @@ function _M:projectDoStop(typ, tg, damtype, dam, particles, lx, ly, tmp, rx, ry)
307 308 addGrid(rx, ry)
308 309 elseif typ.cone and typ.cone > 0 then
309 310 local initial_dir = lx and util.getDir(lx, ly, x, y) or 5
310   - core.fov.calc_beam(
  311 + local dir_angle = math.deg(math.atan2(ly - typ.source_actor.y, lx - typ.source_actor.x))
  312 + core.fov.calc_beam_any_angle(
311 313 rx,
312 314 ry,
313 315 game.level.map.w,
... ...
... ... @@ -22,21 +22,7 @@ local dir = 0
22 22 local spread = spread or 55/2
23 23 local radius = radius or 6
24 24
25   -local max = math.max(math.abs(tx), math.abs(ty))
26   -tx = tx / max
27   -ty = ty / max
28   -if tx >= 0.5 then tx = 1 elseif tx <= -0.5 then tx = -1 else tx = 0 end
29   -if ty >= 0.5 then ty = -1 elseif ty <= -0.5 then ty = 1 else ty = 0 end -- Why the hell is ty inverted ? .. but it works :/
30   -
31   -if tx == 1 and ty == 0 then dir = 0
32   -elseif tx == 1 and ty == -1 then dir = 45
33   -elseif tx == 0 and ty == -1 then dir = 90
34   -elseif tx == -1 and ty == -1 then dir = 135
35   -elseif tx == -1 and ty == 0 then dir = 180
36   -elseif tx == -1 and ty == 1 then dir = 225
37   -elseif tx == 0 and ty == 1 then dir = 270
38   -elseif tx == 1 and ty == 1 then dir = 315
39   -end
  25 +dir = math.deg(math.atan2(ty, tx))
40 26
41 27 return { generator = function()
42 28 local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
... ...
... ... @@ -22,21 +22,7 @@ local dir = 0
22 22 local spread = spread or 55/2
23 23 local radius = radius or 6
24 24
25   -local max = math.max(math.abs(tx), math.abs(ty))
26   -tx = tx / max
27   -ty = ty / max
28   -if tx >= 0.5 then tx = 1 elseif tx <= -0.5 then tx = -1 else tx = 0 end
29   -if ty >= 0.5 then ty = -1 elseif ty <= -0.5 then ty = 1 else ty = 0 end -- Why the hell is ty inverted ? .. but it works :/
30   -
31   -if tx == 1 and ty == 0 then dir = 0
32   -elseif tx == 1 and ty == -1 then dir = 45
33   -elseif tx == 0 and ty == -1 then dir = 90
34   -elseif tx == -1 and ty == -1 then dir = 135
35   -elseif tx == -1 and ty == 0 then dir = 180
36   -elseif tx == -1 and ty == 1 then dir = 225
37   -elseif tx == 0 and ty == 1 then dir = 270
38   -elseif tx == 1 and ty == 1 then dir = 315
39   -end
  25 +dir = math.deg(math.atan2(ty, tx))
40 26
41 27 return { generator = function()
42 28 local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
... ...
... ... @@ -22,21 +22,7 @@ local dir = 0
22 22 local spread = spread or 55/2
23 23 local radius = radius or 6
24 24
25   -local max = math.max(math.abs(tx), math.abs(ty))
26   -tx = tx / max
27   -ty = ty / max
28   -if tx >= 0.5 then tx = 1 elseif tx <= -0.5 then tx = -1 else tx = 0 end
29   -if ty >= 0.5 then ty = -1 elseif ty <= -0.5 then ty = 1 else ty = 0 end -- Why the hell is ty inverted ? .. but it works :/
30   -
31   -if tx == 1 and ty == 0 then dir = 0
32   -elseif tx == 1 and ty == -1 then dir = 45
33   -elseif tx == 0 and ty == -1 then dir = 90
34   -elseif tx == -1 and ty == -1 then dir = 135
35   -elseif tx == -1 and ty == 0 then dir = 180
36   -elseif tx == -1 and ty == 1 then dir = 225
37   -elseif tx == 0 and ty == 1 then dir = 270
38   -elseif tx == 1 and ty == 1 then dir = 315
39   -end
  25 +dir = math.deg(math.atan2(ty, tx))
40 26
41 27 return { generator = function()
42 28 local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
... ...
... ... @@ -22,21 +22,7 @@ local dir = 0
22 22 local spread = spread or 55/2
23 23 local radius = radius or 6
24 24
25   -local max = math.max(math.abs(tx), math.abs(ty))
26   -tx = tx / max
27   -ty = ty / max
28   -if tx >= 0.5 then tx = 1 elseif tx <= -0.5 then tx = -1 else tx = 0 end
29   -if ty >= 0.5 then ty = -1 elseif ty <= -0.5 then ty = 1 else ty = 0 end -- Why the hell is ty inverted ? .. but it works :/
30   -
31   -if tx == 1 and ty == 0 then dir = 0
32   -elseif tx == 1 and ty == -1 then dir = 45
33   -elseif tx == 0 and ty == -1 then dir = 90
34   -elseif tx == -1 and ty == -1 then dir = 135
35   -elseif tx == -1 and ty == 0 then dir = 180
36   -elseif tx == -1 and ty == 1 then dir = 225
37   -elseif tx == 0 and ty == 1 then dir = 270
38   -elseif tx == 1 and ty == 1 then dir = 315
39   -end
  25 +dir = math.deg(math.atan2(ty, tx))
40 26
41 27 return { generator = function()
42 28 local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
... ...
... ... @@ -22,21 +22,7 @@ local dir = 0
22 22 local spread = spread or 55/2
23 23 local radius = radius or 6
24 24
25   -local max = math.max(math.abs(tx), math.abs(ty))
26   -tx = tx / max
27   -ty = ty / max
28   -if tx >= 0.5 then tx = 1 elseif tx <= -0.5 then tx = -1 else tx = 0 end
29   -if ty >= 0.5 then ty = -1 elseif ty <= -0.5 then ty = 1 else ty = 0 end -- Why the hell is ty inverted ? .. but it works :/
30   -
31   -if tx == 1 and ty == 0 then dir = 0
32   -elseif tx == 1 and ty == -1 then dir = 45
33   -elseif tx == 0 and ty == -1 then dir = 90
34   -elseif tx == -1 and ty == -1 then dir = 135
35   -elseif tx == -1 and ty == 0 then dir = 180
36   -elseif tx == -1 and ty == 1 then dir = 225
37   -elseif tx == 0 and ty == 1 then dir = 270
38   -elseif tx == 1 and ty == 1 then dir = 315
39   -end
  25 +dir = math.deg(math.atan2(ty, tx))
40 26
41 27 return { generator = function()
42 28 local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
... ...
... ... @@ -22,21 +22,7 @@ local dir = 0
22 22 local spread = spread or 55/2
23 23 local radius = radius or 6
24 24
25   -local max = math.max(math.abs(tx), math.abs(ty))
26   -tx = tx / max
27   -ty = ty / max
28   -if tx >= 0.5 then tx = 1 elseif tx <= -0.5 then tx = -1 else tx = 0 end
29   -if ty >= 0.5 then ty = -1 elseif ty <= -0.5 then ty = 1 else ty = 0 end -- Why the hell is ty inverted ? .. but it works :/
30   -
31   -if tx == 1 and ty == 0 then dir = 0
32   -elseif tx == 1 and ty == -1 then dir = 45
33   -elseif tx == 0 and ty == -1 then dir = 90
34   -elseif tx == -1 and ty == -1 then dir = 135
35   -elseif tx == -1 and ty == 0 then dir = 180
36   -elseif tx == -1 and ty == 1 then dir = 225
37   -elseif tx == 0 and ty == 1 then dir = 270
38   -elseif tx == 1 and ty == 1 then dir = 315
39   -end
  25 +dir = math.deg(math.atan2(ty, tx))
40 26
41 27 return { generator = function()
42 28 local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
... ...
... ... @@ -22,21 +22,7 @@ local dir = 0
22 22 local spread = spread or 55/2
23 23 local radius = radius or 6
24 24
25   -local max = math.max(math.abs(tx), math.abs(ty))
26   -tx = tx / max
27   -ty = ty / max
28   -if tx >= 0.5 then tx = 1 elseif tx <= -0.5 then tx = -1 else tx = 0 end
29   -if ty >= 0.5 then ty = -1 elseif ty <= -0.5 then ty = 1 else ty = 0 end -- Why the hell is ty inverted ? .. but it works :/
30   -
31   -if tx == 1 and ty == 0 then dir = 0
32   -elseif tx == 1 and ty == -1 then dir = 45
33   -elseif tx == 0 and ty == -1 then dir = 90
34   -elseif tx == -1 and ty == -1 then dir = 135
35   -elseif tx == -1 and ty == 0 then dir = 180
36   -elseif tx == -1 and ty == 1 then dir = 225
37   -elseif tx == 0 and ty == 1 then dir = 270
38   -elseif tx == 1 and ty == 1 then dir = 315
39   -end
  25 +dir = math.deg(math.atan2(ty, tx))
40 26
41 27 return { generator = function()
42 28 local sradius = (radius + 0.5) * (engine.Map.tile_w + engine.Map.tile_h) / 2
... ...
... ... @@ -57,6 +57,7 @@ newTalent{
57 57 getHeal = function(self, t) return self:combatTalentSpellDamage(t, 4, 40) end,
58 58 getDuration = function(self, t) return self:getTalentLevel(t) + 2 end,
59 59 action = function(self, t)
  60 + local tg = self:getTalentTarget(t)
60 61 self:project(tg, self.x, self.y, DamageType.LITE, 1)
61 62 -- Add a lasting map effect
62 63 game.level.map:addEffect(self,
... ...
... ... @@ -73,16 +73,22 @@ newTalent{
73 73 return 2 + self:getTalentLevel(t) / 2
74 74 end,
75 75 no_npc_use = true,
  76 + getDamage = function(self, t)
  77 + return self:combatDamage() * 0.8
  78 + end,
76 79 action = function(self, t)
77 80 local tg = {type="ball", range=0, selffire=false, radius=self:getTalentRadius(t), talent=t, no_restrict=true}
78   - self:project(tg, self.x, self.y, DamageType.PHYSKNOCKBACK, {dam=self:combatDamage() * 0.8, dist=4})
  81 + self:project(tg, self.x, self.y, DamageType.PHYSKNOCKBACK, {dam=t.getDamage(self, t), dist=4})
79 82 self:doQuake(tg, self.x, self.y)
80 83 return true
81 84 end,
82 85 info = function(self, t)
83 86 local radius = self:getTalentRadius(t)
84   - return ([[You slam your foot onto the ground, shaking the area around you in a radius of %d, damaging them for %d and knocking back up to 4 titles away.
85   - The damage will increase with the Strength stat]]):format(radius, self:combatDamage() * 0.8)
  87 + local dam = t.getDamage(self, t)
  88 + return ([[You slam your foot onto the ground, shaking the area around you in a radius of %d.
  89 + Creatures caught by the quake will be damaged for %d and knocked back up to 4 titles away.
  90 + The terrain will also be moved around within the quake's radius.
  91 + The damage will increase with the Strength stat.]]):format(radius, dam)
86 92 end,
87 93 }
88 94
... ...
... ... @@ -69,7 +69,7 @@ newTalent{
69 69 range = 0,
70 70 radius = function(self, t) return 1 + self:getTalentLevelRaw(t) end,
71 71 target = function(self, t)
72   - return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRange(t), selffire=false, talent=t}
  72 + return {type="ball", range=self:getTalentRange(t), radius=self:getTalentRadius(t), selffire=false, talent=t}
73 73 end,
74 74 getDamage = function(self, t) return self:combatTalentSpellDamage(t, 10, 180) end,
75 75 action = function(self, t)
... ...
... ... @@ -195,6 +195,48 @@ static int lua_fov_calc_beam(lua_State *L)
195 195 return 0;
196 196 }
197 197
  198 +static int lua_fov_calc_beam_any_angle(lua_State *L)
  199 +{
  200 + int x = luaL_checknumber(L, 1);
  201 + int y = luaL_checknumber(L, 2);
  202 + int w = luaL_checknumber(L, 3);
  203 + int h = luaL_checknumber(L, 4);
  204 + int radius = luaL_checknumber(L, 5);
  205 + float dir_angle = luaL_checknumber(L, 6);
  206 + float beam_angle = luaL_checknumber(L, 7);
  207 + struct lua_fov fov;
  208 + if (lua_isuserdata(L, 10))
  209 + {
  210 + fov.cache = (struct lua_fovcache*)auxiliar_checkclass(L, "fov{cache}", 10);
  211 + fov.cache_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  212 + }
  213 + else
  214 + {
  215 + lua_pop(L, 1);
  216 + fov.cache_ref = LUA_NOREF;
  217 + fov.cache = NULL;
  218 + }
  219 + fov.L = L;
  220 + fov.apply_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  221 + fov.opaque_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  222 + fov.cache = NULL;
  223 + fov.w = w;
  224 + fov.h = h;
  225 +
  226 + fov_settings_init(&(fov.fov_settings));
  227 + fov_settings_set_opacity_test_function(&(fov.fov_settings), map_opaque);
  228 + fov_settings_set_apply_lighting_function(&(fov.fov_settings), map_seen);
  229 + fov_beam_any_angle(&(fov.fov_settings), &fov, NULL, x, y, radius+1, dir_angle, beam_angle);
  230 + map_seen(&fov, x, y, 0, 0, radius, NULL);
  231 + fov_settings_free(&(fov.fov_settings));
  232 +
  233 + luaL_unref(L, LUA_REGISTRYINDEX, fov.apply_ref);
  234 + luaL_unref(L, LUA_REGISTRYINDEX, fov.opaque_ref);
  235 + if (fov.cache_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, fov.cache_ref);
  236 +
  237 + return 0;
  238 +}
  239 +
198 240 static int lua_distance(lua_State *L)
199 241 {
200 242 double x1 = luaL_checknumber(L, 1);
... ... @@ -436,6 +478,7 @@ static const struct luaL_reg fovlib[] =
436 478 {"calc_default_fov", lua_fov_calc_default_fov},
437 479 {"calc_circle", lua_fov_calc_circle},
438 480 {"calc_beam", lua_fov_calc_beam},
  481 + {"calc_beam_any_angle", lua_fov_calc_beam_any_angle},
439 482 {NULL, NULL},
440 483 };
441 484
... ...
... ... @@ -237,7 +237,7 @@ static float fov_slope(float dx, float dy) {
237 237 h = height(settings, dx, data->radius); \
238 238 break; \
239 239 case FOV_SHAPE_CIRCLE: \
240   - h = (unsigned)sqrtf((float)(data->radius*data->radius - dx*dx)); \
  240 + h = (unsigned)(sqrt((data->radius)*(data->radius) + data->radius - dx*dx)); \
241 241 break; \
242 242 case FOV_SHAPE_OCTAGON: \
243 243 h = (data->radius - dx)<<1; \
... ... @@ -435,3 +435,131 @@ void fov_beam(fov_settings_type *settings, void *map, void *source,
435 435 BEAM_DIRECTION_DIAG(FOV_SOUTHEAST, ppy, ppn, pmy, pmn, mpn, mpy, mmn, mmy);
436 436 BEAM_DIRECTION_DIAG(FOV_SOUTHWEST, pmy, mpn, ppy, mmn, ppn, mmy, pmn, mpy);
437 437 }
  438 +
  439 +#define BEAM_ANY_DIRECTION(offset, p1, p2, p3, p4, p5, p6, p7, p8) \
  440 +angle_begin -= offset; \
  441 +angle_end -= offset; \
  442 +start_slope = angle_begin; \
  443 +end_slope = betweenf(angle_end, 0.0f, 1.0f); \
  444 +fov_octant_##p1(&data, 1, start_slope, end_slope, true, true); \
  445 +\
  446 +if (angle_end - 1.0 > FLT_EPSILON) { \
  447 +start_slope = betweenf(2.0f - angle_end, 0.0f, 1.0f); \
  448 +fov_octant_##p2(&data, 1, start_slope, 1.0f, true, false); \
  449 +\
  450 +if (angle_end - 2.0 > FLT_EPSILON) { \
  451 +end_slope = betweenf(angle_end - 2.0f, 0.0f, 1.0f); \
  452 +fov_octant_##p3(&data, 1, 0.0f, end_slope, false, true); \
  453 +\
  454 +if (angle_end - 3.0 > FLT_EPSILON) { \
  455 +start_slope = betweenf(4.0f - angle_end, 0.0f, 1.0f); \
  456 +fov_octant_##p4(&data, 1, start_slope, 1.0f, true, false); \
  457 +\
  458 +if (angle_end - 4.0 > FLT_EPSILON) { \
  459 +end_slope = betweenf(angle_end - 4.0f, 0.0f, 1.0f); \
  460 +fov_octant_##p5(&data, 1, 0.0f, end_slope, false, true); \
  461 +\
  462 +if (angle_end - 5.0 > FLT_EPSILON) { \
  463 +start_slope = betweenf(6.0f - angle_end, 0.0f, 1.0f); \
  464 +fov_octant_##p6(&data, 1, start_slope, 1.0f, true, false); \
  465 +\
  466 +if (angle_end - 6.0 > FLT_EPSILON) { \
  467 +end_slope = betweenf(angle_end - 6.0f, 0.0f, 1.0f); \
  468 +fov_octant_##p7(&data, 1, 0.0f, end_slope, false, true); \
  469 +\
  470 +if (angle_end - 7.0 > FLT_EPSILON) { \
  471 +start_slope = betweenf(8.0f - angle_end, 0.0f, 1.0f); \
  472 +fov_octant_##p8(&data, 1, start_slope, 1.0f, false, false); \
  473 +}}}}}}}
  474 +
  475 +#define BEAM_ANY_DIRECTION_DIAG(offset, p1, p2, p3, p4, p5, p6, p7, p8) \
  476 +angle_begin -= offset; \
  477 +angle_end -= offset; \
  478 +start_slope = betweenf(1.0 - angle_end, 0.0f, 1.0f); \
  479 +end_slope = 1.0 - angle_begin; \
  480 +fov_octant_##p1(&data, 1, start_slope, end_slope, true, true); \
  481 +\
  482 +if (angle_end - 1.0 > FLT_EPSILON) { \
  483 +end_slope = betweenf(angle_end - 1.0f, 0.0f, 1.0f); \
  484 +fov_octant_##p2(&data, 1, 0.0f, end_slope, false, true); \
  485 +\
  486 +if (angle_end - 2.0 > FLT_EPSILON) { \
  487 +start_slope = betweenf(3.0f - angle_end, 0.0f, 1.0f); \
  488 +fov_octant_##p3(&data, 1, start_slope, 1.0f, true, false); \
  489 +\
  490 +if (angle_end - 3.0 > FLT_EPSILON) { \
  491 +end_slope = betweenf(angle_end - 3.0f, 0.0f, 1.0f); \
  492 +fov_octant_##p4(&data, 1, 0.0f, end_slope, false, true); \
  493 +\
  494 +if (angle_end - 4.0 > FLT_EPSILON) { \
  495 +start_slope = betweenf(5.0f - angle_end, 0.0f, 1.0f); \
  496 +fov_octant_##p5(&data, 1, start_slope, 1.0f, true, false); \
  497 +\
  498 +if (angle_end - 5.0 > FLT_EPSILON) { \
  499 +end_slope = betweenf(angle_end - 5.0f, 0.0f, 1.0f); \
  500 +fov_octant_##p6(&data, 1, 0.0f, end_slope, false, true); \
  501 +\
  502 +if (angle_end - 6.0 > FLT_EPSILON) { \
  503 +start_slope = betweenf(7.0f - angle_end, 0.0f, 1.0f); \
  504 +fov_octant_##p7(&data, 1, start_slope, 1.0f, true, false); \
  505 +\
  506 +if (angle_end - 7.0 > FLT_EPSILON) { \
  507 +end_slope = betweenf(angle_end - 7.0f, 0.0f, 1.0f); \
  508 +fov_octant_##p8(&data, 1, 0.0f, end_slope, false, false); \
  509 +}}}}}}}
  510 +
  511 +void fov_beam_any_angle(fov_settings_type *settings, void *map, void *source,
  512 + int source_x, int source_y, unsigned radius,
  513 + float dir_angle, float beam_angle) {
  514 +
  515 + fov_private_data_type data;
  516 + float start_slope, end_slope, angle_begin, angle_end;
  517 +
  518 + data.settings = settings;
  519 + data.map = map;
  520 + data.source = source;
  521 + data.source_x = source_x;
  522 + data.source_y = source_y;
  523 + data.radius = radius;
  524 +
  525 + if (beam_angle <= 0.0f) {
  526 + return;
  527 + } else if (beam_angle >= 360.0f) {
  528 + _fov_circle(&data);
  529 + return;
  530 + }
  531 +
  532 + while (dir_angle >= 360.0f) {
  533 + dir_angle -= 360.0f;
  534 + }
  535 +
  536 + while (dir_angle < 0.0f) {
  537 + dir_angle += 360.0f;
  538 + }
  539 +
  540 + /* Calculate the angles as a percentage of 45 degrees */
  541 + angle_begin = (dir_angle - 0.5*beam_angle) / 45.0f;
  542 + angle_end = (dir_angle + 0.5*beam_angle) / 45.0f;
  543 + if (angle_begin < 0.0f) {
  544 + angle_begin += 8.0f;
  545 + angle_end += 8.0f;
  546 + }
  547 +
  548 + if (1.0f - angle_begin > FLT_EPSILON) {
  549 + BEAM_ANY_DIRECTION(0.0f, ppn, ppy, pmy, mpn, mmn, mmy, mpy, pmn);
  550 + } else if (2.0f - angle_begin > FLT_EPSILON) {
  551 + BEAM_ANY_DIRECTION_DIAG(1.0f, ppy, pmy, mpn, mmn, mmy, mpy, pmn, ppn);
  552 + } else if (3.0f - angle_begin > FLT_EPSILON) {
  553 + BEAM_ANY_DIRECTION(2.0f, pmy, mpn, mmn, mmy, mpy, pmn, ppn, ppy);
  554 + } else if (4.0f - angle_begin > FLT_EPSILON) {
  555 + BEAM_ANY_DIRECTION_DIAG(3.0f, mpn, mmn, mmy, mpy, pmn, ppn, ppy, pmy);
  556 + } else if (5.0f - angle_begin > FLT_EPSILON) {
  557 + BEAM_ANY_DIRECTION(4.0f, mmn, mmy, mpy, pmn, ppn, ppy, pmy, mpn);
  558 + } else if (6.0f - angle_begin > FLT_EPSILON) {
  559 + BEAM_ANY_DIRECTION_DIAG(5.0f, mmy, mpy, pmn, ppn, ppy, pmy, mpn, mmn);
  560 + } else if (7.0f - angle_begin > FLT_EPSILON) {
  561 + BEAM_ANY_DIRECTION(6.0f, mpy, pmn, ppn, ppy, pmy, mpn, mmn, mmy);
  562 + } else if (8.0f - angle_begin > FLT_EPSILON) {
  563 + BEAM_ANY_DIRECTION_DIAG(7.0f, pmn, ppn, ppy, pmy, mpn, mmn, mmy, mpy);
  564 + }
  565 +}
... ...
... ... @@ -238,6 +238,28 @@ void fov_beam(fov_settings_type *settings, void *map, void *source,
238 238 fov_direction_type direction, float angle
239 239 );
240 240
  241 +/**
  242 + * Calculate a field of view from source at (x,y), pointing
  243 + * in the given direction (in degrees) and with the given angle. The larger
  244 + * the angle, the wider, "less focused" the beam. Each side of the
  245 + * line pointing in the direction from the source will be half the
  246 + * angle given such that the angle specified will be represented on
  247 + * the raster.
  248 + *
  249 + * \param settings Pointer to data structure containing settings.
  250 + * \param map Pointer to map data structure to be passed to callbacks.
  251 + * \param source Pointer to data structure holding source of light.
  252 + * \param source_x x-axis coordinate from which to start.
  253 + * \param source_y y-axis coordinate from which to start.
  254 + * \param radius Euclidean distance from (x,y) after which to stop.
  255 + * \param dir_angle Direction angle, in degrees.
  256 + * \param beam_angle The angle at the base of the beam of light, in degrees.
  257 + */
  258 +void fov_beam_any_angle(fov_settings_type *settings, void *map, void *source,
  259 + int source_x, int source_y, unsigned radius,
  260 + float dir_angle, float beam_angle
  261 +);
  262 +
241 263 #ifdef __cplusplus
242 264 } /* extern "C" */
243 265 #endif
... ...