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

Messages - Jeff

#16
Development / Re: How to configure game window
July 19, 2019, 12:51:31 AM
Quote from: Blueblue3D on July 17, 2019, 02:37:09 AM
Thanks for the reply. I've been fiddling for a while but I'm having trouble understand how Solarus organizes scripts. If I want to put a camera:set_size() call in game:on_started(), what script file would I put it in? Or would I make a new script?

You could create a new script. Not sure what your directory looks like but if you have nowhere to put it all ready you could create a game.lua file either in the scripts folder or, optionally, in a subfolder you create called meta.

The script would use metatables so if you aren't familiar with them, it may be confusing. I'm not entirely familiar with them so what I have to say will be pretty basic, I think. It would also require the multi_events script that the solarus team has generously shared with their game files.

The following should change the camera size everytime the game is started; although I can't say that this will be the best or most efficient way to do this:

require("scripts/multi_events")  --This is required for this script to work. It allows the script to be called on its own.

local game_meta = sol.main.get_metatable("game")
game_meta:register_event("on_started", function()   local map = game:get_map()
                                        local camera = map:get_camera()

                                        camera:set_size(width, height)  --size will be replaced with the size of the camera on screen.
                                         --If your screen is the standard 320x240 then you could make                                           
                                         --the camera 320, 200 and it should leave a black bar at the bottom of the screen.

end)


then just require your game.lua script in either the main script (messy if you have to require too many scripts) or in another script that would then be called in the main lua.  With the sample quest, I believe there is a script called features.lua that fills this purpose. It collects many scripts into one and then is required at the beginning of the main.lua.

so at the top of your main.lua you should type this:

require("scripts/game")  --If you saved it in the scripts folder. require("scripts/meta/game") if you added the subfolder.


unless you compile many of your scripts into one feature script; which is recommended.

Hope this helps.
#17
Your scripts / Re: Simple Leveling up system
July 19, 2019, 12:38:14 AM
Quote from: Max on March 09, 2019, 06:08:27 AM
Lua is all cool with decimals, but I believe game:set_value() will round to the nearest integer, as will most engine functions like set_life.

sorry for the necro, but a relatively easy way around this is to convert to and from a string when saving the value and getting the value. game functions won't remove the decimal if the value is saved as a string.
#18
Hey gman, not sure if you got any further with this but when adding sprites to a quest you can't simply click the png file as with other categories. You have to manually create a sprite (by right clicking on the folder and selecting add sprite) and then define the source image as your png file. That won't clear up your error but it is how you can add sprites to your quest from png files.

As for the item:on_obtaining(variant, savegame_variable) code you posted, that is an event that is called by the engine when you obtain an item. Variant and savegame_variable pull that info from the item in question so if the hero is obtaining a green rupee, the engine sets the variant to 1 and the savegame_variable to whatever the savegame_variabke is for that item (I think it is just rupees for the rupee item, but I'm at work so I can't check right now). That event doesn't save the item to the game, I don't believe. You can use game:get/set_value() to save things but there should be default behaviour for items like rupees and keys. Unless you are missing scripts still...which it seems like you might be.

Edit: can you post the item scripts you have for rupee and small_key?
#19
Thank you both for the feedback!

@llamazing -- I edited the script with your recommendation and it is working just fine. ~~Not sure if it really is more random or not, it seems the same.~~ But I like the idea of writing less code so I appreciate the tip.

Edit: it definitely is more random considering I don't have to make a bunch of changes to the seed to get random numbers.
#20
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.
#21
This is crazy that I find this thread because I was just thinking about this problem a little while back and something like solution #2 is what I figured would work best.

I'm trying to work on an ARPG mix of Dark Souls and ALttP and I had planned on having interchangeable weapons and armour. I don't know for certain that this would work on a large scale, but my thought was that you would layer the armour/weapon sprites on top of/underneath the hero sprite and synchronise them. It is a bit of work to make all the sprite sheets but it's not all that terrible. As a proof of concept, I used a custom enemy sprite and overlaid the weapon (a broken straight sword) in his hand.

I copied the soldier.lua from the ALttp_1.6 resource pack and changed a few things and named it hollow.lua. This function:

function enemy:order_sprites(main_sprite,sword_sprite)
    local direction4 = enemy:get_direction4_to(enemy:get_facing_position())
print(direction4)
      if direction4 == 1 or direction4 == 2 then
        enemy:bring_sprite_to_back(sword_sprite)
        enemy:bring_sprite_to_front(main_sprite)
        print("sword in back")
      else
        enemy:bring_sprite_to_front(sword_sprite)
        enemy:bring_sprite_to_back(main_sprite)
        print("sword in front")
      end
    return true
  end


is what I used to change the sprite overlay depending on the direction of the entity. It is called in the hollow.lua here:

function enemy:check_hero()

    local _, _, layer = enemy:get_position()
    local _, _, hero_layer = hero:get_position()
    local near_hero = layer == hero_layer
        and enemy:get_distance(hero) < 500
        and enemy:is_in_same_region(hero)

    if near_hero and not going_hero then
      if properties.play_hero_seen_sound then
        sol.audio.play_sound("hero_seen")
      end
      enemy:go_hero()
    elseif not near_hero and going_hero then
      enemy:go_random()
    end
    sol.timer.stop_all(self)
    sol.timer.start(enemy, 50, function() enemy:order_sprites(main_sprite, sword_sprite) end)   --timer to ensure weapon sprite is in front/
                                                                                                --behind the enemy when necessary
    sol.timer.start(self, 100, function() enemy:check_hero() end)
  end


I call it every 50ms because it doesn't perform well above that (weapon sprites pop through after the hero has changed direction). I also haven't tested this with any other circumstance aside from this single enemy on the Kakariko Village map from the resource pack, so I have no clue if it would work with 10 or more enemies on the same map. I had planned to use this for the hero too...no clue if that would work too, but that is for a little bit later on.

Comments and feedback are appreciated.
#22
As llamazing suggested, the tostring and tonumber option worked out perfectly. I had tried that but I put them in the wrong place to get the expected results. Thank you for the helpful tip, llamazing.

@Diarandor: I ended up setting it up to calculate the value whenever you call it but it still saves the value (for now) because I'm not sure if there will items that directly affect the multiplier (without affecting Endurance). So a little of both solutions helped here.

I appreciate this community for being so helpful; this post wasn't even about getting help but you helped me reconfigure my scripts to work properly. Do either of you know, by chance, why it is that game values are truncated? That was my main reason for posting. I wasn't sure if anyone knew.
#23
You're saying to just use the function to calculate the number anytime it is needed? I suppose I could, I just thought it would be better to save it; not sure why.
#24
The function mentioned is one I defined however it doesn't have anything in it that would truncate the decimal.

I think what you have posted may just work. I was trying tostring and tonumber but I don't think I was placing them correctly for the desired effect. I will try it the way you have said and see if it helps.

It beats my original plan: change everything over to hero_meta functions. That way, my get/set_value becomes get/set_property which doesn't work as expected ( although I suspect I haven't properly changed al of my scripts to match the new hero_meta versus the old game_meta setup).

I'll post back tomorrow and hopefully will have some successful results.
#25
Sorry, I will try to explain better. There are a few scripts that work with this so I will post them if this post doesn't get across what I'm talking about.

I'm working on an RPG that is supposed to be a mix of Dark Souls 3 and ALttP. It has lots of parameters like Strength, Endurance, and Vigor and some of these parameters are added or multiplied together to define other parameters.

My current issue lies in determining my hero's vitality level. Vitality level depends on three factors: Endurance level, Strength level, and Vigor level.

(strength * 2) + (vigor * endurance multiplier) = vitality

So the parameters (Strength, Vigor, Endurance) all have min and max values (1 - 99). For Strength and Vigor, all I need are the levels; so if my Strength level is 45, I use it in the first part as (45 * 2). However, the Endurance Multiplier is calculated using the Endurance level and its min and max values are 1.01 up to 1.9999999; so if my Endurance level is 25 then my Endurance Multiplier would be 1.340.

This is where the problem lies. I have functions to get,set,add,remove,and calculate all these values but when I call the functions, like game:get_end_mult() (to get my endurance multiplier, obviously), the decimals are removed from the value leaving it as 1 or 2 depending on how large the decimal portion was. I'm currently working on trying the same thing but with the hero metatable instead of the game_metatable. My first test seemed to work; the value printed was the full decimal value that I had typed in.

I was just hoping to be able to integrate all the stats and params into the game table...I suppose its not really necessary for anything besides health, stamina, and magic. I made this post mostly because I am curious as to what the reason is for the game table truncating values.
#26
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.
#27
I really appreciate the help. I have been working with it for a while now and, while it shows no errors, it doesn't work as intended. By no means do I want nor expect you to do the work for me; as you said, it defeats the purpose of the learning process. I will just have to continue to expand my Lua knowledge until I can understand better where I am making the mistake. Looking forward to learning more Lua and Solarus.

Many thanks, again!
#28
I really appreciate the fast replies!

@Diarandor: your code make it look so easy...clearly I have much to learn. I'll try implementing that later today, after work. Am I missing a call for this script somewhere though? Because I feel like it isn't being called properly.

@llamazing: I'll definitely keep those functions in mind. Once I can get a proof of concept working for myself, I'd like to add more to it so that it functions properly in a game, and it looks like what you mentioned is going to be extremely helpful. The game I'm working on is going to be styled like a two stick shooter; essentially the wasd would control the hero movement direction and the mouse would control hero facing direction. So I do want the hero to constantly face the cursor, unless it is directly on top of the hero, in which case he should simply look North.

Really hoping I can get this done with your help  because my next task is to add a stamina resource to the game, alongside life and magic. I've been trying to use the anger bar from OLB as a reference but I can't figure out how to add the resource to the game just yet. I'm assuming it has to do with meta tables so I suppose I'll need to get to that point in the book before really understanding how to do that. I feel bad for asking for help on here when I haven't learned wverything I can on my own but I'm glad I wasn't met with negativity. Thanks again and I'll post back whether or not  I get it working tonight!
#29
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.