|
member
|
OP
member
Joined: Jul 2015
|
I need a script that will fire from a PC running through a trigger and clean up monster corpses in the level. Been looking for some type of command to do this with.
Can anyone please point me in the right direction?
|
|
|
|
addict
|
addict
Joined: Mar 2016
|
I'm not sure what you mean by "clean up". There is no way to permanently remove characters (dead or alive) from a game, unless they were created as temporary characters in the first place (in which case they will be removed automatically when dying and saving/reloading the game). At most, you can set them them off-stage. To iterate over all characters in the current level, you can use CharacterLaunchIterator.
|
|
|
|
member
|
OP
member
Joined: Jul 2015
|
Hay Tinkerer,
It could be my misunderstanding the of how this is handled.
With my issue. After revisiting the level and the creatures respawning we now have a pile of dead monsters copse everywhere. Takes away from the environment, they don't seem to disappear even reading that the way I spawned them in my script, makes the corpse temporary and it should disappear after some time I guess. But its in no way fast enough or seems to even ever happen in testing...
so I need a trigger at the front door to deal with this. Off-stage I guess will work... I just don't want to see that and the PC has already looted them.
CharacterLaunchIterator looks sway outside my scripting level.
In nwn we had a script that would call on Onenter, or Onexit. Great place to fire a cleanup script. To remove junk players drop and any corpses. If you return to the level later on. The monsters have respawned. But their not standing in a corpse of themselves ...
I need to add context I think. I have an ecosystem type mod. I can reuse a lot of areas, so there is maintenance that need done on each area , like cleaning the last run through that dungeon. Re-setting the chests and loot.
Also, there are effects on the corpses that are very distracting.
You would thing the corpse type on the object would handle this? What's the logic in the type of container, as compared to the ability to "de-spawn" " off-stage" a looted corpse?
dose not compute...
Last edited by Detect; 01/03/18 01:27 AM.
|
|
|
|
member
|
OP
member
Joined: Jul 2015
|
Full Definition(s) call CharacterLaunchIterator((STRING)_Event) Description Causes story event _Event to be thrown for every character in the current level. Once the last such character has been iterated, an additional story event _Event will be thrown for object NULL_00000000-0000-0000-0000-000000000000, so that you can perform any necessary clean-up or finalise processing.
lol what does this mean in human terms>? is there a away to identify looted, corpse for removal(off-stage")? is Null a dead monster?
Last edited by Detect; 01/03/18 01:54 AM.
|
|
|
|
enthusiast
|
enthusiast
Joined: May 2017
|
Hi Detect. CharacterLaunchIterator calls the event you specify (a string value) on every character in the current level. Example:
IF
GameStarted(_,_)
THEN
CharacterLaunchIterator("Detect_Events_OnCharacterIterate");
IF
StoryEvent((CHARACTERGUID)_Character, "Detect_Events_OnCharacterIterate")
AND
_Character != NULL_00000000-0000-0000-0000-000000000000
AND
CharacterGetDisplayName(_Character,_,_Name)
AND
StringConcatenate("[Detect] Iterator ran on ", _Name, _Message)
THEN
DebugBreak(_Message);
IF
StoryEvent(NULL_00000000-0000-0000-0000-000000000000, "Detect_Events_OnCharacterIterate")
THEN
DebugBreak("[Detect] Character iteration finished.");
As you can see here, it's pretty straightforward. The iterator simply creates an event, with the name you specify, for each character in the current level. Then, once that's done, it calls the event one last time for the value of a null GUIDSTRING (NULL_00000000-0000-0000-0000-000000000000).
|
|
|
|
member
|
OP
member
Joined: Jul 2015
|
LaughingLeader you always make the scripting seem so simple. Thanks for this again man!
I will test this out and report back shortly... amazing!!
|
|
|
|
member
|
OP
member
Joined: Jul 2015
|
Assumptions - The script runs "on start" so no trigger needed? Runs when the area is loaded/reloaded? Is a final Null state after the character is looted? Is there implications in terms of always iterating or will it only run once?
the scrip complies with no errors.
trying to figure out the best way to test it... macgyver some rig in my builder area, or just go prod on a group run through...
|
|
|
|
enthusiast
|
enthusiast
Joined: May 2017
|
The sample script I supplied runs when the game is "started", after the level has loaded and is ready on the client side: GameStartedFiguring out when to run the iterator for your specific needs is going to be up to you of course, but here's some ideas for events to use: RegionStartedRegionEndedDB_CurrentLevelFor me personally, if I were to make a level that would be continuously populated with new enemies, I would use one of the temporary character creation queries to create my enemies: TemporaryCharacterCreateAtTriggerTemporaryCharacterCreateAtPositionTemporaryCharacterCreateAtPositionOutOfSightToThe advantage of temporary characters are their corpses aren't saved when reloading the level. If you want loot to remain despite their corpse disappearing, one possible solution would be to create a new container when they die (like a backpack or a bag) and transfer their loot to that container. Then that container could always be destroyed after it's been emptied.
|
|
|
|
member
|
OP
member
Joined: Jul 2015
|
hmmm this is some interesting advice
TemporaryCharacterCreateAtTrigger TemporaryCharacterCreateAtPosition TemporaryCharacterCreateAtPositionOutOfSightTo
I am using "CharacterCreateAtPosition" can I just find and replace?
|
|
|
|
member
|
OP
member
Joined: Jul 2015
|
obviously swapping out CharacterCreateAtPosition for TemporaryCharacterCreateAtPosition is going to solve this issue.
lets see what testing brings...
Last edited by Detect; 03/03/18 12:43 AM.
|
|
|
|
member
|
OP
member
Joined: Jul 2015
|
Here's were the script landed, but in testing it does not work.
However, the script did help me find a major bug that I was able to crush. So now all my towns people don't come to assist the PC in this one silly situation.
So here's where I placed the script. It was placed in my story level:
IF DB_CheckLevelStart("TheOldRuin") AND DB_CurrentLevel("NorthHall") THEN GoalCompleted;
IF GameStarted(_,_) THEN CharacterLaunchIterator("Detect_Events_OnCharacterIterate");
IF StoryEvent((CHARACTERGUID)_Character, "Detect_Events_OnCharacterIterate") AND _Character != NULL_00000000-0000-0000-0000-000000000000 AND CharacterGetDisplayName(_Character,_,_Name) AND StringConcatenate("[Detect] Iterator ran on ", _Name, _Message) THEN DebugBreak(_Message);
IF StoryEvent(NULL_00000000-0000-0000-0000-000000000000, "Detect_Events_OnCharacterIterate") THEN DebugBreak("[Detect] Character iteration finished.");
testing: start game run outside the town walls kill something, run back inside town walls, zone into another level. Then zone back to the level we are testing run out to the monster copse and its still there.
Also, CharacterCreateAtPosition & TemporaryCharacterCreateAtTrigger this seems to be a query or something, so I can't just find and replace...
Last edited by Detect; 04/03/18 12:57 PM.
|
|
|
|
member
|
member
Joined: Nov 2017
|
Gamestarted is probably too early for your script to work. As per the notes in its documentation https://docs.larian.game/Osiris/API/GameStarted, the level isn't ready on the server side until the RegionStarted event. As a more general problem: Is this your level wrapper goal? It should close when the level is loaded (as per the very first lines you quoted, IF DB_CheckLevelStart("TheOldRuin") AND DB_CurrentLevel("NorthHall") THEN GoalCompleted;), so that all of the level-specific goals, which should be parented to it, activate. This means that placing the logic here can't work: either the level isn't ready, or the logic is inactive. As per the documentation for that call, https://docs.larian.game/Osiris/API/TemporaryCharacterCreateAtPosition, TemporaryCharacterCreateAtPosition returns the character being summoned, as you may want to perform actions on it when it is spawned.
|
|
|
|
member
|
OP
member
Joined: Jul 2015
|
Thanks. Moved it out of the level story and placed it as a script under the story level. Now its not inside those its in its on script with no GoalCompleted, its not working. I know its a sample script but its a real challenge to test it.
RegionStarted and GameStarted are both events right? Do I need RegionStarted some place to get the script to fire?
Last edited by Detect; 04/03/18 02:59 PM.
|
|
|
|
member
|
OP
member
Joined: Jul 2015
|
I will mess about with: DB_CurrentLevel((STRING)_LevelName)
see if this will get the script to trigger
Last edited by Detect; 04/03/18 03:31 PM.
|
|
|
|
addict
|
addict
Joined: Mar 2016
|
So here's where I placed the script. It was placed in my story level:
IF DB_CheckLevelStart("TheOldRuin") AND DB_CurrentLevel("NorthHall") THEN GoalCompleted;
IF GameStarted(_,_) THEN CharacterLaunchIterator("Detect_Events_OnCharacterIterate");
IF StoryEvent((CHARACTERGUID)_Character, "Detect_Events_OnCharacterIterate") AND _Character != NULL_00000000-0000-0000-0000-000000000000 AND CharacterGetDisplayName(_Character,_,_Name) AND StringConcatenate("[Detect] Iterator ran on ", _Name, _Message) THEN DebugBreak(_Message);
IF StoryEvent(NULL_00000000-0000-0000-0000-000000000000, "Detect_Events_OnCharacterIterate") THEN DebugBreak("[Detect] Character iteration finished.");
testing: start game run outside the town walls kill something, run back inside town walls, zone into another level. Then zone back to the level we are testing run out to the monster copse and its still there.
LaughingLeader's example was an illustration of how to use the CharacterLaunchIterator() Osiris call, not code that literally does what you asked. The above code logs each character as it receives the event from the iterator (which you can see in the editor log or in the osirislog.log file). It does not actually set anything off-stage. I would strongly recommend you to watch the Osiris tutorial videos linked from the Osiris wiki page and to then read the "Osiris Overview" linked from the same page. LaughingLeader's own tutorial on Osiris is also good.
|
|
|
|
member
|
OP
member
Joined: Jul 2015
|
Design: Osiris triggered an assert: [Detect] Iterator ran on Master Of Time Timestamp: 04-03-2018 16:11:15:128 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Deer Timestamp: 04-03-2018 16:11:15:129 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Warrior Trader Timestamp: 04-03-2018 16:11:15:131 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Deer Timestamp: 04-03-2018 16:11:15:131 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Boon Boy Timestamp: 04-03-2018 16:11:15:132 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Deer Timestamp: 04-03-2018 16:11:15:133 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Master Of Eternal Darkness Timestamp: 04-03-2018 16:11:15:133 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Deer Timestamp: 04-03-2018 16:11:15:134 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Master Of Knowledge Timestamp: 04-03-2018 16:11:15:134 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Deer Timestamp: 04-03-2018 16:11:15:134 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Character iteration finished. Timestamp: 04-03-2018 16:11:15:135 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Master Of Time Timestamp: 04-03-2018 16:11:15:135 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Deer Timestamp: 04-03-2018 16:11:15:135 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Warrior Trader Timestamp: 04-03-2018 16:11:15:137 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Deer Timestamp: 04-03-2018 16:11:15:138 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Boon Boy Timestamp: 04-03-2018 16:11:15:138 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Deer Timestamp: 04-03-2018 16:11:15:139 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Master Of Eternal Darkness Timestamp: 04-03-2018 16:11:15:140 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Deer Timestamp: 04-03-2018 16:11:15:140 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Master Of Knowledge Timestamp: 04-03-2018 16:11:15:140 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Iterator ran on Deer Timestamp: 04-03-2018 16:11:15:141 Function: esv::OsirisGameFunctions::DebugBreak Location: EoCServer\Server\OsirisGameFunctions.cpp (1922) Design: Osiris triggered an assert: [Detect] Character iteration finished.
nothing is happening to the corpse
Last edited by Detect; 04/03/18 04:44 PM.
|
|
|
|
member
|
OP
member
Joined: Jul 2015
|
Guys,
I really appreciate the help and tough love, but I am a freacking builder. I am way over my head here! I will fumble through with all of your help. But c"mon give a guy a break here.
Seriously. Logic: I need the corpse to disappear.
But I will go away with my tail between my legs!
I think* The solution is to; from the beginning use: TemporaryCharacterCreateAtPosition I will have to rebuild all my scripts that are spawning monsters in each level to accommodate: TemporaryCharacterCreateAtPosition Current state is: CharacterCreateAtPosition
this is a bit of work because I don't have a working TemporaryCharacterCreateAtPosition script created.
Big design error on my part!! Any scripters out there want to take the wheel on this project... IN terms of scripting lead role; or at lease let me consult with you on future things. Kindly let me know.
I just fired my self for this role!
One of those record-scratching-to-halt moments...
* I think, but not sure. That's called "I think". Other uses: IIRC.
Last edited by Detect; 04/03/18 05:27 PM.
|
|
|
|
member
|
OP
member
Joined: Jul 2015
|
just tested this and still the corpse remains.
re-zoned a few times...
/*MOB Spawner UPTOP Boar 1*/ IF CharacterEnteredTrigger(_Character, TRIGGERGUID_Monkworks_SpawnTrigger_Boar000_001_0470adec-fec8-49c4-be07-4b8b89999bba) AND GetPosition(TRIGGERGUID_Monkworks_SpawnPoint_Boar_001_8124395a-3428-4b8c-a17d-ac7aaed382ce, _X, _Y, _Z) AND NOT DB_MonkWorksBoar000Database(_) AND TemporaryCharacterCreateAtPosition(_X, _Y, _Z, "CHARACTERGUID_Monkworks_Boar000_7c0d5742-cda0-4381-b41f-9dccfba783cb", 1, _Boar000) THEN DB_MonkWorksBoar000Database(_Boar000); IF CharacterDied(_Boar000) AND DB_MonkWorksBoar000Database(_Boar000) THEN NOT DB_MonkWorksBoar000Database(_Boar000);
|
|
|
|
member
|
member
Joined: Nov 2017
|
These characters are temporary in the sense that they aren't saved - they should disappear on save-load. Does that work?
I may be reading over it - where in your code do you expect your character to be set off-stage?
|
|
|
|
enthusiast
|
enthusiast
Joined: May 2017
|
As Tinkerer said, my example was just that - an example on how the character iterator works. You can see it actually worked correctly, given the log messages you shared: Design: Osiris triggered an assert: [Detect] Iterator ran on Master Of Time
As for when to set your characters off-stage, one idea would be to do so when the player steps into a trigger you designate as the "level transition start" trigger. This task would also be easier if you added all your monsters to a shared database, instead of each type getting its own. If you need to later retrieve certain types of monsters, you could just add a shared value in the DB like so:
TemporaryCharacterCreateAtPosition(_X, _Y, _Z, "CHARACTERGUID_Monkworks_Boar000_7c0d5742-cda0-4381-b41f-9dccfba783cb", 1, _Boar000)
THEN
DB_MonkWorks_SpawnedEnemies("Boar", _Boar000);
I suggest leaving their database entries in-tact when they die, and removing them when you actually set them off-stage: INIT:
//Replace this with your actual trigger
DB_MonkWorks_LevelTransitionTrigger((TRIGGERGUID)LevelTransition_Level1_bdc5b3da-041a-4d98-bb68-149869203e83);
KB:
IF
CharacterEnteredTrigger(_Character, _Trigger)
AND
DB_IsPlayer(_Character)
AND
DB_MonkWorks_LevelTransitionTrigger(_Trigger)
AND
NOT DB_MonkWorks_CleanupRunning(_)
AND
MonkWorks_QRY_CleanupNeeded()
THEN
DB_MonkWorks_CleanupRunning(1);
MonkWorks_System_Cleanup();
QRY
MonkWorks_QRY_CleanupNeeded()
AND
SysCount("DB_MonkWorks_SpawnedEnemies", 2, _TotalEnemies)
AND
_TotalEnemies > 0
THEN
DB_NOOP(1);
PROC
MonkWorks_System_Cleanup()
AND
DB_MonkWorks_SpawnedEnemies(_Type, _Enemy)
THEN
SetOnStage(_Enemy, 0);
NOT DB_MonkWorks_SpawnedEnemies(_Type, _Enemy);
PROC
MonkWorks_System_Cleanup()
AND
NOT DB_MonkWorks_SpawnedEnemies(_,_)
THEN
NOT DB_MonkWorks_CleanupRunning(1);
As you can see here, I made both a custom query to check if we need to clean up (if any spawned enemies are in the database), and a proc for actually iterating through said database and setting the enemy off stage. This is pretty basic stuff (once you're familar with the story scripting syntax/basics!), so I recommend giving this a read, and the articles listed under "Recommended Reading" as well.
|
|
|
|
|