Another bug list!
Hey killap,
Sorry for the delay in this list. Depending on the complexity, it may be advisable to move some of these fixes to a Unofficial Patch 1.3a (or whatever).
-- The Haen.
====================
The Den
1. A few more typos to fix in dcVic.msg:
-> Line 167: "This darn radio isn't going to repair it's self." should read "This darn radio isn't going to repair itself."
-> Line 501: "I got'm from Ed. A brahmin dealer over in Vault City." should read "I got'm from Ed, a brahmin dealer over in Vault City.
-> Line 601: "I mean it STOP IT!" should read "I mean it! STOP IT!" (You could also insert a period instead of an exclamation mark, but I feel that the latter is more thematically consistent.)
-> Line 710: "ruff" should be "rough"
-> Line 832: The last sentence in Line 832 currently reads: "I haven't had her home cooking on a long time." This should be "I haven't had her home cooking for a long time."
-> Line 840: "to far" should be "too far".
-> Line 1500: "What ever you say, Boss." should be "Whatever you say, Boss."
-> Line 2809: Extra space before the word "honest."
-> Line 3200, 3300: Insert comma after the word "actually".
-> Line 4202: "Did you smell something, Boss?" should read "Do you smell something, Boss?" (more idiomatically accurate to use "Do" instead of "Did".)
-> Lines 4502, 4506, 4514: Remove unncessary period after the ellipsis.
-> Line 4505: "The Boss, sure wouldn't leave me behind…." should be "The Boss sure wouldn't leave me behind…" (Note that two elements are removed: the extra comma after "Boss", and the unnecessary period after the ellipsis)
-> Line 4700: "Not to much, Boss." should be "Not too much, Boss."
NCR
1. If you successfully lower a force field and then try to raise it back up but fail, you get the message "You fail to lower the force field." However, since all NCR emitter scripts use the msg file for the SAD emitter scripts, implementing the fix I suggested in the SAD section (see below) should fix this issue as well.
2. If you use a tool (or, thanks to your fixes, a super tool kit) to temporarily disable an emitter, a skill roll is made against your science skill. The roll should probably be made against your repair skill instead. Note that this is an "original bug" all the way from v1.02D of the scripts. As in the case with the emitter scripts in the SAD, all emitter scripts in the NCR will need to be corrected.
3. Again, similarly to the SAD emitters, using the super tool kit to disable emitters offers no bonus at all compared to using the tool. Judging by the benefits given by other "extended" toolsets such as extended lockpicks, the bonus given to the super tool kit should be twice that of the tool. In other words, the bonus given to super tool kits should be a +40 compared to the tool's +20 modifier.
4. Almost none of the doors have scripts attached to them. Given the so-called too many objects bug caused by the presence of too many scripts, it may be a good idea to leave this one alone.
5. You can shoot through the northeast corner of the Saloon outside of NCR. The problem is tile 21341. Tile 21341 is occupied only by a Bar scenery object (i.e. if you move the bar, there will be a gaping hole which, while not visible in-game, allows the player to magically walk through the wall), which is by default both Light Thru and Shoot Thru. Placing a wall blocker on the same tile should do the trick, as does setting the bar object's Shoot Thru flag to NO.
San Francisco
1. If you successfully lower a force field and then try to raise it back up but fail, you get the message "You fail to lower the force field." However, since all San Francisco emitter scripts use the msg file for the SAD emitter scripts, implementing the fix I suggested in the SAD section (see below) should fix this issue as well.
2. If you use a tool (or, thanks to your fixes, a super tool kit) to temporarily disable an emitter, a skill roll is made against your science skill. The roll should probably be made against your repair skill instead. Note that this is an "original bug" all the way from v1.02D of the scripts. As in the case with the emitter scripts in the SAD, all emitter scripts in San Francisco will need to be corrected.
3. Almost none of the doors have scripts attached to them. Given the so-called too many objects bug caused by the presence of too many scripts, it may be a good idea to leave this one alone.
4. When entering town for the first time, moving the the Dragon/Lo Pan after fight scene can move them on top of wandering peasant -- so you get the effect of one critter occupying the same tile as another. I'm not sure if the wandering peasant is stuck there forever -- or at least until you decide to challenge the Dragon/Lo Pan to a fight!
There are several possible solutions to this. Perhaps the easiest fix is to place blocking hexes on Lo Pan's and the Dragon's home tile on the initial map, and then remove the blockers just prior to moving Lo Pan and the Dragon back into their respective places.
5. You can walk on the shadows under the pier on the eastern side of the pier map, resulting in some pretty interesting graphical effects as you and your party seemingly walk on both the upper level of the pier and the lower level at the same time. To test this, go the pier in San Francisco, head to the eastern part of the map, take the stairs down to the beach, and then try walking on the shadows cast by the upper pier. Fortunately, this problem is easily solved: placing a blocking hex on tile 26871 should do the trick.
6. On the Pier map, there is a single tent located on the beaches. In it are a couple of beds plus a bowl (with a pestle). Thanks to a lack of blocking hexes, you and your party can walk over the bowl, and over most of the two beds (oops). Several strategically placed blocking hexes should fix the problem.
7. The next few items document several issues and inconsistencies with Ken Lee, mostly due to major weaknesses in design and in dialog structure. I will list them one by one and then suggest a possible unified solution at the end of my listing.
It is possible to get Ken Lee to both grant you access to the Emperor computer and then claim that you can't have access to it (unless you perform a task) at the same time. Here's how to get the Emperor's spokesman to contradict himself: 1) Before speaking with Ken, learn about the tanker needing fuel. 2) Speak to Ken and ask for fuel right away. 3) If you pass an admittedly difficult speech check, then Ken will grant you access to the Emperor computer right away. 4) Exit the dialog then talk to Ken Lee again. 5) Pick the lines "Who are you?", then "I'd like to see the Emperor." 6) Give Ken your real name when he asks for it. 7) Ken will say you need to fulfill a task before you can see the emperor! Seems like Ken forgot he gave you permission already. Luckily for you, you still have valid access to the Emperor computer, so you don't have to do anything more for the Shi if that is your choice.
8. Even if Ken Lee tells you that you must get the Vertibird plans for the Shi before meeting the Emperor, you can weasel your way out of the responsibility. Here's how to do it: 1) Talk to Ken Lee, and get the quest to obtain the Vertibird plans for the Shi. 2) Go and kill the AHS-9 in any way you want (super-stimpak, massacre the Hubologists, one-shot sneak-kill, etc.) 3) Return and talk to Ken Lee, and he'll somehow magically know of your deed and grant you immediate access to the Emperor. Note that you will be granted access to the Emperor even though you haven't yet retrieved the plans (oops). This scenario only really makes sense if you killed the AHS-9 before you have ever spoken to Ken Lee. But if the player actually does this (i.e. off AHS-9 before talking to Ken), then he or she will never be able to get the quest to retrieve the Vertibird plans for the Shi. It is tough to say whether or not this is the developers' original intent. But my guess is that it isn't.
9. If you turn the Shi hostile, but somehow manage to sneak into dialog range with Ken Lee without triggering combat -- one way this can be easily done is by disabling the force field leading to the Emperor computer without proper authorization, and then entering sneak mode and going back to Ken Lee -- you get the dialog "Go on", while displaying the last dialog from ANY critter. This is similar to the bug with Franc from Broken Hills I discovered in one of my previous bug lists, and has a similar cause: a node to a floater is being initialized using the start_gdialog function, and the engine doesn't quite like it. The fix is to avoid calling start_gdialog and its associated commands in this scenario.
10. When you talk to Ken and ask him about your lost tribe, he'll claim that he knows nothing about the matter, and that the Emperor might know about it. You then get an option to ask him more questions, or to say "Thanks. I'll do that." and leave the dialog. This, of course, does not make sense, given that Ken hasn't actually told you to do anything. The fix is to change the corresponding line (line 169) in the .msg file to something more appropriate, such as: "I see. Thanks for your time." No other dialogue nodes in Ken Lee's script file use line 169, so it should be safe to change.
11. One final problem to address: After the player has successfully killed AHS-9 and returned to Ken, he will rightfully congratulate the player for the player's success, and then ask if the player wants to speak with the Emperor. The option to answer "No" was commented out in the script file -- probably because Node001 as it currently stands isn't really able to handle the dialog changes necessary to reflect AHS-9's demise -- and so the player has to answer "Yes", unless the player is stupid, in which case they reply "Err..." and exit the dialog without getting anything (another minor bug). This is fine as it goes. The problem is that Ken asks the player the same question again and again on each subsequent conversation! Ideally, Ken should not need to bring up the topic again once the player has been given the secret to accessing the Emperor. The fix to this latter problem is easy -- modify the conditional slightly for bringing up Node030 -- but the true issue is to somehow fix Node001 and Node030 to properly process the state where the player has been granted access to Emperor, and the state where the player has done enough to be granted access to the Emperor, but for whatever reason has chosen not to uncover the secret yet.
Now that all of the problems have been listed, a unified solution may be suggested. That said, a 'fix' for most of these issues is problematic, since the general weakness of the dialog in San Francisco leaves us questioning exactly what the original developers' intent was. Did the developers want the player to be able to get the quest to retrieve the Vertibird plans for the Shi regardless of whether or not they have access to the Emperor? Or did they want the player to have an "all-or-nothing" approach in getting access to the Emperor (i.e. either the player passes a speech check, or else he or she has to perform the two tasks for the Shi in order to get access)? Did the developers really intend for killing the AHS-9 to be the single necessary and sufficient condition in being granted access to the Emperor? Did they really intend for players to be able to talk their way to the Emperor without doing the two quests (strong arguments can be made either way here, judging by dialog structure)?
In the fix I had suggested below, I assumed that if the player passes the speech check, then he or she will never be able to get the two quests from the Shi (unless if for some reason they are already active). Otherwise, BOTH quests have to be done before access is granted. Also, killing the AHS-9 before ever speaking with Ken Lee is good enough to grant the player access to the Emperor, but not if the player has already started to prove himself or herself with the Vertibird plans quest. Finally, once the player has been granted access to the Emperor computer, Ken Lee will never bring up the issue again. With that in mind, we can make the following changes:
Code:
procedure talk_p_proc begin
Evil_Critter:=0;
Slavery_Tolerant:=SLAVE_INTOLERANT;
Karma_Perception:=KARMA_PERCEPTION4;
CheckKarma;
GetReaction;
if (local_var(LVAR_Pissed) == 0) then begin
if (san_fran_flag(SF_SHI_ENEMY)) then begin
call Node026;
end else if (local_var(LVAR_State) == STATE_INSULTED) then begin
call Node036;
end else if (local_var(LVAR_State) == STATE_NONAME) then begin
start_gdialog(NAME,self_obj,4,-1,-1);
gSay_Start;
call Node037;
gSay_End;
end_dialogue;
end else if (san_fran_flag(SF_OZ9_DEAD) and not san_fran_flag(SF_LEE_OK_FUEL_TANKER) and not (SHI_WANT_PLANS) and dude_iq > 3) then begin
start_gdialog(NAME,self_obj,4,-1,-1);
gSay_Start;
call Node030;
gSay_End;
end_dialogue;
end else if (struggle_flag(STRUG_SHIRECRUIT)) then begin
call Node038;
end else if (elron_whirly(EL_WH_GIVEN) and shi_whirly(SH_WH_ACCEPTED)) then begin
start_gdialog(NAME,self_obj,4,-1,-1);
gSay_Start;
call Node033;
gSay_End;
end_dialogue;
end else if (shi_whirly(SH_WH_GIVEN)) then begin
start_gdialog(NAME,self_obj,4,-1,-1);
gSay_Start;
call Node034;
gSay_End;
end_dialogue;
end else if (shi_whirly(SH_WH_ACCEPTED) or shi_whirly(SH_WH_STEALELE)) then begin
start_gdialog(NAME,self_obj,4,-1,-1);
gSay_Start;
call Node035;
gSay_End;
end_dialogue;
end else if (shi_whirly(SH_WH_REJECTED)) then begin
start_gdialog(NAME,self_obj,4,-1,-1);
gSay_Start;
call Node018;
gSay_End;
end_dialogue;
end else begin
start_gdialog(NAME,self_obj,4,-1,-1);
gSay_Start;
call Node001;
gSay_End;
end_dialogue;
end
end else begin
call doGuardsMessage;
end
if (callGuards == 1) then begin
callGuards := 0;
set_local_var(LVAR_Pissed, 1);
add_timer_event(self_obj, 0, TIMER_CHECK_DIST);
end
if (turnFieldOff == 1) then begin
turnFieldOff := 0;
set_san_fran_flag(SF_EMPEROR_FIELD_OFF);
end
set_local_var(LVAR_Herebefore, 1);
end
procedure Node001 begin
if (good_critter_reaction) then begin
Reply(103);
end else if (neutral_critter_reaction) then begin
Reply(105);
end else begin
Reply(104); // bad or horrible
end
NLowOption(106, Node234, 4);
if (local_var(LVAR_N5_cnt) == 0 and not san_fran_flag(SF_LEE_OK_FUEL_TANKER)) then
NOption(107, Node005, 4);
NOption(108, Node006, 4);
if (Fallout2_tribe_kidnapped) then
NOption(109, Node019, 4);
if (tanker_flag(TANK_KNOWN) and not local_var(LVAR_Speech_Failed)) then
NOption(110, Node2539, 4);
if (local_var(LVAR_Herebefore) != 0 and not san_fran_flag(SF_LEE_OK_FUEL_TANKER)) then
NOption(111, Node203108, 4);
if (struggle_flag(STRUG_ELRECRUIT)) then
NOption(112, Node027, 4);
NOption(113, Node999, 4);
end
procedure Node030 begin
set_struggle_flag(STRUG_DONE);
COMPLETE_KILL_OZ9_QST
Reply(194);
NOption(195, Node031, 4);
NOption(196, Node001, 4); // Uncommented this line since Node001 is "fixed"
end
In the above, I'm assuming that you changed the conditional Fallout2_tribe_kidnapped directly in the header files. Of course, if you interpret the original developers' intent to be something different, then the above will need to be re-adjusted accordingly.
12. If the player asks to see the Emperor, then if Ken likes the player, he's suppose to give the player some tasks to prove their worthiness to see the Emperor (Node008). Otherwise, if Ken doesn't like the player, he's supposed to categorically deny the player access to the Emperor (Node009). Unfortunately, this doesn't quite work out, because the procedure doing the checking, Node89, is called only once in the entire script (Node005). All other places in the script calls Node008 directly, thus bypassing the Node89 check even if Ken happens to dislike the player.
The obvious fix therefore is to change all direct calls to Node008 to Node89. The following nodes in fcKenLee.ssl will need this change: Node203108, Node007, Node014, Node016, and Node008a.
13. This is a more generic bug dating all the way back from the Original 1.0 version that affects more than just Ken Lee, though I first observed it in his script. In Node001, Node234, and Node89, the script determines if Ken likes the player before issuing a suitable reply. Unfortunately, this doesn't quite pan out the way the developers intended it to. The macro good_critter_reaction checks if LVAR_Reaction_Level is greater than or equal to REACTION_LEVEL_GOOD, which is valued at 2. The macro neutral_critter_reaction checks if LVAR_Reaction_Level is equal to REACTION_LEVEL_NEUTRAL, which is equal to 0. This means that the case where LVAR_Reaction_Level is equal to 1 (REACTION_LEVEL_DECENT) falls through the cracks entirely, and is treated by Ken Lee as if the player had a bad or horrible reaction level. It should also be noted that REACTION_LEVEL_POOR (value of -1) would also be incorrectly processed, though the way this particular script is set up precludes this from happening.
The fix is to go to MODREACT.H and change the macro neutral_critter_reaction to something more reasonable, such as:
Code:
#define neutral_critter_reaction ((local_var(LVAR_reaction_level) <= REACTION_LEVEL_DECENT and local_var(LVAR_reaction_level) >= REACTION_LEVEL_POOR))
This will also fix the other three scripts in the game using this macro under similar circumstances (HCPHIL.SSL, HCSTEVE.SSL, SCRAWPAT.SSL), thus also incorrectly missing out on the REACTION_LEVEL_DECENT and REACTION_LEVEL_POOR. Needless to say, all four of these scripts will need to be re-compiled for the changes to take effect.
14. This is perhaps a subjective bug, more suitable for the RP, but I'll let you be the judge. Basically, the biology, chemistry, and physics terminals found in the Shi HQ do not behave consistently across the board. Each terminal begins in a deactivated state, and all three needs to be activated, and the password guessed/hacked, before the player can access the information contained therein. However, whereas the Chemistry station allows the player to either Log Out or Deactivate the workstation, both the Biology and the Physics terminals only give the player the option to Deactivate the station. Moreover, if the player leaves the workstation in an activated state (i.e. activate the station, but Log Out without hacking or guessing the password), both the Biology and Chemistry terminals will remember that they are activated, but the Physics workstation behaves as if it was never activated in the first place! Also, the text is slightly different -- all things being equal, the login and activation text should be the same, though this is admittedly subjective. I'll leave this last detail for you to decide.
Fixing the inconsistency requires determining what the developers originally intended, which is difficult in this case. In suggesting the fixes below, I assume that the Chemistry station is working perfectly. A rather large reason why I did this is that making this assumption means we fix only two scripts instead of three, and I am lazy.
At any rate, assuming the Chemistry station is perfects means that 1) All stations start out deactivated. 2) Activated stations remain activated. 3) Players should have the option of either Logging Out or Deactivating the workstation when they are done.
For the Biology station, all that is needed is a Log Out option at the root menu. This is done by changing procedure Node002, as thus:
Code:
procedure Node002 begin
Reply(109);
NOption(110, Node005, 1);
NOption(111, Node006, 1);
NOption(112, Node007, 1);
NOption(113, Node008, 1);
NOption(114, Node009a, 1);
NOption(108, Node999, 1);
end
Changes to the Physics station are a bit more involved. The reason why the station always remain in a deactivated state is because the flag used to indicate an activated state (SF_EMP_ROOM_PHY) is for some odd reason never set anywhere in the script. For that matter, this flag is never unset either, unless the player attempts to copy the vertibird plans.
Therefore, in this script, we need to both set the flag, add a Log Out option to the root menu, and finally modify the Deactivate option in the root menu to unset the flag. To do this, we need to modify both Node001 and Node002, and add a new procedure Node008a in between the two procedures (similar to how it is set up in the other two stations). So something like the following:
Code:
procedure Node001 begin
set_san_fran_flag(SF_EMP_ROOM_PHY);
Reply(103);
NLowOption(104, Node999);
NOption(105, NodeGuess, 4);
if (dude_item(PASSWORD_PAPERS_PID)) then begin
NOption(106, Node002, 4);
end
NOption(107, NodeHack, 4);
NOption(108, Node999, 4);
end
procedure Node008a begin
unset_san_fran_flag(SF_EMP_ROOM_PHY);
call Node008;
end
procedure Node002 begin
Reply(109);
NOption(110, Node56, 4);
NOption(111, Node007, 4);
NOption(112, Node008a, 4);
NOption(108, Node999, 4);
end
15. When you browse through the various entries in the Shi workstations, the game realistically advances time to reflect the fact that your character has spent some time searching through the archives -- there are a few exceptions in the Biology and Physics stations, but the contents of those entries make it very clear that the player has only one short note to read, so advancing time in those cases is unnecessary. However, for some reason, the Polymers entry under the Chemistry workstation does not advance time at all, even though your character "wades" past symbology and technical discussion in order to understand what's going on. To be consistent, a delay of 15 minutes should be attached to this entry (similar to the other Chemistry entry). To do this, modify Node006 in fsCheSta.ssl as thus:
Code:
procedure Node006 begin
game_time_advance(ONE_GAME_MINUTE * 15);
Reply(123);
NOption(124, Node002, 1);
end
16. Similar to the bug in the Chemistry station above, there is one entry in the Physics terminal that should advance time, but doesn't. Advancing time by 20 minutes in Node007 of fsPhySta.ssl ought to do the trick, as thus:
Code:
procedure Node007 begin
game_time_advance(ONE_GAME_MINUTE * 20);
Reply(123);
NOption(124, Node002, 4);
end
17. The lack of time delay is also discovered when browsing the same physics and chemistry entries via the Emperor computer. The solution is to modify Node019 and Node025 in fsEmpTer.ssl, as thus:
Code:
procedure Node019 begin
game_time_advance(ONE_GAME_MINUTE * 15);
Reply(195);
NOption(196, Node017, 4);
end
procedure Node025 begin
game_time_advance(ONE_GAME_MINUTE * 20);
Reply(210);
NOption(211, Node022, 4);
end
18. The next few bugs are all about our resident spleenless wonder: Chip. There are several issues associated with Chip, of which this one is arguably the most interesting, dating all the way back to the at least the Official v1.02D Patch, maybe even in the Original v1.0. To reproduce the problem: Talk to Chip and help him to resolve his spleen problem. After he has been cured, watch him walk back to his home tile. Say hi to Chip, and note that his dialog has updated to reflect his better health and mood. Now, walk out of the tanker after interacting with Chip, and then walk back in again to greet him...but wait, he has disappeared for good! Hmmm...
The problem is found in the procedure CheckLoad. The code in procedure CheckLoad is only executed if LVAR_Return_Time is set to some value, and the latter only occurs once the player positively resolves spleen quest and Chip makes his way to Dr. Fung. Unfortunately, since LVAR_Return_Time is never reset, this means that once Chip starts his visit Dr. Fung, the code in procedure CheckLoad is run every single time -- even after Chip is cured and feeling better. This is an issue because CheckLoad is set to make Chip visible only after the game time has a greater value than LVAR_Return_Time
and the spleen is not marked as re-inserted into Chip, or else turn him invisible. The only time this conditional is true is after Chip finishes visiting Dr. Fung, and processing takes place to walk Chip back to his home tile and mark his spleen as re-inserted. After that, however, LVAR_Return_Time is still less than game time, but the spleen is no longer not re-inserted, making the conditional false. So CheckLoad turns Chip invisible, and since the conditional will never become true again, Chip is effectively invisible for the rest of the game.
There are several relatively simple ways to fix this bug. Reseting LVAR_Return_Time back to zero one option. Or else, check for the presence of the reinserted spleen before making Chip invisible, as thus:
Code:
procedure CheckLoad begin
debug_msg("FCCHIP: CHECKLOAD lvar_return_time: " + local_var(LVAR_Return_Time));
if (local_var(LVAR_Return_Time)) then begin
if (game_time >= local_var(LVAR_Return_Time) and not spleen_flag(SP_REINSERTED)) then begin
set_obj_visibility(self_obj, OBJ_VIS);
set_spleen_flag(SP_REINSERTED);
COMP_QUEST(REP_BONUS_SAN_FRAN_SPLEEN_REINSERTED, REP_HERO_SAN_FRAN_SPLEEN_REINSTERTED, EXP_SPLEEN_REINSTERTED);
add_timer_event(self_obj, 0, TIMER_WALK_ON);
end else if (not spleen_flag(SP_REINSERTED)) then begin
set_obj_visibility(self_obj, OBJ_INVIS);
debug_msg("FCCHIP: invis 2");
add_timer_event(self_obj, game_ticks(60), TIMER_CHECK_LOAD);
end
end
end
19. Another bug with Chip, but fortunately, this one is minor: after Chip is cured, he walks back to his home tile...and decides to stare at the wall for the rest of the game -- or at least, before you decide to walk out of the tanker and make him invisible (see previous bug). The simple solution is to call the animate_rotation macro under the timer event TIMER_WALK_ON after he has walked back to his home tile, as thus:
Code:
end else if (fixed_param == TIMER_WALK_ON) then begin
if (self_tile != CHIP_LOAD_TILE and not anim_busy(self_obj)) then begin
debug_msg("FCCHIP: should be walking to load tile");
if (not self_visible) then begin
set_obj_visibility(self_obj, OBJ_VIS);
end
reg_anim_clear(self_obj);
reg_anim_begin();
animate_move_to_tile(CHIP_LOAD_TILE);
reg_anim_end();
add_timer_event(self_obj, game_ticks(1), TIMER_WALK_ON);
end else if (self_tile != CHIP_LOAD_TILE and anim_busy(self_obj)) then begin
add_timer_event(self_obj, game_ticks(1), TIMER_WALK_ON);
end else if (self_tile == CHIP_LOAD_TILE) then begin
animate_rotation(3);
end
end
20. A final Chip bug report: If you have to pay Dr. Fung in order for him to operate on Chip, and you tell Chip the news, Chip will very sensibly start walking his way to the doctor's place. And if you should try to engage Chip in conversation as he is walking away, you get a float message saying: "Thanks for all your help, buddy." However, if you should be lucky enough to engage Dr. Fung's services for free, and you tell Chip about the news, you can still engage Chip in a full conversation while he's walking away! All things being equal, one would expect the float message to also show up under this scenario.
The reason for this bug is due to states not being set. More specifically, paying for Dr. Fung's services sets the spleen quest to state SP_CHIPTOLD, which in turn triggers the float message on dialog. But for some reason, when Dr. Fung's services are free, the state SP_CHIPTOLD is not being set -- in fact, for some strange reason, an entirely different part of the script is being run, though both branches of the script ultimately end up doing the exact same thing, with the exception of not setting to state to SP_CHIPTOLD. The obvious solution therefore is to set the state SP_CHIPTOLD under the free service branch, as thus:
Code:
procedure NodeWalk begin
set_spleen_flag(SP_CHIPTOLD);
set_local_var(LVAR_Return_Time, game_time + ONE_GAME_DAY);
add_timer_event(self_obj, 0, TIMER_WALK_OFF);
UpReactMinor;
call Node999;
end
21. When the player talks to Suze after rescuing her, and asks her if she found anything interesting, the player can respond with "Yes, it is. Let's go." as if the rescue effort was still ongoing. Conversely, if the player can find time to chat with Suze during the rescue attempt, the player can actually engage in full dialog, as if the full rescue had already taken place.
If you look at the dialog node structure, it is very clear the developers meant for the player to be able to quickly ask Suze one single question during the rescue, and then to have time for a more in-depth conversation after the rescue -- there are even different node branches set up for each condition. Unfortunately, one of the nodes (Node004) is referenced by both branches, and this leads to the crossover dialog that make things a bit out of place.
The fix is to check the state in Node004 and to limit the player's options, similar to below:
Code:
procedure Node004 begin
Reply(113);
if (badger_flag(BADGER_GFRIEND2)) then begin
NOption(114, Node008, 4);
NOption(115, Node005, 4);
NOption(127, Node999, 4);
end else
NOption(116, Node999, 4);
end
22. If you have a character with 10 Charisma, and you get either of the enhanced combat armor implants, then ACE is not able to raise your Charisma back to 10 when you try to do so using the Charisma chip. This is similar to the bug where the Fallout 2 Hintbook cannot raise your Charisma stat to 10, and the cause of the bug is the exact same reason. Therefore, the fix implemented in the Hintbook will also work in this case.
23. Minor text error in line 216 of fckenlee.msg. There is a space at the end of this line, but the script file fckenlee.ssl assumes that there's no such space, and adds its own space. This results in an extra space being printed, and the simplest solution is to remove the space in line 216 of the message file -- though of course you can always make the modification on the script side of things (Node037).
24. I noticed that you had added a local variable to ensure that only one copy of the Vertibird plans may be copied from the Shi Physics terminal. I'm not quite sure whether or not this is part of the developers' original intention -- doesn't it make sense that you can make as many copies as you want (even if the extra copies are useless to you)? At any rate, copying the plans from the Emperor terminal directly allows the player to make multiple copies without any restrictions. So to be consistent we should either remove the restriction in the Physics terminal, or implement the restriction in the Emperor terminal.
Sierra Army Depot
1. If you successfully lower a force field (either by using the Repair skill directly on an emitter or using a Tool/Super Toolkit on it), and then try to raise it back up but fail, you get the message "You fail to lower the force field." This is because the conditional check in wsemit1a.ssl and other similar scripts do not check to see if the field is enabled or disabled at the time of failure.
Fixing all the conditionals in the emitter scripts and updating the msg file with some new text is doable, but I'd recommend the simpler solution of changing line 109 in wsemit1a.msg to read "You fail to affect the force field." instead, seeing that all SAD emitter scripts (and most other emitter scripts from the other maps) use this msg file. Note that this will fix the other force field enable/disable message mismatches from the other areas that I referred to earlier in this list.
2. If you lower a force field, and exit to another map before it comes back up, then the force field will stay permanently down. Even if you manually re-enable it, if you disable it again the force field will stay down. The easiest way to replicate this bug is on level 3: disable any one of the force fields on level 3, hitch the elevator down to level 4 before it comes back up, and then return. Et voila...a permanently disabled forcefield!
After further investigation, I believe this is an engine bug: if a timer event is queued up to make something visible/invisible but was not set off before the player exits the map, then the timer event is fubared, wiping out any actions that were supposed to take place. Needless to say, this can have much wider implications beyond just this scenario here at the SAD!
In this particular case, the script actually responsible for making force fields disappear is the force field script, and not the emitter script -- when the player disables the force field, the emitter script changes a map variable that is picked up in the corresponding force field script's map_update_p_proc procedure, and the force field script does the actual work for lowering or raising the force field (or technically speaking, making the force field visible or invisible). Notice that the timer event is set if the force field's status is FIELD_DISABLED and LVAR_Timed_Event is equal to 0. If both of these conditionals are true, then the force field is rendered invisible, LVAR_Timed_Event is set to 1, and a timer event is set to fire about 20 seconds later in real time. When the timer event fires, the force field is made visible again, and LVAR_Timed_Event is set back to 0. If, however, the timer event is fubared (due to map exit), then the force field is never made visible again. Even if the player manually does so by fiddling with the emitter, LVAR_Timed_Event is still equal to 1, which means the conditional for adding the timer event never becomes true (i.e. it will never automatically become visible again).
We may not be able to fix the engine bug, but we can work around the problem. One possible workaround is to add procedure map_enter_p_proc to the force field script and look for LVAR_Timed_Event == 1 as its conditional -- this can only happen if the player leaves the map before a timed event has expired -- and to process the code accordingly. So, something like this should work:
Code:
procedure map_enter_p_proc begin
if (obj_pid(self_obj) != -1) then begin
FIELD_PTR:=self_obj;
end
if (local_var(LVAR_Timed_Event) == 1) then begin
set_local_var(LVAR_Timed_Event,0);
set_map_var(FIELD_STATUS,FIELD_ENABLED);
if (obj_pid(self_obj) != -1) then begin
set_obj_visibility(self_obj,0); // vis
end
end
end
3. In the level 4 of the SAD, after you have scanned Clifton's eyeball on the level 4 retinal scanner once, you can open the elevator by using the elevator door directly and totally bypass the retinal scanner in the future. Moreover, if you use the retinal scanner, nothing happens even though the game acknowledges the event with the Access Granted message. This is unlike the other retinal scanners in the game, which opens the elevator doors for you when you apply the correct eyeball to it.
On looking at the code, it seems that the developers' original intention (for all retinal scanners and their corresponding elevator doors) was to force the player to use the correct eyeball initially to gain access, but then allow the player from that point forward to directly use the elevator doors to gain access. Unfortunately, this does not work, due to two separate problems: 1) The same map variable (MVAR_Eyeball_Used) is being used to keep track of the state of the retinal scan for levels 1 and 2, so having the ability to use the elevator door directly on one level means you need the eyeball for the other level. 2) No code is put in place for correctly processing the auto-opening of the door on Level 4 -- the developers put the conditional to check if the current map is MAP_SIERRA_123, but forgot about the else part (i.e. level 4).
The most direct fix is to complete the conditional in procedure map_update_p_proc of wiElvDor.ssl, but that still leaves the inconsistent elevator door behaviour for levels 1 and 2. It is possible to fix this inconsistency by introducing another map variable and add in extra processing, but I feel that the player being able to directly use the elevator door after the retinal scan is a design bug (i.e. working as designed/intended, but the design is flawed). Why? Well, the description for the door says that the player can see no way to interact with the door, and they must be opened from somewhere else. Being able to use the doors directly is inconsistent with this description. Therefore, I would also recommend modifying procedure use_p_proc to deny the player the ability to open the elevator doors directly, and force him/her to use the retinal scanner.
If both of my recommendations are implemented, then the code in wiElvDor.ssl would look something like this:
Code:
procedure map_update_p_proc begin
if (cur_map_index == MAP_SIERRA_123) then begin
if ((elevation(self_obj) == map_var(MVAR_Eyeball_Used)) and (tile_num(self_obj) != 19918)) then begin
obj_open(self_obj);
end
else if ((elevation(self_obj) == map_var(MVAR_Eyeball_Level)) and (tile_num(self_obj) == 19918)) then begin
obj_open(self_obj);
end
end
else if (map_var(MVAR_Eyeball_Used_4) == elevation(self_obj)) then begin
obj_open(self_obj);
end
end
procedure use_p_proc begin
script_overrides;
display_msg(mstr(100));
end
4. In the two emitter scripts for level 3, near the end of the procedure use_obj_on_p_proc you will find the same instruction repeated two times, as thus:
Code:
set_global_var(GVAR_SIERRA_BASE_SECURITY,SIERRA_SECURITY_ON);
set_global_var(GVAR_SIERRA_BASE_SECURITY,SIERRA_SECURITY_ON);
Needless to say, this is a bit odd. Checking the emitter scripts from all other levels of the SAD shows that, with the exception of emitter 2D, they only have the 1 line, and do not repeat it. Emitter 2D has the line repeated twice, like the emitter scripts found on level 3.
The most straightforward fix is to eliminate the redundant line, but looking at the rest of the code, it is supposed to behave similar to the case where the emitter was blown up. So I would replace/add a line in the emitter scripts to reflect this, as follows:
Code:
set_global_var(GVAR_SIERRA_BASE_ALERT,SIERRA_ALERT_ON);
set_global_var(GVAR_SIERRA_BASE_SECURITY,SIERRA_SECURITY_ON);
Not that it currently has much impact: as far as I know, GVAR_SIERRA_BASE_ALERT does nothing at all, other than having your Brainbot turning it off. GVAR_SIERRA_BASE_SECURITY is the more important of the two, since it has impact on the security bots' behaviour in the SAD. Nonetheless, a fix should be made for "future extendability" and/or code maintenance purposes.
5. Line 101 of wiRetScn.msg should read "Access denied." (lower case "d" plus the period) in order to maintain thematic consistency with the rest of the messages that comes from the retinal scanner.
6. The next set of bugs concern the extraction chamber found in level 4. As such, I'll list them one by one before suggesting an integrated solution that takes care of them all.
You get 500xp for extracting a brain -- even if no one was in the extraction room (oops). The problem lies in Node014 of wsterm4b.ssl. The experience award for extracting a brain makes no check to see if the there were any brains extracted in the first place. The obvious fix is to check to see if any victims -- urm, I meant, experimental subjects -- had expired (i.e. Room_Capacity > 0) before awarding the experience points.
7. In order for anyone's brain to be extracted, they have to be in your party. So, if they are in the room but not in your party, their brains cannot be extracted. This means, for example, that you can't lure the security bots on level 4 into the extraction chamber, sneak around them, and then use the extraction process to destroy them. (Sure, they have no brains to be extracted, but if the extraction chamber is powerful enough to tear through the Brainbot and its "enhanced" robotic shell, it's probably powerful enough to tear through anything.)
The obvious solution is to exclude the conditional check for the critter being a party member and only check to see if they are in the room. Unfortunately, due to technical reasons this is much easier said than done (I personally suspect this is why the original developers made the party member conditional check in the first place): the command used to check if a critter belongs to your party also happens to give you one of the most efficient ways to obtain a pointer to the critter object. However, if we assume that the critter will no longer necessarily be in the player's party, picking up a pointer to it becomes a much more daunting proposition. In fact, it becomes necessary to check each and every tile in the extraction chamber for the existence of a critter, acquire a pointer to it if the critter exists, and then process it accordingly. Fortunately, the number of tiles to check is not that large, and numerically they follow a set pattern. Therefore, a few efficiently coded while loops should suffice.
8. Even if a critter is in your party, there's no guarantee that its brains will be scooped. More specifically, there is no check in place for K-9 and Laddie, though strangely enough a check exists for Dogmeat, Robodog, and the Pariah Dog. The obvious fix is to add conditional checks for both K-9 and Laddie.
9. The player is getting human brains even when something not human is undergoing the extraction process. For example, you can currently extract human brains from Dogmeat, Robodog, Goris, and the Pariah Dog. Even more amazingly, you can extract
two human brains from the Pariah Dog, since it survives the first extraction attempt! Hmmm...
Also, should one really expect human brains from Lenny and Marcus? In the suggested fix I have below, I have laid it out so that they still yield human brains when scooped, since that is the conservative thing to do. But I've also structured it in a way that it shouldn't be too hard to change things up if needed.
The fix here is to make specific checks for canines, deathclaws, and possibly mutants, and process brain type accordingly. It shouldn't be to hard to do since you have similar checks set up for the different Skynet varieties. In an ideal solution (possibly something to think about in your Restoration Project), one would create new brain protos for canine, deathclaw, and mutant brains -- this was certainly intended by the developers judging by the currently unused "not(Room_Species)" conditional check in Node014 -- but for the purposes of the unofficial patch I've set them yield no brains instead.
As for the Pariah Dog yielding two brains, the fix here is to simply up the damage inflicted by the extraction chamber to something much more lethal -- say, 10000 damage instead of the current relatively underpowered 1000 damage. This would kill tough critters like the Pariah Dog in one shot, and avoid having it surviving for another merry-go-round with the extraction chamber.
10. Finally, you cannot scoop you own brain, though amazingly the code exists in Node014 to do so -- apparently you would extract a human brain from yourself and in return, your intelligence gets reduced to 1, and you lose half your current hit points. This means that you can potentially scoop as many brains as you want from your character as possible, and it would not even be fatal unless possibly in the event that your current hitpoint level is 1. It's a mystery why this code is here in the first place -- maybe the developers wanted the possibility of having the machine extract your brain, enhance it in some fashion, and then have it placed back into the player for an intelligence boost? Who know? But it may be something else for you to consider for the Restoration Project...
Anyway, regardless of intent, the code does not work. Why? For the simple reason that the player needs to be in the extraction chamber in order for this bit of code to even activate, and there is currently no way to do that
AND work the terminal at the same time. The obvious tactic of getting Myron (or some other science-based party member) to work the terminal while the player stands in the chamber is precluded due to the lack of a use_skill_on_p_proc event handler in the wsterm4b.ssl script.
The fix is to add procedure use_skill_on_p_proc to the script. Also, for the sake of consistency, I've made the extraction procedure fatal to the player instead of merely causing some damage. If you decide to keep the original half of current hp damage, then you will need to add additional code in place to ensure that the machine can only extract one human brain from the player.
When all the above points are taken in totality, I've suggested the following code as a solution (no doubt you'd be able to write something more elegant and efficient, since I'm a bit rusty on my coding nowadays...). Note that I've created 3 new procedures (use_skill_on_p_proc, Check_And_Kill_Row, and Check_And_Kill) and revamped Node014 to use them.
Code:
procedure use_skill_on_p_proc
procedure Check_And_Kill_Row(variable start_tile, variable pid);
procedure Check_And_Kill(variable pid);
#define BRAIN_HUMAN (0)
#define BRAIN_ABNORMAL (1)
#define BRAIN_CHIMP (2)
#define BRAIN_CYBERNETIC (3)
#define BRAIN_NONE (4)
// Allows Myron or some other science geek to use the
// terminal -- useful if the player wants to suicide.
procedure use_skill_on_p_proc begin
script_overrides;
variable skill;
skill:=action_being_used;
if (skill == SKILL_SCIENCE) then begin
call use_p_proc;
end
end
procedure Check_And_Kill_Row(variable start_tile, variable pid) begin
variable i := 0;
variable end_tile := 0;
variable extracted_obj_ptr := 0;
variable extracted_count := 0;
i := start_tile;
end_tile := start_tile+10;
while (i <= end_tile) begin
if (tile_contains_obj_pid(i, self_elevation, pid) then begin
extracted_obj_ptr := tile_contains_pid_obj(i, self_elevation, pid);
extracted_count+=1;
critter_damage(extracted_obj_ptr,10000);
end
i+=1;
end
return extraction_count;
end
procedure Check_And_Kill(variable pid) begin
variable tile_row_start := 0;
variable extracted := 0;
tile_row_start := 16513;
while (tile_row_start <= 17713) begin
extracted += Check_And_Kill_Row(tile_row_start, pid);
tile_row_start+=200;
end
return extracted;
end
procedure Node014 begin
variable Room_Capacity:=0;
variable New_Brain;
variable Brain_Type:=BRAIN_HUMAN;
variable Security_Bot_Killed:=0; // see below for explanation
variable i;
// Things that give human brain -- Marcus and Lenny may be moved
// the same section as Goris (Do ghouls and super mutants, given
// all their mutations, still have a human brain?)
Room_Capacity += Check_And_Kill(PID_VIC);
Room_Capacity += Check_And_Kill(PID_MYRON);
Room_Capacity += Check_And_Kill(PID_MARCUS);
Room_Capacity += Check_And_Kill(PID_JOHN_MACRAE);
Room_Capacity += Check_And_Kill(PID_SULIK);
Room_Capacity += Check_And_Kill(PID_LENNY);
Room_Capacity += Check_And_Kill(PID_DOC);
Room_Capacity += Check_And_Kill(PID_DAVIN);
Room_Capacity += Check_And_Kill(PID_MIRIA);
Room_Capacity += Check_And_Kill(PID_ROBOBRAIN_HUMAN);
// The dogs -- can give no brains or abnormal brains as desired
i := Check_And_Kill(PID_CYBERDOG);
if (i > 0) then begin
Brain_Type := BRAIN_NONE;
Room_Capacity += i;
end
i := Check_And_Kill(PID_DOGMEAT);
if (i > 0) then begin
Brain_Type := BRAIN_NONE;
Room_Capacity += i;
end
i := Check_And_Kill(PID_PARIAH_DOG);
if (i > 0) then begin
Brain_Type := BRAIN_NONE;
Room_Capacity += i;
end
i := Check_And_Kill(PID_K9);
if (i > 0) then begin
Brain_Type := BRAIN_NONE;
Room_Capacity += i;
end
i := Check_And_Kill(PID_LADDIE);
if (i > 0) then begin
Brain_Type := BRAIN_NONE;
Room_Capacity += i;
end
// Goris certainly shouldn't yield human brain
// Set to no brain, but can easily be changed to
// abnormal brain
i := Check_And_Kill(PID_GORIS);
if (i > 0) then begin
Brain_Type := BRAIN_NONE;
Room_Capacity += i;
end
// Special case for Skynet
i := Check_And_Kill(PID_BRAINBOT);
if (i > 0) then begin
Brain_Type := BRAIN_CYBER;
Room_Capacity += i;
end
i := Check_And_Kill(PID_ROBOBRAIN_ABNORMAL);
if (i > 0) then begin
Brain_Type := BRAIN_ABNORMAL;
Room_Capacity += i;
end
i := Check_And_Kill(PID_ROBOBRAIN_CHIMP);
if (i > 0) then begin
Brain_Type := BRAIN_CHIMP;
Room_Capacity += i;
end
// Check to see if player lured any security bots
// into the extraction chamber -- these shouldn't
// yield brains, for obvious reasons. Note also the
// use of the variable "Security_Bot_Killed". It
// doesn't make sense to give the player a karma
// penalty for destroying security bots using a
// smart tactic, but at the same time, their presence
// should trigger the extraction failure condition.
// So we need to know if any security bots were in
// the room, but not add them to the room capacity
// count. Obviously, this may not be part of the
// original developers' intent (assuming they even
// thought that far ahead), so feel free to discard
// this part of the code or save it for the RP.
i := Check_And_Kill(PID_EYEBOT);
if (i > 0) then begin
Brain_Type := BRAIN_NONE;
Security_Bot_Killed := 1;
end
i := Check_And_Kill(PID_MISSILE_BOT);
if (i > 0) then begin
Brain_Type := BRAIN_NONE;
Security_Bot_Killed := 1;
end
i := Check_And_Kill(PID_TOUGH_MISSILE_BOT);
if (i > 0) then begin
Brain_Type := BRAIN_NONE;
Security_Bot_Killed := 1;
end
// Kill player if player is in extraction room
// Not sure if script engine allows direct damage
// to the dude_obj while still in dialog system,
// so the actual damage can be moved to after the
// dialog ends in talk_p_proc if this bit of code
// causes problems. See talk_p_proc in ecbridge.ssl
// to see how the Bridgekeeper handles player death.
if (In_Room(dude_obj)) then begin
Room_Capacity+=1;
critter_damage(dude_obj,10000);
while (dude_iq > 1) begin
set_critter_stat(dude_obj,STAT_iq,-1);
end
end
inc_general_rep(REP_BONUS_EXTRACTING_ORGANS * Room_Capacity);
if ((local_var(LVAR_Gave_Xp) == 0) and ((Room_Capacity > 0) or (Security_Bot_Killed == 1)) then begin
give_xp(EXP_EXTRACT_ORGAN);
set_local_var(LVAR_Gave_Xp,1);
end
// Kill ppl in room
debug_msg("Room_Capacity == "+Room_Capacity);
// only true if no security bots and no one else was in extraction chamber
if ((Room_Capacity == 0) and (Security_Bot_Killed == 0)) then
Reply(148);
else if (Room_Capacity > 1) then
Reply(149);
// since all bots yield BRAIN_NONE, this captures the Security_Bot_Killed==1 condition as well
else if (Brain_Type == BRAIN_NONE) then
Reply(149);
else if (not(Room_Species)) then
Reply(150);
else begin
if (Brain_Type == BRAIN_HUMAN) then
New_Brain:=create_object(PID_HUMAN_BRAIN,0,0);
else if (Brain_Type == BRAIN_ABNORMAL) then
New_Brain:=create_object(PID_ABNORMAL_BRAIN,0,0);
else if (Brain_Type == BRAIN_CHIMP) then
New_Brain:=create_object(PID_CHIMP_BRAIN,0,0);
else if (Brain_Type == BRAIN_CYBERNETIC) then
New_Brain:=create_object(PID_CYBERNETIC_BRAIN,0,0);
move_to(New_Brain,16515,0);
Reply(mstr(151)+mstr(152));
end
NOption(153,Node999,004);
end
Vault City
1. This is in reference to an earlier Vault City bug I reported, where the player can shoot through the walls of the bar in the Vault City Council Area towards the entrance of the Council Building itself, despite seemingly having all the right wall blockers in place. I'm sure you have discovered the cause of the bug by now, but just in case:
The wall blocker on tile 20317 has Light Thru and Shoot Thru properties set to "YES" for some odd reason. These should be set to "NO".
========
Edit: Somehow, the formatting got messed up for neutral_critter_reaction. I've fixed it up...darn HTML formatting!
Edit2: Fix up more code screw-ups thanks to bugged function and more darn HTML auto-formatting...