Skip to content
Snippets Groups Projects
Commit 5556d44b authored by dg's avatar dg
Browse files

mouse support

targeting code, actived by tactical display


git-svn-id: http://svn.net-core.org/repos/t-engine4@41 51575b47-30f0-44d4-a5cc-537603b46e54
parent a9769f94
No related branches found
No related tags found
No related merge requests found
game/data/gfx/border_9.png

253 B | W: | H:

game/data/gfx/border_9.png

259 B | W: | H:

game/data/gfx/border_9.png
game/data/gfx/border_9.png
game/data/gfx/border_9.png
game/data/gfx/border_9.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -23,8 +23,8 @@ end
function _M:init(title, w, h, x, y, alpha, font)
self.title = title
self.w, self.h = w, h
self.x = x or (game.w - self.w) / 2
self.y = y or (game.h - self.h) / 2
self.display_x = x or (game.w - self.w) / 2
self.display_y = y or (game.h - self.h) / 2
self.font = font
if not font then self.font = core.display.newFont("/data/font/Vera.ttf", 12) end
self.surface = core.display.newSurface(w, h)
......@@ -41,9 +41,9 @@ function _M:display()
s:erase()
s:merge(tiles:get(nil, 0,0,0, 0,0,0, "border_7.png"), 0, 0)
s:merge(tiles:get(nil, 0,0,0, 0,0,0, "border_9.png"), self.w - 9, 0)
s:merge(tiles:get(nil, 0,0,0, 0,0,0, "border_1.png"), 0, self.h - 9)
s:merge(tiles:get(nil, 0,0,0, 0,0,0, "border_3.png"), self.w - 9, self.h - 9)
s:merge(tiles:get(nil, 0,0,0, 0,0,0, "border_9.png"), self.w - 8, 0)
s:merge(tiles:get(nil, 0,0,0, 0,0,0, "border_1.png"), 0, self.h - 8)
s:merge(tiles:get(nil, 0,0,0, 0,0,0, "border_3.png"), self.w - 8, self.h - 8)
for i = 8, self.w - 9 do
s:merge(tiles:get(nil, 0,0,0, 0,0,0, "border_8.png"), i, 0)
s:merge(tiles:get(nil, 0,0,0, 0,0,0, "border_8.png"), i, 20)
......
......@@ -28,5 +28,5 @@ 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="enemies", name="Enemies", reaction={players=-100,poorsods=-100} }
_M:add{ short_name="poorsods", name="Poor Sods", reaction={} }
require "engine.class"
require "engine.Mouse"
--- Represent a game
-- A module should subclass it and initialize anything it needs to play inside
......@@ -14,6 +15,9 @@ function _M:init(keyhandler)
self.logSeen = function() end
self.w, self.h = core.display.size()
self.dialogs = {}
self.mouse = engine.Mouse.new()
self.mouse:setCurrent()
end
--- Starts the game
......@@ -36,8 +40,8 @@ end
--- Displays the screen
-- Called by the engine core to redraw the screen every frame
function _M:display()
for i, d in ipairs(game.dialogs) do
d:display():toScreen(d.x, d.y)
for i, d in ipairs(self.dialogs) do
d:display():toScreen(d.display_x, d.display_y)
end
end
......@@ -50,6 +54,8 @@ function _M:registerDialog(d)
table.insert(self.dialogs, d)
self.dialogs[d] = #self.dialogs
end
--- Undisplay a dialog, removing its own keyhandler if needed
function _M:unregisterDialog(d)
if not self.dialogs[d] then return end
table.remove(self.dialogs, self.dialogs[d])
......
......@@ -2,9 +2,10 @@ require "engine.class"
module(..., package.seeall, class.make)
function _M:init(w, h, max, fontname, fontsize, color, bgcolor)
function _M:init(x, y, w, h, max, fontname, fontsize, color, bgcolor)
self.color = color or {255,255,255}
self.bgcolor = bgcolor or {0,0,0}
self.display_x, self.display_y = x, y
self.w, self.h = w, h
self.font = core.display.newFont(fontname or "/data/font/Vera.ttf", fontsize or 10)
self.font_h = self.font:lineSkip()
......@@ -12,12 +13,13 @@ function _M:init(w, h, max, fontname, fontsize, color, bgcolor)
self.log = {}
getmetatable(self).__call = _M.call
self.max = max or 4000
self.scroll = 0
self.changed = true
end
function _M:call(str, ...)
local lines = str:format(...):splitLines(self.w - 4, self.font)
for i = #lines, 1, -1 do
for i = 1, #lines do
print("[LOG]", lines[i])
table.insert(self.log, 1, lines[i])
end
......@@ -39,11 +41,19 @@ function _M:display()
-- Erase and the display the map
self.surface:erase(self.bgcolor[1], self.bgcolor[2], self.bgcolor[3])
local i = 1
local i, dh = 1, 0
while i < self.h do
if not self.log[i] then break end
self.surface:drawColorString(self.font, self.log[i], 0, (i-1) * self.font_h, self.color[1], self.color[2], self.color[3])
if not self.log[self.scroll + i] then break end
self.surface:drawColorString(self.font, self.log[self.scroll + i], 0, self.h - (i) * self.font_h, self.color[1], self.color[2], self.color[3])
i = i + 1
dh = dh + self.font_h
end
return self.surface
end
function _M:scrollUp(i)
self.scroll = self.scroll + i
if self.scroll > #self.log - 1 then self.scroll = #self.log - 1 end
if self.scroll < 0 then self.scroll = 0 end
self.changed = true
end
......@@ -24,7 +24,8 @@ rememberDisplayOrder = { TERRAIN }
-- @param h height
-- @param tile_w width of a single tile
-- @param tile_h height of a single tile
function _M:setViewPort(w, h, tile_w, tile_h)
function _M:setViewPort(x, y, w, h, tile_w, tile_h)
self.display_x, self.display_y = x, y
self.viewport = {width=w, height=h}
self.tiles = Tiles.new(tile_w, tile_h)
self.tile_w, self.tile_h = tile_w, tile_h
......@@ -42,6 +43,8 @@ end
--- Creates a map
-- @param w width (in grids)
-- @param h height (in grids)
-- @param x screen coordonate where the map will be displayed (this has no impact on the real display). This is used to compute mouse clicks
-- @param y screen coordonate where the map will be displayed (this has no impact on the real display). This is used to compute mouse clicks
function _M:init(w, h)
self.w, self.h = w, h
self.map = {}
......
require "engine.class"
--- Basic mousepress handler
-- The engine calls receiveMouse when a mouse is clicked
module(..., package.seeall, class.make)
function _M:init()
self.areas = {}
end
--- Called when a mouse is pressed
-- @param button
-- @param x coordinate of the click
-- @param y coordinate of the click
function _M:receiveMouse(button, x, y)
for i, m in ipairs(self.areas) do
if x >= m.x1 and x < m.x2 and y >= m.y1 and y < m.y2 then
m.fct(button, x, y)
end
end
end
--- Setups as the current game keyhandler
function _M:setCurrent()
core.mouse.set_current_handler(self)
_M.current = self
end
--- Registers a click zone that when clicked will call the object's "onClick" method
function _M:registerZoneClick(x, y, w, h, fct)
table.insert(self.areas, {x1=x,y1=y,x2=x+w,y2=y+h, fct=fct})
end
function _M:unregisterZoneClick(fct)
for i, m in ipairs(self.areas) do
if m.obj == obj then self.areas[fct] = nil break end
end
end
require "engine.class"
--- handles targetting
module(..., package.seeall, class.make)
function _M:init(map, source_actor)
self.display_x, self.display_y = map.display_x, map.display_y
self.w, self.h = map.viewport.width, map.viewport.height
self.tile_w, self.tile_h = map.tile_w, map.tile_h
self.active = false
self.sr = core.display.newSurface(map.tile_w, map.tile_h)
self.sr:alpha(125)
self.sr:erase(255, 0, 0)
self.sb = core.display.newSurface(map.tile_w, map.tile_h)
self.sb:alpha(125)
self.sb:erase(0, 0, 255)
self.source_actor = source_actor
self.target = {x=self.source_actor.x, y=self.source_actor.y}
end
function _M:display()
-- Entity tracking, if possible and if visible
if self.target.entity and self.target.entity.x and self.target.entity.y and game.level.map.seens(self.target.entity.x, self.target.entity.y) then
self.target.x, self.target.y = self.target.entity.x, self.target.entity.y
end
-- Do not display if not requested
if not self.active then return end
local s = self.sb
local l = line.new(self.source_actor.x, self.source_actor.y, self.target.x, self.target.y)
local lx, ly = l()
while lx and ly do
if not game.level.map.seens(lx, ly) then s = self.sr end
s:toScreen(self.display_x + lx * self.tile_w, self.display_y + ly * self.tile_h)
lx, ly = l()
end
end
function _M:setActive(v)
if v == nil then
return self.active
else
self.active = v
end
end
function _M:scan(dir, radius)
radius = radius or 20
local actors = {}
local checker = function(self, x, y)
if game.level.map.seens(x, y) and game.level.map(x, y, engine.Map.ACTOR) then
table.insert(actors, {
a = game.level.map(x, y, engine.Map.ACTOR),
dist = math.abs(self.target.x - x)*math.abs(self.target.x - x) + math.abs(self.target.y - y)*math.abs(self.target.y - y)
})
end
return false
end
if dir ~= 5 then
-- Get a list of actors in the direction given
core.fov.calc_beam(self.target.x, self.target.y, radius, dir, 45, checker, function()end, self)
else
-- Get a list of actors all around
core.fov.calc_circle(self.target.x, self.target.y, radius, checker, function()end, self)
end
table.sort(actors, function(a,b) return a.dist<b.dist end)
if #actors > 0 then
self.target.entity = actors[1].a
end
end
......@@ -22,6 +22,7 @@ function _M:display()
self.changed = false
self.surface = core.display.newSurface(300, self.font_h * #self.text)
self.surface:alpha(200)
-- Erase and the display the map
self.surface:erase(self.bgcolor[1], self.bgcolor[2], self.bgcolor[3])
......
......@@ -163,3 +163,15 @@ getmetatable(tmps).__index.drawColorStringCentered = function(s, font, str, dx,
end
end
dir_to_coord = {
[1] = {-1, 1},
[2] = { 0, 1},
[3] = { 1, 1},
[4] = {-1, 0},
[5] = { 0, 0},
[6] = { 1, 0},
[7] = {-1,-1},
[8] = { 0,-1},
[9] = { 1,-1},
}
......@@ -7,6 +7,7 @@ local QuitDialog = require "mod.dialogs.Quit"
local Calendar = require "engine.Calendar"
local Zone = require "engine.Zone"
local Map = require "engine.Map"
local Target = require "engine.Target"
local Level = require "engine.Level"
local Grid = require "engine.Grid"
local Actor = require "mod.class.Actor"
......@@ -20,11 +21,8 @@ function _M:init()
end
function _M:run()
self:setupCommands()
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")
Map:setViewPort(0, 0, self.w, math.floor(self.h * 0.80), 16, 16)
self.calendar = Calendar.new("/data/calendar_rivendell.lua", "Today is the %s %s of the %s year of the Fourth Age of Middle-earth.\nThe time is %02d:%02d.", 122)
self.day_of_year = self.calendar:getDayOfYear(self.turn)
......@@ -33,7 +31,7 @@ function _M:run()
self.tooltip = engine.Tooltip.new(nil, nil, {255,255,255}, {30,30,30})
self.log = engine.LogDisplay.new(self.w * 0.5, self.h * 0.20, nil, nil, nil, {255,255,255}, {30,30,30})
self.log = engine.LogDisplay.new(0, self.h * 0.80, self.w * 0.5, self.h * 0.20, nil, nil, nil, {255,255,255}, {30,30,30})
self.log("Welcome to #00FF00#Tales of Middle Earth!")
self.logSeen = function(e, ...) if e and self.level.map.seens(e.x, e.y) then self.log(...) end end
......@@ -41,10 +39,17 @@ function _M:run()
self:changeLevel(1)
self.target = Target.new(Map, self.player)
self.target.target.entity = self.player
self.old_tmx, self.old_tmy = 0, 0
-- Ok everything is good to go, activate the game in the engine!
self:setCurrent()
self:registerDialog(require('mod.dialogs.EnterName').new())
self:setupCommands()
self:setupMouse()
-- self:registerDialog(require('mod.dialogs.EnterName').new())
end
function _M:changeLevel(lev)
......@@ -64,7 +69,7 @@ function _M:tick()
end
function _M:display()
self.log:display():toScreen(0, self.h * 0.80)
self.log:display():toScreen(self.log.display_x, self.log.display_y)
if self.level and self.level.map then
if self.level.map.changed then
......@@ -73,19 +78,26 @@ function _M:display()
end
local s = self.level.map:display()
if s then
s:toScreen(0, 0)
s:toScreen(self.level.map.display_x, self.level.map.display_y)
end
local mx, my = core.mouse.get()
local tt = self.level.map:checkAllEntities(math.floor(mx / self.level.map.tile_w), math.floor(my / self.level.map.tile_h), "tooltip")
local tmx, tmy = math.floor(mx / self.level.map.tile_w), math.floor(my / self.level.map.tile_h)
local tt = self.level.map:checkAllEntities(tmx, tmy, "tooltip")
if tt then
self.tooltip:set(tt)
local t = self.tooltip:display()
if t then t:toScreen(mx, my) end
end
if self.old_tmx ~= tmx or self.old_tmy ~= tmy then
self.target.target.x, self.target.target.y = tmx, tmy
end
self.old_tmx, self.old_tmy = tmx, tmy
self.target:display()
end
engine.GameTurnBased:display()
engine.GameTurnBased.display(self)
end
function _M:setupCommands()
......@@ -168,15 +180,19 @@ function _M:setupCommands()
end,
_GREATER = {"alias", "_LESS"},
-- Toggle tactical displau
[{"_t","alt"}] = function()
_t = function()
if Map.view_faction then
Map:setViewerFaction(nil)
self.log("Tactical dislpay disabled.")
self.log("Tactical display disabled.")
self.level.map.changed = true
self.target:setActive(false)
else
Map:setViewerFaction("players")
self.log("Tactical dislpay enabled.")
self.log("Tactical display enabled.")
self.level.map.changed = true
self.target:setActive(true)
-- Find nearest target
self.target:scan(5)
end
end,
-- Toggle tactical displau
......@@ -187,6 +203,43 @@ function _M:setupCommands()
[{"_x","ctrl"}] = function()
self:registerDialog(QuitDialog.new())
end,
-- Targeting movement
[{"_LEFT","ctrl","shift"}] = function() self.target.target.entity=nil self.target.target.x = self.target.target.x - 1 end,
[{"_RIGHT","ctrl","shift"}] = function() self.target.target.entity=nil self.target.target.x = self.target.target.x + 1 end,
[{"_UP","ctrl","shift"}] = function() self.target.target.entity=nil self.target.target.y = self.target.target.y - 1 end,
[{"_DOWN","ctrl","shift"}] = function() self.target.target.entity=nil self.target.target.y = self.target.target.y + 1 end,
[{"_KP4","ctrl","shift"}] = function() self.target.target.entity=nil self.target.target.x = self.target.target.x - 1 end,
[{"_KP6","ctrl","shift"}] = function() self.target.target.entity=nil self.target.target.x = self.target.target.x + 1 end,
[{"_KP8","ctrl","shift"}] = function() self.target.target.entity=nil self.target.target.y = self.target.target.y - 1 end,
[{"_KP2","ctrl","shift"}] = function() self.target.target.entity=nil self.target.target.y = self.target.target.y + 1 end,
[{"_KP1","ctrl","shift"}] = function() self.target.target.entity=nil self.target.target.x = self.target.target.x - 1 self.target.target.y = self.target.target.y + 1 end,
[{"_KP3","ctrl","shift"}] = function() self.target.target.entity=nil self.target.target.x = self.target.target.x + 1 self.target.target.y = self.target.target.y + 1 end,
[{"_KP7","ctrl","shift"}] = function() self.target.target.entity=nil self.target.target.x = self.target.target.x - 1 self.target.target.y = self.target.target.y - 1 end,
[{"_KP9","ctrl","shift"}] = function() self.target.target.entity=nil self.target.target.x = self.target.target.x + 1 self.target.target.y = self.target.target.y - 1 end,
[{"_LEFT","ctrl"}] = function() self.target:scan(4) end,
[{"_RIGHT","ctrl"}] = function() self.target:scan(6) end,
[{"_UP","ctrl"}] = function() self.target:scan(8) end,
[{"_DOWN","ctrl"}] = function() self.target:scan(2) end,
[{"_KP4","ctrl"}] = function() self.target:scan(4) end,
[{"_KP6","ctrl"}] = function() self.target:scan(6) end,
[{"_KP8","ctrl"}] = function() self.target:scan(8) end,
[{"_KP2","ctrl"}] = function() self.target:scan(2) end,
[{"_KP1","ctrl"}] = function() self.target:scan(1) end,
[{"_KP3","ctrl"}] = function() self.target:scan(3) end,
[{"_KP7","ctrl"}] = function() self.target:scan(7) end,
[{"_KP9","ctrl"}] = function() self.target:scan(9) end,
}
self.key:setCurrent()
end
function _M:setupMouse()
-- self.mouse:registerZoneClick(Map.display_x, Map.display_y, Map.viewport.width, Map.viewport.height, function()
-- end)
self.mouse:registerZoneClick(self.log.display_x, self.log.display_y, self.w, self.h, function(button)
if button == "wheelup" then self.log:scrollUp(1) end
if button == "wheeldown" then self.log:scrollUp(-1) end
end)
end
......@@ -187,9 +187,23 @@ static int lua_get_mouse(lua_State *L)
return 2;
}
extern int current_mousehandler;
static int lua_set_current_mousehandler(lua_State *L)
{
if (current_mousehandler != LUA_NOREF)
luaL_unref(L, LUA_REGISTRYINDEX, current_mousehandler);
if (lua_isnil(L, 1))
current_mousehandler = LUA_NOREF;
else
current_mousehandler = luaL_ref(L, LUA_REGISTRYINDEX);
return 0;
}
static const struct luaL_reg mouselib[] =
{
{"get", lua_get_mouse},
{"set_current_handler", lua_set_current_mousehandler},
{NULL, NULL},
};
......@@ -554,8 +568,113 @@ static const struct luaL_reg rnglib[] =
{NULL, NULL},
};
/******************************************************************
******************************************************************
* Line *
******************************************************************
******************************************************************/
typedef struct {
int stepx;
int stepy;
int e;
int deltax;
int deltay;
int origx;
int origy;
int destx;
int desty;
} line_data;
/* ********** bresenham line drawing ********** */
int lua_line_init(lua_State *L)
{
int xFrom = luaL_checknumber(L, 1);
int yFrom = luaL_checknumber(L, 2);
int xTo = luaL_checknumber(L, 3);
int yTo = luaL_checknumber(L, 4);
line_data *data = (line_data*)lua_newuserdata(L, sizeof(line_data));
auxiliar_setclass(L, "line{core}", -1);
data->origx=xFrom;
data->origy=yFrom;
data->destx=xTo;
data->desty=yTo;
data->deltax=xTo - xFrom;
data->deltay=yTo - yFrom;
if ( data->deltax > 0 ) {
data->stepx=1;
} else if ( data->deltax < 0 ){
data->stepx=-1;
} else data->stepx=0;
if ( data->deltay > 0 ) {
data->stepy=1;
} else if ( data->deltay < 0 ){
data->stepy=-1;
} else data->stepy = 0;
if ( data->stepx*data->deltax > data->stepy*data->deltay ) {
data->e = data->stepx*data->deltax;
data->deltax *= 2;
data->deltay *= 2;
} else {
data->e = data->stepy*data->deltay;
data->deltax *= 2;
data->deltay *= 2;
}
return 1;
}
int lua_line_step(lua_State *L)
{
line_data *data = (line_data*)auxiliar_checkclass(L, "line{core}", 1);
if ( data->stepx*data->deltax > data->stepy*data->deltay ) {
if ( data->origx == data->destx ) return 0;
data->origx+=data->stepx;
data->e -= data->stepy*data->deltay;
if ( data->e < 0) {
data->origy+=data->stepy;
data->e+=data->stepx*data->deltax;
}
} else {
if ( data->origy == data->desty ) return 0;
data->origy+=data->stepy;
data->e -= data->stepx*data->deltax;
if ( data->e < 0) {
data->origx+=data->stepx;
data->e+=data->stepy*data->deltay;
}
}
lua_pushnumber(L, data->origx);
lua_pushnumber(L, data->origy);
return 2;
}
int lua_free_line(lua_State *L)
{
line_data *data = (line_data*)auxiliar_checkclass(L, "line{core}", 1);
lua_pushnumber(L, 1);
return 1;
}
static const struct luaL_reg linelib[] =
{
{"new", lua_line_init},
{NULL, NULL},
};
static const struct luaL_reg line_reg[] =
{
{"__gc", lua_free_line},
{"__call", lua_line_step},
{NULL, NULL},
};
int luaopen_core(lua_State *L)
{
auxiliar_newclass(L, "line{core}", line_reg);
auxiliar_newclass(L, "fov{core}", fov_reg);
auxiliar_newclass(L, "sdl{surface}", sdl_surface_reg);
auxiliar_newclass(L, "sdl{font}", sdl_font_reg);
......@@ -565,5 +684,6 @@ int luaopen_core(lua_State *L)
luaL_openlib(L, "core.key", keylib, 0);
luaL_openlib(L, "core.game", gamelib, 0);
luaL_openlib(L, "rng", rnglib, 0);
luaL_openlib(L, "line", linelib, 0);
return 1;
}
......@@ -14,6 +14,7 @@
#include "core_lua.h"
lua_State *L = NULL;
int current_mousehandler = LUA_NOREF;
int current_keyhandler = LUA_NOREF;
int current_game = LUA_NOREF;
int px = 1, py = 1;
......@@ -103,6 +104,37 @@ void on_event(SDL_Event *event)
docall(L, 7, 0);
}
break;
case SDL_MOUSEBUTTONDOWN:
if (current_mousehandler != LUA_NOREF)
{
lua_rawgeti(L, LUA_REGISTRYINDEX, current_mousehandler);
lua_pushstring(L, "receiveMouse");
lua_gettable(L, -2);
lua_remove(L, -2);
lua_rawgeti(L, LUA_REGISTRYINDEX, current_mousehandler);
switch (event->button.button)
{
case SDL_BUTTON_LEFT:
lua_pushstring(L, "left");
break;
case SDL_BUTTON_MIDDLE:
lua_pushstring(L, "middle");
break;
case SDL_BUTTON_RIGHT:
lua_pushstring(L, "right");
break;
case SDL_BUTTON_WHEELUP:
lua_pushstring(L, "wheelup");
break;
case SDL_BUTTON_WHEELDOWN:
lua_pushstring(L, "wheeldown");
break;
}
lua_pushnumber(L, event->button.x);
lua_pushnumber(L, event->button.y);
docall(L, 4, 0);
}
break;
}
}
......@@ -209,6 +241,7 @@ int main(int argc, char *argv[])
{
switch(event.type)
{
case SDL_MOUSEBUTTONDOWN:
case SDL_KEYDOWN:
/* handle key presses */
on_event(&event);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment