Tabletop Simulator

Tabletop Simulator

Spirit Island - [By MJ & iakona]
Deso 16 Jul, 2020 @ 1:18pm
Adding Deso's Custom Adversaries
First amazing work on the update. I even managed to make it work for My Portugal and Spain adversaries. But I know next to nothing in LUA, so some issues might be due my lack of knowledge:

There are two things caught my attention in the process:
1 - Spain replaces a town with a city without having to remove it first
2 - Portugual cannot track inland lands adequately on NorthEast thematic map (#4 is a coastal land)
< >
Showing 1-15 of 16 comments
Deso 16 Jul, 2020 @ 1:19pm 
--Portugal script
difficulty={[0] = 1, 2, 3, 5, 7, 9, 10}
fearCards={[0] = {0,0,0}, {0,0,0}, {0,1,0}, {0,1,1}, {1,1,1}, {1,2,1}, {1,2,2}}
broadcast={
[0] = nil,
nil,
nil,
nil,
"Remember Portugal can only build Cities in inland lands at Level 6",
"Remember Portugal can only build Cities in inland lands at Level 6",
"Remember Portugal can only build Cities in inland lands at Level 6",
}
reminderSetup = true
mapSetup = true


-- Add reminder tokens for Build (1) Ravage (3) Explore (5)
function GetReminderSetup(params)
local reminderTiles = {}
if params.level >= 1 then
reminderTiles.build = true
end
if params.level >= 3 then
reminderTiles.ravage = true
end
if params.level >= 5 then
reminderTiles.explore = true
end
return reminderTiles
end


-- Does it need some coordinate to put the reminder tokens? I'll use existing ones and call it a day
function ReminderSetup(params)
local aidBoard = Global.getVar("aidBoard")
if params.level >= 1 then
if not params.other.build then
getObjectFromGUID("be2c91").setPositionSmooth(aidBoard.positionToWorld({-0.72,0.1,2.26}))
end
end
if params.level >= 3 then
if not params.other.ravage then
getObjectFromGUID("16ab25").setPositionSmooth(aidBoard.positionToWorld({-0.2,0.1,2.26}))
end
end
if params.level >= 5 then
if not params.other.explore then
getObjectFromGUID("f4a568").setPositionSmooth(aidBoard.positionToWorld({-1.24,0.1,2.26}))
end
end
end


function MapSetup(params)
if params.level >= 2 then
-- add 1 Explorer and Blight to land #1
table.insert(params.pieces[1],"Explorer")
table.insert(params.pieces[1],"BlightInfinite")
end
if params.level >= 4 then
-- add a town to the a lowest numbered inland lands (4+) without invaders or blight
local lowestNumberedInlandLandWithoutInvaderBlight = 4
-- first town look between 4 and the last(#) params.pieces
for i=lowestNumberedInlandLandWithoutInvaderBlight, #params.pieces, 1 do
--for each land check
local landLackExplorer = true
local landLackTown = true
local landLackCity = true
local landLackBlight = true

for _,v in pairs (params.pieces) do
if v == "Explorer" then
landLackExplorer = false
break
end
end

for _,v in pairs (params.pieces) do
if v == "Town" then
landLackTown = false
break
end
end

for _,v in pairs (params.pieces) do
if v == "City" then
landLackCity = false
break
end
end

for _,v in pairs (params.pieces) do
if v == "BlightInfinite" then
landLackBlight = false
break
end
end

evaluate_condition = (landLackExplorer and landLackTown and landLackCity and landLackBlight)

if evaluate_condition then
--if it lacks invaders and blight add town
lowestNumberedInlandLandWithoutInvaderBlight = i
table.insert(params.pieces[lowestNumberedInlandLandWithoutInvaderBlight],"Town")
break
end
end
--Add the second_town
lowestNumberedInlandLandWithoutInvaderBlight = lowestNumberedInlandLandWithoutInvaderBlight + 1;

for i=lowestNumberedInlandLandWithoutInvaderBlight, #params.pieces, 1 do
--for each land check
local landLackExplorer = true
local landLackTown = true
local landLackCity = true
local landLackBlight = true

for _,v in pairs (params.pieces) do
if v == "Explorer" then
landLackExplorer = false
break
end
end

for _,v in pairs (params.pieces) do
if v == "Town" then
landLackTown = false
break
end
end

for _,v in pairs (params.pieces) do
if v == "City" then
landLackCity = false
break
end
end

for _,v in pairs (params.pieces) do
if v == "BlightInfinite" then
landLackBlight = false
break
end
end

evaluate_condition = (landLackExplorer and landLackTown and landLackCity and landLackBlight)

if evaluate_condition then
--if it lacks invaders and blight add town
lowestNumberedInlandLandWithoutInvaderBlight = i
table.insert(params.pieces[lowestNumberedInlandLandWithoutInvaderBlight],"Town")
break
end
end
--end of second town ]]


end


return params.pieces
end
Deso 16 Jul, 2020 @ 1:20pm 
--spain script

difficulty={[0] = 0, 3, 4, 6, 7, 8, 10}
fearCards={[0] = {0,0,0}, {0,0,0}, {0,1,0}, {1,0,0}, {1,0,1}, {1,1,1}, {1,2,1}}
reminderSetup = true
mapSetup = true


-- Add reminder tokens for Build (1) Ravage (3) Explore (5)
function GetReminderSetup(params)
local reminderTiles = {}
if params.level >= 1 then
reminderTiles.build = true
end
if params.level >= 5 then
reminderTiles.ravage = true
end
return reminderTiles
end


-- Does it need some coordinate to put the reminder tokens? I'll use existing ones and call it a day
function ReminderSetup(params)
local aidBoard = Global.getVar("aidBoard")
if params.level >= 1 then
if not params.other.build then
getObjectFromGUID("be2c91").setPositionSmooth(aidBoard.positionToWorld({-0.72,0.1,2.26}))
end
end
if params.level >= 5 then
if not params.other.ravage then
getObjectFromGUID("16ab25").setPositionSmooth(aidBoard.positionToWorld({-0.2,0.1,2.26}))
end
end
end
--]]

function MapSetup(params)
if params.level >= 2 then
-- replace highest town with city
local highestNumberedLandWithTown = 0
for i=#params.pieces,1,-1 do
local landHasTown = false
for _,v in pairs (params.pieces) do
if v == "Town" then
landHasTown = true
break
end
end
if landHasTown then
highestNumberedLandWithTown = i
--replace the town with a city oddly works like this, without removing the town
table.insert(params.pieces[highestNumberedLandWithTown],"City")
-- then stop looping if it finds highest town index
break
end
end
end
if params.level >= 4 then
-- add city to land #2
table.insert(params.pieces[2],"City")
end
return params.pieces
end
iakona  [developer] 16 Jul, 2020 @ 7:34pm 
Hi Deso thanks for taking an interest in setting up custom adversaries. So taking a look at reminder code you have setup it appears to be using the same guids as base game reminder tiles. So assuming you didn't create your own customs ones for the adversary you can leave off the GetReminderSetup and ReminderSetup functions

For spain all you really need to do is change the value in the table so something like this should do:

function MapSetup(params)
if params.level >= 2 then
-- replace highest town with city
for i=#params.pieces,1,-1 do
local landHasTown = false
for j,v in pairs (params.pieces) do
if v == "Town" then
params.pieces[j] = "City"
landHasTown = true
break
end
end
if landHasTown then
break
end
end
end
if params.level >= 4 then
-- add city to land #2
table.insert(params.pieces[2],"City")
end
return params.pieces
end

As for Portugal looking at your broadcast definition it appears to only be relevant for level 6, so you can make level 4 and 5 nil. The feature was primarily intended for non scripted setup like Sweden's Royal Backing, but you're free to use it whatever way you want. Portugal's Map setup could be done like this

function MapSetup(params)
if params.level >= 2 then
-- add 1 Explorer and Blight to land #1
table.insert(params.pieces[1],"Explorer")
table.insert(params.pieces[1],"BlightInfinite")
end
if params.level >= 4 then
-- add a town to the a lowest numbered inland lands (4+) without invaders or blight
local lowestInland = 4
local count = 0
for i=lowestInland, #params.pieces, 1 do
local noInvadersOrBlight = true
for _,v in pairs (params.pieces) do
if v == "Explorer" or v == "Town" or v == "City" or v == "BlightInfinite" then
noInvadersOrBlight = false
break
end
end

if noInvadersOrBlight then
--if it lacks invaders and blight add town
table.insert(params.pieces,"Town")
count = count + 1
end
if count == 2 then
break
end
end
end
return params.pieces
end

One thing I noticed about your code samples above is that when you were trying to iterate through all the pieces for each land, you were missing the

As for NE thematic having a 4th coastal land thanks for bringing this to my attention, I'll update the API to start adding the map guid into the params object, I think that would be the most straight forward fix for this
Deso 16 Jul, 2020 @ 8:09pm 
Thanks for the help. That code do look way better and will probably avoid bugs i haven't foreseen..

I used the existing reminder just to signal my abilities, regardless of nationality on it.

So the broadcast is different per level - that's good to know.

Spain is currently working. Oddly enough.
iakona  [developer] 16 Jul, 2020 @ 9:54pm 
Yea broadcast, like fear and difficulty have 7 values defined (for levels 0-6 of adversary). Not sure how often you play to play with double adversaries, but you may run into issues with reminder tiles and your custom adversaries with how that code is currently setup.

Both the code snippets I posted above were working for me (besides the Portugal Thematic issue), are you having issues besides that for Portugal?
Deso 17 Jul, 2020 @ 8:53am 
No issues.
So double adversaries can break the reminder pieces. I guess I'll remove it then.
iakona  [developer] 17 Jul, 2020 @ 2:31pm 
Well you could change your Lua code around, just wanted to point out that with the current version if another adversary uses a build tile then spain 1+ won't move one over there since you have an if not
iakona  [developer] 18 Jul, 2020 @ 4:33pm 
so a new version just got pushed out on the workshop today, included in the changes is the the MapSetup function will now have a guid entry to in the params table that you can use to determine which board you are setting up on. So you'll want to compare that value against the guids for the 2 NE boards (there's a standard and a reskinned version of it) to determine if you should start the loop at index 4 or 5
Deso 19 Jul, 2020 @ 10:54am 
I'll give it a try tomorow then.
Busy day - i'll try soon enough.
EDIT This week has been a bit full. I'll give a heads up later.
Last edited by Deso; 24 Jul, 2020 @ 10:55am
iakona  [developer] 27 Jul, 2020 @ 4:15pm 
So in the update that went out earlier today the reminder interface got changed a little to be more streamlined, and I also added a new interface for setting up UI related elements. In order to test out these concepts I went ahead and scripted your adversary as test cases

--spain script
difficulty={[0] = 1, 3, 4, 6, 7, 8, 10}
fearCards={[0] = {0,0,0}, {0,0,0}, {0,1,0}, {1,0,0}, {1,0,1}, {1,1,1}, {1,2,1}}
reminderSetup = true
mapSetup = true
hasUI = true

function ReminderSetup(params)
local reminderTiles = {}
if params.level >= 1 then
reminderTiles.build = "a178fa"
end
if params.level >= 5 then
reminderTiles.ravage = "135124"
end
return reminderTiles
end

function AdversaryUI(params)
local ui = {}
ui.escalation = {}
ui.escalation.tooltip = "Add 1 Explorer to each land of the shown terrain."
if params.level >= 1 then
ui.one = {}
ui.one.name = "Quicksilver Mining"
ui.one.tooltip = "When Building in lands without Dahan or\nBlight, add a Blight instead of a Town/City."
end
if params.level >= 3 then
ui.three = {}
ui.three.name = "Retreat and Rebuild"
ui.three.tooltip = "Whenever a City is destroyed,\nadd a Town to an adjacent land."
end
if params.level >= 5 then
ui.five = {}
ui.five.name = "Disciplined Warfare"
ui.five.tooltip = "Each turn, Dahan do not fight back\nafter a Ravage unless a Fear card\nhas been resolved that turn."
end
if params.level >= 6 then
ui.six = {}
ui.six.name = "Encomienda System"
ui.six.tooltip = "When Ravaging, Invaders deal +1 damage.\n(Total, if thare are any Invaders.)"
end
return ui
end

function MapSetup(params)
if params.level >= 2 then
-- replace highest town with city
for i=#params.pieces,1,-1 do
local landHasTown = false
for j,v in pairs (params.pieces) do
if v == "Town" then
params.pieces[j] = "City"
landHasTown = true
break
end
end
if landHasTown then
break
end
end
end
if params.level >= 4 then
-- add city to land #2
table.insert(params.pieces[2],"City")
end
return params.pieces
end

--Portugal script
difficulty={[0] = 1, 2, 3, 5, 7, 9, 10}
fearCards={[0] = {0,0,0}, {0,0,0}, {0,1,0}, {0,1,1}, {1,1,1}, {1,2,1}, {1,2,2}}
reminderSetup = true
mapSetup = true
hasUI = true

function ReminderSetup(params)
local reminderTiles = {}
if params.level >= 1 then
reminderTiles.build = "a178fa"
end
if params.level >= 3 then
reminderTiles.ravage = "135124"
end
if params.level >= 5 then
reminderTiles.ravage = "a5b6b3"
end
return reminderTiles
end

function AdversaryUI(params)
local ui = {}
ui.escalation = {}
ui.escalation.tooltip = "On each board, pick a land of the\nshown terrain without Blight. Add\n1 Blight there if there are Invaders."
if params.level >= 1 then
ui.one = {}
ui.one.name = "Great Naval Empire"
ui.one.tooltip = "When Invaders would Build a City in an Inland\nland, add a Town instead. When Invaders Build\nin a Coastal land, add both a Town and a City."
end
if params.level >= 3 then
ui.three = {}
ui.three.name = "Concentrated Population"
ui.three.tooltip = "If Blight is added to a Coastal land\nduring Ravage, add an extra Blight.\nThe additional Blight does not destory\nPresence or cause cascades."
end
if params.level >= 5 then
ui.five = {}
ui.five.name = "Massive Slave Trade"
ui.five.tooltip = "After Setup, when Exploring,\nplace 1 Town instead of 1 Explorer\non each of the lowest numbered\nterrain type matching the card.\n(This has no effect for the \"Coastal\nLands\" card during Stage II.)"
end
if params.level >= 6 then
ui.six = {}
ui.six.name = "A Kingdom United"
ui.six.tooltip = "Invaders build Cities normally in Inland lands."
end
return ui
end

function MapSetup(params)
if params.level >= 2 then
-- add 1 Explorer and Blight to land #1
table.insert(params.pieces[1],"Explorer")
table.insert(params.pieces[1],"BlightInfinite")
end
if params.level >= 4 then
-- add a town to the a lowest numbered inland lands (4+) without invaders or blight
local lowestInland = 4
if params.guid == "f4fc81" or params.guid == "14a35f" then
lowestInland = 5
end
local count = 0
for i=lowestInland, #params.pieces, 1 do
local noInvadersOrBlight = true
for _,v in pairs (params.pieces) do
if v == "Explorer" or v == "Town" or v == "City" or v == "BlightInfinite" then
noInvadersOrBlight = false
break
end
end

if noInvadersOrBlight then
--if it lacks invaders and blight add town
table.insert(params.pieces,"Town")
count = count + 1
end
if count == 2 then
break
end
end
end
return params.pieces
end
Deso 28 Jul, 2020 @ 4:24pm 
I did some finishing touches - thanks a lot for the headstart on the new features.
My Spain Adversary had a revision in 2 abilities and difficultity, so I had to implement these changes as well.

* The new UI features are pretty cool. Themouse hover text is a nice touch.
* Both Spain and Portugal took some additional tweaking to work.
* I'm not sure why the portugal script for adding 2 towns didn't work for me. It is working like this.
* On the upperside the identification of the board seemed to work like a charm.
* Spain probably needed an additional index to substitute the right town in the right land, so i end up using table.remove and table.insert functions.
* These are Cool generic reminders. There was a mix up of them, but I sorted it out.


--spain script
difficulty={[0] = 0, 2, 3, 4, 6, 7, 9}
fearCards={[0] = {0,0,0}, {0,0,0}, {0,1,0}, {1,0,0}, {1,0,1}, {1,1,1}, {1,2,1}}
reminderSetup = true
mapSetup = true
hasUI = true

function ReminderSetup(params)
local reminderTiles = {}
if params.level >= 1 then
reminderTiles.build = "a178fa"
end
if params.level >= 6 then
reminderTiles.ravage = "135124"
end
return reminderTiles
end

function AdversaryUI(params)
local ui = {}
ui.escalation = {}
ui.escalation.tooltip = "Add 1 Explorer to each land of the shown terrain."
if (params.level>=1 and params.level<4 ) then
ui.one = {}
ui.one.name = "Quicksilver Mining (I)"
ui.one.tooltip = "When Building in lands without Dahan or\nBlight, add a Blight instead of a Town/City."
end
if params.level >= 3 then
ui.three = {}
ui.three.name = "Retreat and Rebuild"
ui.three.tooltip = "Whenever a City is destroyed, add a Town\n to an adjacent land without a Town."
end
if params.level >= 4 then
ui.five = {}
ui.five.name = "Quicksilver Mining (II)"
ui.five.tooltip = "When Building in lands without Dahan or\nBlight, add a Blight in addition to a Town/City."
end
if params.level >= 6 then
ui.six = {}
ui.six.name = "Encomienda System"
ui.six.tooltip = "When Ravaging, Invaders deal +1 damage.\n(Total, if thare are any Invaders.)"
end
return ui
end

function MapSetup(params)
if params.level >= 2 then
for i=#params.pieces,1,-1 do
local landHasTown = false
for index, v in pairs (params.pieces) do
if v == "Town" then
landHasTown = true
table.remove(params.pieces,index)
table.insert(params.pieces,"City")
break
end
end
if landHasTown then
break
end
end
end
if params.level >= 5 then
-- add city to land #2
table.insert(params.pieces[2],"City")
end
return params.pieces
end


--Portugal script
difficulty={[0] = 1, 2, 3, 5, 7, 9, 10}
fearCards={[0] = {0,0,0}, {0,0,0}, {0,1,0}, {0,1,1}, {1,1,1}, {1,2,1}, {1,2,2}}
broadcast={
[0] = nil,
"Due Great Naval Empire, building only places Towns in inland lands.",
"Due Great Naval Empire, building only places Towns in inland lands.",
"Due Great Naval Empire, building only places Towns in inland lands.",
"Due Great Naval Empire, building only places Towns in inland lands.",
"Due Great Naval Empire, building only places Towns in inland lands.",
"You are facing Portugal level 6. Good Luck.",
}
reminderSetup = true
mapSetup = true
hasUI = true


function ReminderSetup(params)
local reminderTiles = {}
if params.level >= 1 then
reminderTiles.build = "a5b6b3"
end
if params.level >= 3 then
reminderTiles.ravage = "135124"
end
if params.level >= 5 then
reminderTiles.explore = "a178fa"
end
return reminderTiles
end



function AdversaryUI(params)
local ui = {}
ui.escalation = {}
ui.escalation.tooltip = "On each board, pick a land of the\nshown terrain without Blight. Add\n1 Blight there if there are Invaders."
if params.level >= 1 then
ui.one = {}
ui.one.name = "Great Naval Empire"
ui.one.tooltip = "When Invaders would Build a City in an Inland\nland, add a Town instead. When Invaders Build\nin a Coastal land, add both a Town and a City."
end
if params.level >= 3 then
ui.three = {}
ui.three.name = "Concentrated Population"
ui.three.tooltip = "If Blight is added to a Coastal land\nduring Ravage, add an extra Blight.\nThe additional Blight does not destory\nPresence or cause cascades."
end
if params.level >= 5 then
ui.five = {}
ui.five.name = "Massive Slave Trade"
ui.five.tooltip = "After Setup, when Exploring,\nplace 1 Town instead of 1 Explorer\non each of the lowest numbered\nterrain type matching the card.\n(This has no effect for the \"Coastal\nLands\" card during Stage II.)"
end
if params.level >= 6 then
ui.six = {}
ui.six.name = "A Kingdom United"
ui.six.tooltip = "Invaders build Cities normally in Inland lands."
end
return ui
end

function MapSetup(params)
if params.level >= 2 then
-- add 1 Explorer and Blight to land #1
table.insert(params.pieces[1],"Explorer")
table.insert(params.pieces[1],"BlightInfinite")
end
if params.level >= 4 then
-- add a town to the a lowest numbered inland lands (4+) without invaders or blight
local lowestInland = 4
if params.guid == "f4fc81" or params.guid == "14a35f" then
lowestInland = 5
end
local count = 0
for i=lowestInland, #params.pieces, 1 do
--for each land check start at true
local noInvadersOrBlight = true
--Then for each piece on that land, check if there is a forbidden piece
for _,v in pairs (params.pieces) do

if v == "Explorer" then
noInvadersOrBlight = false
break
end

if v == "Town" then
noInvadersOrBlight = false
break
end

if v == "City" then
noInvadersOrBlight = false
break
end

if v == "BlightInfinite" then
noInvadersOrBlight = false
break
end

end
--If there isn't a forbidden piece - add town and increase count
if noInvadersOrBlight then
--if it lacks invaders and blight add town
table.insert(params.pieces,"Town")
count = count + 1
end
if count == 2 then
break
end
end
end
return params.pieces
end
Last edited by Deso; 28 Jul, 2020 @ 4:40pm
iakona  [developer] 28 Jul, 2020 @ 4:49pm 
So looking over your changes, while not a huge deal you might want to have Spain 4 UI elements assign to the ui.four table. For Portugal it looks like you swapped the generic explore and build tile guids around. Pretty sure explore tile is a5b6b3.
Deso 28 Jul, 2020 @ 5:22pm 
Fixed it then. Thanks a lot.
I even got the multistep evaluation for portugal inland towns working, it was probably due the mistake in the reminder piece that it bugged previously.
iakona  [developer] 9 Aug, 2020 @ 11:55am 
Heads up Deso in an upcoming update to this mod the custom adversary interface for loss conditions. In the PnP rules for JE it mentioned only using 1 Adversary Loss Condition, but that got changed sometime in JE development, so now both adversaries loss conditions will be used.

If you run into any issues getting that hooked up, please let me know
Deso 9 Aug, 2020 @ 5:39pm 
Well I didn't use any loss condition, since both adversaries are somewhat blight focused.
It'll probably take a a couple of weeks to go back to double adversaries, since we want to defeat each of them at level 6.

I did manage to add some blight cards. I didn't get the consequences of that "immediate" switch they have.
Last edited by Deso; 9 Aug, 2020 @ 5:41pm
< >
Showing 1-15 of 16 comments
Per page: 1530 50