Author Topic: How to require from a map?  (Read 1973 times)

Zefk

  • Hero Member
  • *****
  • Posts: 536
  • Just helping Solarus
    • View Profile
    • Zelzec
How to require from a map?
« on: October 15, 2016, 04:02:21 am »
Hello,

I tried loading an external script using require from the map script and I tried the same thing from the game manager, but it seems the map script prevented the script from loading in the game manager.

In the map I did:

Code: ( lua) [Select]
local name_listing = require("scripts/pick_name.lua")

code here.....

if key == "p" then
  name_listing:name_picker() -- Require name_list.lua
end

It worked, but the map script stopped running. How would I get both scripts to run at the same time? Does it have to do with both scripts using same functions for key presses and image drawing?

-Zefk

llamazing

  • Full Member
  • ***
  • Posts: 198
    • View Profile
Re: How to require from a map?
« Reply #1 on: October 15, 2016, 05:36:57 am »
It should totally be possible to have your game manager and your map running the same script. Although I'm not sure why you'd want the map and the game manager to both be processing key presses for the same script. You're going to have to provide more detail on what your script does and what you are trying to accomplish.

If one of your on_key_pressed() functions returns true, it prevents the on_key_pressed() function from getting called elsewhere for that key press that was already handled.

Zefk

  • Hero Member
  • *****
  • Posts: 536
  • Just helping Solarus
    • View Profile
    • Zelzec
Re: How to require from a map?
« Reply #2 on: October 15, 2016, 06:33:16 am »
Quote
If one of your on_key_pressed() functions returns true, it prevents the on_key_pressed() function from getting called elsewhere for that key press that was already handled.
I think this is the case.

Scripts:
I will paste my scripts and simplified my map script because it was too long, but beware....they are still a little messy. This is kinda just an experiment.

game manager.lua (I commented out "name_listing:name_picker() " because it would not run with the map script.)
Code: ( lua) [Select]
local game_manager = {}

local name_listing = require("scripts/pick_name.lua")
local initial_game = require("scripts/initial_game")
require("scripts/menus/alttp_dialog_box")

-- Starts the game from the given savegame file,
-- initializing it if necessary.

function game_manager:start_game()

  --name_listing:name_picker() 

  local exists = sol.game.exists("save1.dat")
  local game = sol.game.load("save1.dat")
  if not exists then
    -- Initialize a new savegame.
    game:set_max_life(12)
    game:set_life(game:get_max_life())
    game:set_ability("lift", 2)
    game:set_ability("sword", 1)
  end
  game:start()

  local hero = game:get_hero()
  hero:set_tunic_sprite_id("main_heroes/eldran")
end

return game_manager

first_map.lua: (This shows an image textbox menu. I normally would not have this code in a map script. I am seeing if it works.)

Without all the code:
Code: ( lua) [Select]
local name_listing = require("scripts/pick_name.lua")
 
code here.....
 
if key == "p" then
  name_listing:name_picker() -- Require name_list.lua
end

With all the code simplified:
Code: ( lua) [Select]
local name_listing = require("scripts/pick_name.lua")

--Tell the script it is a map and to use game functions
local name_listing = require("scripts/pick_name.lua")
local map = ...
local game = map:get_game()


--A table because I like tables and it prevents upvalue errors
local text_box = {

--Lowercase arrays because listing these variables would be a pain.
      main_box = {},
      main_box_row_2 = {},
      main_box_row_3 = {},
      main_box_row_4 = {},
      box_x ={},

      place_x = {},
     
      num1_place = {},

--Boolean for the lower case letters, numbers, and special characters

      num1_img = sol.surface.create("lower_case/1.png"),
   
--box images to false
     blinker = false,
     lower_case = false,
     upper_case = false,
     letter_box_background = false,

--load box images
     blinker_img = sol.surface.create("blinker.png"),
     large_box_img = sol.surface.create("large_box.png"),
     main_box_img = sol.surface.create("main_box.png"),
     lower_case_img = sol.surface.create("lower_case.png"),
     upper_case_img = sol.surface.create("upper_case.png"),
     letter_box_background_img = sol.surface.create("letter_input_background.png"),

--direction keyboard to false, so it does not mess with hero movements.
      key_picker_direction = 0,
      right_key = false,
      left_key = false,
      up_key = false,
      down_key = false,

--Place for char input
      place = {},

      shift = {},
      lowercase_shift = true,
      uppercase_shift = false,

      naming_character = {},

      character = {},
     
      char = {},
      name = {},
      character_num ={},
      character_cals = {},
}

--Main box that browses the letters, numbers, and special characters.
--***************place checks. Keep space, blinker movement/animation, and erase in mind.

--text_box.place[0] = true does nothing apparently, so this activates text_box.place[1] = true
local place = true

--Naming for character number "1" which is most likely the hero.
text_box.character_num[1] = true

--Calculate which character string is true during naming. zero makes character one false based on the calculations for "enter."
--This must equal zero because each time you press enter 1 is added.
-- EX: *Presses enter* character_cal = 1 (now you can name character 2)
local character_cal = 0

--Amount or number of characters set to false. That means the characters that are done being named (enter pressed).
--This must equal zero because each time you press enter 1 is added.
-- Ex: text_box.character_num[amount_false] = true
local amount_false = 0

--This is a backspace and input limit. Make sure this is one (1) below char_amount. If char_limit is 15, then char_amount is 16 for 15 letters, numbers, and/or special characters. Otherwise, it will not backspace.
local char_limit = 15

--This is the loop amount. This must be 16 to make 15 false when using backspace. If 150, then set it to 151.
local char_amount = 16

--Number of images to show. I set the limit to 15.
local char_image_num = 15

--Character limit. Want to name a million monsters? Ex: Pokemon? Change it to over 150!
local character_limit = 15

--Max char to make a string that will be passed on to the textbox with $v
local max_char = 15


--The draw function for showing images
function sol.main:on_draw(screen)

--Textbox images and blinker
  if text_box.letter_box_background == true then
    text_box.letter_box_background_img:draw(screen)
  end

  if text_box.blinker == true then
    text_box.blinker_img:draw(screen,-1,-2)
  end

  if text_box.upper_case == true then
    text_box.upper_case_img:draw(screen)
  end

  if text_box.lower_case == true then
    text_box.lower_case_img:draw(screen)
  end

  if text_box.large_box == true then
    text_box.large_box_img:draw(screen)
  end

  if text_box.cancel_box == true then
    text_box.cancel_box_img:draw(screen)
  end

--Main green box letter picker positions

for x = 0,11 do
--first row
  if text_box.main_box[x] == true then
    text_box.main_box_img:draw(screen, text_box.box_x[x])
  end
--second row
  if text_box.main_box_row_2[x] == true then
    text_box.main_box_img:draw(screen, text_box.box_x[x],22)
  end
--third row
  if text_box.main_box_row_3[x] == true then
    text_box.main_box_img:draw(screen, text_box.box_x[x],42)
  end
--4th row
  if text_box.main_box_row_4[x] == true then
    text_box.main_box_img:draw(screen, text_box.box_x[x],62)
  end
end

--Large green main text boxes
  if text_box.main_box[12] == true then
    text_box.large_box_img:draw(screen,0,0)
  end

  if text_box.main_box_row_2[12] == true then
    text_box.large_box_img:draw(screen,0,20)
  end

  if text_box.main_box_row_3[12] == true then
    text_box.large_box_img:draw(screen,0,40)
  end

  if text_box.main_box_row_4[12] == true then
    text_box.large_box_img:draw(screen,0,60)
  end

--Display char images
 for char = 1,char_image_num do
--lowercase drawing
--Draw text number 1 (one) up to 15 places
  if text_box.num1_place[char] == true then
    text_box.num1_img:draw(screen, text_box.place_x[char])
  end

end

end --end of draw function


function sol.main:on_key_pressed(key)

  if key == "space" then

    --text_box.blinker = true
if text_box.lowercase_shift == true then
    text_box.lower_case = true
else
    text_box.lower_case = false
end

if text_box.uppercase_shift == true then
    text_box.upper_case = true
else
    text_box.upper_case = false
end

    text_box.letter_box_background = true
    text_box.key_picker_direction = 1
    text_box.left_key = true
    text_box.right_key = true
    text_box.up_key = true
    text_box.down_key = true

    if place == true then
      text_box.place[1] = true
    else
      text_box.place[1] = false
    end

    game:set_paused(true)

  end

--Left control for the key place digits

  if key == "right" and text_box.right_key == true
  then
       print("minus 12 from browse 12")
       sol.audio.play_sound("cursor")
       if text_box.key_picker_direction == 12
       then
            text_box.key_picker_direction = text_box.key_picker_direction - 12
            text_box.main_box[12] = false
       end
  end



--Key main box green picker
--1 to 12 calculations
for x = 0,4  do
  text_box.box_x[x] = x * 17 - 17
  for x = 5,7 do
    text_box.box_x[x] = x * 16 - 13
       for x = 7,9 do
         text_box.box_x[x] = x * 16 - 12
         for x = 10,11 do
           text_box.box_x[x] = x * 16 - 11
         end
      end
   end
end

--Calculations "char"
for char = 1,char_image_num  do
  text_box.place_x[char] = char * 9
end


  if text_box.key_picker_direction == 1 then
        text_box.main_box[1] = true
        text_box.main_box[2] = false
  end




if text_box.uppercase_shift == true then
  if text_box.key_picker_direction == 48 and key == "e" then
        text_box.shift[2] = true
        text_box.key_picker_direction = 0
        text_box.lowercase_shift = true
        text_box.uppercase_shift = false
  end
end



if text_box.lowercase_shift == true then
  if text_box.key_picker_direction == 48 and key == "e" then
        text_box.shift[1] = true
        text_box.uppercase_shift = true
        text_box.lowercase_shift = false
  end
end



for i = 0,char_amount do

--input from box position 1
if text_box.place[i] == true then
 
  if key == "e" and text_box.place[i] == true then
        sol.audio.play_sound("wrong")
  end

--Delete or backspace
 if text_box.key_picker_direction == 12 and key == "e"  then

   if i <= 16 then
    if text_box.naming_character[i] == true then
      table.remove(text_box.character)
    end

      text_box.exclamation_place[i - 1] = false

      if text_box.place[1] == true then
        text_box.place[i - 2] = true
        --text_box.place[i] = false
      else
      text_box.place[i - 1] = true
      text_box.place[i] = false
      print("*************************************************************************************", i)
      end
     end
     break
end

  if text_box.key_picker_direction == 1 and key == "e" and text_box.lowercase_shift == true then
--Inserting char "1" calculations for 15 different characters

    if i <= char_limit then

     if text_box.naming_character[i] == true then
       text_box.char[i] = "1"
       table.insert(text_box.character,text_box.char[i])
     end

        text_box.num1_place[i] = true
        text_box.place[i + 1] = true
        text_box.place[i] = false
       break
    end
  else
  if text_box.key_picker_direction == 1 and key == "e" then
--Inserting char "!" calculations for 15 different characters


    if i <= char_limit then

     if text_box.naming_character[i] == true then

       text_box.char[i] = "!"
       table.insert(text_box.character,text_box.char[i])
     end
        text_box.exclamation_place[i] = true

        text_box.place[i + 1] = true
        text_box.place[i] = false
       break
    end
  end
end
end

if text_box.shift[1] == true then
   if text_box.uppercase_shift == true then
     text_box.upper_case = true
     text_box.lower_case = false
     print("uppercased!")
   end

   if text_box.lowercase_shift == true then
     if text_box.upper_case == true then
       text_box.key_picker_direction = 48
     end
     text_box.upper_case = false
     text_box.lower_case = true
     print("lowercased!")
   end
end

--Allow 15 char to pass on to the character being named.
for i = 1,max_char do
text_box.naming_character[i] = true
end


print("Browse is:", text_box.key_picker_direction)
print("Char is:", table.concat(text_box.character))

for i = 1,character_limit do
  if text_box.character_num[i] == true then
    text_box.name[i] = table.concat(text_box.character)

   print("character", i, "name is:", text_box.name[i])
   break
  end
end

for i = 1,character_limit do
  print("character", i, "1 name is:", text_box.name[i])
 --break
end

if key == "p" then
  name_listing:name_picker()
end

end

pick_name.lua (This is in the scripts folder. It shows an image with text on it. I want it to show while the map script image menu is showing)
Code: ( lua) [Select]
--Tell the script to use game functions
local game = ...

local name_listing = {}

function name_listing:name_picker(game)

local name_list ={
      browse_list = 0,

      green_box = {},
      green_box_y ={},

      list_bg = false,
      list = false,
      up_list = false,
      down_list = false,
      list_bg_img = sol.surface.create("name_pick/name_list_bg.png"),
      list_img = sol.surface.create("name_pick/name_list.png"),
      green_box_img = sol.surface.create("name_pick/green_box.png"),
}


local list_box_amount = 8

--The draw function for showing images
function sol.main:on_draw(screen)

   if list_bg == true then
     name_list.list_bg_img:draw(screen)
   end

   if list == true then
     name_list.list_img:draw(screen)
   end

   for y = 0,list_box_amount do
     if name_list.green_box[y] == true then
       name_list.green_box_img:draw(screen,0,name_list.green_box_y[y])
     end
   end
end --end of draw function

function sol.main:on_key_pressed(key)

  if key == "o" then
    list_bg = true
    list = true
    up_list = true
    down_list = true
  end

  if key == "up" and up_list == true then
    sol.audio.play_sound("cursor")
    if name_list.browse_list <= 8 then
      name_list.browse_list = name_list.browse_list + 1
    end
  end

  if key == "down" and down_list == true then
    sol.audio.play_sound("cursor")
    if name_list.browse_list >= 0 then
      name_list.browse_list = name_list.browse_list - 1
    end
  end

  for y = 0,list_box_amount do
    name_list.green_box_y[y] = y * 9
  end


  if name_list.browse_list == 1 then
        name_list.green_box[1] = true
        name_list.green_box[2] = false
  end

  if name_list.browse_list == 2 then
        name_list.green_box[1] = false
        name_list.green_box[2] = true
        name_list.green_box[3] = false
  end

  if name_list.browse_list == 3 then
        name_list.green_box[2] = false
        name_list.green_box[3] = true
        name_list.green_box[4] = false
  end

  if name_list.browse_list == 4 then
        name_list.green_box[3] = false
        name_list.green_box[4] = true
        name_list.green_box[5] = false
  end

  if name_list.browse_list == 5 then
        name_list.green_box[4] = false
        name_list.green_box[5] = true
        name_list.green_box[6] = false
  end

  if name_list.browse_list == 6 then
        name_list.green_box[5] = false
        name_list.green_box[6] = true
        name_list.green_box[7] = false
  end

  if name_list.browse_list == 7 then
        name_list.green_box[6] = false
        name_list.green_box[7] = true
        name_list.green_box[8] = false
  end

  if name_list.browse_list == 8 then
        name_list.green_box[7] = false
        name_list.green_box[8] = true
        name_list.green_box[9] = false
  end
end -- End of buttoon press function

end -- end of require function

return name_listing

llamazing

  • Full Member
  • ***
  • Posts: 198
    • View Profile
Re: How to require from a map?
« Reply #3 on: October 15, 2016, 07:43:07 am »
Your problem is that your script defines sol.main:on_key_pressed(key), which can only be defined once. When your game_manager calls the pick_name.lua script, it defines sol.main:on_key_pressed(key). Then when your map loads the calls the pick_name.lua script, a new function is assigned to sol.main:on_key_pressed(key), overwriting the old one.

Using sol.main:on_key_pressed(key) is not the correct way to do things. You really only need that for handling key presses that are handled all the time, including when there isn't a game running (an example would be alt+f4 to exit). And then only define sol.main:on_key_pressed(key) exactly one time. Likewise for sol.main:on_draw()

What you should do instead is make your pick_name.lua script be a menu. So in your pick_name.lua script:
Code: (lua) [Select]
--function sol.main:on_draw(screen) --replace this line with the following
function name_listing:on_draw(screen)

--function sol.main:on_key_pressed(key) --replace this line with the following
function name_listing:on_key_pressed(key)

And then to "run" your script, do the following:
Code: (lua) [Select]
--from game_manager.lua:
local name_listing = require("scripts/pick_name.lua")

function game_manager:start_game()
local exists = sol.game.exists("save1.dat")
local game = sol.game.load("save1.dat") --note this line must come before starting the menu

sol.menu.start(game, name_listing) --assuming you want to start the menu as soon as your game starts

--additional code...
end

--from first_map.lua:
local name_listing = require("scripts/pick_name.lua")
local map = ...

--additional code...

--function sol.main:on_draw(screen) --replace this line with the following
function map:on_draw(screen)

--additional code...

end

--function sol.main:on_key_pressed(key) --replace this line with the following
function map:on_key_pressed(key)

--additional code...

if key == "p" then
sol.menu.start(self, name_listing)
end
end

When you no longer want the pick_name.lua script to be drawing to the screen or handling key press events, call the following:
Code: (lua) [Select]
sol.menu.stop(name_listing)
And by the way, you should delete the following line from your pick_name.lua script. It doesn't work the way you think it works for scripts loaded using require.
Code: (lua) [Select]
local game = ... --delete this line (line 2)

Zefk

  • Hero Member
  • *****
  • Posts: 536
  • Just helping Solarus
    • View Profile
    • Zelzec
Re: How to require from a map?
« Reply #4 on: October 15, 2016, 08:07:35 am »
I understand now. I will rework my scripts to follow the menu process. Thank you llamazing for using your time to assist me.

MetalZelda

  • Hero Member
  • *****
  • Posts: 551
    • View Profile
Re: How to require from a map?
« Reply #5 on: October 16, 2016, 02:56:56 pm »
The problem is, if you are using this menu as a way to draw bitmaps on the screen without using map:on_draw() (which is the way to go), it wouldn't work, because your require is recognized as menu, so you need to start the menu through sol.menu.start(map, name_listing) to draw the content of your menu. Llamazing got it right