Fallout 2 mod Unofficial Fo2 patch thread - problems, reports, suggestions

killap said:
Darek said:
SorgFall said:
There is only one remaining, if I'm not mistaken the very last unfixed bug in Fallout 2.
Dream on... :wink:
I had mentioned this a while back, but the too many items bug should finally be addressed in the upcoming release. As far as I and others could tell, it was the result of having too many items with scripts attached to them. Nearly every item that had one has been altered and as a result, the bug no longer rears its ugly head!

There you go. I told you the you were more than capable to solve all of those you noted hard-coded and unfixable, and you still didn't believe me after you fixed two thirds of them. :clap:
 
I just recently started having a problem with my followers becoming "cowards" 100% of the time regardless of their hp or combat settings.
It happened I think at some point while i was doing stuff in modoc, haven't found a way to fix it yet....Anyway, I was just wandering could anyone help me with this? It's something I've never experienced before installing Kilap's patch+vault restoration thing.
 
torotacoman, it's because they got crippled.
Examine them and use Doctor skill on them / find a doctor will solve the problem.
 
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...
 
Per said:
Note that

Code:
set_critter_stat(dude_obj,STAT_iq,1);

will increase IN by 1.

It does? Ugh...so much for relying on the documentation that shipped with the Fallout 2 Mapper! :oops:

In that case, though, the SAD brain extraction machine becomes much more interesting. It now appears that originally, it would take off half of the player's hp, increase the int stat by 1, and extract a human brain -- assuming that the player can somehow work the machine from within the extraction chamber. And because the player doesn't die, in theory this can be done over and over again. Definitely seems like part of an incomplete feature...

-- The Haen.
 
No, the intent certainly was to lower IN to 1 - it was just that half of the scripters didn't know how this command worked. Hence the 1.0 bugs with raising CH when boxing and so on.
 
Ah, I see.

At any rate, I'll correct the script to (I hope) properly lower the int to 1...not that it does anything much currently given the player bites the dust....

-- The Haen.
 
Haenlomal said:
At any rate, I'll correct the script to (I hope) properly lower the int to 1...not that it does anything much currently given the player bites the dust....
Careful with that. iirc set_critter_stat was the bugged one that failed if you tried to reduce a stat by more than, umm, 3 I think, at once. Either loop it, or use set_critter_base_stat instead.
 
It's bugged? Ugh...didn't know that! Oh well, I just noticed that the HTML formatting messed up the code anyway, so I better fix that up!

Thanks,

-- The Haen.

Edit: Fixed! Hopefully the code in the SAD section makes much more sense now... :)
 
Here's the rest of the bugs I found in San Francisco, plus some more I dug up in Navarro. Relative to its complexity, San Francisco has to be one of the most bugged areas of Fallout 2!

All that's left is the Enclave... Well, there is the Military Base, but I don't anticipate too much trouble there. Then again, that's what I said about SAD, and look what I found....

-- The Haen.

------------------

San Francisco

1. The merchants and the bartender in the Tanker are referred to as "Tanker Merchant" and "Tanker Bartender" respectively. However, all three have them have proper names: The gun merchant is Cal, the other merchant is Jenna, and the bartender is Slim. I guess the developers forgot to update the placeholder text. At any rate, going to scrname.msg and changing lines 1202, 1203, and 1204 to "Cal", "Slim", and "Jenna" respectively should solve the problem.

2. Similarly, if you look at the dialog history (or combat logs, if you decide to beat down the Shi) of Dr. Jing Tie Gahng, he is only referred to as a "Chemist". Updating line 992 in scrname.msg as appropriate should solve this problem. Similarly, Mai Da Chiang is simply referred to as "Gun Merchant". The line to update in this case is line 925.

3. Mismatched names -- part III. In other words, the Hubologists' turn! In their case, though, there's only one person that needs updating: Harry the Rocketman is simply "Rocketman". The line to update in scrname.msg is 1067.

3. Dr. Fung's name is referred to as "Dr Fung" - note the missing period after "Dr". To maintain consistency with all other doctors in the game, this should be "Dr. Fung" instead. The line to update is line 856 in scrname.msg.

4. While talking to Marc the punk, you may get the following interesting exchange:

Code:
MARC: You want to know what our plans are? We're going to keep moving around until we can find a place that hasn't been screwed over by human greed and then we're going to try to set up a better society.

YOU: Do you know how you're going to do that?

MARC: We're hoping that if we can avoid society's mistakes. Hell, things can't get much worse.

The "if" in Marc's second line doesn't make sense given the context of the conversation. It should probably be removed. The relevant line to change is line 160 in fcMarc.msg

5. When you first talk to Slim, the bartender in the Tanker, then assuming his bar is open for business, he'll greet you with: "I'm Slim. What'll you have?" Your character can then answer with: "Sure, show me what you've got." which doesn't quite fit (it makes more sense on subsequent visits). Changing "Sure, show me what you've got." to "Show me what you've got." should fix this line under all contexts. The line to change is line 108 in fctnkbar.msg

6. If you talk to Dave H. after you have become a bona fide member of the Hubologists, he'll say: "Greetings, enlightened one." and one of your possible responses is "In no way. Thanks." This obviously doesn't make sense. What's more, every time the player returns to this root node during the same conversation, Dave H. will greet the player with "Greetings, enlightened one." all over again.

There are a few ways to solve this problem, but I think the easiest way to solve it is to modify the greeting line to something more appropriate and general. The greeting line is found in line 104 of fcDaveh.msg, and something like "How can I help you, enlightened one?" should do.

7. Minor typo in line 192 of fcDaveh.msg. Since Dave is quoting someone, the period at the end of the quotation should be inside the quotation mark, not outside it.

8. If you tell Dave that Vikki thinks he's hot, he will be willing to do any number of favors for you. However, unless that favor is formatting the Hubologist hard drive, he'll always reply with the line "I'm going to move on Vikki... umm... soon. What can I help you with?" Note that there is no acknowledgement that he had actually performed any of the favors that you asked him to do, though fortunately on checking the script Dave does indeed do what you asked him to do.

The problem lines in Node015. You have the following piece of script at the very beginning of Node015:

Code:
   if (not dave_flag(DAVE_TOLD)) then
      Reply(164);
   else
      Reply(200);

Line 164 contains a much more appropriate acknowledgement statement ("There you go. Anything else?"). However, since all possible paths into Node015 has the bit DAVE_TOLD set somewhere ahead of it, it is impossible for not dave_flag(DAVE_TOLD) to be true, and hence line 200 ("I'm going to move on Vikki... umm... soon. What can I help you with?") is always displayed.

Since line 200 only makes sense as a greeting line when the player initiates dialog with Dave H., the fix is to modify both talk_p_proc and Node015 to account for this possibility. Introduce a new local variable, and have it display line 200 only if it is turned on. So something like this:

Code:
variable Greet_15:=0;

procedure talk_p_proc begin

   // Code snipped to save space

   end else if (dave_flag(DAVE_TOLD)) then begin
      Greet_15:=1;
      start_gdialog(NAME,self_obj,4,-1,-1);
      gSay_Start;
         call Node015;
      gSay_End;
      end_dialogue;

   // Code snipped to save space
end

procedure Node015 begin
   if (not Greet_15) then
      Reply(164);
   else begin
      Greet_15:=0;
      Reply(200);
   end

9. If you get Dave to transfer gas to the tanker from any source after telling him that Vikki finds him hot, you get no experience points for doing so. This is different from when you tell Dave to transfer gas after telling him that Juan and Vikki made fun of him (where you DO get the experience points).

On looking at the script, it seems that the developers remembered to make a macro call to COMP_QUEST in the latter scenario, while accidentally leaving it out in the former. The fix therefore is to change nodes 015b and 015c to make the appropriate macro call, as thus:

Code:
procedure Node015b begin
   if (not san_fran_flag(SF_EMPEROR_FORMATTED)) then begin
      unset_san_fran_flag(SF_GAS_ELRONS);
      COMPLETE_TANKER_FUEL;
      set_shihacked_flag(SHI_TRUE);
      COMP_QUEST(REP_BONUS_SAN_FRAN_TANKER_FUEL_DAVE_SHI, REP_HERO_SAN_FRAN_TANKER_FUEL_DAVE_SHI, EXP_TANKER_FUEL_DAVE_SHI);
      call Node015;
   end else begin
      call Node023;
   end
end

procedure Node015c begin
   COMPLETE_TANKER_FUEL;
   unset_san_fran_flag(SF_GAS_ELRONS);
   COMP_QUEST(REP_BONUS_SAN_FRAN_TANKER_FUEL_DAVE_EL, REP_HERO_SAN_FRAN_TANKER_FUEL_DAVE_EL, EXP_TANKER_FUEL_DAVE_EL);
   call Node015;
end

10. If you tell Dave that Juan and Vikki made fun of him, you get a one time chance to have Dave do a number of favors for you. One of those favors is to format the Hubologist hard drive, which he'll gladly do out of a sense of revenge. However, you do not get any reputation bonuses for getting the Hubologist hard drive formatted. This is inconsistent with the scenario where you tell Dave H. that Vikki thinks he's hot. Under the latter scenario, you do get the reputational bonuses for getting the Hubologist hard drive formatted (see Node017). The code for awarding the reputational bonuses for hard drive formatting should probably be added to Node12a to make things consistent.

11. If you tell Dave that Juan and Vikki made fun of him, get him to agree to do you favors to get back at them, and did not request a hard drive format as your first favor, then Dave will acknowledge your request with line 146 ("There you go. Now get out of here. I'm going to format the computer and leave."). The player can milk more favors from Dave, and will be met with this response after every single favor.

Despite the threat, however, the hard drive never gets wiped, and Dave never leaves, for the simple reason that no such code is in place for him to do so. The solution is to create a new procedure Node999a that will do the dirty work after you've finished milking Dave out of favors, and then call it from Node011, as thus:

Code:
procedure Node011 begin
   Reply(146);
   if (elron_whirly(EL_WH_GIVEN) and (SHI_WANT_PLANS or san_fran_flag(SF_BROTHER_PLANS)) and not dude_item(PID_VERTIBIRD_PLANS)) then
      NOption(147, Node011a, 4);
   if (not san_fran_flag(SF_GAS_ELRONS) and (tanker_flag(TANK_KNOWN) and not tanker_flag(TANK_FUEL))) then
      NOption(148, Node011b, 4);
   if (san_fran_flag(SF_GAS_ELRONS) and (tanker_flag(TANK_KNOWN) and not tanker_flag(TANK_FUEL))) then
      NOption(149, Node011c, 4);
   BOption(150, Node013a, 4);
   NOption(151, Node999a, 4);
end

procedure Node999a begin
   set_san_fran_flag(SF_ELRON_DRIVE_FORMAT);
   COMP_QUEST(REP_BONUS_SAN_FRAN_FORMAT_ELRON, REP_HERO_SAN_FRAN_ELRON_FORMAT, 0);
   call Node999;
end

For plot consistency's sake, you may want to consider adding a call to Node999a from Node010's exit line. Though if you decide to do that, it may be necessary to give some warning to the player about what's going to happen. Then again, realistically speaking given the circumstances, Dave would probably wipe out the drive and run with no one none the wiser if he's so bent on revenge. :) Of course, all this is my subjective interpretation, so it's entirely up to you to decide what you want to do.

12. Another bug that happens after you tell Dave Vikki and Juan made fun of him: if you get Dave to try to siphon fuel from the Shi under these circumstances, he'll be able to do it even if you had previously formatted the Emperor computer...oops! Amazingly enough, the check for a formatted Emperor computer is made if you get a happy Dave to hack the Shi, but for some reason this check was skipped out on angry Dave. Angry Dave's kung fu must be strong in order to read and manipulate functions from a formatted drive! :P

Anyway, the fix is simply to copy the checking mechanism over to the appropriate node and create a new node (say, Node024) and some new dialog for the situation, as thus:

Code:
procedure Node011b begin
   if (not san_fran_flag(SF_EMPEROR_FORMATTED)) then begin
      unset_san_fran_flag(SF_GAS_ELRONS);
      COMPLETE_TANKER_FUEL;
      set_shihacked_flag(SHI_TRUE);
      COMP_QUEST(REP_BONUS_SAN_FRAN_TANKER_FUEL_DAVE_SHI, REP_HERO_SAN_FRAN_TANKER_FUEL_DAVE_SHI, EXP_TANKER_FUEL_DAVE_SHI);
      call Node011;
   end else begin
      call Node024;
   end
end

procedure Node011 begin
   Reply(146);
   if (elron_whirly(EL_WH_GIVEN) and (SHI_WANT_PLANS or san_fran_flag(SF_BROTHER_PLANS)) and not dude_item(PID_VERTIBIRD_PLANS)) then
      NOption(147, Node011a, 4);
   if (not san_fran_flag(SF_GAS_ELRONS) and (tanker_flag(TANK_KNOWN) and not tanker_flag(TANK_FUEL))) then
      NOption(148, Node011b, 4);
   if (san_fran_flag(SF_GAS_ELRONS) and (tanker_flag(TANK_KNOWN) and not tanker_flag(TANK_FUEL))) then
      NOption(149, Node011c, 4);
   BOption(150, Node013a, 4);
   NOption(151, Node999a, 4);
end

procedure Node024 begin
   Reply(201);
   if (elron_whirly(EL_WH_GIVEN) and (SHI_WANT_PLANS or san_fran_flag(SF_BROTHER_PLANS)) and not dude_item(PID_VERTIBIRD_PLANS)) then
      NOption(141, Node011a, 4);
   if (not san_fran_flag(SF_GAS_ELRONS) and (tanker_flag(TANK_KNOWN) and not tanker_flag(TANK_FUEL))) then
      NOption(143, Node011b, 4);
   if (san_fran_flag(SF_GAS_ELRONS) and (tanker_flag(TANK_KNOWN) and not tanker_flag(TANK_FUEL))) then
      NOption(144, Node011c, 4);
   NOption(145, Node999a, 4);
end

This is assuming that a new line 201 is created in fcDaveh.msg and looks something like:

Code:
{201}{}{Their system hasn't been responding for a while. Looks like someone formatted their databases. Like what I'll be doing here once I'm done with you. Anything else?}

13. In your list of bug fixes, you stated: "If you drop the Vertibird Plans after getting Handy to copy them from you, you can ask him to do it again. This is no longer the case." However, this is still true if Dave is unhappy with Juan and Vikki. The fix you made by defining an additional LVAR and checking that instead of the player's inventory somehow wasn't applied to Node010 and Node011 -- these two still check the player's inventory. The obvious solution is to apply your fix in Node014 and Node015 to Node010 and Node011. The LVAR processing you had in Node015a will also need to be applied to Node11a. Finally, if you followed my recommendation above and created a new Node024, then your fix will need to be applied there as well.

14. Line 199 in fcDaveh.msg currently doesn't flow well in context with the rest of the conversation. I'd recommend adding a friendly "Anything else?" at the end of the line to make things flow better, as thus:

Code:
{199}{}{Sorry, their system hasn't been responding for a while. There's no way for me to get into it. Anything else?}

15. This is not really a bug, but more in the matter of code maintenance. In REPPOINT.H, two of the #define statements, REP_BONUS_TOLD_DAVE_LOVE and REP_BONUS_FOOLED_DAVE, are for some reason placed under the Den section. For future code purposes it would be better to put them under the San Francisco section.

16. The two lit flares that the player can loot from the vanilla game are now unlit flares. For some odd reason, though, these two flares would not stack with other normal unlit flares -- perhaps the protos were changed directly without actually removing them? I know that directly changing protos of existing objects can cause odd behaviour. My recommendation is to completely remove those two flares, save the map, then add in two new flares, and then re-save the map. Other than that, I don't know what else we can do to truly make those two flares normal.

17. Another code maintenance type thingy: In EXPPOINT.H, there are two #define statements for EXP_DRAGON_BEAT_TEST. Fortunately, since they both have the value of 8000, it ultimately doesn't really change anything. For code maintenance's sake, though, I would recommend changing one of them to EXP_LOPAN_BEAT_TEST, and then changing the reference in fcLopan.ssl to point to that one instead.

18. There is an extra space between the two sentences that form line 193 of fcRocMan.msg.

19. If the tanker merchants somehow bite the dust (probably because you killed them), and you try to loot their tables where they stored their stuff, you'll find that you can't. Instead, the player character animates as normal as if it is searching through the stuff, but is promptly interrupted in mid-animation and does absolutely nothing. Using indirect ways to attempt to access the table (like using the Steal skill) results in similar failed attempts.

The problem lies in destroy_p_proc of fcTnkGmr.ssl and fcTnkMer.ssl. The script that governs the merchants' tables checks an imported variable to see if the merchants are alive, and if yes, to set up a timer event to force the merchant to initiate dialogue with the player. Unfortunately, when the merchants are killed, the variable was not updated. Therefore, the guard script still thinks the merchants are alive, and tries to send a timer event to them. Since they are, of course, dead, nothing happens (though I think there may be possible memory leakage and blind writes here!).

The fix is to update the appropriate variable upon death. For fcTnkGmr.ssl, this should be:

Code:
procedure destroy_p_proc begin

/* Increment the aligned critter counter*/
   inc_good_critter

/* Set global_variable for Enemy status*/
   i_tgun_merchant := -1
end

For fcTnkMer.ssl, this should be:

Code:
procedure destroy_p_proc begin

/* Increment the aligned critter counter*/
   inc_good_critter

/* Set global_variable for Enemy status*/
   i_tmer_merchant := -1
end

20. Here's a problem that took me a while to track down and affects almost every script in San Francisco. It has no visible effect most of the time, but luckily it manifested itself with Dave H. To reproduce: Get Dave to tell you about his crush on Vikki. Talk to Vikki about it, and then return to tell Dave that Vikki thinks he's hot (in theory, you can tell him that Vikki and Juan made fun of him, but due to another bug already described above (Bug #10), nothing happens with respect to this bug). When Dave agrees to do favors for the playing, have him format the Hubologist hard drive. You get the rather interesting message "You gain 0 experience points."

Why is it interesting? Because it isn't supposed to occur: the scripts in San Francisco rely heavily on a macro called COMP_QUEST that takes on three arguments. The three arguments affect global reputation, town reputation, and experience points respectively. If anyone of the three arguments are zero, the macro is supposed to silently ignore any processing that would normally be associated with that particular argument, and move on to the next one. Unfortunately, this doesn't quite work: Each of the arguments are processed in turn by a single macro, each of which consists of multiple commands. However, none of the if-else blocks processing the arguments are enclosed by begin-end statements, so only the first line in each called macro are subjected to the conditional checks. This is fine for the argument processing the town reputation, which ultimately boils down to several commands nested within each other, thus expanding to only one line of code. But the other macros consist of commands spread across multiple lines. The experience points message happens to be on the second line of the macro give_xp, so it is displayed regardless of the truth value of the conditional.

The fix is to modify COMP_QUEST in SANFRAN.H to wrap each if-else block with begin-end, as thus:

Code:
#define COMP_QUEST(grep, trep, exp)     \
   if (grep != 0) then begin                 \
      inc_general_rep(grep);            \
   end                                       \
   if (trep != 0) then begin                 \
      inc_san_fran_rep(trep);           \
   end                                       \
   if (exp  != 0) then begin                 \
      give_xp(exp);                     \
   end

Note that after this change, it is no longer necessary to include the semi-colon at the end of each COMP_QUEST macro call -- in fact it is a syntax error to do that -- so all COMP_QUEST macro calls need to be updated (i.e. lots of work with San Fran scripts). If this is too much work, then it is possible to modify COMP_QUEST to this rather inelegant form in order to retain the semi-colon:

Code:
#define COMP_QUEST(grep, trep, exp)     \
   if (grep != 0) then begin                 \
      inc_general_rep(grep);            \
   end                                       \
   if (trep != 0) then                       \
      inc_san_fran_rep(trep);           \
   if (exp  != 0) then                       \
      give_exp_points(exp);             \
   if (exp  != 0) then                       \
      display_msg(message_str(SCRIPT_GENERIC,100)+exp+message_str(SCRIPT_GENERIC,101))

21. When you challenge either Lo Pan or the Dragon to a duel to the death, most of the Shi guards and peasants still run around in between turns. This is not that surprising, seeing that there's a critter_add_trait command that puts them on the same team -- TEAM_SAN_FRAN_SHI, to be more precise. The fix is to change TEAM_SAN_FRAN_SHI in procedure DoChallenge to something else -- probably to whatever team you assigned to the fighters in the tests.

22. If, during your fight to the death with Lo Pan or the Dragon, you manage to knock them out, you can walk away from them and end combat (entering sneak mode helps). Eventually they will regain consciousness, and stand up. When you talk to them, they act as if no challenge is taking place, and that you're still standing with them in the respective martial arts schools! You can even offer to take their tests if you haven't already, and the game tries to put you through testing. However, since your own party members would have flagged either the Dragon or Lo Pan as the enemy, and since their badly damaged persons are standing next to the ring, chances are that your team members kill them before you're done your test. In this case, you get the congratulatory message about killing them, after which your character is stuck forever in the ring.

The obvious fix is to make sure the fight keeps on going. Adding an additional check in talk_p_proc for LVAR_Challenge == 1, and to have them automatically attack the player if true, works. Another possible method is to add that check in critter_p_proc instead, but technically speaking, it is possible for the player to sneak in a talk attempt before the beat has past, so the former method is safer. Maybe combining both...

23. Just a minor nitpick type of bug: For both the Dragon and Lo Pan, if you ask them about the tests, they claim that they are the final challenge after you've beaten their five students. Obviously in the test, it isn't them you are fighting, though the final critters that you do fight are just as tough as them. I would update their conversation to say they are fighting their chosen apprentice, second-in-command, or something similar. The lines to edit are 233 in both fcDragon.msg and fcLoPan.msg. Note that there's also an extra space in front of the word "However" in 233 for both files, so you might as well go an fix that while you're at it. For fcLoPan.msg, there's an additional extra space in front of "to protect my men".

24. Since we are on the topic of extra spaces, for fcDragon.msg, there's one extra space in lines 113 and 128. For fcLoPan.msg, line 230 has double spacing between each of its three sentences.

25. If you kill Lo Pan without successfully completing his test (or more accurately, getting his quest for you to take out the Dragon after you've finished his test), then you get 2000 bonus experience points plus 5 San Francisco town reputation points. However, if you kill the Dragon without taking the Dragon's test, nothing special happens. There are two issues here.

The first issue is getting no bonuses for killing the Dragon. When one kills Lo Pan under the afore-mentioned conditions, the player is awarded EXP_LOPAN_CHALLENGE_NO_MISSION experience plus REP_HERO_SAN_FRAN_KILL_LOPAN town reputation points. These two bonuses are used nowhere else in game. In EXPPOINT.H and REPPOINT.H, there are two very similar defines for the Dragon (EXP_DRAGON_CHALLENGE_NO_MISSION and REP_HERO_SAN_FRAN_KILL_DRAGON respectively), but these are totally unused in the game. I think it's safe to say that the original developers accidentally left these out for the Dragon!

The second issue is the conditional itself. Given the name of the experience point bonus EXP_LOPAN_CHALLENGE_NO_MISSION, I think it is more likely that the award was supposed to be given if the player challenges and kills Lo Pan without being sent on a mission by the Dragon, instead of the other way around. This is subjective, of course, but I think it makes sense given how the rest of the script is laid out for both the Dragon and Lo Pan.

If you accept both problems I reported as the developers' original intentions, then procedure destroy_p_proc in both fcDragon.ssl and fcLoPan.ssl need updating. For fcDragon.ssl, this should look something like:

Code:
procedure destroy_p_proc begin

/* Increment the aligned critter counter*/

/* Set global_variable for Enemy status*/
   set_san_fran_flag(SF_DRAGON_DEAD);
   if (local_var(LVAR_Challenge) == 1) then begin
      if (global_var(GVAR_SAN_FRAN_LOPAN_KDRAGON_QST) == 0) then begin
         give_xp(EXP_DRAGON_CHALLENGE_NO_MISSION);
         inc_san_fran_rep(REP_HERO_SAN_FRAN_KILL_DRAGON);
      end
      inc_neutral_critter
      fadeout(1);
      if (combat_is_initialized) then
         terminate_combat;
      move_to(dude_obj, local_var(LVAR_Old_Dude_Tile), elevation(dude_obj));
      call ReturnInven;
      fadein(1);
      display_msg(mstr(214));
   end else begin
      inc_good_critter
   end
end

And for fcLoPan.ssl, this should look like:

Code:
procedure destroy_p_proc begin

/* Increment the aligned critter counter*/

/* Set global_variable for Enemy status*/
   set_san_fran_flag(SF_LOPAN_DEAD);

   if (local_var(LVAR_Challenge) == 1) then begin
      if (global_var(GVAR_SAN_FRAN_DRAGON_KLOPAN_QST) == 0) then begin
         give_xp(EXP_LOPAN_CHALLENGE_NO_MISSION);
         inc_san_fran_rep(REP_HERO_SAN_FRAN_KILL_LOPAN);
      end
      inc_evil_critter
      fadeout(1);
      move_to(dude_obj, local_var(LVAR_Old_Dude_Tile), elevation(dude_obj));
      call ReturnInven;
      fadein(1);
      display_mstr(214);
      if (combat_is_initialized) then
         terminate_combat;
   end else begin
      inc_evil_critter
   end
end

26. This is an admittedly subjective bug, but here goes: When you talk to both the Dragon and Lo Pan, you get the impression that both are equally matched in their skills and their strengths, even down to their students. That's why even one person would tip the balance of power.

However, if you check out Lo Pan's stats, they are much weaker than the Dragon's stats. A small difference is understandable -- after all, the Dragon has been winning the fights so far, but not such a giant discrepancy that makes Lo Pan weaker in hitpoints than most of his students. Given how equally matched the Dragon and Lo Pan is supposed to be, I am inclined to think that Lo Pan's weaker stats (especially the ridiculously low hitpoint total) is a developer oversight.

I would recommend upping Lo Pan's stats to be identical to the Dragon's stats, but maybe make his Unarmed skill 5% lower to account for the Dragon's edge. The adjustment will also need to be made for Master Khung as well, since Lo Pan's top student is a clone (stats wise) for Lo Pan himself, so it inherited all the same strengths and weaknesses.

27. You can run through the walls in some areas of the BOS Bunker Basement. To fix this, blocking hexes need to be placed on the following tiles: 17328, 17928, 18128, and 18140. The map file to fix is sfchina2.map, on elevation 2. (The same gaps exist for the copy of the BOS Bunker Basement located on elevation 3, but I believe that one is only used for the Horrigan/Matt cutscene.)


Navarro

1. Doctor Schreber is simply referred to as "Doctor" during dialog screen or combat. Updating line 1158 in scrname.msg will fix this. (Note that they spelled his name wrong in the comments!)

2. The next few bugs concern our favourite Deathclaw prisoner, Xarn. If the player manages to unlock the backdoor leading to the air vent before ever speaking with the deathclaw (one way to do this is to grab the blue key card from Schreber's office, but then go back out the front gates and then back down through the air vent instead of going directly to the Deathclaw's prison), then Xarn initiates seemingly normal conversation with the player, asking if the player is to be his "executioner". If the players claims that he or she is there rescue him instead, Xarn will express his disbelief. The player can then insist on his or her sincerity, pointing out the fact that the backdoor is already unlocked and waiting. At this point, the conversation ends rather abruptly, though Xarn does take advantage of the open door and make good his escape. However, if the player is stupid (i.e. intelligence less than 4), then the conversation ends with Xarn thanking the player and the player acknowledging the thanks.

The problem lies in Node004a. This node was supposed to display Xarn's thank you message and the player's subsequent acknowledgement. However, both player reply options are calls to NLowOption, so the intelligent player has no reply options, giving the conversation a very abrupt end. The fix is to change one of the NLowOption calls to be an NOption call instead, as thus:

Code:
procedure Node004a begin
   set_global_var(GVAR_NAVARRO_XARN, NAVARRO_XARN_KNOW_ABOUT);
   set_local_var(LVAR_dq_accept, 1);
   Reply(175);

   NLowOption(176,Node999);
   NOption(177,Node999,004);
end

3. Here's a rather interesting bug that has several outward symptoms but all of them have the same root cause. Here's one way to reproduce this bug. Go visit Xarn and ask him to tell his story. Xarn will finish his story with a plea for the your help. Tell Xarn that you need time to think about it, and he'll acquiesce to your request. Go back, retrieve the blue key pass, and unlock the back door. Xarn will proceed to heartily thank the player via a float message before attempting to make good his escape.

Now, talk to Xarn before he has completely escaped, and he'll ask if you are still thinking about helping him out or not! But, umm... you've already helped him out. Depending on how you ended your last conversation with Xarn before freeing him, Xarn can alternately ask you if you had changed your mind, have located the pass key, or even if you are finally ready to battle him!

The reason for this bug is because one of the LVAR_dq_(whatever) states is set to 1 during conversation with Xarn, and talk_p_proc makes no check to see if Xarn is making his escape or not. The simple fix is to check to see if Xarn is in the process of making his great escape, which happens to corresponds to LVAR_Freed == 1. If yes, Xarn should repeat his float message. Obviously, the check for this condition should be placed before any of the LVAR_dq_(whatever) conditional checks or even any of the full dialogue options. So something like:

Code:
procedure talk_p_proc begin

   if (local_var(LVAR_Personal_Enemy) == 1) then begin
       call Node998;
   end
   if (talk_to_dude == 1) then begin
      talk_to_dude:=0;
      start_gdialog(NAME,self_obj,4,-1,-1);
      gSay_Start;
         call Node017;
      gSay_End;
      end_dialogue;
   end
   else if (map_var(MVAR_Xarn_In_Party) == 1) then begin
      call Node022;
   end
   else if (local_var(LVAR_Freed) == 1) then begin
      floater(178);
   end
   else if( global_var(GVAR_NAVARRO_BASE_ALERT) > 0 ) then begin
      start_gdialog(NAME,self_obj,4,-1,-1);
      gSay_Start;
         call Node017;
      gSay_End;
      end_dialogue;
   end
   else if (local_var(LVAR_dq_accept) == 1) then begin
      start_gdialog(NAME,self_obj,4,-1,-1);
      gSay_Start;
         call Node014;
      gSay_End;
      end_dialogue;
   end
   else if (local_var(LVAR_dq_think) == 1) then begin
      start_gdialog(NAME,self_obj,4,-1,-1);
      gSay_Start;
         call Node013;
      gSay_End;
      end_dialogue;
   end
   else if (local_var(LVAR_dq_refuse) == 1) then begin
      start_gdialog(NAME,self_obj,4,-1,-1);
      gSay_Start;
         call Node012;
      gSay_End;
      end_dialogue;
   end
   else if (local_var(LVAR_dq_kill) == 1) then begin
      start_gdialog(NAME,self_obj,4,-1,-1);
      gSay_Start;
         call Node011;
      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

4. A relatively minor bug: once the player has freed Xarn, the float message says "Thank you again, my friend. I owe you a debt that can not be repaid."

The "again" part only really makes sense if the player has previously told Xarn during full dialogue that he or she has located the blue pass key and will be using it to open the backdoor. And even then, taking out the word "again" would make sense in this particular context. I would recommend taking out the word "again" so that this simple float message would make sense for all contexts.

There is a second issue with this statement: The words "can not" should really be the one word "cannot".

Taking both minor issues into account, line 178 in ccXarn.msg should be changed to read:

Code:
{178}{}{Thank you, my friend. I owe you a debt that cannot be repaid.}

5. This is a bug all the way from v1.02D of Fallout: If you put Navarro on alert and get Xarn to join you, and then proceed to open the back door, Xarn will thank the player and make good his escape...or does he? You see, whenever you switch levels on Navarro, Xarn will magically re-appear somewhere close to the player, though he will remain stationary and not move about -- though he will do so if you push him or engage the Enclave in combat within his detection zone. If you talk to Xarn, he will give float combat messages. The only way to permanently get rid of Xarn in this case is to either get him killed in combat, or else walk close to the gas station exit and put yourself in combat mode for at least one round. In this latter case, Xarn will thank the player for being a true pack brother and then leave to warn his tribe.

The reason why this bug is happening is due to critter_p_proc of ccXarn.ssl. When critter_p_proc detects that Xarn is free to escape (LVAR_Freed == 1), it proceeds to make Xarn escape without bothering to check if Xarn has joined the player. And since critter_p_proc is structured in such a way that only one conditional code can be executed (i.e. if two conditionals are true then the first conditional to be processed gets executed, and the other one is never processed), this means that the code for moving Xarn along with the player never gets run again since it is the very last conditional (MVAR_Xarn_In_Party == 1) that critter_p_proc processes.

However, once Xarn has escaped, LVAR_Freed is changed to 2. This is also a conditional check made in critter_p_proc, so once again the (MVAR_Xarn_In_Party == 1) conditional check is bypassed. Since it is bypassed, and since Xarn only moves when this conditional is processed, the player witnesses the Xarn standing still behaviour. At the same time, if procedure map_update_p_proc of Navarro.ssl detects that MVAR_Xarn_In_Party == 1 and the player is on a different elevation than Xarn, it will move Xarn to the same elevation, within 5 tiles of the player.

The most obvious fix is to switch off the flag MVAR_Xarn_In_Party once the player has freed Xarn, but thematically, this doesn't really fit in with the general honorable behaviour of the talking deathclaws -- beating a retreat without making sure the rest of the pack is safe. Therefore, a more complete fix would be to check if MVAR_Xarn_In_Party == 1 before triggering the code to free Xarn. If Xarn is already in the party, then he won't abandon the player -- and the free Xarn code never gets triggered. This is done by modifying the second conditional in critter_p_proc of ccXarn.ssl from:

Code:
   else if ( ( map_var(MVAR_Xarn_Door) == 1 ) and ( local_var( LVAR_Said_Thanks ) == 0 ) ) then begin

to:

Code:
   else if ( ( map_var(MVAR_Xarn_Door) == 1 ) and ( local_var( LVAR_Said_Thanks ) == 0 ) and ( not ( map_var(MVAR_Xarn_In_Party) == 1 ) ) ) then begin

6. The player can still receive all the experience points associated from joining, freeing, and killing Xarn...or at least, that's what the display window claims. In actual fact, the player only receives the experience points for whichever of the actions listed above was committed first, though the "You gain x experience points." message is displayed regardless of whether or not any actual experience points are awarded. This is of course much better than v1.02D, where the experience points were actually being awarded(!), but it would be desirable to also remove the erroneous xp gain messages to avoid confusing the player.

Another related point is that all reputational bonuses and penalties are still being applied. The player should only be receiving one set of bonuses and/or penalties depending on how they dealt with Xarn.

The cause of the bug lies in the conditional check used to give players experience points. For example, this is the code used for granting the player experience points for killing Xarn:

Code:
     if (global_var(GVAR_NAVARRO_XARN) < NAVARRO_XARN_FINISHED) then
        give_xp(EXP_XARN_KILL);

While this seems fine, give_xp() is not an engine function, but a macro which calls two separate engine functions -- the first one awards the experience points, and the second one sends a message to the display window stating how many experience points were gained. Since the conditional is not enclosed with begin-end, only the first statement (the actual awarding of the xp) is subject to the conditional, and the display xp message is executed regardless of the conditional. This is very similar to the COMP_QUEST bug described in the San Francisco section.

With the above in mind, the fix is quite obvious -- enclose the conditional in a begin-end block. There are three places that need this. The first is destroy_p_proc:

Code:
procedure destroy_p_proc begin
/* Increment the aligned critter counter*/

  //need to check if dude killed him as it might be someone else
  if (source_obj == dude_obj) then begin
     set_map_var(MVAR_Xarn_In_Party,0); //xarn no longer in party if dead
     if (global_var(GVAR_NAVARRO_XARN) < NAVARRO_XARN_FINISHED) then begin
        display_msg(mstr(800));
        give_xp(EXP_XARN_KILL);
        inc_general_rep(REP_BONUS_CC_XARN_KILL);
        set_global_var(GVAR_NAVARRO_XARN, NAVARRO_XARN_FINISHED); //player has dealt w/xarn
     end
     inc_good_critter
  end
end

The second is in Node016:

Code:
procedure Node016 begin
   if (global_var(GVAR_NAVARRO_XARN) < NAVARRO_XARN_FINISHED) then begin
      set_local_var(LVAR_freed,1);
      floater(178); //Xarn needs to exit thru door
      display_msg(mstr(810));
      give_xp(EXP_XARN_FREED);
      inc_general_rep(REP_BONUS_CC_XARN_FREED);
      set_global_var(GVAR_NAVARRO_XARN, NAVARRO_XARN_FINISHED); //player has dealt w/xarn
   end
   //give_xp();
end

And finally, Node800 needs to be updated:

Code:
procedure Node800 begin
   if (global_var(GVAR_NAVARRO_XARN) < NAVARRO_XARN_FINISHED) then begin
      display_msg(mstr(820));
      give_xp(EXP_XARN_JOIN);
      inc_general_rep(REP_BONUS_CC_XARN_JOIN);
      set_global_var(GVAR_NAVARRO_XARN, NAVARRO_XARN_FINISHED); //player has dealt w/ xarn
      set_map_var(MVAR_Xarn_In_Party,1);
      critter_add_trait(self_obj,TRAIT_OBJECT,OBJECT_TEAM_NUM,TEAM_PLAYER);
   end
end

7. This is more a matter of code maintenance, but when Xarn leaves the player, he should be removed from the player's team. While this does not impact current functionality, if someone should decide to place Xarn back into action as part of an expansion pack (or Restoration Mod plus 8-)), then it would be useful to tie up loose ends. This is easily done by modifying procedure leave_player in ccXarn.ssl as thus:

Code:
procedure leave_player begin
   if (map_var(MVAR_Xarn_In_Party) == 1) then begin
      floater(500);
      set_map_var(MVAR_Xarn_In_Party, 0);
      gfade_out(600);
      move_to(self_obj,0,0);
      set_local_var(LVAR_freed,2);
      critter_add_trait(self_obj,TRAIT_OBJECT,OBJECT_TEAM_NUM,TEAM_VAULT13);
      gfade_in(600);
   end
end

8. If you talk to the guard outside the commander's office as an intelligent player, one of your reply options (assuming you're clad in power armor) is "What this place?", which sounds rather unintelligent.
This is not surprising, because the script accidentally references the dumb line instead of the more intelligent sounding "What is this place?". To fix, go to Node001 of ccDrGrd.ssl and change:

Code:
   NOption(104,Node002,004);

to:
Code:
   NOption(108,Node002,004);

9. Before attacking you, some of the guards will say "Secure all stations! We're on alert". Note the missing punctuation at the end -- there should either be a period or perhaps the more thematically consistent exclamation mark there. The lines to update are line 152 in ccDrGrd.msg, and line 113 in ccGrdCA.msg, ccGrdPA.msg, and ccMedGrd.msg.

10. A couple of minor typographical errors in ccRaul.msg:
-> line 115: Extra space at the beginning of line
-> line 121: "old mans clock." should be "old man's clock."

11. Cookie the cook is simply called "Cook" during combat or in the dialogue screen. Updating line 1230 in scrname.msg to "Cookie" should fix the problem.

12. If you approach the deactivated K-9 with Lenny in your party, you get some very odd dialogue. K-9 will call you master (regardless of whether or not Dr. Schreber is alive) and you seem to get the normal party options, as if K-9 is in your party, but most of them does absolutely nothing.

The reason is that use_p_proc in ccFaK9.ssl has an explicable conditional check for Lenny being in your party (there's another conditional there, but the other one can never be true). The fix is to remove this conditional check in use_p_proc, but see below for another major error in this procedure.

13. ****** CRASH BUG ALERT! ****** If the player accidentally tries to talk to the disabled K-9 when still in combat, it will crash the game. The reason is that the engine tries to bring up the dialogue interface, and evidently combat mode really doesn't like that sort of thing.

The fix is to encapsulate use_p_proc in ccFaK9.ssl with the outer conditional to check for combat. If the player is in combat, the script should ignore the use attempt. This is accomplished by using combat_is_initialized. Taken together with the previous bug, use_p_proc should look something like:

Code:
procedure use_p_proc begin

   if (not combat_is_initialized) then begin
      if (local_var(LVAR_Personal_Enemy) == 1) then begin
          if (local_var(LVAR_fixed) == 0) then begin
             call Node017;
          end
          else begin
             call Node018;
             call Node998;
          end
      end
//      else if (leaving PC's party) then begin
//      end
//      else if (learning attempt) then begin
//      end
//    else if ((Lenny_In_Party) or (party_is_waiting)) then begin
//       start_gdialog(NAME,self_obj,4,-1,-1);
//       gSay_Start;
//          call Node1000;
//       gSay_End;
//       end_dialogue;
//    end
      //THIS NEEDS TO BE ADDED!
      else if (map_var(MVAR_Doctor_Dead) == 0) then begin
         start_gdialog(NAME,self_obj,4,-1,-1);
         gSay_Start;
            call Node012;
         gSay_End;
         end_dialogue;
      end
      else if ( local_var( LVAR_Part ) == 1 ) then begin
         start_gdialog(NAME,self_obj,4,-1,-1);
         gSay_Start;
            call Node013;
         gSay_End;
         end_dialogue;
      end
      else if (local_var(LVAR_Herebefore) == 0) then begin
          set_local_var(LVAR_Herebefore,1);
          start_gdialog(NAME,self_obj,4,-1,-1);
          gSay_Start;
             call Node001;
          gSay_End;
          end_dialogue;
      end
      else begin
          start_gdialog(NAME,self_obj,4,-1,-1);
          gSay_Start;
             call Node011;
          gSay_End;
          end_dialogue;
      end
   end

end

14. Small code inconsistency in ccFaK9.ssl: In use_skill_on_p_proc, there is a destroy_object call for the Motivator after it is removed from the player's inventory. However, if the player uses the K-9 motivator directly on the animal (use_obj_on_p_proc), it is removed from the inventory, but the motivator itself is not destroyed. The fix is to insert the destroy_object command in the appropriate spot in use_obj_on_p_proc, as thus:

Code:
procedure use_obj_on_p_proc begin
   script_overrides;

   if( map_var(MVAR_Doctor_Dead) == 0 ) then begin
      dialogue_system_enter;
   end
   else begin
      Tool:=obj_pid(obj_being_used_with);
      if (Tool == PID_K9_MOTIVATOR) then begin
         repair_check:=roll_vs_skill(dude_obj,SKILL_REPAIR,-10);
         if (is_success(repair_check)) then begin
            item:=obj_carrying_pid_obj(dude_obj, PID_K9_MOTIVATOR);
            rm_obj_from_inven(dude_obj,item);
            destroy_object(item);
            call Node800;
         end
         else begin
            floater(155);
         end
      end
      else begin //using wrong part
         display_msg(mstr(420));
      end
   end
end

15. If the player attempts to fix K-9 while Doctor Schreber is still alive, then absolutely nothing happens -- all things being equal, one would expect either the Doctor to warn the player away, or for the dog to remind the player that the player is not his master.

The problem lies in talk_p_proc. Trying to fix K-9 invokes either use_obj_on_p_proc or use_skill_on_p_proc. Both of these event handlers check to see if the doctor is still alive, and if yes, they both invoke dialogue_system_enter. Unfortunately, talk_p_proc, while it does exist, is absolutely empty. This explains the observed behaviour of absolutely nothing happening.

The solution is to call use_p_proc in procedure talk_p_proc, as thus:

Code:
procedure talk_p_proc begin
   call use_p_proc;
end
 
I just wanted to say WOW. Haenlomal, you're the man and you should definitely get some credit for this!
 
Nice. This makes a good argument for always using begin/end (or curly braces or whatever your language of choice uses) with if statements, even when it contains just one line of code.

I have to disagree about one of Xarn's lines. "Can not" is valid English, and fits better with his formal style of speaking.
 
Kanhef said:
I have to disagree about one of Xarn's lines. "Can not" is valid English, and fits better with his formal style of speaking.

After a little consideration I agree with this. "Can not" suggests emphasis on the "not" and it's not hard to imagine Xarn speaking that way.
 
I just instaled Fallout 1 and it does not work - "not enaugh free hard disk space", but there is a lot of it. What do I need to do?

P.S. I thank you at the begining :D.

EDIT: solved (edited the fallout.cfg).
 
Hello, I encountered two bugs during my last play through of Fallout 2 with Killap's Unofficial Patch. I'm not certain if the two bugs I experienced were already in Fallout or a result of the patch, but I shall describe them both.

1.) After driving around in the Highwayman and initiating several random encounters to collect firearms to sell, I stopped in New Reno's west end. I sold the firearms for ammo and tried to click on Myron to give it to him and was unable to get any response from him. He still followed me around, and after zoning out and initiating another encounter he still acted normally (shooting a few guys then getting shot and then running away.. lol.) I was just unable to initiate the talk screen. The game didn't recognize that I had clicked on him no matter how many times I had. I was quite frustrated and didn't keep that saved game, I loaded an earlier one and eventually saved over that slot.

2.) In NCR I was doing the mission to give the ranger's map to the slaver. When I came back and clicked on the slaver to complete the quest every line of his dialog was "EEEEEEEE EEEEEEEE" I tried loading an earlier save and doing the quest over, but every time I gave him the map his dialog changed to that.. several lines of it. Through trial and error I got past it by saving the game and then talking to him and hitting random answer lines until the quest was completed and I didn't get shot. I also didn't think to keep this save game and later saved over that slot as well.

Sorry that I am unable to present any screenshots or saved games of the bugs that I encountered. It just didn't cross my mind at the time that it might come in handy at a later date. Thank you all for all of the hard work and time that has gone into the unofficial patch. I love Fallout 2, and this has made it immeasurably more enjoyable.
 
#1 sounds like the 'apathetic Vic' bug. I'm not sure what goes wrong, but it can be triggered by trying to interact with an NPC when they're unconscious or lost a turn in combat.

Don't know about #2, seems like a problem with the dialogue file.
 
Hello Killap and everybody, sorry for my english, i speak a little bit. Pls correct following in the Unofficial patch:
1.Vic's script. There is wrong dialog line, during first talking with him after buying fm Metzger. Instead of question about flask, chosen ask about Ed, but Vic answer about flask.

2.In the Modoc. I give gold watch to forrel, then say to kornelius about forrel's wall safe-box. Kornelius gous discuss with forrel. I'm clicking mouse on the forrel and kornelius, then going out fm map, and fly to windows.(

3.In the Gecko. I bring Gordon's disk to Macclur, take part fm Rendall, return to Gecko, talk with brain, and found out wrong dialog, hi speak dialog line instead of Zamok (You have symbol...). After reloaded, talk with brain again and flying windows
 
Hello, this is my first post on this forum.
Terrible thing has happen to me.
I am playing on this patch: http://www.nma-fallout.com/forum/dload.php?action=file&file_id=86

The story: After leaving 4th level of Enclave, where reactor is, to higher one, game crashes. No mean if I kill president, spread FEV or doing nothing - game crashes ang I get an Aplication Error.
I reinstalled game, but it seems to be not working - game still crashes.

Could you help me with this?
If nothing can be done, could someone send me savegame after blasting reactor, with char on 3th level of Enclave?
Of course - savegame from polish edition on patch 1.05.

Excuse me my crappy english.


----
It's propably not fault of patch, but I have this patch installed, so i have to write here.

------
Savegame could be also from nonpatched game.
 
kol said:
Of course - savegame from polish edition on patch 1.05.

1.05 has some problems, so it could very well be that.

On a different note, I noticed something that may be more fit for the RP. The item descriptions say that broc flower is "plentiful" and xander root is "rare". However, the map script actually spawns more roots than flowers: 2-4 of each and possibly 1 more root.

There's also nothing to stop roots and flowers from spawning in multitudes on top of each other if you leave them be and enter and exit the map many times, but I suppose that might be a lesser concern.
 
Back
Top