Larian Banner: Baldur's Gate Patch 9
Previous Thread
Next Thread
Print Thread
Page 1 of 2 1 2
#602452 17/04/17 11:15 PM
Joined: Apr 2017
O
Onimuru Offline OP
stranger
OP Offline
stranger
O
Joined: Apr 2017
Can anyone help me out with a clever way to make a non party member follow player1 to a new region/subregion. I have tried various checks for region,sight and distance in both Story and charscripts and I now I'm really sad so someone please help me out :)

Last edited by Onimuru; 17/04/17 11:25 PM.
Onimuru #602550 20/04/17 07:34 PM
Joined: Mar 2016
Location: Belgium
T
addict
Offline
addict
T
Joined: Mar 2016
Location: Belgium
You should not need any special code for subregions. Afaik they just show a special marker, but they're not different levels. So your regular follow code (CharacterFollowCharacter) should work just fine.

For region swaps, I think this should work:
Code
IF
CharacterEnteredRegion(_Player,_Region)
AND
DB_CharacterHasFollower(_Player,_Follower)
THEN
CharacterTeleportToCharacter(_Follower,_Player,"");

Make sure both _Follower and _Player are global.

Tinkerer #602571 21/04/17 02:38 AM
Joined: Apr 2017
O
Onimuru Offline OP
stranger
OP Offline
stranger
O
Joined: Apr 2017
Thanks allot, the character not being global is probably the issue then, I hadn't thought of that. Is there a way to change that on the fly? I didn't place the character, I've spawned it from a template and I can't change the global value in the template.

Also on a side note, the command in charScripts: CharacterGetFollow(_, _), does this serve any purpose other than identifying a character to follow? It always failed so I couldn't test this. Seems like it should have a built in stop so that idle reactions (with lower priority) can run but when just using CharacterFollow(%CHARACTER01, -1, -1) the game keeps that reaction active indefinitely unless it's interrupted by something else.

Last edited by Onimuru; 21/04/17 02:39 AM.
Onimuru #602605 21/04/17 06:59 PM
Joined: Jun 2015
F
enthusiast
Offline
enthusiast
F
Joined: Jun 2015
No chance to change it on-thefly. Osiris needs to know a character at compile time. Spawned characters don't exist at compile time.
I think adding a new global character to the game, even if it did not make the game crash, will not work. My own experiments with changing objects from global to not global resulted in crashes, I think because the global chars are stored somewhere in the save files and the game crashed when it did not find them anymore. So I also think that adding a global character will not add it to an existing savegame. (But that's speculation as always, no real knowledge ;-)


You can experiment with creating a summon skill with infinitve summon time, try using -1 for the number of turns variable. A summon should count as a party member and follow the summoner wherever he/she goes. If there should be a way to dismiss this follower, you'd have to kill it by script and you'd probably need a second skill or item for this. And the summon would probably require a special charscript to identify itself against some event.
I don't remember though if summons really auto-follow through portals.
The disadvantage of a spell is that it's executed by the engine and you have no control over it.
If you'd need no despawn, you could use a scroll to cast the summon spell from so that you avoid problems with multiple skill uses.


The other possibility would be to pre-place the follower and never spawn it but teleport it around when needed (if it should be 'despawnable'). Such a character would never auto-follow through portals though. On 'dismiss', you'd simply CharacterSetOnStage( 0 ) it. I don't know if setting the char offstage would deactivate the follow script though.


You'd have to modify the resurrect skills too to be usable on non-party members, or introduce a follower-only resurrect skill. You can look at the Death Knight Bane spell as a sample for a spell that uses 'tags' to restrict use of a spell on a specific target. (in 'data "TargetConditions" "..."' I think; must be a spell of type 'target' then of course, but I think all resurrect spells are of that type already.)
If you don't care about 'abusability' of the regular resurrect spells, you can modify them to work for non-party npcs.


For your object script questions, some knowledgeable modders will show up. I only ever used object scripts when there was really no other way to do it or when doing something in Osiris would have been far more complex than an object script ;-)

FrauBlake #602624 22/04/17 12:11 PM
Joined: Apr 2017
O
Onimuru Offline OP
stranger
OP Offline
stranger
O
Joined: Apr 2017
Thank you for your reply, I will look into using a summon instead because trying to mimic party behavior is hard lol.

The best I could come up with was:

Code
IF
CharacterUsedItem(_Player,_Item)
THEN
TimerLaunch("CC_TIMER02", 850);

IF
TimerFinished("CC_TIMER02")
AND
CharacterGetDistanceToCharacter(_Follower,_Player,_Dist)
AND
_Dist >= 10   //Not sight because _Player might be sneaking or invisible
THEN
CharacterTeleportToCharacter(_Follower,_Player,"");


I originally tried using triggers because they're conveniently placed but after the trigger has been unregistered, it no longer acts as a trigger at all which is a shame.

If the summon doesn't work out I will just use a running timer because there's no way to predict when a player has actually used the item (like gates for instance) and so the above code with fail quite allot.

Last edited by Onimuru; 22/04/17 12:12 PM.
Onimuru #602625 22/04/17 12:41 PM
Joined: Sep 2015
A
addict
Offline
addict
A
Joined: Sep 2015
You could also spawn a character as a summon from an object script and define a player character as the owner:
Code
 SpawnCharacter(_Char,[CharacterTemplate],__Me,0,1,__Me)


The character will follow you to every place of the game world and without a time limit.

A bit more information on what exactly you're trying to do would help to give more specific advice.


My mods for DOS 1 EE: FasterAnimations - QuietDay - Samaritan
Abraxas* #602626 22/04/17 02:02 PM
Joined: Apr 2017
O
Onimuru Offline OP
stranger
OP Offline
stranger
O
Joined: Apr 2017
Well I originally just wanted to get rid of CHARACTER_Player2 but I liked the RP system and there are quite a few dialog event that need player2 around so I turned player2 into a cat with some cool behavior. I just like messing around with game code more than playing to be honest, I did this with Stellaris as well smile

I'm not sure if a summon will still qualify as player2, I haven't messed with dialog yet. I check it out but I think I should just band aid it with a timer since there isn't a way to track another player through a charScript (or it's not even considered because it's too far away I should say) and Osiris lacks the commands. I did the same thing with the character template in character creation because when the gender is changed, it overrides the scripts and Osiris can't measure character templates for a trigger so I just start/stop a timer. I don't like the Story code at all, it seems far too limited.

Last edited by Onimuru; 22/04/17 02:04 PM.
Abraxas* #602630 22/04/17 10:13 PM
Joined: Apr 2017
O
Onimuru Offline OP
stranger
OP Offline
stranger
O
Joined: Apr 2017
Like I can do this, I think that's pretty cool smile
Code
EVENT ccOnDamage
VARS
	CHARACTER:_CHARACTER
	CHARACTERTEMPLATE:_CHARACTERTEMPLATE
	DAMAGE:_DAMAGE
	FLOAT:_FLOAT01
	FLOAT:_FLOAT02
	ITEM:_ITEM
ON
	OnDamage(_DAMAGE, _FLOAT01, _CHARACTER, _ITEM)
ACTIONS
	Set(%CHARACTER03, _CHARACTER)
	Set(%ITEM01, _ITEM)
	IF "(c1)"
		IsGreaterThen(_FLOAT01, 0.00)
	THEN
		IF "((!c1)&c2)"
			IsEqual(_CHARACTER, null)
			IsEqual(%INT04, 0)
		THEN
			IF "(!(c1&c2))"
				CharacterHasStatus(__Me, FROZEN)
				CharacterHasStatus(__Me, PETRIFIED)
			THEN
				IF "(c1&c2&c3)"
					IsRandom(0.05)
					CharacterGetTemplate(__Me, _CHARACTERTEMPLATE)
					IsEqual(_CHARACTERTEMPLATE, %CHARACTERTEMPLATE02)
				THEN
					SpawnItem("LOOT_Bone_A_ff6c1d1d-3425-4ee2-a790-06363d85ecd4", __Me, 1)
				ENDIF
				CharacterPlayEffect(__Me, "FX_GP_Status_Bleeding_A_Effect1")
				PlayEffectAt(__Me, "FX_GP_Footstep_A_Small_Blood")
				Set(%INT04, 1)
			ENDIF
		ENDIF
		IF "(c1&(!c2))"
			CharacterGetStat(_FLOAT02, __Me, Vitality)
			IsLessThen(_FLOAT02, 0.5)
		THEN
			IF "(c1&(!c2))"
				CharacterGetTemplate(__Me, _CHARACTERTEMPLATE)
				IsEqual(_CHARACTERTEMPLATE, %CHARACTERTEMPLATE01)
			THEN
				GlobalSetEvent("CC_GLOBALEVENT01")		//Normal cat
				PlayEffectAt(__Me, "FX_Skills_WitchCraft_TargetedCurse_Impact_A")
			ENDIF
		ELIF "(c1&(!c2))"
			CharacterGetStat(_FLOAT02, __Me, Vitality)
			IsGreaterThen(_FLOAT02, 0.5)
		THEN
			IF "(c1&(!c2))"
				CharacterGetTemplate(__Me, _CHARACTERTEMPLATE)
				IsEqual(_CHARACTERTEMPLATE, %CHARACTERTEMPLATE02)
			THEN
				GlobalSetEvent("CC_GLOBALEVENT02")		//Skeletal cat
				PlayEffectAt(__Me, "FX_Skills_WitchCraft_TargetedCurse_Impact_A")
			ENDIF
		ENDIF
	ENDIF
	DelayReaction("Idle_Peace", 5.0)

Onimuru #602650 23/04/17 12:10 PM
Joined: Jun 2015
F
enthusiast
Offline
enthusiast
F
Joined: Jun 2015
Yes, Osiris API lacks a lot, but so do object scripts.
Only stuff that Larian ever needed in their games is in Osiris, at least it looks like it. Some of the existing APIs are not used in D:OS, so one can suppose they were used in previous games.
It's anything but a generic API. Everybody who used it had to implement either a lot of workarounds to do stuff they wanted or it was not doable at all.
Both APIs for example have no way to query the items equipped by a character nor can the items themselves be examined. All that is hidden in the engine.

A summon will *not* qualifiy as player2, because like a spawn, a summon is not a global character known at compile time.
Rewriting everything that involves the two players, although doable, would require more than a lot of effort. (I'd suppose you'd want to be done with it this decade ...)

Character scripts stop working when you're too far away from a character.
I had to implement a combination of item scripts and story code for the field beds in XC_Bags to auto-disappear after a defined time. They would not disappear when the party moved out of range too quickly with item/character scripts only.
The reason I had to do it was less for the item to disappear because that wouldn't have mattered but for the internal flag indicating that a bed 'is out', which needed to be reset for the skill to be usable again. Did not work with item scripts only because they stopped working when out of range.
(I had dismissed the original SpawnItem() call in favor of global beds with teleport and SetOnStage() because of my paranoia of object handle waste ;-)

FrauBlake #602675 23/04/17 08:24 PM
Joined: Mar 2016
Location: Belgium
T
addict
Offline
addict
T
Joined: Mar 2016
Location: Belgium
Originally Posted by FrauBlake
Character scripts stop working when you're too far away from a character.

That is correct, but you can disable this for individual characters (and hence all behaviour scripts attached to them) via the CharacterForceUpdate() call in a behaviour script: CharacterForceUpdate(1) to keep it active at all times, and CharacterForceUpdate(0) to revert to the default behaviour.

There's a call from Osiris that does the same: CharacterForceSynch(). Note, however, that CharacterForceSynch(_Char,1) by itself does not make a character active. It only ensures that once it becomes active, it does not become inactive again. Therefore, if you use this call from Osiris, you should afterwards send an event that is caught by the target character so that it becomes active (events are always caught by all characters/items, even inactive ones).

Onimuru #602677 23/04/17 08:48 PM
Joined: Sep 2015
A
addict
Offline
addict
A
Joined: Sep 2015
Oh, this is a delicious information from you, Tinkerer! This opens up new possibilities for object scripting! smile


My mods for DOS 1 EE: FasterAnimations - QuietDay - Samaritan
Tinkerer #602682 23/04/17 09:44 PM
Joined: Apr 2017
O
Onimuru Offline OP
stranger
OP Offline
stranger
O
Joined: Apr 2017
Thanks for that insight <3 That's very good to know.

FrauBlake #602684 23/04/17 10:30 PM
Joined: Apr 2013
N
addict
Offline
addict
N
Joined: Apr 2013
Some notes for D:OS 2:

Originally Posted by FrauBlake
Both APIs for example have no way to query the items equipped by a character nor can the items themselves be examined.

This was partially addressed with the "CharacterGetEquippedWeapon" and "CharacterGetEquippedShield" functions. Still no way to query the whole set of equipped items though frown
One possibility would be using ItemLaunchIterator to iterate through all items and check them one by one, or alternatively keeping an "is equipped" database by hooking ItemEquipped and ItemUnEquipped, and storing the items into the database. Both are quite nasty workarounds though.

Originally Posted by FrauBlake
A summon will *not* qualifiy as player2, because like a spawn, a summon is not a global character known at compile time.

Would it be possible to use "CombatGetNumberOfInvolvedPartyMembers" and "CombatGetInvolvedPartyMember" to enumerate summons?

Originally Posted by FrauBlake
paranoia of object handle waste ;-

Object handles are finally 64-bit, so we cannot run out of them like in D:OS 1.

Tinkerer #602803 26/04/17 03:49 AM
Joined: Jun 2013
old hand
Offline
old hand
Joined: Jun 2013
Originally Posted by Tinkerer
Originally Posted by FrauBlake
Character scripts stop working when you're too far away from a character.

That is correct, but you can disable this for individual characters (and hence all behaviour scripts attached to them) via the CharacterForceUpdate() call in a behaviour script: CharacterForceUpdate(1) to keep it active at all times, and CharacterForceUpdate(0) to revert to the default behaviour.


Originally Posted by Abraxas*
Oh, this is a delicious information from you, Tinkerer! This opens up new possibilities for object scripting! smile


This information would have been super useful about a year and a half ago when I had a full schedule for about 30 NPCs implemented in charscript only to have to rewrite half of it hahaha

SniperHF #602833 27/04/17 06:24 AM
Joined: Mar 2016
Location: Belgium
T
addict
Offline
addict
T
Joined: Mar 2016
Location: Belgium
Originally Posted by SniperHF

This information would have been super useful about a year and a half ago when I had a full schedule for about 30 NPCs implemented in charscript only to have to rewrite half of it hahaha

That would be about three months before I had even heard of Osiris smile (and behaviour scripts came even later)

Additionally, I learned about this on the inside. Yes, I joined Larian as a scripter at the start of this year party

Onimuru #602835 27/04/17 07:33 AM
Joined: Sep 2015
A
addict
Offline
addict
A
Joined: Sep 2015
Quote
Yes, I joined Larian as a scripter at the start of this year party

A good catch, I'd say! Congratulations! smile


My mods for DOS 1 EE: FasterAnimations - QuietDay - Samaritan
Onimuru #602841 27/04/17 06:16 PM
Joined: Mar 2016
Location: Belgium
T
addict
Offline
addict
T
Joined: Mar 2016
Location: Belgium
Thanks smile

Norbyte #602847 27/04/17 08:54 PM
Joined: Jun 2015
F
enthusiast
Offline
enthusiast
F
Joined: Jun 2015
Originally Posted by Norbyte
Some notes for D:OS 2:

Originally Posted by FrauBlake
Both APIs for example have no way to query the items equipped by a character nor can the items themselves be examined.

This was partially addressed with the "CharacterGetEquippedWeapon" and "CharacterGetEquippedShield" functions. Still no way to query the whole set of equipped items though frown
One possibility would be using ItemLaunchIterator to iterate through all items and check them one by one, or alternatively keeping an "is equipped" database by hooking ItemEquipped and ItemUnEquipped, and storing the items into the database. Both are quite nasty workarounds though.

Originally Posted by FrauBlake
A summon will *not* qualifiy as player2, because like a spawn, a summon is not a global character known at compile time.

Would it be possible to use "CombatGetNumberOfInvolvedPartyMembers" and "CombatGetInvolvedPartyMember" to enumerate summons?

Originally Posted by FrauBlake
paranoia of object handle waste ;-

Object handles are finally 64-bit, so we cannot run out of them like in D:OS 1.

I thought this thread was about EE modding so handles being 64 bit in D:OS2 is not very helpful for EE modding ;-) (They seemed to have been 32 bit in EE already as it looks, see below.)
Hey, shame on you, YOU are the 'Father of EE modding', Sir, you've already forgotten your own child ? ... ;-)


I've thought about keeping track of equipped items with the equip events a couple of time but find it an overkill personally. I don't have the editor open, so cannot look it up, do the equip events take ITEMs or ITEMHANDLEs ? If it's ITEMs, it won't even be thrown for non publics in EE.
Anyway, whenever thinking about the monitoring I decided against it because I find it complete overkill. Almost as bad as polling in programming ;-)


With player2, it's not about querying if a summon exists but about the role, a lot of existing story scripts and dialogs expect a CHARACTER_PLAYER2 to exist.


Actually, handles in EE were not even 32 bit, because that would already have been enough to never have to worry about them.
Raze once gave us the information, that the handle generator is actually a simple counter. A patch note once said, they increased the handle limit to 64k.


Although I don't know it, I suppose, they use a 16bit short for the handle counter. Extending the possible pool from 32k to 64k might have been a simple change from 'short' to 'unsigned short'.
Looking at a save file one time, I came to think that they use several 16 bit short counters for different purposes of handles and 'shift' them to certain windows of a 32bit int, simply by bit-or'ing them with e.g. 0x10000 for items, 0x20000 for characters, 0x30000 for scenery and so forth. Maybe a remainder - as so many things in classic and EE - from earlier Larian games.
The values I saw in the save files were all above 2^16, so it cannot be a pure short that's used to store the actual handle, it's probably a 32bit int.
It's only a stupid implementation of the handle generator that introduced the 64k limit. And even that would have never been a big problem if there was a 'used/free handles bitmap' that would have enabled handle re-use.
The latter could probably never be implemented because none of the API functions ever released their handles, or more precisely, they would have had to report the handle release to some handle bookkeeper which was not the case as it seems.

Version 2 looks like a big cleanup from what you posted in the other thread. Good for future modders. Maybe they finally do it correct instead of 'as quickly as possible', and generic instead of 'what we currently need'.
(Maybe even the extremely annoying 'Magic Pockets' popups can be turned off but I have doubts. They were the main reason I disabled this whole functionality for shovels and pickaxes in XC_Bags ;-)
... and maybe they even implement a real 'game timer' which they wanted to do a long time ago as one of the comments in an Osiris file suggests ;-)


FrauBlake #602868 28/04/17 05:40 AM
Joined: Apr 2013
N
addict
Offline
addict
N
Joined: Apr 2013
Originally Posted by FrauBlake
I thought this thread was about EE modding so handles being 64 bit in D:OS2 is not very helpful for EE modding ;-)

Yeah I know, but I thought the news was exciting enough to share anyway smile

Originally Posted by FrauBlake
Hey, shame on you, YOU are the 'Father of EE modding', Sir, you've already forgotten your own child ? ... ;-)

Tsk, tsk. My statement is actually correct, as you'll see below smile

Originally Posted by FrauBlake
Actually, handles in EE were not even 32 bit, because that would already have been enough to never have to worry about them.
Raze once gave us the information, that the handle generator is actually a simple counter. A patch note once said, they increased the handle limit to 64k.

The _handle_ is actually 32-bit. However, multiple fields are stuffed into this 32-bit handle; an (apparently) 16-bit counter, a type identifier, and some undentified bits (possibly generation count or flags?).

Originally Posted by FrauBlake
Although I don't know it, I suppose, they use a 16bit short for the handle counter. Extending the possible pool from 32k to 64k might have been a simple change from 'short' to 'unsigned short'.

Yeah, one bit was most likely sacrificed for counters from some other function.

Originally Posted by FrauBlake
Looking at a save file one time, I came to think that they use several 16 bit short counters for different purposes of handles and 'shift' them to certain windows of a 32bit int, simply by bit-or'ing them with e.g. 0x10000 for items, 0x20000 for characters, 0x30000 for scenery and so forth. Maybe a remainder - as so many things in classic and EE - from earlier Larian games.
The values I saw in the save files were all above 2^16, so it cannot be a pure short that's used to store the actual handle, it's probably a 32bit int.

Yeah, the lower 16-bits (value & 0x0000FFFF) are the counter, upper 16-bits (so, value & 0xFFFF0000 in binary) is the type+misc flags. My observed type prefix list contains:
0x0000 - CacheTemplate
0x0200 - Trigger
0x0040 - Item
0x0140 - Inventory Factory
0x01C0 - Inventory View
0x0440 - Combat Component
0x0040 - Character Creator
0x0080 - Item Creator
0x0180 - Party


Originally Posted by FrauBlake
It's only a stupid implementation of the handle generator that introduced the 64k limit.

On that we can agree. I'd say that a handle limit as low as 32k is a questionable design decision, but maybe with the original scope of the game it made sense? I wouldn't be so quick to blame this on shortsightedness or lazyness before knowing why the handles work the way they do. (I've already experienced this first-hand when someone criticized my code for being bad, when it was actually fulfilling a design requirement they did not know about :P)

I'd like to note though that each individual type has its separate pool, each with a separate 64k limit (so you can have 64k characters and 64k items, not 64k characters+items).

Originally Posted by FrauBlake
And even that would have never been a big problem if there was a 'used/free handles bitmap' that would have enabled handle re-use. The latter could probably never be implemented because none of the API functions ever released their handles, or more precisely, they would have had to report the handle release to some handle bookkeeper which was not the case as it seems.

There is a "bookkeeper" of sorts for every type. Eg. items have an ItemManager, characters have CharacterManager, etc. This is quite visible in the savegame structure too, each "manager" or component gets its own region in the save file, so I believe it could have been implemented.
Most of the time the rationale behind the "counter with no pool" pattern is that handle usage is uncontrolled, so even though an item was destroyed someone somewhere could be holding a handle to that. Eg. imagine the following situation:
1) Script A gets a handle for character 1111, sets a timer to destroy it after eg. 30 seconds.
2) During those 30 secs, the character gets killed, its ID is released to the free pool.
3) A new character is created that claims the now "free" 1111 id.
4) When the script runs, it now destroys the wrong thing.

This kind of handle misuse can be relatively common and the bugs they cause are quite deceptive and hard to detect. They'll also do random and unpredictable things depending on which ID they reuse. Since Osiris code is probably riddled with such possibilities (which is quite plausible, as you don't want to burden your designers with the task of undersanding concurrency at that level -- quite a headache even for programmers!), I believe the ever-increasing-handles to be a plausible solution for the problem; what they failed to account for was the rapid exhaustion of the ID space.

Originally Posted by FrauBlake
Version 2 looks like a big cleanup from what you posted in the other thread. Good for future modders. Maybe they finally do it correct instead of 'as quickly as possible', and generic instead of 'what we currently need'.
(Maybe even the extremely annoying 'Magic Pockets' popups can be turned off but I have doubts. They were the main reason I disabled this whole functionality for shovels and pickaxes in XC_Bags ;-)
... and maybe they even implement a real 'game timer' which they wanted to do a long time ago as one of the comments in an Osiris file suggests ;-)

We shall see. I'm hoping for the best.

Norbyte #602915 29/04/17 04:25 AM
Joined: Mar 2003
Location: Canada
Support
Offline
Support
Joined: Mar 2003
Location: Canada
Originally Posted by Norbyte
I'd say that a handle limit as low as 32k is a questionable design decision, but maybe with the original scope of the game it made sense?

D:OS became much larger than the original design, and even then no one hit the handle limit in D:OS Classic until after the issue was identified and the limit increased (as much as it could be) in the Enhanced Edition. For D:OS Classic, I have seen 2 reports of this, both with play times of 550+ hours. It was only with changes in one of the EE updates that increased the usage of handles that the limit became reachable by a great deal of crafting/trading/looting, leaving the game running and checking trading periodically, or possibly mods (added crafting, regenerating NPC inventories more frequently, etc).

Page 1 of 2 1 2

Link Copied to Clipboard
Powered by UBB.threads™ PHP Forum Software 7.7.5