Latest Posts

Topic: How to add a custom starting condition?

GunChleoc
Avatar
Joined: 2013-10-07, 15:56
Posts: 3324
Ranking
One Elder of Players
Location: RenderedRect
Posted at: 2016-02-04, 15:30

Looks like I need to run the script myself so I can debug. Do you still have your original script? It might be easier for me to debug from there.


Busy indexing nil values

Top Quote
GunChleoc
Avatar
Joined: 2013-10-07, 15:56
Posts: 3324
Ranking
One Elder of Players
Location: RenderedRect
Posted at: 2016-02-04, 15:33

PkK wrote:

GunChleoc wrote:

The problem here is that the headquarters have different names now, depending on the tribe. So, you need to get the wl.map.TribeDescription for the player, then call get tribe.headquarters to get the building name.

https://wl.widelands.org/docs/wl/autogen_wl_map/#module-interfaces

Something like this should work:

~~~~ local hq_name = wl.Game().players[player.number].tribe.headquarters local hq = wl.Game().players[player.number].get_buildings(hq_name) ~~~~

Would this work with the if test even when the player has been defeated? Would it crash or return 0, NULL or whatever it is in Lua for hq?

Philipp

Good point, one should check if the player is there before doing anything. Same goes for the building I guess.


Busy indexing nil values

Top Quote
PkK

Topic Opener
Joined: 2012-01-06, 12:19
Posts: 236
Ranking
Widelands-Forum-Junkie
Posted at: 2016-02-04, 15:38

GunChleoc wrote:

Looks like I need to run the script myself so I can debug. Do you still have your original script? It might be easier for me to debug from there.

The original (i.e. build 18) version can be found at: http://pholia.tdi.informatik.uni-frankfurt.de/~philipp/widelands/barbarians/

My current version is


include "scripting/infrastructure.lua"

set_textdomain("tribes")

init = {
   descname = _ "Headquarters cheat",
   func = function(player, shared_in_start)

   local sf = wl.Game().map.player_slots[player.number].starting_field
   if shared_in_start then
      sf = shared_in_start
   else
      player:allow_workers("all")
   end

   hq = prefilled_buildings(player, { "barbarians_headquarters", sf.x, sf.y,
      wares = {
         ax = 5,
         bread_paddle = 2,
         blackwood = 32,
         cloth = 5,
         coal = 12,
         felling_ax = 4,
         fire_tongs = 2,
         fish = 6,
         fishing_rod = 2,
         gold = 4,
         grout = 12,
         hammer = 12,
         hunting_spear = 2,
         iron = 12,
         iron_ore = 5,
         kitchen_tools = 4,
         meal = 4,
         meat = 6,
         pick = 8,
         barbarians_bread = 8,
         ration = 12,
         granite = 40,
         scythe = 6,
         shovel = 4,
         snack = 3,
         thatch_reed = 24,
         log = 80,
      },
      workers = {
         barbarians_blacksmith = 2,
         barbarians_brewer = 1,
         barbarians_builder = 10,
         barbarians_charcoal_burner = 1,
         barbarians_carrier = 40,
         barbarians_gardener = 1,
         barbarians_geologist = 4,
         barbarians_lime_burner = 1,
         barbarians_lumberjack = 3,
         barbarians_miner = 4,
         barbarians_ranger = 1,
         barbarians_stonemason = 2,
         barbarians_ox = 5,
      },
      soldiers = {
         [{0,0,0,0}] = 45,
      }
   })

      place_building_in_region(player, "barbarians_battlearena", sf:region(12), {
         wares = {
            barbarians_bread = 8,
            fish = 6,
            meat = 6,
         }
      })

   for i=1,100000 do
     --sleep(600000)
     sleep(1000)
     --local hq = wl.Game().players[player.number].get_buildings("headquarters")
     local hq = wl.Game().map:get_field(sf.x, sf.y).immovable
     --local hq_name = wl.Game().players[player.number].tribe.headquarters
     --local hq = wl.Game().players[player.number].get_buildings(hq_name)

     if hq and hq.type == "warehouse" then
       if hq:get_wares("water") < 1280 then
         hq:set_wares("water", hq:get_wares("water") + 128)
       end
       if hq:get_wares("log") < 1280 then
         hq:set_wares("log", hq:get_wares("log") + 128)
       end
       if hq:get_wares("granite") < 640 then
         hq:set_wares("granite", hq:get_wares("granite") + 64)
       end
       if hq:get_wares("coal") < 240 then
         hq:set_wares("coal", hq:get_wares("coal") + 24)
       end
       if hq:get_wares("ironore") < 80 then
         hq:set_wares("ironore", hq:get_wares("ironore") + 8)
       end
       if hq:get_wares("fish") < 100 then
         hq:set_wares("fish", hq:get_wares("fish") + 4)
       end
       if hq:get_wares("gold") < 100 then
         hq:set_wares("gold", hq:get_wares("gold") + 4)
       end
     end
   end
end
}

return init

I have similar ones for the other tribes.

Philipp

P.S.: I tend to use them on 8-player maps for (4 - #humans) of the AI players, so I get a total of 4 strong players. AIs with custom start script and each human player defeats one AI player before meeting another strong player.


Top Quote
PkK

Topic Opener
Joined: 2012-01-06, 12:19
Posts: 236
Ranking
Widelands-Forum-Junkie
Posted at: 2016-02-04, 15:40

GunChleoc wrote:

PkK wrote:

GunChleoc wrote:

The problem here is that the headquarters have different names now, depending on the tribe. So, you need to get the wl.map.TribeDescription for the player, then call get tribe.headquarters to get the building name.

https://wl.widelands.org/docs/wl/autogen_wl_map/#module-interfaces

Something like this should work:

~~~~ local hq_name = wl.Game().players[player.number].tribe.headquarters local hq = wl.Game().players[player.number].get_buildings(hq_name) ~~~~

Would this work with the if test even when the player has been defeated? Would it crash or return 0, NULL or whatever it is in Lua for hq?

Philipp

Good point, one should check if the player is there before doing anything. Same goes for the building I guess.

The line

if hq and hq.type == "warehouse" then

was sufficient in the original script to keep the game from crashing after a player was defeated.

Philipp


Top Quote
GunChleoc
Avatar
Joined: 2013-10-07, 15:56
Posts: 3324
Ranking
One Elder of Players
Location: RenderedRect
Posted at: 2016-02-04, 16:27

OK, here's my solution:

include "scripting/infrastructure.lua"
include "scripting/coroutine.lua"

set_textdomain("tribes")

function autofill_headquarters(player)
   for i=1,100000 do
      sleep(600)
      local hq = wl.Game().players[player.number]:get_buildings("barbarians_headquarters")[1]
      print(hq.descr.name);

      if hq and hq.type == "warehouse" then
        print("Headquarters" .. hq.name)
        if hq:get_wares("water") < 1280 then
           print("water!")
           hq:set_wares("water", hq:get_wares("water") + 128)
        end
        if hq:get_wares("log") < 1280 then
           hq:set_wares("log", hq:get_wares("log") + 128)
        end
        if hq:get_wares("granite") < 640 then
           hq:set_wares("granite", hq:get_wares("granite") + 64)
        end
        if hq:get_wares("coal") < 240 then
           hq:set_wares("coal", hq:get_wares("coal") + 24)
        end
        if hq:get_wares("iron_ore") < 80 then
           hq:set_wares("iron_ore", hq:get_wares("iron_ore") + 8)
        end
        if hq:get_wares("fish") < 100 then
           hq:set_wares("fish", hq:get_wares("fish") + 4)
        end
        if hq:get_wares("gold") < 100 then
           hq:set_wares("gold", hq:get_wares("gold") + 4)
        end
     end
   end
end

init = {
   descname = _ "Headquarters cheat",
   func = function(player, shared_in_start)

   local sf = wl.Game().map.player_slots[player.number].starting_field
   if shared_in_start then
      sf = shared_in_start
   else
      player:allow_workers("all")
   end

   hq = prefilled_buildings(player, { "barbarians_headquarters", sf.x, sf.y,
      wares = {
         ax = 5,
         bread_paddle = 2,
         blackwood = 32,
         cloth = 5,
         coal = 12,
         felling_ax = 4,
         fire_tongs = 2,
         fish = 6,
         fishing_rod = 2,
         gold = 4,
         grout = 12,
         hammer = 12,
         hunting_spear = 2,
         iron = 12,
         iron_ore = 5,
         kitchen_tools = 4,
         meal = 4,
         meat = 6,
         pick = 8,
         barbarians_bread = 8,
         ration = 12,
         granite = 40,
         scythe = 6,
         shovel = 4,
         snack = 3,
         thatch_reed = 24,
         log = 80,
      },
      workers = {
         barbarians_blacksmith = 2,
         barbarians_brewer = 1,
         barbarians_builder = 10,
         barbarians_charcoal_burner = 1,
         barbarians_carrier = 40,
         barbarians_gardener = 1,
         barbarians_geologist = 4,
         barbarians_lime_burner = 1,
         barbarians_lumberjack = 3,
         barbarians_miner = 4,
         barbarians_ranger = 1,
         barbarians_stonemason = 2,
         barbarians_ox = 5,
      },
      soldiers = {
         [{0,0,0,0}] = 45,
      }
   })

      place_building_in_region(player, "barbarians_battlearena", sf:region(12), {
         wares = {
            barbarians_bread = 8,
            fish = 6,
            meat = 6,
         }
      })

   run(autofill_headquarters(player))
end
}

return init

This will print

barbarians_headquarters
barbarians_headquarters
barbarians_headquarters
barbarians_headquarters
barbarians_headquarters

This will access the building at least - you will still need to adjust the sleeptime, and I am not sure if the extra function is needed. You might need to compare hq.descr.type instead of hq.type - since we're getting an explicit building here, you could also cpmpare hq.descr.name == "barbarians_headquarters" instead.


Busy indexing nil values

Top Quote
PkK

Topic Opener
Joined: 2012-01-06, 12:19
Posts: 236
Ranking
Widelands-Forum-Junkie
Posted at: 2016-02-04, 17:03

Thanks a lot. Based on your version, I wrote this, which now mostly works:

include "scripting/infrastructure.lua"
include "scripting/coroutine.lua"

set_textdomain("tribes")

init = {
   descname = _ "Headquarters cheat",
   func = function(player, shared_in_start)

   local sf = wl.Game().map.player_slots[player.number].starting_field
   if shared_in_start then
      sf = shared_in_start
   else
      player:allow_workers("all")
   end

   hq = prefilled_buildings(player, { "barbarians_headquarters", sf.x, sf.y,
      wares = {
         ax = 5,
         bread_paddle = 2,
         blackwood = 32,
         cloth = 5,
         coal = 12,
         felling_ax = 4,
         fire_tongs = 2,
         fish = 6,
         fishing_rod = 2,
         gold = 4,
         grout = 12,
         hammer = 12,
         hunting_spear = 2,
         iron = 12,
         iron_ore = 5,
         kitchen_tools = 4,
         meal = 4,
         meat = 6,
         pick = 8,
         barbarians_bread = 8,
         ration = 12,
         granite = 40,
         scythe = 6,
         shovel = 4,
         snack = 3,
         thatch_reed = 24,
         log = 80,
      },
      workers = {
         barbarians_blacksmith = 2,
         barbarians_brewer = 1,
         barbarians_builder = 10,
         barbarians_charcoal_burner = 1,
         barbarians_carrier = 40,
         barbarians_gardener = 1,
         barbarians_geologist = 4,
         barbarians_lime_burner = 1,
         barbarians_lumberjack = 3,
         barbarians_miner = 4,
         barbarians_ranger = 1,
         barbarians_stonemason = 2,
         barbarians_ox = 5,
      },
      soldiers = {
         [{0,0,0,0}] = 45,
      }
   })

      place_building_in_region(player, "barbarians_battlearena", sf:region(12), {
         wares = {
            barbarians_bread = 8,
            fish = 6,
            meat = 6,
         }
      })

   for i=1,100000 do
     --sleep(600000)
     sleep(5000)

     local hq = wl.Game().players[player.number]:get_buildings("barbarians_headquarters")[1]

     if hq and hq.descr.name == "barbarians_headquarters" then
       if hq:get_wares("water") < 512 then
         hq:set_wares("water", hq:get_wares("water") + 128)
       end
       if hq:get_wares("log") < 512 then
         hq:set_wares("log", hq:get_wares("log") + 128)
       end
       if hq:get_wares("granite") < 512 then
         hq:set_wares("granite", hq:get_wares("granite") + 64)
       end
       if hq:get_wares("coal") < 256 then
         hq:set_wares("coal", hq:get_wares("coal") + 24)
       end
       if hq:get_wares("iron_ore") < 96 then
         hq:set_wares("iron_ore", hq:get_wares("iron_ore") + 8)
       end
       if hq:get_wares("fish") < 64 then
         hq:set_wares("fish", hq:get_wares("fish") + 4)
       end
       if hq:get_wares("gold") < 64 then
         hq:set_wares("gold", hq:get_wares("gold") + 4)
       end
     end
   end
end
}

return init

For most wares, it works. But for others it doesn't: E.g. now the amount of water keeps changing between 128 and 0 (I used a LAN game with me as observer to test). Do ware amounts now overflow at 256? AFAIR one could have a lot more in the past.

Philipp


Top Quote
GunChleoc
Avatar
Joined: 2013-10-07, 15:56
Posts: 3324
Ranking
One Elder of Players
Location: RenderedRect
Posted at: 2016-02-04, 17:44

PkK wrote:

For most wares, it works. But for others it doesn't: E.g. now the amount of water keeps changing between 128 and 0 (I used a LAN game with me as observer to test). Do ware amounts now overflow at 256? AFAIR one could have a lot more in the past.

I just checked - looks like they do, which is not good. I will change the datatype from 8 to 32 bit.

ETA: Merge request is up: https://code.launchpad.net/~widelands-dev/widelands/fix_ware_amount/+merge/285099

Thanks for flagging this up face-smile.png

ETA: Merged at revision 7788.

Edited: 2016-02-05, 15:20

Busy indexing nil values

Top Quote