diff --git a/game/data/gfx/tactical_enemy.png b/game/data/gfx/tactical_enemy.png new file mode 100644 index 0000000000000000000000000000000000000000..6a89b8e720e6358785254a67217be21faf9b844b Binary files /dev/null and b/game/data/gfx/tactical_enemy.png differ diff --git a/game/data/gfx/tactical_friend.png b/game/data/gfx/tactical_friend.png new file mode 100644 index 0000000000000000000000000000000000000000..cb823e23b85bc9f92941279f3502a725385ab4aa Binary files /dev/null and b/game/data/gfx/tactical_friend.png differ diff --git a/game/data/gfx/tactical_neutral.png b/game/data/gfx/tactical_neutral.png new file mode 100644 index 0000000000000000000000000000000000000000..72f99400ace9541b1dd3edb7a37fd5b829df8686 Binary files /dev/null and b/game/data/gfx/tactical_neutral.png differ diff --git a/game/engine/Actor.lua b/game/engine/Actor.lua index 37d2c82c8a0497dc9a65b5883f2eca98ecbd285e..980bd7324c18571fd5c2da8b2b315f4f1624ba6b 100644 --- a/game/engine/Actor.lua +++ b/game/engine/Actor.lua @@ -1,6 +1,7 @@ require "engine.class" local Entity = require "engine.Entity" local Map = require "engine.Map" +local Faction = require "engine.Faction" module(..., package.seeall, class.inherit(Entity)) @@ -8,9 +9,11 @@ function _M:init(t) t = t or {} self.name = t.name or "unknown npc" self.level = t.level or 1 + self.sight = t.sight or 20 self.energy = t.energy or { value=0, mod=1 } self.energy.value = self.energy.value or 0 self.energy.mod = self.energy.mod or 0 + self.faction = t.faction or "enemies" Entity.init(self, t) end @@ -45,3 +48,9 @@ function _M:useEnergy(val) val = val or game.energy_to_act self.energy.value = self.energy.value - val end + +--- What is our reaction toward the target +-- See Faction:factionReaction() +function _M:reactionToward(target) + return Faction:factionReaction(self.faction, target.faction) +end diff --git a/game/engine/Faction.lua b/game/engine/Faction.lua new file mode 100644 index 0000000000000000000000000000000000000000..11ef3f51b52d37d6425fda522a4038204202f791 --- /dev/null +++ b/game/engine/Faction.lua @@ -0,0 +1,32 @@ +require "engine.class" + +--- Defines factions +module(..., package.seeall, class.make) + +_M.factions = {} + +--- Adds a new faction +-- Static method +function _M:add(t) + assert(t.name, "no faction name") + assert(t.short_name, "no faction short_name") + t.reaction = t.reaction or {} + self.factions[t.short_name] = t +end + + +--- Returns the status of faction f1 toward f2 +-- @param f1 the source faction +-- @param f2 the target faction +-- @return a numerical value representing the reaction, 0 is neutral, <0 is aggressive, >0 is friendly +function _M:factionReaction(f1, f2) + -- Faction always like itself + if f1 == f2 then return 100 end + if not self.factions[f1] then return 0 end + return self.factions[f1].reaction[f2] or 0 +end + +-- Add a few default factions +_M:add{ short_name="players", name="Players", reaction={enemies=-100} } +_M:add{ short_name="enemies", name="Enemies", reaction={player=-100,poorsods=-100} } +_M:add{ short_name="poorsods", name="Poor Sods", reaction={} } diff --git a/game/engine/Map.lua b/game/engine/Map.lua index 5da2febce9a01932e755a310454eccd2d2593b1e..285943137a4da68ab2df57acf946289ec5db85a8 100644 --- a/game/engine/Map.lua +++ b/game/engine/Map.lua @@ -1,6 +1,7 @@ require "engine.class" local Entity = require "engine.Entity" local Tiles = require "engine.Tiles" +local Faction = require "engine.Faction" --- Represents a level map, handles display and various low level map work module(..., package.seeall, class.make) @@ -29,6 +30,15 @@ function _M:setViewPort(w, h, tile_w, tile_h) self.tile_w, self.tile_h = tile_w, tile_h end +--- Defines the faction of the person seeing the map +-- Usualy this will be the player's faction. If you do not want to use tactical display, dont use it +function _M:setViewerFaction(faction, friend, neutral, enemy) + self.view_faction = faction + self.faction_friend = "tactical_friend.png" + self.faction_neutral = "tactical_neutral.png" + self.faction_enemy = "tactical_enemy.png" +end + --- Creates a map -- @param w width (in grids) -- @param h height (in grids) @@ -77,11 +87,6 @@ function _M:fov(x, y, d) for i = 0, self.w * self.h - 1 do self.seens[i] = nil end end self._fov(x, y, d) - - -- Also seen the source itself - self.seens(x, y, true) - self.lites(x, y, true) - self.remembers(x, y, true) end --- Runs the FOV algorithm on the map, ligthing grids to allow rememberance @@ -95,11 +100,6 @@ function _M:fovLite(x, y, d) for i = 0, self.w * self.h - 1 do self.seens[i] = nil end self._fov_lite(x, y, d) end - - -- Also seen the source itself - self.seens(x, y, true) - self.lites(x, y, true) - self.remembers(x, y, true) end --- Sets/gets a value from the map @@ -150,6 +150,7 @@ function _M:display() local e, si local z local order + local friend for i = 0, self.w - 1 do for j = 0, self.h - 1 do e, si = nil, 1 z = i + j * self.w @@ -163,6 +164,17 @@ function _M:display() elseif self.remembers[z] then self.surface:merge(self.tiles:get(e.display, e.color_r/3, e.color_g/3, e.color_b/3, e.color_br/3, e.color_bg/3, e.color_bb/3, e.image), i * self.tile_w, j * self.tile_h) end + -- Tactical overlay ? + if self.view_faction and e.faction then + friend = Faction:factionReaction(self.view_faction, e.faction) + if friend > 0 then + self.surface:merge(self.tiles:get(nil, 0,0,0, 0,0,0, self.faction_friend), i * self.tile_w, j * self.tile_h) + elseif friend < 0 then + self.surface:merge(self.tiles:get(nil, 0,0,0, 0,0,0, self.faction_enemy), i * self.tile_w, j * self.tile_h) + else + self.surface:merge(self.tiles:get(nil, 0,0,0, 0,0,0, self.faction_neutral), i * self.tile_w, j * self.tile_h) + end + end end end end end diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index 352acacfd5faec57eda67494a186d32d14a87277..b42b0f37b5bda5369bcb43417b89d9631671bae5 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -22,6 +22,7 @@ function _M:run() Zone:setup{npc_class="mod.class.NPC", grid_class="mod.class.Grid", object_class="engine.Entity"} Map:setViewPort(self.w, math.floor(self.h * 0.80), 16, 16) + Map:setViewerFaction("players") self.zone = Zone.new("ancient_ruins") diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua index 96187d5245368fe1116108cf7484843322855aad..fd6f353415d6ade79d0064d0b3d01b34f878a0d8 100644 --- a/game/modules/tome/class/Player.lua +++ b/game/modules/tome/class/Player.lua @@ -5,7 +5,7 @@ module(..., package.seeall, class.inherit(mod.class.Actor)) function _M:init(t) mod.class.Actor.init(self, t) - + self.faction = "players" self.combat = { dam=10, atk=4, apr=2, def=6, armor=4 } end diff --git a/game/modules/tome/class/interface/Combat.lua b/game/modules/tome/class/interface/Combat.lua index 77c09ca209a6b1621db2ebc9bc09dc80d726d632..d331987361adead959668fba7d0cc41edb8b3409 100644 --- a/game/modules/tome/class/interface/Combat.lua +++ b/game/modules/tome/class/interface/Combat.lua @@ -24,6 +24,7 @@ function _M:attackTarget(target) -- If hit is over 0 it connects, if it is 0 we still have 50% chance if hit > 0 or (hit == 0 and rng.percent(50)) then local dam = rng.avg(sc.dam * 2 / 3, sc.dam) - math.max(0, tc.armor - sc.apr) + if dam < 0 then dam = 0 end game.logSeen(target, "%s hits %s for #aaaaaa#%0.2f physical damage#ffffff#.", self.name:capitalize(), target.name, dam) target:takeHit(dam, self) else diff --git a/game/modules/tome/data/zones/ancient_ruins/npcs.lua b/game/modules/tome/data/zones/ancient_ruins/npcs.lua index 7065f30bbc1db1aec97829781158c42ca8ec779d..3044269494f490c6fe06f1d8854cb6c89939f01a 100644 --- a/game/modules/tome/data/zones/ancient_ruins/npcs.lua +++ b/game/modules/tome/data/zones/ancient_ruins/npcs.lua @@ -14,6 +14,7 @@ return { { name = "baby dragon", display = "d", color_r=128, + faction = "poorsods", level = 1, exp_worth = 1, life = 30, mana = 1000, diff --git a/src/core_lua.c b/src/core_lua.c index 7ae5fbbe68b0e390a18a31052f89d260cb3f2d0f..df52d60252013a9adea128e96b9c96844b960a78 100644 --- a/src/core_lua.c +++ b/src/core_lua.c @@ -64,7 +64,6 @@ static int lua_new_fov(lua_State *L) fov->opaque_ref = opaque_ref; fov->map_ref = map_ref; fov_settings_init(&(fov->fov_settings)); - fov_settings_set_shape(&(fov->fov_settings), FOV_SHAPE_CIRCLE); fov_settings_set_opacity_test_function(&(fov->fov_settings), map_opaque); fov_settings_set_apply_lighting_function(&(fov->fov_settings), map_seen); @@ -90,6 +89,7 @@ static int lua_fov(lua_State *L) int radius = luaL_checknumber(L, 4); fov_circle(&(fov->fov_settings), fov, NULL, x, y, radius+1); + map_seen(fov, x, y, 0, 0, radius, NULL); return 0; } @@ -98,14 +98,16 @@ static int lua_fov_calc_circle(lua_State *L) int x = luaL_checknumber(L, 1); int y = luaL_checknumber(L, 2); int radius = luaL_checknumber(L, 3); - int map_ref = luaL_ref(L, LUA_REGISTRYINDEX); - int apply_ref = luaL_ref(L, LUA_REGISTRYINDEX); - int opaque_ref = luaL_ref(L, LUA_REGISTRYINDEX); - struct lua_fov fov; + fov.map_ref = luaL_ref(L, LUA_REGISTRYINDEX); + fov.apply_ref = luaL_ref(L, LUA_REGISTRYINDEX); + fov.opaque_ref = luaL_ref(L, LUA_REGISTRYINDEX); fov_settings_init(&(fov.fov_settings)); + fov_settings_set_opacity_test_function(&(fov.fov_settings), map_opaque); + fov_settings_set_apply_lighting_function(&(fov.fov_settings), map_seen); fov_circle(&(fov.fov_settings), &fov, NULL, x, y, radius+1); + map_seen(&fov, x, y, 0, 0, radius, NULL); fov_settings_free(&(fov.fov_settings)); luaL_unref(L, LUA_REGISTRYINDEX, fov.apply_ref); @@ -122,9 +124,10 @@ static int lua_fov_calc_beam(lua_State *L) int radius = luaL_checknumber(L, 3); int direction = luaL_checknumber(L, 4); float angle = luaL_checknumber(L, 5); - int map_ref = luaL_ref(L, LUA_REGISTRYINDEX); - int apply_ref = luaL_ref(L, LUA_REGISTRYINDEX); - int opaque_ref = luaL_ref(L, LUA_REGISTRYINDEX); + struct lua_fov fov; + fov.map_ref = luaL_ref(L, LUA_REGISTRYINDEX); + fov.apply_ref = luaL_ref(L, LUA_REGISTRYINDEX); + fov.opaque_ref = luaL_ref(L, LUA_REGISTRYINDEX); int dir = 0; switch (direction) @@ -139,10 +142,11 @@ static int lua_fov_calc_beam(lua_State *L) case 9: dir = FOV_NORTHEAST; break; } - struct lua_fov fov; - fov_settings_init(&(fov.fov_settings)); + fov_settings_set_opacity_test_function(&(fov.fov_settings), map_opaque); + fov_settings_set_apply_lighting_function(&(fov.fov_settings), map_seen); fov_beam(&(fov.fov_settings), &fov, NULL, x, y, radius+1, dir, angle); + map_seen(&fov, x, y, 0, 0, radius, NULL); fov_settings_free(&(fov.fov_settings)); luaL_unref(L, LUA_REGISTRYINDEX, fov.apply_ref);