Jump to content

Cam's Playthrough bugs


CamDawg

Recommended Posts

In Tyrianna's home, NPC s can not pass the stairs, resulting in her assassins never being able to succeed. While the cat no longer tries to summon guards, if the locked chest is opened it can summon guards hours/days/months after you've left.

 

Typo in William Reirrac's dialogue from the GTU.

 

Protector of the Second has no lore value, hence it always appears identified.

 

In the Asylum maze, on of the imps near the crystal is on impassable ground and can not move (basically, it's stuck in a wall).

 

// item requires lore
COPY_EXISTING ~leat03.itm~ ~override~ // protector of the second
 WRITE_SHORT 0x42 60
 BUT_ONLY_IF_IT_CHANGES

//moves imp to passable ground
COPY_EXISTING ~ar1513.are~ ~override~
 READ_LONG  0x54 "actor_off"
 READ_SHORT 0x58 "actor_num"
 FOR (index = 0; index < actor_num; index = index + 1) BEGIN
READ_ASCII ("%actor_off%" + 0x80 + ("%index%" * 0x110)) "cre_file"
PATCH_IF ("%cre_file%" STRING_COMPARE_CASE "imp01" = 0) BEGIN
  READ_SHORT("%actor_off%" + 0x20 + ("%index%" * 0x110)) "x_coord"
  READ_SHORT("%actor_off%" + 0x22 + ("%index%" * 0x110)) "y_coord"
  PATCH_IF (("%x_coord%" = 1639) AND ("%y_coord%" = 1140)) BEGIN
	WRITE_SHORT("%actor_off%" + 0x20 + ("%index%" * 0x110)) 1724
	WRITE_SHORT("%actor_off%" + 0x22 + ("%index%" * 0x110)) 1164
	WRITE_SHORT("%actor_off%" + 0x24 + ("%index%" * 0x110)) 1724
	WRITE_SHORT("%actor_off%" + 0x26 + ("%index%" * 0x110)) 1164
	SET "index" = "%actor_num%" // kill loop
  END
END
 END
 BUT_ONLY_IF_IT_CHANGES

 

I'll have to think about the best way for ctalarm.bcs to not suck.

Link to comment

You stumbled on some old bugs... Play-throughs are great for finding the more obvious bugs, but admittedly they take more time.

 

I modified my alarm scripts for containers to make them more realistic... here are some suggestions based on my working experiments of the past. Pseudo-code...

- Am I open?
 - No, do nothing.
 - Yes, can I see a neutral actor? (the container's owner/guard)
- No, do nothing. (nobody's around)
- Yes, is that actor a humanoid? (non-humanoids usually don't care)
  - No, do nothing. (just an animal, undead or monster)
  - Yes, is the person who opened me invisible somehow?
	- No, sound the alarm. (busted!)
	- Yes, do nothing. (got away clean)

I got tired of being 'seen' when nobody was around, or by the cat in that safehouse, so I decided to overhaul the scripts.

 

You could modify/delete the actor type checking. I added it to show some versatility. In the case of the safehouse, the actor type checking allows you to loot the container if the cat is the only neutral actor present.

Link to comment
I'll have to think about the best way for ctalarm.bcs to not suck.

 

Hello,

 

if it is only this one trap in Paladin-stronghold, I would suggest a special script for this trap. If all traps are mentioned here, that have this script assigned, then I have only a more complicate scripting solution... :).

 

This script is used in my game on 69 traps (so said my NI). For only one trap, I would rename it and set an area-global, so that it would only call the enfoarm.cre once.

 

example:

rename it to ctpala.bcs (or something) and assign the followed to it.

 

IF

Opened([ANYONE])

!StateCheck(LastTrigger,STATE_INVISIBLE)

!StateCheck(LastTrigger,STATE_IMPROVEDINVISIBILITY)

Global("TrapDisarmed","ARXXXX",0)

THEN

RESPONSE #100

SetGlobal("TrapDisarmed","ARXXXX",1)

CreateCreature("ENFORAM",[-1.-1],0) // No such index

END

 

IF

True()

THEN

RESPONSE #100

NoAction()

END

 

If all traps are mentioned, I would have set them one Global and script all other into the arxxxx.bcs, because there are unfortunatly often more than one trap with this script in one area... But it would take much more work though... :)

 

Regards

 

Roana

Link to comment

Really, the only issue that needs to be addressed with the trap is the time element. I had burgled the house (the cat sounding the alarm is fixed already); when I went there a week later during the paladin stronghold quests (woo, go multi strongholds) Tyrianna's NORH guard sounded the alarm.

Link to comment
ENFORAM sticks around longer than it should. Just delete the Wait() before it destroys itself.

 

Hello :D,

 

I have made a little research in my old BG1-trap-fixes, and after reading additional once more this point in Sim's scripting guide, I have found an easy solution (silly me, not to look first in this guide :D ).

 

change the last block in ENFORAM.BCS as followed:

 

IF

OR(2)

!See([NOTGOOD.HUMANOID])

Global("warn","LOCALS",1)

THEN

RESPONSE #100

Wait(5)

DestroySelf()

END

 

The original trigger !See([NOTGOOD]) includes the cat that is there in the AR0415, and so the ENFORAM.CRE will never disappear, as it sees "NOTGOOD" - the cat ;)

 

Regards

 

Roana

Link to comment

Yeah, fixed. The Wait(5) should remain as it gives a slight window for folks to notice you. If someone came around a corner 3 seconds after you opened the locked chest, I think they could put two and two together.

 

// containers can summon guards days after they're open
COPY_EXISTING ~enforam.bcs~ ~override~
 DECOMPILE_BCS_TO_BAF
REPLACE_TEXTUALLY ~!See(\[NOTGOOD\])~ ~!See([NEUTRAL.HUMANOID])~
 COMPILE_BAF_TO_BCS
 BUT_ONLY_IF_IT_CHANGES

Link to comment

Actually, no. This would still have the problem of enforam.cre sticking around if the PC was invisible or dead. Basically, if it's not summoning guards, we want enforam.cre to wait five seconds and disappear. Since the second block will only get evaluated if the first is false, then we can be exceptionally lazy and just make it a True() block:

 

// containers can summon guards days after they're open
COPY_EXISTING ~enforam.bcs~ ~override~
 DECOMPILE_BCS_TO_BAF
REPLACE_TEXTUALLY ~OR(2)[%tab% %lnl%%mnl%%wnl%]+!See([NOTGOOD])[%tab% %lnl%%mnl%%wnl%]+Global("warn","LOCALS",1)~ ~True()~
 COMPILE_BAF_TO_BCS
 BUT_ONLY_IF_IT_CHANGES

 

Or would this keep resetting the Wait()?

Link to comment

It shouldn't reset the Wait(). Actions from the same block shouldn't get added to the queue and don't interrupt it (however the engine decides it's at the same block in a script that it's currently executing). You can use ActionListEmpty() in place of True() if you want to be super sure.

 

My concern is with the outstanding bug where BD reports they can be summoned if you leave and come back. The assumption is that if you leave the area while ENFORAM is waiting, it won't execute its DestroySelf(), and processing will start over if you return to the area (and this time, you'll probably be visible or the active actors might have changed).

 

We might be able to get away with a LOCALS timer and have it DestroySelf() at the head of the script if the timer's expired, but the triggers to get everything working together with only 3 blocks might suck (but I don't have access to the original script at the moment).

 

Maybe:

IF
OnCreation()
THEN
RESPONSE #100
SetGlobalTimer()
Continue()
END

IF
Stuff()
GlobalTimerNotExpired()
THEN
RESPONSE #100
Caught()
END

IF
GlobalTimerExpired()
THEN
RESPONSE #100
DestroySelf()
END

?

Link to comment
Actually, no. This would still have the problem of enforam.cre sticking around if the PC was invisible or dead. Basically, if it's not summoning guards, we want enforam.cre to wait five seconds and disappear. Since the second block will only get evaluated if the first is false, then we can be exceptionally lazy and just make it a True() block:

 

// containers can summon guards days after they're open
COPY_EXISTING ~enforam.bcs~ ~override~
 DECOMPILE_BCS_TO_BAF
REPLACE_TEXTUALLY ~OR(2)[%tab% %lnl%%mnl%%wnl%]+!See([NOTGOOD])[%tab% %lnl%%mnl%%wnl%]+Global("warn","LOCALS",1)~ ~True()~
 COMPILE_BAF_TO_BCS
 BUT_ONLY_IF_IT_CHANGES

 

Or would this keep resetting the Wait()?

 

Hello,

 

well, maybe, I should claerify this more :D:

 

Here are TWO scripts involved:

 

the script on the trap itself (CTALARM.BCS):

 

IF

Opened([ANYONE])

!StateCheck(LastTrigger,STATE_INVISIBLE)

!StateCheck(LastTrigger,STATE_IMPROVEDINVISIBILITY)

THEN

RESPONSE #100

CreateCreature("ENFORAM",[-1.-1],0) // No such index

END

 

IF

True()

THEN

RESPONSE #100

NoAction()

END

 

This will ONLY spawn the ENFOARM.CRE, if the PC IS VISIVLE

 

and the second script: the script on the spawned ENFOARM.CRE (ENFOARM.BCS):

 

IF

See([PC])

See([NEUTRAL.HUMANOID])

!Dead("LastSeenBy(Myself)")

Global("warn","LOCALS",0)

THEN

RESPONSE #50

SetInterrupt(FALSE)

SetGlobal("warn","LOCALS",1)

DisplayStringHead(LastSeenBy(Myself),58585) // Diebe!

DisplayStringHead(Myself,9896) // Jemand hat Euch bemerkt! Ihr hört, wie die Wache gerufen wird!

ActionOverride(LastSeenBy(Myself),Enemy())

Wait(3)

CreateCreatureObject("AMNCEN1",Myself,0,0,0) // Amnischer Zenturion

CreateCreatureObject("AMNLEG1",Myself,0,0,0) // Amnischer Legionär

CreateCreatureObject("AMNLEG1",Myself,0,0,0) // Amnischer Legionär

CreateCreatureObject("AMNLEG1",Myself,0,0,0) // Amnischer Legionär

CreateCreatureObject("AMNLEG1",Myself,0,0,0) // Amnischer Legionär

CreateCreatureObject("COWENF1",Myself,0,0,0) // Verhüllter Vollstrecker

CreateCreatureObject("COWENF1",Myself,0,0,0) // Verhüllter Vollstrecker

SetInterrupt(TRUE)

RESPONSE #30

SetInterrupt(FALSE)

SetGlobal("warn","LOCALS",1)

DisplayStringHead(LastSeenBy(Myself),58585) // Diebe!

DisplayStringHead(Myself,9896) // Jemand hat Euch bemerkt! Ihr hört, wie die Wache gerufen wird!

ActionOverride(LastSeenBy(Myself),Enemy())

Wait(3)

CreateCreatureObject("AMNLEG1",Myself,0,0,0) // Amnischer Legionär

CreateCreatureObject("AMNLEG1",Myself,0,0,0) // Amnischer Legionär

SetInterrupt(TRUE)

RESPONSE #30

SetInterrupt(FALSE)

SetGlobal("warn","LOCALS",1)

DisplayStringHead(LastSeenBy(Myself),58585) // Diebe!

DisplayStringHead(Myself,9896) // Jemand hat Euch bemerkt! Ihr hört, wie die Wache gerufen wird!

ActionOverride(LastSeenBy(Myself),Enemy())

Wait(3)

CreateCreatureObject("AMNCEN1",Myself,0,0,0) // Amnischer Zenturion

CreateCreatureObject("COWENF1",Myself,0,0,0) // Verhüllter Vollstrecker

SetInterrupt(TRUE)

RESPONSE #10

SetInterrupt(FALSE)

SetGlobal("warn","LOCALS",1)

DisplayStringHead(LastSeenBy(Myself),58585) // Diebe!

DisplayStringHead(Myself,9896) // Jemand hat Euch bemerkt! Ihr hört, wie die Wache gerufen wird!

ActionOverride(LastSeenBy(Myself),Enemy())

Wait(3)

CreateCreatureObject("AMNCEN1",Myself,0,0,0) // Amnischer Zenturion

CreateCreatureObject("AMNCEN1",Myself,0,0,0) // Amnischer Zenturion

CreateCreatureObject("AMNCEN1",Myself,0,0,0) // Amnischer Zenturion

CreateCreatureObject("AMNLEG1",Myself,0,0,0) // Amnischer Legionär

CreateCreatureObject("AMNLEG1",Myself,0,0,0) // Amnischer Legionär

CreateCreatureObject("AMNLEG1",Myself,0,0,0) // Amnischer Legionär

CreateCreatureObject("COWENF1",Myself,0,0,0) // Verhüllter Vollstrecker

CreateCreatureObject("COWENF1",Myself,0,0,0) // Verhüllter Vollstrecker

CreateCreatureObject("COWENF1",Myself,0,0,0) // Verhüllter Vollstrecker

SetInterrupt(TRUE)

END

 

IF

OR(2)

!See([NOTGOOD.HUMANOID])

Global("warn","LOCALS",1)

THEN

RESPONSE #100

Wait(5)

DestroySelf()

END

 

This will either spawn the guards, if the creature sees NOTGOOD and THEN set the LOCALS to 1 OR DestroySelf, if it not sees NOTGOOD or has already spawned guards after 5 seconds.

 

Well, while this creature only will be spawned, if the PC is visible, you don't need to exclude unvisible PC from the script of the (in this case not existing) ENFOARM.CRE. But if this creature IS ALREADY there, spawned by the CTALARM.BCS, then it will ONLY be destroyed, if it has done the job to spawn the guards, or if it not sees any NOTGOOD creature, as it is in the original. But a NOTGOOD creature is also a cat, so you have only to specify, that it should be a HUMANOID too, or NOTGOOD will ever return true, if a cat is running around ;)

 

I know, that this is more complicate, as it was in BG1, because in BG1 all this is bounded in one script, that is assigned on the trap. In BG1 the trap-script will on condition OPENED not only check the invisible STATE of the PC, but additional the See NOTGOOD in the same block. If this block returned true, this first and only script also calls the guards. There I have had only to fix the ACTXX.BCSs to check not only for NOTGOOD, but for NOTGOOD.HUMANOID, so that cats, running alone there in a room, don't call guards ;)

 

Hm... - well, I know, it IS more complicate in BG2 as in BG1, and additional once more complicate to explain this. I hope, this all sounds not too confusing to you ;)

 

Otherwise, please try to trust me this one time, fix this, as I have said above and test it - I promise, it will fix the cat-problem (I know, I'm only a woman, but even not a normal woman in logical-thinking, and scripting is my favorite pleasure in the BG-games - I know, I make also faults, but this time I'm really very sure, I'm right) :D

 

Regards

 

Roana

 

(I have not written some words in capital letters to cry at you, only to try, to make something more clear)

Link to comment
We might be able to get away with a LOCALS timer and have it DestroySelf() at the head of the script if the timer's expired, but the triggers to get everything working together with only 3 blocks might suck (but I don't have access to the original script at the moment).

I was thinking something a little different--instead of that final True() block containing the DestroySelf, have it set the timer instead. Then DestroySelf() when the timer ends, i.e.

 

IF timer expired THEN destroySelf END

IF thief gets caught (existing block, no change) THEN create guards END

IF true THEN set timer END

 

Add a variable to make sure the last block doesn't repeat, and we've got it. Since the second block already has a no-repeat variable the timer always gets set on either the first or second pass of the script and the guards never get summoned on an expired timer.

Link to comment

Except that you'll set the timer forever and ever and ever, it looks like it'll work the same. I just didn't want to suggest a method that both creates a new variable (set timer once) and then the timer itself. Data overload!

 

But yeah, that's my current thought without looking at the script. (We should probably look at ALARM25 too.)

Link to comment

@Roana:

See([NEUTRAL.HUMANOID])
...
!See([NOTGOOD.HUMANOID])

I presume you mean [NOTGOOD.HUMANOID] on the second one. ;)

 

Even so, while it works in this case, I prefer scripts to be self-contained. A modder may create a mod that uses enforam.cre without going through ctalarm.bcs. Given the choice between a fix that applies to one case or several, I'll take the latter.

Link to comment
Except that you'll set the timer forever and ever and ever, it looks like it'll work the same.
Add a variable to make sure the last block doesn't repeat, and we've got it.

 

I know you want a way that doesn't invoke a second variable, but I'm also trying to imagine the easiest patching path. Looking at our stuff though, I think it's probably about the same--some R_Ts and an EXTEND_TOP all told. ;)

Link to comment
@Roana:

See([NEUTRAL.HUMANOID])
...
!See([NOTGOOD.HUMANOID])

I presume you mean [NOTGOOD.HUMANOID] on the second one. ;)

 

Even so, while it works in this case, I prefer scripts to be self-contained. A modder may create a mod that uses enforam.cre without going through ctalarm.bcs. Given the choice between a fix that applies to one case or several, I'll take the latter.

 

Hello :D,

 

yes, I mean the second, cause the first is already in the original script :D

 

Well, if you want to include non-visible PC here too, the append after block:

 

IF

OR(2)

!See([NOTGOOD.HUMANOID])

Global("warn","LOCALS",1)

THEN

RESPONSE #100

Wait(5)

DestroySelf()

END

 

this:

 

IF

OR(2)

!See([PC])

Global("warn","LOCALS",1)

THEN

RESPONSE #100

Wait(5)

DestroySelf()

END

 

The timer, you want is done by the Wait(5) action ;)

 

Regards

 

Roana

 

Edited: translation fault

Link to comment

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...