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 - alexgleason

#106
Not sure if this is a bug or user error, but I wanted to share.

My goal is to disable the "attack" command completely and use the sword as a standard item (with hero:start_attack()). In main.lua:

Code ( lua) Select

function game:on_command_pressed(command)
  -- Disable attacking; the stick is a regular item
  if command == "attack" then
    return true
  end
  ...
end


However, when I swing the sword, I can actually still press and hold the attack button while the sword is mid-animation. This causes sword-loading to trigger. I'm baffled by the fact I can do this when I've overridden the attack command to "return true" whenever it's pressed. ???

I ended up adding this to scripts/meta/hero.lua to solve my issue:

Code ( lua) Select
-- The hero can only swing the sword, nothing else
function hero:on_state_changed(state)
  if state == "sword loading"
  or state == "sword tapping"
  or state == "sword spin attack" then
    hero:freeze()
    hero:unfreeze()
  end
end


Freezing and unfreezing the hero when going into the sword loading state effectively disables that state, which is what I want. (In my game the sword is limited)
#107
Quote from: Max on October 12, 2018, 12:07:12 AM
so your downside is my upside, haha.

Aaaannndd this is how a bug becomes a feature. ;D
#108
Wait, I got it! Just had to add hero:unfreeze(). This code works:

Code ( lua) Select
-- ♡ Copying is an act of love. Please copy and share.

-- Script that lets you use the sword as a normal item.
-- Note that the sword button cannot be held with this method (for charging or tapping)

local item = ...
local game = item:get_game()

function item:on_created()
  self:set_savegame_variable("stick")
  self:set_assignable(true)
end

function item:on_using()
  local hero = game:get_hero()
  hero:unfreeze()
  hero:start_attack()
  item:set_finished()
end


Thanks Christopho!

EDIT 1:

Note that this approach has some downsides:

1. The item button cannot be held to hold the sword for longer. You'll need to script that if you want it. I did achieve that here with a different type of item.
2. It doesn't seem you can tap the item button to swing the sword very fast. The animation must totally complete before you can press the item button again.

EDIT 2:

Using the held item command approach improves the situation:

Code ( lua) Select
-- ♡ Copying is an act of love. Please copy and share.

-- Script that lets you use the sword as a normal item.
-- Note that the sword button cannot be held with this method (for charging or tapping)

local item = ...
local game = item:get_game()

function item:on_created()
  self:set_savegame_variable("stick")
  self:set_assignable(true)
end

function item:on_command_pressed(command)
  local hero = game:get_hero()
  hero:start_attack()
  item:set_finished()
end


This enables me to tap the sword button very quickly and I don't have to unfreeze the hero first. It still does not let me press and hold the sword button, which doesn't seem possible with the current API. Fortunately this is a feature I'm not using in my game and have disabled anyway.
#109
Quote from: Christopho on October 11, 2018, 09:04:03 PM
I guess it is because the attack is not allowed during the item state. Try to call item:set_finished() just before hero:start_attack().

Ohh, that makes sense! Calling item:set_finished() lets the function continue executing, but strangely the sword is still never swung. This is my code now.

Code ( lua) Select
local item = ...
local game = item:get_game()

function item:on_created()
  self:set_savegame_variable("stick")
  self:set_assignable(true)
end

function item:on_using()
  print("beep")
  item:set_finished()
  print("boop")
  game:get_hero():start_attack()
  print("blip")
end


Pressing the item button does indeed print:

beep
boop
blip


But the sword still doesn't swing. The player doesn't freeze, either. Nothing happens except printing to the console. ???
#110
Quote from: Christopho on October 11, 2018, 08:27:38 PM
sol.main.game does not exist yet (i.e. is nil) at the time your script is executed. And your script is executed the first time you require() it, so most likely long before you assign something to sol.main.game.

OMG thank you! It took me a minute to understand what you meant. The menu script itself is executed before sol.main.game is set, but the function call happens after, so it has access to it. Thank you for bringing me clarity. ;D
#111
Hi, I was hoping to create an item that triggers the hero's normal attack on_using(). It's simple:

Code ( lua) Select
local item = ...
local game = item:get_game()

function item:on_created()
  self:set_savegame_variable("stick")
  self:set_assignable(true)
end

function item:on_using()
  print("beep")
  game:get_hero():start_attack() -- Normal sword attack
end


When I equip the item and press the button, the console outputs "beep", and then the player becomes frozen. The sword is not swung. From the console, I can unfreeze the player with: sol.main.game:get_hero():unfreeze().

Any clue why start_attack() isn't working here? I can call sol.main.game:get_hero():start_attack() from the console at any time and it works, but the same thing doesn't work inside this item script. Thanks!
#112
Quote from: llamazing on October 07, 2018, 11:10:50 PM
So if the script is also required somewhere else, then instead of running the script a second time, the return values saved from the first time the require command was used will simply be passed along to wherever else the script gets required.

Thank you for clarifying this! I found this thread very helpful.

Variable scope still trips me up. For instance, in this menu script I don't understand why this code doesn't work:

Code ( lua) Select
local menu = {}
local game = sol.main.game -- Use `game` as a shorthand for `sol.main.game`

function menu:on_started()
  print(game:get_item_assigned(1):get_name())
end

return menu


Error: In on_started: [string "scripts/menus/my_menu.lua"]:5: attempt to index upvalue 'game' (a nil value)

Yet this code works just fine:

Code ( lua) Select
local menu = {}

function menu:on_started()
  -- Use sol.main.game directly
  print(sol.main.game:get_item_assigned(1):get_name())
end

return menu


Using sol.main.game works great. 👍 (I'm using the boilerplate code which sets sol.main.game within main.lua)

More confusingly, this code also doesn't work.

Code ( lua) Select
local menu = {}
game = sol.main.game -- Use a global variable this time

function menu:on_started()
  print(game:get_item_assigned(1):get_name())
end

return menu


Error: In on_started: [string "scripts/menus/item_menu.lua"]:5: attempt to index global 'game' (a nil value)

I thought when you require() a Lua script, any global variables created by the script persist throughout the whole codebase. I'm super confused why these don't work. I thought variable scope was the problem, but maybe not?
#113
Your projects / Re: Vegan on a Desert Island
October 11, 2018, 07:37:36 PM
Quote from: Diarandor on October 05, 2018, 08:31:01 PM
Have you played Survival Kids from the gbc? (Gameplay here: https://www.youtube.com/watch?v=eQet3NwtHO4) I played it a little bit and I believe this game might have taken some inspiration from there too, or at least it has some things in common. I never finished it because it was too hard for a casual player like me, though. If you haven't played it, I recommend you to take it a look at it for inspiration and good ideas in your game. :)

Hey, thanks for this!! Incidentally I recognize those palm tree sprites, which I stumbled upon looking for art inspiration, but I never looked into the actual game. I will definitely give it a shot and see if there's anything I can glean from it. ;D
#114
General discussion / Re: We have moved
September 30, 2018, 07:44:17 PM
Quote from: Neovyse on September 30, 2018, 11:37:25 AM
That's a good idea! Can Matric be used without discord, as standalone ?

Yep, I use it for a lot of stuff. For example, here's the chatroom for my Solarus game I'm developing: https://riot.im/app/#/room/#voadi:matrix.org
#115
My game runs at full speed normally. But sometimes I'll leave the game window open while I'm working on some code. When I return 20 minutes later it's often lagging quite a bit. CPU usage goes up to 100% on one of my cores.

It's possible my game code is causing this, but I'm not sure where. I'm not using game:on_update() anywhere and I don't think I'm firing off any events that never stop. Has anyone else experienced this? Solarus 1.5.3
#116
General discussion / Re: We have moved
September 29, 2018, 08:30:35 PM
I wasn't very active on the old chat anyway, but it was nice that it had an active bridge to matrix.org, meaning I could join the discussion using completely free and open-source software.

It's possible to bridge Matrix and Discord, but it's more difficult: https://matrix.org/docs/projects/as/matrix-appservice-discord.html Out of the box, Matrix will bridge with IRC, Gitter, and Slack.
#117
Development / Re: How to filter an entity iterator?
September 25, 2018, 09:22:41 PM
This library seems to do what I want, but it doesn't look possible in normal Lua: https://github.com/starwing/luaiter

It has a fitlerout(func, iter) function.
#118
Development / Re: Item command held on item?
September 25, 2018, 08:51:16 PM
Here's how I achieved this.

In main.lua, within the sol.main:start_savegame(game) function:

Code (lua) Select

-- ♡ Copying is an act of love. Please copy and share.

-- Returns an item for item_ command strings
function get_item_for_command(command)

  local slot = tonumber(string.match(command, "^item_([12])$"))

  if slot then
    local item = game:get_item_assigned(slot)
    return item
  else
    return nil
  end
end


function game:on_command_pressed(command)

  -- Handle items with item:on_command_pressed()
  local item = get_item_for_command(command)
  if item and item.on_command_pressed ~= nil then
    item:on_command_pressed(command)
    return true
  else
    -- Fall back to item:on_using()
    return false
  end

end

function game:on_command_released(command)

  -- Handle items with item:on_command_released()
  local item = get_item_for_command(command)
  if item and item.on_command_released ~= nil then
    item:on_command_released(command)
    return true
  else
    return false
  end

end


Then within the item itself, simply implement item:on_command_pressed() and item:on_command_released().

Code ( lua) Select

-- ♡ Copying is an act of love. Please copy and share.

function item:on_command_pressed(command)
  print(string.format("%s command pressed", item:get_name()))
end

function item:on_command_released(command)
  print(string.format("%s command released", item:get_name()))
end


In this case, item:on_using() is never called. If you choose not to implement item:on_command_pressed() for a particular item, it will fall back to item:on_using().

I'm a bit afraid I've missed something which I'll discover later, but this works in normal circumstances.
#119
Development / Re: How to filter an entity iterator?
September 24, 2018, 12:55:36 AM
What I'm trying to do is actually return a new entity iterator. For context, I'm making an item similar to the gust jar in Minish Cap. I'm wanting item:get_suckable_entities() to return an entity iterator containing items of a certain type in a certain region so I can loop over it.

I just managed to finish writing this code:

Code ( lua) Select
-- Get suckable entities
function item:get_suckable_entities()

  local map  = self:get_map()

  -- Get entities in suckable rectangle
  local entities = map:get_entities_in_rectangle(self:get_suckable_rectangle())

  -- Filter only suckable types
  filtered = {}
  for entity in entities do
    for model in item:get_suckable_models() do
      if entity:get_type() == "custom_entity" and entity:get_model() == model then
        table.insert(filtered, entity)
      end
    end
  end

  function filtered_entities()
    local i = 0
    local n = table.getn(filtered)
    return function()
      i = i + 1
      if i <= n then return filtered[i] end
    end
  end

  return filtered_entities()
end


It totally works, but I was hoping there would be a way to achieve this without dumping everything into a filtered table first and then creating a new iterator out of that table.

Thanks for your reply. :)

EDIT: My full code is now here for context https://gitlab.com/voadi/voadi/blob/master/data/items/vacuum.lua
#120
Development / How to filter an entity iterator?
September 24, 2018, 12:03:15 AM
So I've used:

Code ( lua) Select
map:get_entities_in_rectangle(x, y, width, height)

which gave me back a nice entity iterator.

The problem is, I only want some of those entities. For example, I might want only entities where:

Code ( lua) Select
entity:get_type() == "custom_entity" and entity:get_model() == "trash"

I know how to loop through it and build a new array, but I'd like to learn how to create a new entity iterator. Is it possible to do this without dumping the contents of the first iterator into an array first? I'm new to Lua and trying to figure this out. :)

Thanks!