New GUI scripting concepts and foundation
Re: New GUI scripting concepts and foundation
No worries, Xanathar. I hope you had great time off-line.
There's actually still a lot of things to do here. Current code is what was referred at one point a low level API. The code still doesn't support displaying images, you can't use relative positions ('bottom', 'middle' etc.), It is not possible to specify alpha-channel, so the display is a bit transparent. Also, JKos pointed out that the event triggering mechanism may be time consuming as we are calling entitiesAt() every frame.
There's actually still a lot of things to do here. Current code is what was referred at one point a low level API. The code still doesn't support displaying images, you can't use relative positions ('bottom', 'middle' etc.), It is not possible to specify alpha-channel, so the display is a bit transparent. Also, JKos pointed out that the event triggering mechanism may be time consuming as we are calling entitiesAt() every frame.
Re: New GUI scripting concepts and foundation
is there any reason not to have them on onMove/onTurn events ? (apart from the engine bug where you can turn without triggering onTurn if you use the free view mode ?)as we are calling entitiesAt() every frame
Waking Violet (Steam, PS4, PSVita, Switch) : http://www.wakingviolet.com
The Sunset Gate [MOD]: viewtopic.php?f=14&t=5563
My preciousss: http://www.moonsharp.org
The Sunset Gate [MOD]: viewtopic.php?f=14&t=5563
My preciousss: http://www.moonsharp.org
Re: New GUI scripting concepts and foundation
I think it's doable, just less reliable. onTurn is not needed as you need to step onto specific grid to enable event, no matter what direction the party is looking. What if you teleport into event location or fall on it through a pit? Will onMove work? JKos suggested a timer set to small value (0.2 second?).Xanathar wrote:is there any reason not to have them on onMove/onTurn events ? (apart from the engine bug where you can turn without triggering onTurn if you use the free view mode ?)as we are calling entitiesAt() every frame
If onMove is called when you teleport of fall, then it solves the problem nicely. If not, I think the timer would be a better way to go.
Re: New GUI scripting concepts and foundation
You are right about the teleport / pit problems (I would find it weird to have them trigger an npc but well some might find them cool): a solution could be having the main entity do a find of all "triggers" at startup, and create on the fly and bind a pressure plate to them. (this is what I do in grimq for auto-printers and auto-secrets)
Waking Violet (Steam, PS4, PSVita, Switch) : http://www.wakingviolet.com
The Sunset Gate [MOD]: viewtopic.php?f=14&t=5563
My preciousss: http://www.moonsharp.org
The Sunset Gate [MOD]: viewtopic.php?f=14&t=5563
My preciousss: http://www.moonsharp.org
Re: New GUI scripting concepts and foundation
Yes, I've developped a marker code based on that to set zones in my dungeon (and then filter my timers, spawners and various functions depending on where the player is):Xanathar wrote:You are right about the teleport / pit problems (I would find it weird to have them trigger an npc but well some might find them cool): a solution could be having the main entity do a find of all "triggers" at startup, and create on the fly and bind a pressure plate to them. (this is what I do in grimq for auto-printers and auto-secrets)
Code: Select all
zone = "mainStairs"
subZone = nil
zoneLocations = {}
function setZoneLocations()
local markers = grimq.fromAllEntitiesInWorld()
:where("name", "zone_marker")
:toIterator()
for zMarker in markers do
local level, x, y = zMarker.level, zMarker.x, zMarker.y
local zKey = level.."."..x.."."..y
zoneLocations[zKey] = zMarker.zone
spawn("pressure_plate_hidden", level, x, y, 0)
:setTriggeredByParty(true)
:setTriggeredByMonster(false)
:setTriggeredByItem(false)
:setSilent(true)
:addConnector("activate", "coreScript", "setZone")
end
end
function setZone()
local level, x, y = party.level, party.x, party.y
local zKey = level.."."..x.."."..y
if zoneLocations[zKey] ~= nil then
local zParts = help.split(zoneLocations[zKey],'.')
zone = zParts[1]
if zParts[2] ~= nil then
subZone = zParts[2]
else
subZone = nil
end
--print(zone,subZone)
end
end
EDIT: Altough not necessary, as you see I also store the zone data in a table indexed by level.x.y, in case I need to access this also from a script somewhere. Originally I used a quick timer which checked if the index [party.level, party.x, party.y] existed. That's still faster than an allEntities...
The advantage of this approach is that you can easily set triggers directly in the editor. Disadvantage is that it's not dynamic and cannot be changed afterwards, as you cannot destroy script_entities.
An alternative way would be to use wall_texts, as these you can "move" by destroying the text object and the pressure plate, and respawning it again. (You would need to keep pressure plate ids when initializing).
The advantage of that would be that you could just type "templeOfLight.altarRoom" in the wall text. Disadvantage would be that if you want to store different variables, like " npcName = 'John', npcAction = 'dialogue1' ", then you would need to code a parser to get this into usable code. Centaur Soldier should really step in here, he's developping a system for saving/restoring data in wall texts for our LotNR project.
Re: New GUI scripting concepts and foundation
Ok, I pushed the concept a bit:
markerScript entity:
and this in an .lua:
So now it's really modular:
1. It scans onParty_marker objects in the dungeon and stores in the md table all predefined variables to look for.
2. Then, when the party enters the marker square, it calls onParty, from where you can do anything with that data.
3. When the party leaves the square, it call onUnparty.
And there's a moveMarker function, I realized that since we don't rely on the original onParty_marker object to get data, but rather on the position index of the md table, we can move that freely, just changing the index and respawning the pressure plate.
So you can use this to define an npc encounter with any amount of variables, and have it move around too.
EDIT: How it looks in the editor:

I think it makes defining events very user-friendly.
EDIT 2: Updated the code with a setMarker and removeMarker functions to allow those markers to be also generated dynamically from a script. Also added an onUparty trigger. If you just want to check what's the current id the party stepped on from onDrawGui, you could always call something like gw.setCurrentEventId(md[mIndex].markerId) from onParty and gw.setCurrentEventId(nil) from onUnparty.
EDIT 3: Realized all the level.x.y key was not necessary as I can get the id from the trigger plate. Code is much simpler now. The only problem is that you need to predefine which variables can be put in the marker. I think that using a wallText object instead of a script_entity object, we could parse it to get any variables from it without predefining them.
markerScript entity:
Code: Select all
-- Table of markers data
md = {}
function getMarkersData()
local markers = grimq.fromAllEntitiesInWorld()
:where("name", "onParty_marker")
:toIterator()
for m in markers do
-- variables to look for in markers
local data = {}
if m.var1 then
data.var1 = m.var1
end
if m.var2 then
data.var2 = m.var2
end
if m.var3 then
data.var3 = m.var3
end
setMarker(m.id, m.level, m.x, m.y, data)
end
end
function moveMarker(id, level, x, y)
local data = md[id]
md[id] = nil
findEntity(id..".trigger"):destroy()
setMarker(id, level, x, y, data)
end
function setMarker(id, level, x, y, data)
md[id] = {}
md[id].level = level
md[id].x = x
md[id].y = y
for i, v in pairs(data) do
md[id][i] = v
end
if findEntity(id..".trigger") then
findEntity(id..".trigger"):destroy()
end
spawn("pressure_plate_hidden", level, x, y, 0, id..".trigger")
:setTriggeredByParty(true)
:setTriggeredByMonster(false)
:setTriggeredByItem(false)
:setSilent(true)
:addConnector("activate", "markerScript", "onParty")
:addConnector("deactivate", "markerScript", "onUnparty")
end
function removeMarker(id)
md[id] = nil
findEntity(id..".trigger"):destroy()
end
function onParty(trigger)
id = string.sub(trigger.id, 0, -9)
if md[id] then
--do anything you want here, calling other functions using stored data. For example:
print("on:",id)
end
end
function onUnparty(trigger)
id = string.sub(trigger.id, 0, -9)
if md[id] then
--do anything you want here, calling other functions using stored data. For example:
print("off:",id)
end
end
function autoexec()
getMarkersData()
end
Code: Select all
cloneObject {
name = "onParty_marker",
baseObject = "script_entity",
editorIcon = 104,
}1. It scans onParty_marker objects in the dungeon and stores in the md table all predefined variables to look for.
2. Then, when the party enters the marker square, it calls onParty, from where you can do anything with that data.
3. When the party leaves the square, it call onUnparty.
And there's a moveMarker function, I realized that since we don't rely on the original onParty_marker object to get data, but rather on the position index of the md table, we can move that freely, just changing the index and respawning the pressure plate.
So you can use this to define an npc encounter with any amount of variables, and have it move around too.
EDIT: How it looks in the editor:

I think it makes defining events very user-friendly.
EDIT 2: Updated the code with a setMarker and removeMarker functions to allow those markers to be also generated dynamically from a script. Also added an onUparty trigger. If you just want to check what's the current id the party stepped on from onDrawGui, you could always call something like gw.setCurrentEventId(md[mIndex].markerId) from onParty and gw.setCurrentEventId(nil) from onUnparty.
EDIT 3: Realized all the level.x.y key was not necessary as I can get the id from the trigger plate. Code is much simpler now. The only problem is that you need to predefine which variables can be put in the marker. I think that using a wallText object instead of a script_entity object, we could parse it to get any variables from it without predefining them.
Re: New GUI scripting concepts and foundation
Done a commit:
My biggest issue so far: working in one big scripting entity and everyone changing dungeon.lua does not scale IMHO.
For grimq I did split it into many files, having a batch "compiling" it all into one big file and copying the text to the clipboard so that workflow is:
What do you think ? Any other idea ?
- Added a 3D button object, which mimics "motif" style buttons, with hover highlight and bevel borders
- Added onClick event which mimics the click semantics in GUIs. If you press the mouse, the button is "down" but the click event is raised when the mouse gets up again if - and only if - the cursor is still on the button (allowing cancelling an action moving the mouse away)
- As far as I know, transparency should be managed ok, but I didn't test really
- Added some utility methods: rgb2yuv, normalizeColorComponent, yuv2rgb, changeBrightness, isPointInBox, setColor, resetColor, drawBevel, defaultValue (nitpicking - it's more YCbCr than YUV, and is in whatever range it is - more than enough for the bevel purpose, we are not doing movies or broadcast tv here
)
My biggest issue so far: working in one big scripting entity and everyone changing dungeon.lua does not scale IMHO.
For grimq I did split it into many files, having a batch "compiling" it all into one big file and copying the text to the clipboard so that workflow is:
- Work on lua files in the src directory
- Click build.cmd
- Go to dungeon editor, paste over the code
- Test, go to bullet 1 until ready
What do you think ? Any other idea ?
Waking Violet (Steam, PS4, PSVita, Switch) : http://www.wakingviolet.com
The Sunset Gate [MOD]: viewtopic.php?f=14&t=5563
My preciousss: http://www.moonsharp.org
The Sunset Gate [MOD]: viewtopic.php?f=14&t=5563
My preciousss: http://www.moonsharp.org
Re: New GUI scripting concepts and foundation
modular is good for everyone and long term usage, better to invest the effort to set it up that way from the beginning stages in my opinion
Finished Dungeons - complete mods to play
Re: New GUI scripting concepts and foundation
Cool stuff Xanathar and welcome back. I have a another idea: If we include my framework to this project we can split it to several script entities and files and still keep the installation fairly easy. I think we have to include it anyway if we are going to implement freeze time.
I could remove all unecessary optional modules from it and leave only the core modules for this project, and it includes grimq too so we could use auto functions for events and all other awesome stuff.
gw could for example contain only the public api, core functionality and utility functions.
Then we could move the implementation of the elements to separate script entity/entities.
But it's just a suggestion and I'm sure that your batch compiling method is good enough too. Even though this is my suggestion I'm not sure if I like it so I will leave the decission to you, it's your project
Edit: I could make a quick conceptual demo to another branch so we could test how it works. It should't be much work.
I could remove all unecessary optional modules from it and leave only the core modules for this project, and it includes grimq too so we could use auto functions for events and all other awesome stuff.
gw could for example contain only the public api, core functionality and utility functions.
Then we could move the implementation of the elements to separate script entity/entities.
But it's just a suggestion and I'm sure that your batch compiling method is good enough too. Even though this is my suggestion I'm not sure if I like it so I will leave the decission to you, it's your project
Edit: I could make a quick conceptual demo to another branch so we could test how it works. It should't be much work.
- LoG Framework 2http://sites.google.com/site/jkoslog2 Define hooks in runtime by entity.name or entity.id + multiple hooks support.
- cloneObject viewtopic.php?f=22&t=8450
- cloneObject viewtopic.php?f=22&t=8450
Re: New GUI scripting concepts and foundation
Hi JKos,
about the framework inclusion, I think this whole project is targeted towards complex mods (if your gui is just a button you are probably served better with a DYI solution), which would probably benefit of having the fw anyway, so I wouldn't worry too much about that. Plus that would reinforce the idea of having the framework as a somewhat standard asset which would be an additional benefit.
Just as a clarification: do you mean using the same initialization as the framework currently does (using and staying with separate files) ?
Let's share the blame ehm I mean, the decisions 
about the framework inclusion, I think this whole project is targeted towards complex mods (if your gui is just a button you are probably served better with a DYI solution), which would probably benefit of having the fw anyway, so I wouldn't worry too much about that. Plus that would reinforce the idea of having the framework as a somewhat standard asset which would be an additional benefit.
Just as a clarification: do you mean using the same initialization as the framework currently does (using and staying with separate files) ?
No no, please, it's our project (our = of everyone who contributes)I will leave the decission to you, it's your project
Waking Violet (Steam, PS4, PSVita, Switch) : http://www.wakingviolet.com
The Sunset Gate [MOD]: viewtopic.php?f=14&t=5563
My preciousss: http://www.moonsharp.org
The Sunset Gate [MOD]: viewtopic.php?f=14&t=5563
My preciousss: http://www.moonsharp.org
