Jump to content

Ironing out a few bugs


Chokboyz

Recommended Posts

Here are several (last ?) bugs that needs to be fixed prior to an executable release. Don't hesitate to post informations on these (what is the problem, example of the problem, compatibility breaking, etc) as this will make the fixing process a lot faster.

 

By the way, if there's any bug you consider should belong to the list, don't hesitate to mention it.

 

Bugs :

  • When the party is split up, Affect PC special nodes should only affect the active PC ? (any compatibility breaking ?)

    Fixed, only the Kill/Raise Node has been left untouched.

  • Apparently event timers are broken. (an example of bad behavior would be nice smile Here again, no compatibility breaking ?)

    Should be done with the new timers handling method.

  • Empties! Found one cause, keep an eye open in the case there was another ...
  • Creatures in one time place town encounters don’t check their life flag. (compatibility breaking ?)

    Hopes not, this has been fixed.

  • Changing the visibility (i.e., opaque, transparent, etc.) of terrain types often does not work. (examples would be appreciated here ... Firing arrows through solid walls or in the dark has already been fixed)
  • 100% in Blades doesn’t equal 100%. (if there is any occurence that comes to your mind besides random number calculation, summon chances, dropping chances, statistic affecting chances, monsters field appearing chances, don't hesitate to mention it).
Here's what has already been done (note that some bugs were Windows specific, the Mac version should be up-to-date thanks to Celtic Minstrel) :

Click to reveal.. (Changelog)
- Custom Scenario Loading now works.

- Conceal Ability Flag now works.

- Game now uses the font that comes with it.

- Strengh potions can now be made (Ishad Nha)

- Add/Lose Sanctuary and Add/Lose Martyr's Shield abilities fixed. (Ishad Nha)

- Acidic weapons works as living saving charm fixed. (Ishad Nha)

- Fixed the raise_dead node so that it actually raise dead. (Ishad Nha)

- Fixed the second part of a special node dialog called from a conversation wasn't properly recorded (actually read).

- Fixed custom items weren't properly masked (transparent background) in the inventory .

- The Defense skill was used rather than the Thrown Missiles skill when firing missiles weapons .

- Fixed the Paralysing Ray trap wasn't working.

- Fixed the petrification touch was causing disease. You now have the same chance of being petrified that when a basilisk gazes at you each time your are hit (subject to changes) (!).

- Make the automap updates after terrain change/swap/transform.

- Cleaned and expanded the Debug Mode. Type 'D' to begin debug mode and '/' to see commands. (Ishad Nha)

- Corrected doubling 152 index in m_pic_index (little alien beast graphic can now be used). (Ishad Nha)

- Corrected the "Town Special Encounter" node so that it makes full use of the ten groups.

- Fixed the ring of Will was not checked during mind duel. (Lots of people)

- Fixed Destroy Items and Move Items nodes so that they work for rectangles as well as a single space.

- Hide Town now works.

- Appears/Disappears on Day X now works. So does Appears/Disappears on Events.

- Fixed the day_reached function so that it correctly checks if the major event between 1 and 10 has occured (0 always happens)

- Nimble trait actually gave lower chance to disarm a trap, picklock and to put poison correctly. Fixed, the game now gives bonus to nimble ones rather than penalizing characters without the trait.

- Changing non-conveyer belt terrain into conveyer belt terrain will not work unless the town where the change occurs begins with a least one square of conveyer belt terrain as default. Fixed

- Step on sound code implemented.

- Corrected the Affect Statistic Node random calculation method, so that 100 happens all the time (and 0 never).

- Conveyor freezes upon loading fixed.

- Chances of dropping fixed, so that 100 happens all the time (and 0 never)

- Monster radiates field and rect_spec were plagued with the same random calculation as affect statistic node. Monster special ability : summons is now accurate.

- Last missile weapon in a group that possess special abilities will fail when fired and last stack of an ordinary thrown item that is placed immediately prior to a stack of another missile weapon with a special ability in that PC’s inventory will gain the special ability of the adjacent missile weapon fixed.

- Fixed the bug where you could fire an exploding arrow everywhere on the map, even if the target was out of range or not in sight.

- The 16 different area descriptions can now be used.

- The Spells “Resurrection” and "Raise Dead" did not require a Resurrection Balm, despite advertisements to the contrary. This is fixed in new scenarios (major version more or equal to 2) and left alone in legacy scenarios for compatibility reasons.

- If two friendly NPCs occupy the same space, and they both have dialogued personalities, talking to either of them will talk count as if talking to the first placed mosnter. This prevent the game from freezing.

- According to the BOE Manual, the Affect Party — Do Damage special node allows the scenario designer to vary the Pict. box. Doing so will supposedly only cause damage to the PC who triggers the special, if the party is in combat node. Fortunately, this has been fixed.

- Ice and Magic damaging terrains now displays the right effect/plays the right sound when damaging the party while not in combat.

- “Map Not Available” Option implemented. => (temporary ?) assigned to SDF[308][0]

- Fixed (?) oddities appearing in the map with animated terrains (torches, firecamp, water, ...).

- 100 town bug lurking ? <= should be done

 

Changes :

- Add a preference option that displays or not the start-up picture and music.

- Changed the "Wait 40 moves" dialog to "Wait 80 moves" to better reflect the time actually waited.

- Added a "Fast Boom Space Effects" option that speeds up any boom sfx in the game.

- The party status text (Flying, Firewalk, Detect Life, Stealth) is not longer black on black. It should be readable now.

- Once identified, the exploding arrows now shows the radius of the explosion.

 

 

Chokboyz

 

Link to comment
Share on other sites

I'm not entirely sure whether I've implemented everything on that list, but I think I've dealt with most of them.

 

Just a note: don't try to make use of the "Map Not Available" option – it's almost certainly temporary and will at some point be assigned to some other place (probably in the town and/or outdoor record).

Link to comment
Share on other sites

Originally Posted By: Chokboyz
Bugs :
    [*]When the party is split up, Affect PC special nodes should only affect the active PC ? (any compatibility breaking ?)


I think this actually does have the potential to break compatibility with some scenarios (or at least, to create an exploitable glitch). For example, some scenarios include time limits on either certain sections or the scenario as a whole, which are enforced by killing the party if time runs out. If your changes are implemented, then if the party can get to a Split Party node while the timer is running and wait for it to run out while the party is still split, they can get past the death node with only one dead PC and the rest of their party still alive, which is not the intended behaviour. I'm not sure how many scenarios are likely to be affected by this in practice, but there are certainly some, like Spy's Quest, that include both party-splitting and death timers.
Link to comment
Share on other sites

  • 2 weeks later...

Creatures in one time place town encounters don’t check their life flag has been fixed.

If this break any compatibility, this is the last chance to say it ... smile

 

Examples (recipes ?) for the Empty bug (which is not fixed, as i've encountered one in the room filled with sleepy gas in Baba Yaga's hut) and the Event Timers bug would be nice wink

 

Chokboyz

 

Edit : Forgot to post the code ...

In the activateMonsters() function (name may vary in Mac version), i've replaced the line

if (monst.dudes.monst_start.spec_enc_code == code)

by

if (monst.dudes.monst_start.spec_enc_code == code && party.stuff_done[monst.dudes.monst_start.spec1][monst.dudes.monst_start.spec2] == 0)

Link to comment
Share on other sites

Oh, right.

 

Still, it's not necessary in the current_town_type, since friendly could be stored directly in the current_town_type and which_town already is stored there.

 

It's necessary in the party record though.

 

I don't think I've made any such changes yet.

Link to comment
Share on other sites

  • 1 month later...

Two potentially compatibility breaking changes have been made (you can activate and desactivated them at will for now, the make version of the scenario will be checked in the future):

 

  • Stairway nodes can now be called anytime/anywhere (if talking, the dialog ends and the party is moved), except while in combat.

    Should i also include combat mode (the combat ends, then the party is moved) ? That would prevent some exploit (e.g timers triggers stairway node, but the player bypass it by getting into combat mode right before the triggering)

  • Event Timers now kicks in even while resting outdoor/in inn (that should fix broken scenario timers).

    The "Change Time" node is not affected (it's not about passing time, it's about setting time), but the "Have a Rest" node is a problem : if a timer kicks in while resting through such a node what should we do ? Break the first node chain ? Stack a second chain on top of the first ? Do nothing and document the feature ?

Don't hesitate to comment wink

 

Chokboyz

Link to comment
Share on other sites

My thoughts on the matter, based solely on your summary:

 

For the first, it seems to me that your suggested method of dealing with combat mode sounds like a good idea, as it would make the overall behavior more uniform, assuming that doing so doesn't involve overly great technical difficulty.

 

The second is much tougher, since it's basically a concurrent code execution problem. Breaking the first chain, the one containing the rest node if I understand correctly, seems like a bad idea, as it could leave the scenario stuck in an inconsistent state: the timer's chain doesn't necessarily have the knowledge to deal with whatever the first chain might have been doing when interrupted. The second option seems to me attractive, conditional on it not being difficult to implement and making sure that designers understand its implications. I can imagine that there are a number of simple things that a timer might do that wouldn't really interfere with other node chains containing a rest, like say, healing the party a little or some such, and it should be no big deal to let such things happen 'concurrently'. On the hand, there are big, likely plot-important node sequences designers might create which could interfere with each other in an ugly way if one included a rest and another was attached to a timer. One solution would be to simply warn designers about this, and leave it up to them not to build interfering code. Another might be to let a timer have a setting for what it should do it it would interrupt another node sequence, with possible options being to have it just run in the middle of the other sequence (fine for minor, non-interfering things), abort (fine for minor but interfering things), or defer until after the other nodes (for important, interfering timed sequences). This would be more technically involved, but would give designers a nicely fine level of control. Of course, there's always the last option, which is to leave the current behavior (which I assume is that timers are ignored during resting nodes?) and leave it up to designers to code around it. This is both the path-of-least-resistance and also might not be so bad, as this is a kind of odd edge case.

Link to comment
Share on other sites

A few odd things I noticed:

 

1) The Spiderweb Software logo screen when you start BoE no longer plays the sound. The splash screen with the bald guy still plays the music, but I believe the Spidweb logo used to play the sound that plays when you enter a darkened town. Not really important, but just noticing.

 

2) When you exit the Preferences screen in the game via the OK button, it automatically reduces the window as though you had selected "Small Window (not full screen)". However, when I selected that option, hit OK (at which point it did what it should) and then went back to Preferences and selected to display the game Centered, that weird behavior stopped.

 

3) In the scenario editor, when you load a new town, it automatically enters the Edit Town Terrain screen. This is inconvenient if you want to edit dialogue.

Link to comment
Share on other sites

Originally Posted By: Niemand
For the first, it seems to me that your suggested method of dealing with combat mode sounds like a good idea, as it would make the overall behavior more uniform, assuming that doing so doesn't involve overly great technical difficulty.

I thought as much, so i've began to include the combat mode (i turned to be harder than i thought, but i should make it). I'm also thinking about putting a check on a given variable (pic/SDF_1/SDF_2) to activate combat-active Stairway nodes ...

Originally Posted By: Niemand
The second is much tougher,

You summed up pretty good the different options available. I'm leaving that alone for the moment, as i/we need some more thinking on that before deciding ... smile

Originally Posted By: The Almighty Doer of Stuff
1) The Spiderweb Software logo screen when you start BoE no longer plays the sound. The splash screen with the bald guy still plays the music, but I believe the Spidweb logo used to play the sound that plays when you enter a darkened town. Not really important, but just noticing.

Left off on purpose, putting it back would be quite simple.

Originally Posted By: The Almighty Doer of Stuff
2) When you exit the Preferences screen in the game via the OK button, it automatically reduces the window as though you had selected "Small Window (not full screen)". However, when I selected that option, hit OK (at which point it did what it should) and then went back to Preferences and selected to display the game Centered, that weird behavior stopped.

That's really weird, i've been unable to reproduce that ... When does that happens ? Everytime you clicked "Ok" or only once ?

Originally Posted By: The Almighty Doer of Stuff
3) In the scenario editor, when you load a new town, it automatically enters the Edit Town Terrain screen. This is inconvenient if you want to edit dialogue.

It should be fairly easily to just load the town without entering. I didn't implement the town entering part, so i assume it's the legacy behavior ?

Thanks, for the comments
Chokboyz
Link to comment
Share on other sites

Originally Posted By: Chokboyz
Stairway nodes can now be called anytime/anywhere (if talking, the dialog ends and the party is moved), except while in combat.
Should i also include combat mode (the combat ends, then the party is moved) ? That would prevent some exploit (e.g timers triggers stairway node, but the player bypass it by getting into combat mode right before the triggering)
At first I was against accepting stairways in combat, but after some thought I changed my mind. However, I'm now wondering if it would be better to not end combat mode in this situation (at least from the player's viewpoint; this could also be achieved by exiting combat, moving the party, and then re-entering combat).

Originally Posted By: Chokboyz
Event Timers now kicks in even while resting outdoor/in inn (that should fix broken scenario timers).
The "Change Time" node is not affected (it's not about passing time, it's about setting time), but the "Have a Rest" node is a problem : if a timer kicks in while resting through such a node what should we do ? Break the first node chain ? Stack a second chain on top of the first ? Do nothing and document the feature ?
So, the Have a Rest node actually is implemented in the same way as the Rest button outdoors and the inn? As in, it passes time for so long, then sets time?

I believe the current code would prevent the timer from triggering, because if run_special() is called while a special is being executed, it skips it. However, I think it might be cleaner to delay the timer to trigger after the node sequence containing a Rest node terminates. There is a special queue already in the code (it's only used for entering and leaving town in the original code), and I have altered it in such a way that I think it could support this.
Link to comment
Share on other sites

Originally Posted By: Niemand
The second is much tougher, since it's basically a concurrent code execution problem. Breaking the first chain, the one containing the rest node if I understand correctly, seems like a bad idea, as it could leave the scenario stuck in an inconsistent state:
Yes, I agree completely with this.

Originally Posted By: Niemand
the timer's chain doesn't necessarily have the knowledge to deal with whatever the first chain might have been doing when interrupted. The second option seems to me attractive, conditional on it not being difficult to implement and making sure that designers understand its implications.
As I just said, there is something in place which could support this with minimal alterations (alterations that have already been applied to the Mac code).

Originally Posted By: Niemand
I can imagine that there are a number of simple things that a timer might do that wouldn't really interfere with other node chains containing a rest, like say, healing the party a little or some such, and it should be no big deal to let such things happen 'concurrently'.
At the same time, it would be harmless to delay them.

Originally Posted By: Niemand
On the hand, there are big, likely plot-important node sequences designers might create which could interfere with each other in an ugly way if one included a rest and another was attached to a timer. One solution would be to simply warn designers about this, and leave it up to them not to build interfering code. Another might be to let a timer have a setting for what it should do it it would interrupt another node sequence, with possible options being to have it just run in the middle of the other sequence (fine for minor, non-interfering things), abort (fine for minor but interfering things), or defer until after the other nodes (for important, interfering timed sequences). This would be more technically involved, but would give designers a nicely fine level of control.
Actually, I quite like this idea, and it would be exceedingly simple to do, I think. Assuming the special queue already exists, you would simply have to alter the check in run_special that determines if a special is already executing. I think the easiest way for giving the timer priority would be to reset that value, re-call run_special() with the exact same arguments, and then restore the value. For adding to the queue, I think it would be even simpler. And abort is the currently existing behaviour, I think.

Originally Posted By: Niemand
Of course, there's always the last option, which is to leave the current behavior (which I assume is that timers are ignored during resting nodes?) and leave it up to designers to code around it. This is both the path-of-least-resistance and also might not be so bad, as this is a kind of odd edge case.
Yes, I'm pretty sure the node would be ignored by default.
Link to comment
Share on other sites

Originally Posted By: The Almighty Doer of Stuff
1) The Spiderweb Software logo screen when you start BoE no longer plays the sound. The splash screen with the bald guy still plays the music, but I believe the Spidweb logo used to play the sound that plays when you enter a darkened town. Not really important, but just noticing.
I can't imagine why he removed it. It works in my (Mac) version, provided you have sounds enabled.

Originally Posted By: The Almighty Doer of Stuff
3) In the scenario editor, when you load a new town, it automatically enters the Edit Town Terrain screen. This is inconvenient if you want to edit dialogue.
This is certainly not right. The Mac editor does not do this.

Originally Posted By: Chokboyz
I'm also thinking about putting a check on a given variable (pic/SDF_1/SDF_2) to activate combat-active Stairway nodes ...
Let's reserve this for a dedicated "Mode Check?" node.

Originally Posted By: Chokboyz
Left off on purpose, putting it back would be quite simple.
I would like it to be put back, personally. It has no effect either way, really, and the presence of the sound is the legacy behaviour.

Originally Posted By: Chokboyz
It should be fairly easily to just load the town without entering. I didn't implement the town entering part, so i assume it's the legacy behavior ?
I'm pretty sure it's not. At least, it's not legacy behaviour in the Mac version. Perhaps it's something Ishad Nha did. I don't think it's a good idea, for the reason ADoS mentioned (what if you just want to edit dialogue?).
Link to comment
Share on other sites

Originally Posted By: Celtic Minstrel
At first I was against accepting stairways in combat, but after some thought I changed my mind. However, I'm now wondering if it would be better to not end combat mode in this situation (at least from the player's viewpoint; this could also be achieved by exiting combat, moving the party, and then re-entering combat).

I've just finished coding (and testing) the combat mode stairway node and i've added re-entering combat.

Originally Posted By: Celtic Minstrel
So, the Have a Rest node actually is implemented in the same way as the Rest button outdoors and the inn? As in, it passes time for so long, then sets time?

Exact, except it just set the time (no time passes) and health the party.

Originally Posted By: Celtic Minstrel
I believe the current code would prevent the timer from triggering, because if run_special() is called while a special is being executed, it skips it. However, I think it might be cleaner to delay the timer to trigger after the node sequence containing a Rest node terminates. There is a special queue already in the code (it's only used for entering and leaving town in the original code), and I have altered it in such a way that I think it could support this.


That's an excellent idea and i will see how i can implement this wink

Originally Posted By: The Almighty Doer of Stuff
1) The Spiderweb Software logo screen when you start BoE no longer plays the sound. The splash screen with the bald guy still plays the music, but I believe the Spidweb logo used to play the sound that plays when you enter a darkened town. Not really important, but just noticing.

Readded.

Originally Posted By: The Almighty Doer of Stuff
3) In the scenario editor, when you load a new town, it automatically enters the Edit Town Terrain screen. This is inconvenient if you want to edit dialogue.

Changed to only loading.

Chokboyz
Link to comment
Share on other sites

Originally Posted By: Chokboyz
Originally Posted By: Celtic Minstrel
So, the Have a Rest node actually is implemented in the same way as the Rest button outdoors and the inn? As in, it passes time for so long, then sets time?

Exact, except it just set the time (no time passes) and health the party.
So if no time passes, how would a timer get triggered?
Link to comment
Share on other sites

I have an idea. What if, when a timer goes off during a Have A Rest node, the game counts how many moves are left in the Have A Rest node, and stores it to a variable. Then, it waits until the HAR node chain finishes, and triggers the timer. Then, if another timer is called in the same chain as the first timer, the number of moves for the new timer is reduced by a number equal to the lesser of the following two numbers: A) the new timer's move counter, or B) the HAR remaining moves counter. The HAR remaining moves counter is reduced by the same number. If, when that timer resolves, another timer is called (for instance, if it were a loop), the process repeats until the HAR remaining moves counter is empty. If no more timers are called by the time all chains finish, the counter is reset for the next HAR.

 

Perhaps this would minimize the potential timer misalignment that could be caused. I know it's not written very well, but maybe you can understand. If not, feel free to ask questions.

Link to comment
Share on other sites

Originally Posted By: Celtic Minstrel
Let's reserve this for a dedicated "Mode Check?" node.

No problem.

Originally Posted By: Celtic Minstrel
So if no time passes, how would a timer get triggered?

For now, no timers are triggered by Have a Rest nodes, for the previously mentioned reasons.
I thought you were speaking about the original behavior of the Have a Rest node (by the way, Outdoor and Inn resting skips a large portion of the time actually rested in the original version).

Chokboyz
Link to comment
Share on other sites

Originally Posted By: Chokboyz
Originally Posted By: Celtic Minstrel
So if no time passes, how would a timer get triggered?

For now, no timers are triggered by Have a Rest nodes, for the previously mentioned reasons.
I thought you were speaking about the original behavior of the Have a Rest node (by the way, Outdoor and Inn resting skips a large portion of the time actually rested in the original version).
Oh, you're saying the Have A Rest node used to trigger timers, but you changed that? Or it didn't, and you're thinking maybe it should?

Originally Posted By: The Almighty Doer of Stuff
I have an idea. What if, when a timer goes off during a Have A Rest node, the game counts how many moves are left in the Have A Rest node, and stores it to a variable. Then, it waits until the HAR node chain finishes, and triggers the timer. Then, if another timer is called in the same chain as the first timer, the number of moves for the new timer is reduced by a number equal to the lesser of the following two numbers: A) the new timer's move counter, or B) the HAR remaining moves counter. The HAR remaining moves counter is reduced by the same number. If, when that timer resolves, another timer is called (for instance, if it were a loop), the process repeats until the HAR remaining moves counter is empty. If no more timers are called by the time all chains finish, the counter is reset for the next HAR.
I see your point. You want the timer to trigger at the correct time even if it's delayed until after a currently running special sequence ends. This is a convoluted way of doing it, though. Let me see if I can unravel it...

  • During a Have a Rest node, a timer (or other similar special node, if such is added) is triggered.
  • Since a node sequence is already underway, it is queued instead of being run. The time of triggering is stored in the queue.
  • The sequence containing the Have a Rest node ends, and the timer is triggered. The resulting node sequence sets a new timer.
  • Now, you want the new timer to be set in such a way that the number of moves between the timer initially triggering and the other node sequence finishing is counted toward the new timer. Your proposal involves subtracting the difference, whereas my proposal would involve storing the current time, rewinding the clock, and then restoring the time. (This would have to account for the possibility of the timer calling a Change Time node though.)
  • If the number of moves between the timer's initial triggering and the end of the original Have a Rest node sequence was greater than the number of moves of the new timer, you want it to be triggered immediately and the preceding rule applied if yet another timer is set, and so on until the timers catch up to the actual current time.


Now, I think the easiest way to implement this would be to place all timer-triggered nodes into the queue rather than calling run_special() immediately. The special queue would now need to keep track of the time that the node was triggered, and when running through the queue we would have to store the current time, set it to whenever the node was triggered, call run_special(), and then restore it afterwards. Like so:
Code:
long long store_time = univ.party.age;univ.party.age = special_queue[i].trigger_time;// Call run_special() with the other data from special_queue[i] (which is a pending_special_type struct)long long change_time = univ.party.age - special_queue[i].trigger_time;univ.party.age = store_time + change_time;


The pending_special_type (which probably doesn't exist in the original code; the special queue was original composed of several separate arrays rather than one struct array) would need a new field, trigger_time. The above code goes in handle_action, in the part where the special queue is cleared out.

The only other thing to do would be placing a special in the special queue whenever a timer is triggered, rather than calling run_special() immediately. At least, I think that would be the only other thing. To see how to add to the special queue, look at the code handling see monster specials or enter/leave town specials in my code.


(Since I've already written the above code, I'll add it right now.)
Link to comment
Share on other sites

Originally Posted By: Celtic Minstrel
The special queue would now need to keep track of the time that the node was triggered, and when running through the queue we would have to store the current time, set it to whenever the node was triggered, call run_special(), and then restore it afterwards.

This does make the code tied to the timer think that it wasn't delayed, by why is that a good thing? If it cares about the time at all, shouldn't it be given the actual time, not a false time in the past? Basically, if given the actual, delayed time, it's possible to write a little more code (add a few more nodes) in theory to correct for the delay, whereas doing so is impossible if the time is always reported exactly as the expected time whether or not such is true.

I do agree that consolidating everything into a queue is the natural way to handle timers in general. As a matter of fact, if all timers were always in a priority queue, with the priority being how soon the timer should next fire, the entire operation of firing timers is very elegant: after advancing time, check the front of the queue to find out if the timer there fires. If so, run the associated nodes, and then repeat until the front most timer isn't ready to fire. (This may be what you were saying already, so sorry if I'm being redundant.)
Link to comment
Share on other sites

Originally Posted By: Niemand
This does make the code tied to the timer think that it wasn't delayed, by why is that a good thing? If it cares about the time at all, shouldn't it be given the actual time, not a false time in the past? Basically, if given the actual, delayed time, it's possible to write a little more code (add a few more nodes) in theory to correct for the delay, whereas doing so is impossible if the time is always reported exactly as the expected time whether or not such is true.
I dunno, it just seems like a good idea to me. I don't see any reason why a timer would need to know that it was delayed. Can anyone else think of a reason for a timer to know this?

Originally Posted By: Niemand
I do agree that consolidating everything into a queue is the natural way to handle timers in general. As a matter of fact, if all timers were always in a priority queue, with the priority being how soon the timer should next fire, the entire operation of firing timers is very elegant: after advancing time, check the front of the queue to find out if the timer there fires. If so, run the associated nodes, and then repeat until the front most timer isn't ready to fire. (This may be what you were saying already, so sorry if I'm being redundant.)
It's currently just a regular array, but I could put it in an std::priority_queue. I would need to write a comparison function, if I recall correctly, but that's not hard (just compare using the trigger_time member).
Link to comment
Share on other sites

Originally Posted By: Celtic Minstrel
Oh, you're saying the Have A Rest node used to trigger timers, but you changed that? Or it didn't, and you're thinking maybe it should?

The second one smile

Originally Posted By: Niemand
This does make the code tied to the timer think that it wasn't delayed, by why is that a good thing? If it cares about the time at all, shouldn't it be given the actual time, not a false time in the past? Basically, if given the actual, delayed time, it's possible to write a little more code (add a few more nodes) in theory to correct for the delay, whereas doing so is impossible if the time is always reported exactly as the expected time whether or not such is true.

While i agree not delaying things would be nice, it's in practice quite hard to achieve, as in the current state of the code, stacking node chains is not possible (cf the special_in_progress variable).
Concerning the end of the quote, the actual time is used for the delayed node : the triggering time is stored in a member of the pending_special_type struct and the party.age is temporary rewind to the triggering time for the queued special to take place.

Originally Posted By: Niemand
I do agree that consolidating everything into a queue is the natural way to handle timers in general. As a matter of fact, if all timers were always in a priority queue, with the priority being how soon the timer should next fire, the entire operation of firing timers is very elegant: after advancing time, check the front of the queue to find out if the timer there fires. If so, run the associated nodes, and then repeat until the front most timer isn't ready to fire. (This may be what you were saying already, so sorry if I'm being redundant.)

Unfortunately, this real-time trigger firing method would work only if the timed special doesn't happens while a node chain is running (again, the case of "Have a Rest" node). Apart from that, it's indeed a rather elegant solution smile

To Celtic Minstrel :

i've changed the special_queue from short [20] to pending_special_type [20] where the latter is a structure with two members (short queued_special; long trigger_time).
I will try to implement the queue solution, but i disagree with your code :
Quote:
long long store_time = univ.party.age;
univ.party.age = special_queue.trigger_time;
// Call run_special() with the other data from special_queue (which is a pending_special_type struct)
long long change_time = univ.party.age - special_queue.trigger_time;
univ.party.age = store_time + change_time;

For sake of simplicity, let's say party.age is 0. Suppose that the party triggers a "Have a Rest" node that makes them rest 50 (Time Units). During the rest, after 10 T.U (special_queue.trigger_time = 10), a timed trigger fires in and is placed in the queue.
After the rest ends (party.age = 50 = store time ), the timed trigger is processed. Suppose now that a "Change time" or "Have a Rest" node is called by the timer node chain, and 20 T.U is waited.
After the timer node chain ended, change_time = 20 (= current party.age (30) - trigger_time (10)), so party.age is set to 70, which is wrong because the timer node chains took place within the 50 T.U of the first Rest node (timer chain ended at 30 T.U).

I would replace the two last lines with
if(party.age < store_time)
party.age = store_time;


Hope i'm not mistaken,
Chokboyz
Link to comment
Share on other sites

Originally Posted By: Chokboyz

i've changed the special_queue from short [20] to pending_special_type [20] where the latter is a structure with two members (short queued_special; long trigger_time).
Look at my code – you're missing about three members.

Originally Posted By: Chokboyz

I will try to implement the queue solution, but i disagree with your code :
Quote:
long long store_time = univ.party.age;
univ.party.age = special_queue.trigger_time;
// Call run_special() with the other data from special_queue (which is a pending_special_type struct)
long long change_time = univ.party.age - special_queue.trigger_time;
univ.party.age = store_time + change_time;

For sake of simplicity, let's say party.age is 0. Suppose that the party triggers a "Have a Rest" node that makes them rest 50 (Time Units). During the rest, after 10 T.U (special_queue.trigger_time = 10), a timed trigger fires in and is placed in the queue.
After the rest ends (party.age = 50 = store time ), the timed trigger is processed. Suppose now that a "Change time" or "Have a Rest" node is called by the timer node chain, and 20 T.U is waited.
After the timer node chain ended, change_time = 20 (= current party.age (30) - trigger_time (10)), so party.age is set to 70, which is wrong because the timer node chains took place within the 50 T.U of the first Rest node (timer chain ended at 30 T.U).

I would replace the two last lines with
if(party.age < store_time)
party.age = store_time;

Hmm, I do see what you mean. You're saying that a Change Time node should be swallowed up by the timer if it executes during it, while my version effectively extends the timer.

I don't see that either of them is wrong. I'm not sure which is best.
Link to comment
Share on other sites

Originally Posted By: Celtic Minstrel
Look at my code – you're missing about three members.

I had not realized you had already such a structure, i'll complete it smile

Originally Posted By: Celtic Minstrel
Hmm, I do see what you mean. You're saying that a Change Time node should be swallowed up by the timer if it executes during it, while my version effectively extends the timer.

Isn't the purpose of storing the party.age the timer is supposed to trigger, to make it behaves as a real time triggering ? Then why would it extend the party.age if the whole timed event happened during the rested time ? It doesn't happens after resting, it happens while resting ... Or am i missing something ? confused
Of course, if the timed event length is greater then the party.age at the end of the rest, the party.age should be increased accordingly.

Chokboyz
Link to comment
Share on other sites

Okay, I think you're right. Let's do this after running the special in the queue:

Code:
univ.party.age = max(univ.party.age,store_time);

 

By the way, we should use a long long for this since age is a long long now.

 

Originally Posted By: Chokboyz
I had not realized you had already such a structure, i'll complete it smile
Yes, I made it to match the already existing special queue functionality (originally used only for town entry/exit specials). You'll also need the enum for the values indicating when/how the special was triggered.
Link to comment
Share on other sites

Originally Posted By: Celtic Minstrel
Okay, I think you're right. Let's do this after running the special in the queue:
Code:
univ.party.age = max(univ.party.age,store_time);

No problem smile

Originally Posted By: Celtic Minstrel
By the way, we should use a long long for this since age is a long long now.

The age is still a long type in my version of the code. Won't converting it to long long break the save format ?

Chokboyz
Link to comment
Share on other sites

I found a bug in the Windows scenario editor. I had a node chain in my town, which utilized Has Item of Class? (+ take), Random Number?, and Display Message. Then I realized that Has Item of Class? (+ take) only takes one item and not all items with that class (for some reason I never knew that, although it definitely makes sense). So I decided to redo the node chain with only one class and only one HIoC(+t) node , and deleted the whole thing, but left the Town Text items so I could re-enter them in the new nodes.

 

However, when I entered the message numbers in the new Display Message nodes and hit "Create/Edit", I got an asterisk in each of the two text entry fields. Some experimentation revealed that the editor was not deleting the messages, which is good when you've entered a number for an existing message, but then it displays the first two unused (asterisked) messages in the text entry fields, with the asterisks still there.

 

If you don't enter numbers (leave both at -1) and hit "Create/Edit", it selects the first two unused messages and deletes the asterisks, as it should.

 

Also, if you don't enter numbers, hit "Create/Edit", and enter a message, then click OK and hit "Create/Edit" again, the proper messages will be displayed in the text entry fields.

 

EDIT: Also, this seems to happen with all nodes with Display Message-style messages. I don't know if it happens with long messages (the ones with 6). I might test that later.

Link to comment
Share on other sites

Just to be sure : the number entered is not the one read in the town text section ... In fact, if the number x is entered, the town text x + 20 is loaded (that's because the first twenty strings are reserved for town name and rectangles description).

 

Try putting your message number - 20 in place of the message number and see if it works ...

 

Chokboyz

Link to comment
Share on other sites

Yes, that would be the problem.

 

It seems like an awful pain to have to remember to subtract 20 from every message that gets put in a special node. Perhaps for future (non-classic) releases this could be made so you enter the actual string number?

 

Anyway, I found an actual bug, in the Character Editor. The Character Editor allows you to make Spell Points negative. I don't know about other stats.

Link to comment
Share on other sites

Originally Posted By: The Almighty Doer of Stuff
It seems like an awful pain to have to remember to subtract 20 from every message that gets put in a special node. Perhaps for future (non-classic) releases this could be made so you enter the actual string number?
This will be possible because the first 20 strings are stripped away into a separate array (and some are stored singly too), so while you'll enter the same number, the numbers in the list of strings will be shown as different.

I hope that makes sense?

I did the same sort of thing with all strings, town, outdoor, and scenario alike – splitting them up into purpose-based arrays. (Actually std::vectors, but that's a minor detail. It just means there's theoretically no limit on the number of strings you can have.)
Link to comment
Share on other sites

I found another oddity, that was present since the original BoE. The Affect Experience node gives 150% of the experience you tell it to give, it seems. Backwards compatibility needs to be preserved, of course, but for the future perhaps the node should be made more transparent.

Link to comment
Share on other sites

Originally Posted By: The Almighty Doer of Stuff
Anyway, I found an actual bug, in the Character Editor. The Character Editor allows you to make Spell Points negative. I don't know about other stats.

What do you mean ? Does it allows you to input negative numbers or doing negative spells points appears out of nowhere when using the Character Editor ?

Originally Posted By: The Almighty Doer of Stuff
I found another oddity, that was present since the original BoE. The Affect Experience node gives 150% of the experience you tell it to give, it seems. Backwards compatibility needs to be preserved, of course, but for the future perhaps the node should be made more transparent.

That's because the xp given is adjusted by being multiplied by the value at index = level / 2 in the following array :
xp_percent[30] = {150,120,100,90,80,70,60,50,50,50,45,40,40,40,40,35,30,25,23,20,15,15,15,15,15,15,15,15,15,15};

Also, what about your windowed vs fullscreen when clicking ok in preference bug ?

Chokboyz
Link to comment
Share on other sites

Originally Posted By: Chokboyz
That's because the xp given is adjusted by being multiplied by the value at index = level / 2 in the following array :
xp_percent[30] = {150,120,100,90,80,70,60,50,50,50,45,40,40,40,40,35,30,25,23,20,15,15,15,15,15,15,15,15,15,15};
So, we just need to document it then. At a minimum, say that the experience given is adjusted based on the level.
Link to comment
Share on other sites

Originally Posted By: Celtic Minstrel
So, we just need to document it then. At a minimum, say that the experience given is adjusted based on the level.

Right smile

I've finished implementing (and testing) the timed specials queue handling procedure and it's working like a charm (even made a stairway node kicks in right after the Have a Rest node without any problem ...) wink
So, the timer issue should now be mostly ok ... (i've modified the special_increase_age() function a bit, so that every timed special can be triggered via the queue with minimum coding effort, should the need ever arise ...)

Chokboyz
Link to comment
Share on other sites

The Small Window thing stopped happening. It may have been a fluke. I'll try installing a fresh copy in a different directory and see if it happens again later.

 

As for the spell points, it allows you to hit the "-" button for Spell Points to decrease spell points into negative values. I think this was present in the original editor, and I think it resets it to zero after you hit OK, making it merely an aesthetic glitch, although some testing couldn't hurt.

Link to comment
Share on other sites

Originally Posted By: The Almighty Doer of Stuff
The Small Window thing stopped happening. It may have been a fluke. I'll try installing a fresh copy in a different directory and see if it happens again later.
Perhaps it was a corrupted preferences file or something. Or, if there was no preferences file, then perhaps it was a case of not initializing a variable.
Link to comment
Share on other sites

I created a fresh copy of the program in a test directory, from the original ZIP. No problem. Must have been a one-off fluke.

 

Wouldn't be the first time I've had oddities happen. In Exile II, I recently had the top half of an E3 Mutant Giant chase me in the outdoors and run away. Then I had Soldiers that looked like Beggars, Archers that looked like Captains, and an Evil Priest that looked like an E3 Brigand. I restarted the program and the graphics fixed themselves (the half-a-giant was actually some Giant Lizards).

Link to comment
Share on other sites

Originally Posted By: Celtic Minstrel
That's odd, I'm not sure how Exile 2 could get an E3 graphic (unless it somehow loaded the wrong file).

Apart from messing with the graphic files, it would say playing Exile III right before playing Exile II and having a nasty memory overrun somewhere in the code (and yes, there was such in the BoE windows code). wink

Chokboyz
Link to comment
Share on other sites

Another bug: Excess gold is not dropped when a special called during dialogue gives the party lots of gold. Try following the instructions in that unfinished scenario, and when you talk to Deifier, ask him about "Halibut", then "Buckwheat". Then, train Spell Points as high as they will go for all party members. Then say "Kingpin" and then "Buckwheat" again, and train again. Watch the gold counter as you do these things.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...