Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  
Pages: 1 2 3 [4] 5 6 ... 8

Author Topic: Holidays  (Read 9115 times)

Roses

  • Bay Watcher
    • View Profile
Re: Holidays
« Reply #45 on: September 25, 2019, 03:28:01 pm »

Ah, not sure how I missed that. You have holiday_shamrock_countdown() at the top of the file. But the function hasn't been defined yet. You should move that call to the bottom of the file.

I haven't ever used the showAnnouncement, but it looks right. And yes that print("test") is correct.
Logged

brolol.404

  • Bay Watcher
    • View Profile
Re: Holidays
« Reply #46 on: September 25, 2019, 07:43:05 pm »

Ah, not sure how I missed that. You have holiday_shamrock_countdown() at the top of the file. But the function hasn't been defined yet. You should move that call to the bottom of the file.

I haven't ever used the showAnnouncement, but it looks right. And yes that print("test") is correct.

After moving the call to the bottom of the script the error went away after running the script on the command line, but still nothing seems to happen (with or without manually running the command). I may have to put some print statements throughout the code once I get some time to see where the issue is.

Roses

  • Bay Watcher
    • View Profile
Re: Holidays
« Reply #47 on: September 25, 2019, 10:55:13 pm »

Yes, I would suggest throwing some print statements in each of the functions. Everything looks ok to me, are you sure you have the date correct?
Logged

brolol.404

  • Bay Watcher
    • View Profile
Re: Holidays
« Reply #48 on: September 26, 2019, 02:52:20 am »

Yes, I would suggest throwing some print statements in each of the functions. Everything looks ok to me, are you sure you have the date correct?

I am just going off of "z" in game. The wiki says that Granite is March which would be 3/17, but it's possible that the game starts the year with Granite 1, or possibly even Granite 15?

Will this work?

Code: [Select]
print("shamrock tick:", date_shamrock, "current tick:", current_tick, "ticks to shamrock:", ticks)
EDIT:

I also want to add the following code to the holiday (right after the leprechaun is created), but I don't know the variable/function to add a thought, how to give that thought to a random dwarf and how to prevent that dwarf from getting anymore thoughts in this way. Is there a way to make this affect any civ member or any civ member and any visitor instead of just dwarves?

Code: [Select]
holiday_thoughts_shamrock()

Does the function code always have to come before the function call?

Code: [Select]
function holiday_thoughts_shamrock()

local holiday_thought_total = math.random(100)

while (holiday_thought_total > 0) do
local holiday_thought_type = math.random(3)
[choose a random dwarf]
if ([dwarf is not marked])
if (holiday_thought_type == 1)
[give dwarf enjoyment thought]
[mark dwarf]
end
if (holiday_thought_type == 2)
[give dwarf amusement thought]
[mark dwarf]
end
if (holiday_thought_type == 3)
[give dwarf delight thought]
[mark dwarf]
end
holiday_thought_total = holiday_thought_total - 1
end
end
end
« Last Edit: September 26, 2019, 06:53:52 am by brolol.404 »
Logged

Roses

  • Bay Watcher
    • View Profile
Re: Holidays
« Reply #49 on: September 26, 2019, 09:03:35 am »

Yes, I would suggest throwing some print statements in each of the functions. Everything looks ok to me, are you sure you have the date correct?

I am just going off of "z" in game. The wiki says that Granite is March which would be 3/17, but it's possible that the game starts the year with Granite 1, or possibly even Granite 15?
Then it's definitely possible the code is working correctly but calculating a callback time a year away. To test it you could just set ticks to 1200 manually. That way the leprechaun should spawn a day after you start, regardless of the actual day you start on.

Will this work?

Code: [Select]
print("shamrock tick:", date_shamrock, "current tick:", current_tick, "ticks to shamrock:", ticks)Yes, that should work, you could put that right before the dfhack.timeout call and it would tell you pretty much all you need to know

EDIT:

I also want to add the following code to the holiday (right after the leprechaun is created), but I don't know the variable/function to add a thought, how to give that thought to a random dwarf and how to prevent that dwarf from getting anymore thoughts in this way. Is there a way to make this affect any civ member or any civ member and any visitor instead of just dwarves?
Now you are getting into a little more complicated territory. The two things you are going to want are dfhack.units.isDwarf(unit) and df.global.world.units.active The first is a function that checks if the unit is the same race as your fortress (not necessarily a dwarf if you are playing a different race) and the second is a table of current units on the map. You will want to make your own table of units that meet your criteria, then choose one at random, apply your thought, then remove the unit from the list of available units. Below is an example script to get a table of units that you can use.
Code: [Select]
units = {}
n = 0
for i,unit in pairs(df.global.world.units.active) do
  if dfhack.units.isDwarf(unit) then
    n = n + 1
    units[n] = unit
  end
end
As for adding the actual thought, there is an add-thought script in the dfhack script repository which you can look at to see how it works.

Code: [Select]
holiday_thoughts_shamrock()

Does the function code always have to come before the function call?
Only if the function call is by itself. If it is being called from another function it doesn't matter

Code: [Select]
function holiday_thoughts_shamrock()

local holiday_thought_total = math.random(100)

while (holiday_thought_total > 0) do
local holiday_thought_type = math.random(3)
[choose a random dwarf]
if ([dwarf is not marked])
if (holiday_thought_type == 1)
[give dwarf enjoyment thought]
[mark dwarf]
end
if (holiday_thought_type == 2)
[give dwarf amusement thought]
[mark dwarf]
end
if (holiday_thought_type == 3)
[give dwarf delight thought]
[mark dwarf]
end
holiday_thought_total = holiday_thought_total - 1
end
end
end
Just a small note, instead of using a while loop with the subtraction you can use "for i = 1, holiday_thought_total do"
Logged

brolol.404

  • Bay Watcher
    • View Profile
Re: Holidays
« Reply #50 on: September 26, 2019, 10:01:10 am »

Thanks.

Now you are getting into a little more complicated territory. The two things you are going to want are dfhack.units.isDwarf(unit) and df.global.world.units.active The first is a function that checks if the unit is the same race as your fortress (not necessarily a dwarf if you are playing a different race) and the second is a table of current units on the map. You will want to make your own table of units that meet your criteria, then choose one at random, apply your thought, then remove the unit from the list of available units. Below is an example script to get a table of units that you can use.[/color]
Code: [Select]
units = {}
n = 0
for i,unit in pairs(df.global.world.units.active) do
  if dfhack.units.isDwarf(unit) then
    n = n + 1
    units[n] = unit
  end
end
Couple questions on this. Is unit a global variable of DF or is it being defined in the for statement? What does unit in pairs mean? Why is it units[n] instead of units.n like the pos table?
« Last Edit: September 26, 2019, 10:06:58 am by brolol.404 »
Logged

Fleeting Frames

  • Bay Watcher
  • Spooky cart at distance
    • View Profile
Re: Holidays
« Reply #51 on: September 26, 2019, 12:39:41 pm »

units here is a global variable of script. If the first line of that snip was "units = units or {}", it would recall the existing table instead of making a new one on next unchanged script call. Script global variables are stored in dfhack.internal.scripts on per-script basis, though you're generally preferred to use dfhack.script-environment rather than accessing that. (Not to be confused with predefined variables global to all scripts, such as COLOR_YELLOW).

i and unit are local to the for-loop, only have values in the for-loop, and are given those values by the pairs function. pairs function is an iterator function* that will take a list and keep giving new values to i and unit from said list, until it has run through entire table, not necessarily in order.

units.n is equivalent to units['n'].
units[n] is equivalent to units[whatever n is set to].

i.e.
Code: [Select]
local n, units = 1, {}
units[n] = "a"
units.n = "b"
units['1'] = "c"
printall(units)
will output
Code: [Select]
1                      = a
n                      = b
1                      = c


Secondary note on ipairs vs pairs:

Note that here ipairs, which only looks at numerically indiced keys, will appear really similar to pairs, since all keys are set on numbers 0 .. n - indeed, they return the same total count. And ipairs can be great for keeping your data constrained when passing it from function to function. But when it comes to lua tables, it'll count from 1 rather than df's 0, so if you did, say,
Code: [Select]
:lua unitlist = {} for i,v in pairs(df.global.world.units.active) do unitlist[i]=v endthen
Code: [Select]
:lua local count=0 for i,v in ipairs(unitlist) do count = count +1 end print(count)
Will print out 1 less than pairs would, even though directly accessing df.global.world.units.active with pairs and ipairs will give the same count.


* Meaning it returns another function, state variable for keeping track and first variable, and the for loop will keep calling the returned function with the two variables it returned until the first variable is nil. You can write your own iterators, but I don't expect you to need to.

PS: http://www.lua.org/pil/contents.html and http://lua-users.org/wiki/ can be helpful for learning lua in general, though that will make you miss functions like dfhack.timeout(numberOfticks, function).
« Last Edit: September 26, 2019, 01:04:41 pm by Fleeting Frames »
Logged

brolol.404

  • Bay Watcher
    • View Profile
Re: Holidays
« Reply #52 on: September 26, 2019, 05:18:56 pm »

...

interesting. thanks for the explanations :)

So, the year starts on Granite 1 (March 1), not Opal 1 (January 1). I made the updates; however, I now have the following issues.

1. The script doesn't load on it's own. It has to be run manually. I tried moving the script call into OnLoad.init instead of OnMapLoad.init, but it still doesn't load on it's own.

The path is \raw\OnMapLoad.init

Code: [Select]
holiday_shamrock
2. The leprechaun doesn't spawn. Here is the error:

[DFHack]# holiday_shamrock
initializing shamrock holiday
initializing shamrock countdown
shamrock tick:  19200   current tick:   16999   ticks to shamrock:      2201
calibrating leprechaun position
leprechaun positioning: table: 000001EC6289E4A0
C:\Users\bro\Desktop\df_44_12_win\hack\lua\utils.lua:603: bad argument #1 to 'sub' (string expected, got table)
stack traceback:
        [C]: in function 'string.sub'
        C:\Users\bro\Desktop\df_44_12_win\hack\lua\utils.lua:603: in function 'utils.processArgs'
        ...sktop\df_44_12_win/hack/scripts/modtools/create-unit.lua:488: in local 'script_code'
        C:\Users\bro\Desktop\df_44_12_win\hack\lua\dfhack.lua:680: in function 'dfhack.run_script_with_env'
        (...tail calls...)
        ...a\Desktop\df_44_12_win/hack/scripts/holiday_shamrock.lua:19: in global 'holiday_shamrock'
        ...a\Desktop\df_44_12_win/hack/scripts/holiday_shamrock.lua:13: in function <...a\Desktop\df_44_12_win/hack/scripts/holiday_shamrock.lua:13>


It looks like it doesn't like pos for the location in create-unit? Here is the script:

holiday_shamrock.lua

Code: [Select]
print("initializing shamrock holiday")

function holiday_shamrock_countdown()
 local year_tick_total = 1200*28*12
 local current_tick = df.global.cur_year_tick
 local date_shamrock = 1200*(0*28+16)
 local ticks = date_shamrock - current_tick
 if ticks < 0 then
  ticks = ticks + year_tick_total
 end
 print("initializing shamrock countdown")
 print("shamrock tick:", date_shamrock, "current tick:", current_tick, "ticks to shamrock:", ticks)
 dfhack.timeout(ticks+1,'ticks',function () holiday_shamrock(ticks) end)
end

function holiday_shamrock(ticks)
 pos = getPositionSurface()
 print("leprechaun positioning:", pos)
 dfhack.run_script("modtools/create-unit","-race","holiday_LEPRECHAUN","-caste","MALE","-name","PLAINS","-location",pos,"-age",1)
 dfhack.gui.showAnnouncement("The Shamrock Holiday has come! A day of mischief and merriment, this festival celebrates the middle of Spring, when day and night are equal. Keep a watchful eye and guard your valuables. This is the day of the leprechaun!", COLOR_WHITE)
 holiday_shamrock_countdown()
end

function getPositionSurface()
 print("calibrating leprechaun position")
 local rand = dfhack.random.new()
 local mapx, mapy, mapz = dfhack.maps.getTileSize()
 randx = rand:random(mapx)
 randy = rand:random(mapy)
 local pos = {}
 pos.x = randx
 pos.y = randy
 pos.z = mapz - 1
 local j = 0
 while dfhack.maps.ensureTileBlock(pos.x,pos.y,pos.z-j).designation[pos.x%16][pos.y%16].outside do
  j = j + 1
 end
 pos.z = pos.z - j + 1
 return pos
end

holiday_shamrock_countdown()

EDIT:
It shouldn't matter, but it looks like I can simplify this old code since nothing is being passed anymore:
dfhack.timeout(ticks+1,'ticks',function () holiday_shamrock(ticks) end)
end
function holiday_shamrock(ticks)
« Last Edit: September 26, 2019, 05:34:24 pm by brolol.404 »
Logged

Fleeting Frames

  • Bay Watcher
  • Spooky cart at distance
    • View Profile
Re: Holidays
« Reply #53 on: September 27, 2019, 03:29:44 am »

Quote
1. The script doesn't load on it's own. It has to be run manually. I tried moving the script call into OnLoad.init instead of OnMapLoad.init, but it still doesn't load on it's own.

The path is \raw\OnMapLoad.init

Haven't used save-specific scripts myself, but here's the quote lua API:
Quote
If a save directory contains a file called raw/init.lua, it is automatically loaded and executed every time the save is loaded. The same applies to any files called raw/init.d/*.lua.
Note how both init.lua and any files in folder init.d end in lua.

onMapLoad.init, meanwhile, goes into the top-level df folder, same place where all the df's subfolders are kept.

Quote
2. The leprechaun doesn't spawn. Here is the error:

[DFHack]# holiday_shamrock
initializing shamrock holiday
initializing shamrock countdown
shamrock tick:  19200   current tick:   16999   ticks to shamrock:      2201
calibrating leprechaun position
leprechaun positioning: table: 000001EC6289E4A0
C:\Users\bro\Desktop\df_44_12_win\hack\lua\utils.lua:603: bad argument #1 to 'sub' (string expected, got table)
stack traceback:
        [C]: in function 'string.sub'
        C:\Users\bro\Desktop\df_44_12_win\hack\lua\utils.lua:603: in function 'utils.processArgs'
        ...sktop\df_44_12_win/hack/scripts/modtools/create-unit.lua:488: in local 'script_code'
        C:\Users\bro\Desktop\df_44_12_win\hack\lua\dfhack.lua:680: in function 'dfhack.run_script_with_env'
        (...tail calls...)
        ...a\Desktop\df_44_12_win/hack/scripts/holiday_shamrock.lua:19: in global 'holiday_shamrock'
        ...a\Desktop\df_44_12_win/hack/scripts/holiday_shamrock.lua:13: in function <...a\Desktop\df_44_12_win/hack/scripts/holiday_shamrock.lua:13>

It looks like it doesn't like pos for the location in create-unit? Here is the script:
Yeah, pos is the problem; easy to isolate by trying it with a cat and cursor instead. It expects a string (or even a number), not table. Here's an example that can be pasted into console that spawns a cat at a location I grabbed off :lua ~df.global.cursor:
Code: [Select]
:lua dfhack.run_script("modtools/create-unit","-race","CAT","-caste","MALE","-name","PLAINS","-location","[",90, 98, 165,"]","-age",1)Note how every part of location is separated by comma.

Also note how it sets your cursor to that position, which might be undesirable in gameplay if you don't want player to notice it. (In that case, you'd set the cursor back to its old position right afterwards, but here you do want notice).

Also, your edit seems correct.
« Last Edit: September 27, 2019, 03:32:04 am by Fleeting Frames »
Logged

Roses

  • Bay Watcher
    • View Profile
Re: Holidays
« Reply #54 on: September 27, 2019, 09:42:52 am »

Ah yes, sorry, I forgot that you have to change the pos variable into a string to correctly pass it through run_script, doing something like
Code: [Select]
pos = getPositionSurface()
pos = '[ ' ..tostring(pos.x)..' '..tostring(pos.y)..' '..tostring(pos.z).. ' ]'
should work . Note the .. is how you add strings together in lua, and the brackets (with the space) is needed by dfhack for understanding you are passing it a table.
Logged

brolol.404

  • Bay Watcher
    • View Profile
Re: Holidays
« Reply #55 on: September 27, 2019, 10:24:37 am »

Quote
1. The script doesn't load on it's own. It has to be run manually. I tried moving the script call into OnLoad.init instead of OnMapLoad.init, but it still doesn't load on it's own.

The path is \raw\OnMapLoad.init

Haven't used save-specific scripts myself, but here's the quote lua API:
Quote
If a save directory contains a file called raw/init.lua, it is automatically loaded and executed every time the save is loaded. The same applies to any files called raw/init.d/*.lua.
Note how both init.lua and any files in folder init.d end in lua.

onMapLoad.init, meanwhile, goes into the top-level df folder, same place where all the df's subfolders are kept.

Quote
2. The leprechaun doesn't spawn. Here is the error:

[DFHack]# holiday_shamrock
initializing shamrock holiday
initializing shamrock countdown
shamrock tick:  19200   current tick:   16999   ticks to shamrock:      2201
calibrating leprechaun position
leprechaun positioning: table: 000001EC6289E4A0
C:\Users\bro\Desktop\df_44_12_win\hack\lua\utils.lua:603: bad argument #1 to 'sub' (string expected, got table)
stack traceback:
        [C]: in function 'string.sub'
        C:\Users\bro\Desktop\df_44_12_win\hack\lua\utils.lua:603: in function 'utils.processArgs'
        ...sktop\df_44_12_win/hack/scripts/modtools/create-unit.lua:488: in local 'script_code'
        C:\Users\bro\Desktop\df_44_12_win\hack\lua\dfhack.lua:680: in function 'dfhack.run_script_with_env'
        (...tail calls...)
        ...a\Desktop\df_44_12_win/hack/scripts/holiday_shamrock.lua:19: in global 'holiday_shamrock'
        ...a\Desktop\df_44_12_win/hack/scripts/holiday_shamrock.lua:13: in function <...a\Desktop\df_44_12_win/hack/scripts/holiday_shamrock.lua:13>

It looks like it doesn't like pos for the location in create-unit? Here is the script:
Yeah, pos is the problem; easy to isolate by trying it with a cat and cursor instead. It expects a string (or even a number), not table. Here's an example that can be pasted into console that spawns a cat at a location I grabbed off :lua ~df.global.cursor:
Code: [Select]
:lua dfhack.run_script("modtools/create-unit","-race","CAT","-caste","MALE","-name","PLAINS","-location","[",90, 98, 165,"]","-age",1)Note how every part of location is separated by comma.

Also note how it sets your cursor to that position, which might be undesirable in gameplay if you don't want player to notice it. (In that case, you'd set the cursor back to its old position right afterwards, but here you do want notice).

Also, your edit seems correct.

awesome thanks. I will try and move around the OnMapLoad.init and/or add a init.lua and see if that works.

Ah yes, sorry, I forgot that you have to change the pos variable into a string to correctly pass it through run_script, doing something like
Code: [Select]
pos = getPositionSurface()
pos = '[ ' ..tostring(pos.x)..' '..tostring(pos.y)..' '..tostring(pos.z).. ' ]'
should work . Note the .. is how you add strings together in lua, and the brackets (with the space) is needed by dfhack for understanding you are passing it a table.

thanks. I will try this out.

Could a potential problem be that dfhack.random.new() returns a float instead of an integer? I assume that the map tiles are integers. Would changing it to this fix that or does it not matter?

Code: [Select]
randx = math.random(mapx)
randy = math.random(mapy)

Roses

  • Bay Watcher
    • View Profile
Re: Holidays
« Reply #56 on: September 27, 2019, 10:53:27 am »

math.random() produces a float between 0 and 1
math.random(upper) produces an integer between 1 and upper
math.random(lower,upper) produces an integer between lower and upper

So you are correctly getting integers. The issue is just that it wants a string not a table. And there are no automatic conversion functions for changing a table into a string.
Logged

brolol.404

  • Bay Watcher
    • View Profile
Re: Holidays
« Reply #57 on: September 27, 2019, 12:20:27 pm »

math.random() produces a float between 0 and 1
math.random(upper) produces an integer between 1 and upper
math.random(lower,upper) produces an integer between lower and upper

So you are correctly getting integers. The issue is just that it wants a string not a table. And there are no automatic conversion functions for changing a table into a string.

Alright cool thanks!

How does this look? I'm not quite sure if I can just run the add-thought.lua (like below) or if I have to somehow call the addEmotionToUnit function within it?

Code: [Select]
function holiday_thoughts_shamrock()
local units = {}
local n = 0
for i,unit in pairs(df.global.world.units.active) do
  if dfhack.units.isDwarf(unit) then
    n = n + 1
    units.n = unit
  end
end
while n > 0 do
 local holiday_thought_type = math.random(4)
 if (holiday_thought_type == 1)
  dfhack.run_script("add-thought", "-unit",units.n,"-thought","ENJOYMENT","-severity",1)
 end
 if (holiday_thought_type == 2)
  dfhack.run_script("add-thought", "-unit",units.n,"-thought","AMUSEMENT","-severity",1)
 end
 if (holiday_thought_type == 3)
  dfhack.run_script("add-thought", "-unit",units.n,"-thought","DELIGHT","-severity",1)
 end
 if (holiday_thought_type == 4)
  -- no thought
 end
 units.n = nil
 n = n - 1
end
end

Roses

  • Bay Watcher
    • View Profile
Re: Holidays
« Reply #58 on: September 27, 2019, 01:09:02 pm »

1. math.random is inclusive, meaning math.random(4) will give you 1, 2, 3, or 4

2. Your unit.n stuff is wrong. If you want to use numbers as table keys you have to define them using units[n] = unit and then call them using units[n]. As it is written units.n = unit is that same as units["n"] = unit. Also units.1 = unit won't work as lua only takes a string value after the .

3. You should be able to run the add-thought script like that
Logged

brolol.404

  • Bay Watcher
    • View Profile
Re: Holidays
« Reply #59 on: September 27, 2019, 01:38:54 pm »

1. math.random is inclusive, meaning math.random(4) will give you 1, 2, 3, or 4

2. Your unit.n stuff is wrong. If you want to use numbers as table keys you have to define them using units[n] = unit and then call them using units[n]. As it is written units.n = unit is that same as units["n"] = unit. Also units.1 = unit won't work as lua only takes a string value after the .

3. You should be able to run the add-thought script like that

Ah ok thanks. I updated the unit table and will try it out. I only want 1, 2, 3 or 4 as my intention is to get in one of those four if statements. I wasn't sure of there was an if else in lua.

Code: [Select]
function holiday_thoughts_shamrock()
local units = {}
local n = 0
for i,unit in pairs(df.global.world.units.active) do
  if dfhack.units.isDwarf(unit) then
    n = n + 1
    units[n] = unit
  end
end
while n > 0 do
 local holiday_thought_type = math.random(4)
 if (holiday_thought_type == 1)
  dfhack.run_script("add-thought", "-unit",units.n,"-thought","ENJOYMENT","-severity",1)
 end
 if (holiday_thought_type == 2)
  dfhack.run_script("add-thought", "-unit",units.n,"-thought","AMUSEMENT","-severity",1)
 end
 if (holiday_thought_type == 3)
  dfhack.run_script("add-thought", "-unit",units.n,"-thought","DELIGHT","-severity",1)
 end
 if (holiday_thought_type == 4)
  -- no thought
 end
 units[n] = nil
 n = n - 1
end
end
Pages: 1 2 3 [4] 5 6 ... 8