Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - Jeff

#1
Hello everyone!

!!!APOLOGIES!!!
Since the server fire last year (was it 2020 or 2021?) all of these attachments have been lost. I have not had time to reupload them but I will fix this post in the future.

This is intended to be a collection of scripts that will provide features related to aiming the hero. For the moment, I only have a portion of the features working but they seem to be stable in my testing. Currently, this only works with a mouse and keyboard but I do plan to add support for joypads. The idea behind this is to replicate the system from Dark Souls as closely as possible in a 2D enviroment.

Edit: You will also need a cursor sprite and a target marker sprite to draw on the screen.

These are the initial scripts for this collection; they will allow target lock-on and cursor aiming, in conjunction with the supporting scripts.

  • Aim  --  Makes the hero face the position of the cursor.
  • Draw Cursor  --  Draws the cursor on the screen (it is important to set the system cursor visibility to false).
  • Lock On  --  Whenever 'Q' (or whatever key you choose) is pressed, lock on to an enemy within range and line of sight.
  • Draw Target Marker  --  Draw a marker on the currently selected target.
  • Get Position On Screen (Enemy)  --  Converts the enemy's map coordinates into screen coordinates.
  • On Removed  --  When the currently selected target dies, make sure the lock-on is removed properly.
  • Line of Sight  --  Checks the hero's facing direction and tests for obstacles between hero and target.
  • Get Position On Screen (Hero)  --  Same as previous script, but for the hero rather than enemies.

Each of these scripts utilise the multi_events script included with Solarus. Just add the scripts to your quest directory and require them in the proper script (either features or main; however you add new scripts to your quest). I tried to write the scripts clearly enough that they can be modified easily.

I owe a big thanks to several members of the community for helping with this. Diarandor, Llamazing, and Cluedrew most of all!

Let me know any criticism or critiques you may have!
#2
See my comment near the bottom for the updated script! Thank you!


Hey everybody,

This script was originally made by froggy77 (http://forum.solarus-games.org/index.php/topic,520.msg7809.html) and they recently asked for help with updating the script to work with Solarus 1.6. I took some time and got it working with the latest version and so I thought I would re-upload the script for the community. I hope this is okay; I didn't think posting it in the original forum would give it as much visibility and the original post contains some outdated information that is better left out. I did message the original author but after a few days without reply I decided I would post it here, with due credit. Not sure if messages even notify people on here.

Here is the script in it's entirety with all the necessary extra functions and code included at the bottom and below the code is a download for the .lua file:

-- LEVEL (LVL) and EXPERIENCE (EXP) counters shown on the game screen.

-- LVL AND EXP  version 1.6
-- from a script (for rupees) by christopho
-- Modified by froGgy for a Zelda-like (ZL) project.
-- v 1.0:  First version posted. It is just a draft.
-- Modified by Kamigousu on 18/07/19.
-- v 1.6:  Updated for use with Solarus 1.6; basic with lots of potential, mostly just froggy77's original draft.

--Additional code and notes are included at the bottom for convenience. Please read them before continuing.

local lvl_and_exp = {}

function lvl_and_exp:new(game)

  local object = {}
  setmetatable(object, self)
  self.__index = self

  object:initialize(game)

  return object
end

function lvl_and_exp:initialize(game)

  self.game = game
  self.surface = sol.surface.create(112, 24)
  self.digits_text_for_lvl = sol.text_surface.create{
    font = "green_digits",
    horizontal_alignment = "left",
  }
  self.digits_text_for_exp = sol.text_surface.create{
    font = "white_digits",
    horizontal_alignment = "left",
  }
  self.digits_text_for_exp_to_levelup = sol.text_surface.create{
    font = "white_digits",
    horizontal_alignment = "left",
  }
  self.digits_text_for_lvl:set_text(game:get_level())
  self.digits_text_for_exp:set_text(game:get_exp())
  self.lvl_icon_img = sol.surface.create("hud/lvl_and_exp_icon.png")
  self.exp_icon_img = sol.surface.create("hud/lvl_and_exp_icon.png")
  self.slash_icon_img = sol.surface.create("hud/lvl_and_exp_icon.png")
  self.current_lvl_displayed = self.game:get_level()
  self.current_exp_displayed = self.game:get_exp()
  self.current_exp_displayed_length = string.len(self.current_exp_displayed)
  self.t_exp_to_levelup = {100, 200, 300, 400, 500, 600, 700, 800}
  self.max_level = #self.t_exp_to_levelup
  self.digits_text_for_exp_to_levelup:set_text(self.t_exp_to_levelup[self.current_lvl_displayed])
  self:check()
  self:rebuild_surface()
end

function lvl_and_exp:check()

  local need_rebuild = false
  local current_level = self.game:get_level()
  local current_exp = self.game:get_exp()
  local exp_to_levelup = self.t_exp_to_levelup[current_level]
  if exp_to_levelup == nil then
self.current_exp_displayed = self.t_exp_to_levelup[self.max_level]
self.current_exp_displayed_length = string.len(self.current_exp_displayed)
  exp_to_levelup = self.t_exp_to_levelup[self.max_level]
  end
  local difference = 0

-- Current LVL.
if current_level <= self.max_level + 1 then
  if current_level ~= self.current_lvl_displayed then
need_rebuild = true
local increment
if current_level > self.current_lvl_displayed then
  increment = 1
else
  increment = -1
end
self.current_lvl_displayed = self.current_lvl_displayed + increment
-- Play a sound if we have just reached the final value.
if self.current_lvl_displayed == current_level then
  if increment == 1 then
sol.audio.play_sound("victory")
sol.audio.play_sound("treasure")
  else
sol.audio.play_sound("switch")
sol.audio.play_sound("hero_falls")
  end
end
  end
end

-- Current XP.
if current_level <= self.max_level then
  if current_exp ~= self.current_exp_displayed then
need_rebuild = true
local increment
if current_exp > self.current_exp_displayed then
  increment = 1
else
  increment = -1
end
self.current_exp_displayed = self.current_exp_displayed + increment
self.current_exp_displayed_length = string.len(self.current_exp_displayed)
  end

-- Level up
  if self.current_exp_displayed >= exp_to_levelup then
self.game:set_value("current_level", current_level + 1)
difference = current_exp - exp_to_levelup
self.game:set_value("current_exp", difference)
current_exp = self.game:get_value("current_exp")
self.current_exp_displayed = 0
self.current_exp_displayed_length = string.len(self.current_exp_displayed)
  end
end

  -- Redraw the surface only if something has changed.
  if need_rebuild then
    self:rebuild_surface()
  end

  -- Schedule the next check.
  sol.timer.start(self.game, 40, function()
    self:check()
  end)
end

function lvl_and_exp:rebuild_surface()

  self.surface:clear()

  -- LVL (icon).
  self.lvl_icon_img:draw_region(0, 0, 12, 12, self.surface)

  -- XP (icon).
  self.exp_icon_img:draw_region(12, 0, 12, 12, self.surface, 27, 0)
 
  -- SLASH (icon).
  self.slash_icon_img:draw_region(24, 0, 8, 12, self.surface, 35 + (8 * self.current_exp_displayed_length), 4)

    -- Current LVL (counter).
  if self.current_lvl_displayed > self.max_level then
    self.digits_text_for_lvl:set_font("green_digits")
  else
    self.digits_text_for_lvl:set_font("white_digits")
  end
  self.digits_text_for_lvl:set_text(self.current_lvl_displayed)
  self.digits_text_for_lvl:draw(self.surface, 12, 6)
 
  -- Current XP (counter).
  if self.current_lvl_displayed <= self.max_level then
    self.digits_text_for_exp:set_font("white_digits")
    self.digits_text_for_exp:set_text(self.current_exp_displayed)
    self.digits_text_for_exp_to_levelup:set_font("white_digits")
self.digits_text_for_exp_to_levelup:set_text(self.t_exp_to_levelup[self.current_lvl_displayed])
  else
    self.digits_text_for_exp:set_font("green_digits")
    self.digits_text_for_exp:set_text(self.current_exp_displayed)
    self.digits_text_for_exp_to_levelup:set_font("green_digits")
self.digits_text_for_exp_to_levelup:set_text(self.t_exp_to_levelup[self.max_level])
  end
  self.digits_text_for_exp:draw(self.surface, 40, 6)
  self.digits_text_for_exp_to_levelup:draw(self.surface, 40 + (8 * self.current_exp_displayed_length), 12)
end

function lvl_and_exp:set_dst_position(x, y)
  self.dst_x = x
  self.dst_y = y
end

function lvl_and_exp:on_draw(dst_surface)

  local x, y = self.dst_x, self.dst_y
  local width, height = dst_surface:get_size()
  if x < 0 then
    x = width + x
  end
  if y < 0 then
    y = height + y
  end

  self.surface:draw(dst_surface, x, y)
end

return lvl_and_exp



--[[********************************NOTES and CODE********************************


--The segment of code below must go into your initial_game.lua in the initialise_new_savegame(game) function. Do not set the level to 0 or it will create a bug (it is my understanding that it is a bug). Also, you will need to add these values to any current savegame file you try to run the script on. Otherwise the script will not load properly

  --Initialise player experience system.
    game:set_level(1)      --Initialise the player level value for new game.
  game:set_exp(0)       --Initialise the player experience value for new game.


--The following must be put into your hud_config script, in the table with the rest of your hud elements; unless you are putting the exp and lvl display in an inventory screen or some other menu, in which case you will have to require it in the proper lua file.

  --Level and Experience Counter
  {
    menu_script = ("scripts/hud/lvl_and_xp"),
    x = 210,    --X and Y can be changed to wherever you would like the exp counter displayed.
    y = 16,
  },


Finally, you must also add the functions game:get_level/exp(), set_level/exp(), and add_level/exp().  In a seperate file named game.lua (or wherever you have a game metatable available) add the following functions. (This doesn't necessarily need to be in it's own file, but for the sake of organisation and tidy code, I find that defining all of my game_meta functions in one place makes things easier. (I do believe that is something I picked up from reading and learning from so many of the Solarus Team's scripts.)

--The following line can be omitted if you all ready have a file where you get the metatable.
local game_meta = sol.main.get_metatable("game")


function game_meta:get_level()
  return self:get_value("current_level")
end

function game_meta:set_level(level)
  return self:set_value("current_level", level)
end

function game_meta:add_level(level)
  local level = level
  local c_level = self:get_level()
  local level_up = c_level + level
  return self:set_value("current_level", level_up)
end

function game_meta:get_exp()
  return self:get_value("current_exp")
end

function game_meta:set_exp(exp)
  return self:set_value("current_exp", exp)
end

function game_meta:add_exp(exp)
  local exp = exp
  local c_exp = self:get_exp()
  local exp_up = c_exp + exp
  return self:set_value("current_exp", exp_up)
end

You may require this file in your main.lua somehow or use multi_events to call it. Whatever you prefer.
--]]


You will also need to put the lvl_and_exp_icon.png (see attachments at bottom) into your "sprites/hud" folder.
You can also modify the values of the t_exp_to_levelup table to change the experience required to level up. The first index is the experience required to get from level 1 to level 2 and so on.

Hopefully my explanation was clear. I only know basic French or I would write this up in French as well. I have a few other features for it that I have been testing on my own project, one of which is an algorithm to populate the experience table. I may upload some of these changes in the future if they work out well.

Thanks again, froggy77, for this awesome script! I'm all ready putting it to good use!
#3
Hello! During the development of a project of mine, I found myself in need of an drop rate script that would be able to decide the type and number of item(s) you will get when killing an enemy. I didn't find anything on here ( although I could have overlooked something) so I made one of my own that works well enough for me to share. Hopefully someone will find a use for it. It isn't really pretty or perfect, but it works well.

function enemy:on_dying()
  local x, y, layer = self:get_position()
  local chance = math.random(100)
  if chance >= 95 then  --you have a 5% chance for this to execute.
    bonus_drop = math.random(1,3)

  elseif 75 <= chance and chance < 95 then  --you have a 20% chance for this to execute.
    bonus_drop = math.random(1,2)

  elseif 25 <= chance and chance < 75 then  --you have a 50% chance for this to execute.
    bonus_drop = 1
  else  --you have a 25% chance for this to execute.
    self:set_treasure(nil)
  end
return bonus_drop
end

function enemy:on_dead()
  local map = enemy:get_map()
  local bonus_drop = bonus_drop   --# of extra items dropped.
  local c_treasure, c_variant = self:get_treasure() --common treasure (currency)
  local x, y, layer = self:get_position()


  if bonus_drop ~= nil then
    --the following for loop is the heart of this function. It lays out multiple currency units (or items) depending on a random number generator.
    for i = 1, bonus_drop do
      local irons_prop = {    --properties table for irons.
        ["layer"] = layer,
        ["x"] = x + (math.random(-16, 16)),   --using a random range to mix up the placement of each iron spawned.
        ["y"] = y + (math.random(-16, 16)),   --change the +/-16 to the min and max values for the radius of pixels
        ["treasure_name"] = c_treasure,         --that you would like to allow the item to spawn in. The larger the range
        ["treasure_variant"] = c_variant,         --(and the larger the numbers) the larger the spawn area for the items.
      }
      map:create_pickable(irons_prop)
    end
  end
end


The on_dying section sets up the item chance and determines the drop and the on_death function spawns the dropped items on the map in a pseudo random fashion to make them easy to pick up and see. I think the script is pretty self explanatory but any feedback or criticism is welcome.

edited with corrections as described below.
#4
Was working on stats for a new game and noticed that some of the resources like health and stamina were not coming out to their expected value, but rather they were rounded up or down depending on the following decimal. 100.1 becomes 100, 89.97 becomes 90.

I found that other values I printed were coming out with all decimal places intact though these values weren't called through any 'game' function. It mostly hasn't been a problem until I needed to use a multiplier that scales between 1.01 and 1.9999999. Calling the multiplier through the 'game' function I made for it truncates and rounds the number to either 1 or 2. It's causing a little bit of a problem with a few things but nothing game breaking.

Any one know of a work around or a way to get 'game' functions to print out full number values? I have tried a few things but nothing has worked out yet.
#5
Hello, Solarus World.

    I have been learning Solarus through the online tutorial series by Christopho. It has been incredibly helpful. However, there are many things in my current project that are not covered in any of the tutorial videos and I've not been able to find any info on them online. The API has also been incredibly helpful but I admit I lack a complete understanding of Lua and so I may not fully understand everything as written in the API (for instance, I had trouble with the drawable:draw_region()...the two sets of coordinates confused me, but I figured out through practice what they meant). I am very new to using it but I have been quickly picking things up and reading through previously posted links on this forum for Lua learning resources.

    The problem I am facing right now is my face_cursor script. I wanted to allow the player to change their character's facing direction by moving the mouse around on the screen (and add support for joysticks as well). Essentially, I'm looking to make it behave similar to a two stick shooter game. Is this possible in the engine as it stands? I will attach my script, which is just supposed to be a proof of concept, for your scrutiny..

local function init_cursor_info(game)        --Local Function encapsulating lesser functions and pulling 'game'.

  local map = game:get_map()
  local hero = game:get_hero()
  local h_x, h_y, h_L = hero:get_position()
  local h_dir = hero:get_direction()
  local c_x, c_y = sol.input.get_mouse_position()
  local c_dir

  --The following function should update cursor coordinates continuously.
  function game:cursor_update()
   
    local nc_x, nc_y = sol.input.get_mouse_position()

    if nc_x == c_x and nc_y == c_y then
      return
    else
      c_x = nc_x
      c_y = nc_y
    end
 
    return true

  end

  --The following function should update hero coordinates and direction continuously.
  function game:hero_update()
   
    local nh_x, nh_y, nh_L = hero:get_position()
    local nh_dir = hero:get_direction()

    if nh_x == h_x and nh_y == h_y then
      return
    else
      h_x = nh_x
      h_y = nh_y
      h_L = nh_L
    end

    if nh_dir == h_dir then
      return
    else
      h_dir = nh_dir
    end

    return true

  end

  function game:get_cursor_direction()

    local x_chg
    local y_chg

    x_chg = cursor_x - hero_x
    y_chg = cursor_y - hero_y

    if x_chg > 0 and y_chg > 0 then     --Face Hero South-East.
      cur_dir = 7
    elseif x_chg == 0 and y_chg > 0 then --Face Hero South.
      cur_dir = 6
    elseif x_chg < 0 and y_chg > 0 then --Face Hero South-West.
      cur_dir = 5
    elseif x_chg < 0 and y_chg == 0 then --Face Hero West.
      cur_dir = 4
    elseif x_chg < 0 and y_chg < 0 then
      cur_dir = 3
    elseif x_chg == 0 and y_chg < 0 then
      cur_dir = 2
    elseif x_chg > 0 and y_chg < 0 then
      cur_dir = 1
    elseif x_chg > 0 and y_chg == 0 then
      cur_dir = 0
    else if x_chg == 0 and y_chg == 0 then
      cur_dir = 2

    end

    return true

  end                                                  --End of get_cursor_direction()

  function game:on_started()

    local time = 100

    game:cursor_update()
    sol.timer.start(game, time, cursor_update())
    game:hero_update()
    sol.timer.start(game, time, hero_update())
    game:get_cursor_direction()
    sol.timer.start(game, time, get_cursor_direction())

    print(time)                                        --This print was to test if this segment executed...so far it hasn't printed.
  end
end                                                    --Not sure why I needed two ends here...I was getting an error with only one.
end                                                    --End Local Function init_cursor_info(game)

--The following code was taken from OniLinkBegins. My understanding is that this works as is but I am unsure.
-- Set up face_cursor features on any game that starts.
local game_meta = sol.main.get_metatable("game")
game_meta:register_event("on_started", init_cursor_info)

return true


..I'm sure I am making some rookie mistake, but as I said I'm learning still so any advice is appreciated.