Jump to content
Sign in to follow this  

BoA Tips & Tricks

Recommended Posts

With the potential demise of Shadow Vale close at hand, it's time to start porting over some of the more valuable nuggets of information that we had over there. To that end, here is a thread for all those little tricks that are handy to know, but aren't actually documented anywhere.

Share this post

Link to post
Share on other sites

Originally discovered/shared by TM:


The light schedule for BoA, in ticks:


0    - Dawn250  - Full Light3750 - Dusk4000 - Night4250 - Twilight4750 - Daybreak


Next, the base HP for monsters, as determined by level:


1  |2  |3  |4  |5  |6  |7  |8  |9  |10 |---+---+---+---+---+---+---+---+---+---|9  |13 |14 |19 |20 |27 |29 |37 |39 |49 |11 |12 |13 |14 |15 |16 |17 |18 |19 |20 |---+---+---+---+---+---+---+---+---+---|52 |63 |66 |79 |83 |97 |101|117|122|139|21 |22 |23 |24 |25 |26 |27 |28 |29 |30 |---+---+---+---+---+---+---+---+---+---|144|163|169|189|195|217|224|247|254|279|31 |32 |33 |34 |35 |36 |37 |38 |39 |40 |---+---+---+---+---+---+---+---+---+---|287|313|321|349|358|387|396|427|437|469|41 |42 |43 |44 |45 |46 |47 |48 |49 |50 |---+---+---+---+---+---+---+---+---+---|479|513|524|559|570|607|619|657|669|709|51 |52 |53 |54 |55 |---+---+---+---+---|722|763|776|819|833|


Next, some information on buffs:


BLESS: Up to 5 ranks of damage, +25% to hit, +25% to dodge    Ranks:    1/ 2/ 3/ 4/ 5/ 6/ 7/ 8/ 9/10/11/12/             --+--+--+--+--+--+--+--+--+--+--+--+    Bonus:    1/ 1/ 2/ 2/ 2/ 3/ 3/ 3/ 4/ 4/ 4/ 5/    Adds 1d3 +3 per spell level (including the first)

HASTE:    War Blessing - (Intelligence + Priest) / 8 ranks    Haste - (spell level)d3 + (Intelligence + Mage)/3 ranks


And finally, resistances from skills:


  • Dexterity - +5% Fire, +5% Cold, +5% Magic every 4 ranks
  • Intelligence - +5% Mental every 2 ranks
  • Endurance - +5% Poison
  • Hardiness - +1% Fire, +1% Cold, +1% Magic; +5% Poison every 2 ranks; +5% Fire, +5% Cold, +5% Magic every 4 ranks
  • Mage Spells - +5% Magic, +5% Mental every 2 ranks
  • Priest Spells - +5% Mental every 2 ranks
  • Luck - +5% Fire, +5% Cold, +5% Magic, +5% Poison, +5% Acid
  • Magery - +5% Magic, +5% Mental
  • Resistance - +5% Fire, +5% Cold, +5% Magic, +5% Mental


Share this post

Link to post
Share on other sites

Nioca was nice enough to complete the Level:HP chart seen above.


1   |2   |3   |4   |5   |6   |7   |8   |9   |10  |----+----+----+----+----+----+----+----+----+----|9   |13  |14  |19  |20  |27  |29  |37  |39  |49  |11  |12  |13  |14  |15  |16  |17  |18  |19  |20  |----+----+----+----+----+----+----+----+----+----|52  |63  |66  |79  |83  |97  |101 |117 |122 |139 |21  |22  |23  |24  |25  |26  |27  |28  |29  |30  |----+----+----+----+----+----+----+----+----+----|144 |163 |169 |189 |195 |217 |224 |247 |254 |279 |31  |32  |33  |34  |35  |36  |37  |38  |39  |40  |----+----+----+----+----+----+----+----+----+----|287 |313 |321 |349 |358 |387 |396 |427 |437 |469 |41  |42  |43  |44  |45  |46  |47  |48  |49  |50  |----+----+----+----+----+----+----+----+----+----|479 |513 |524 |559 |570 |607 |619 |657 |669 |709 |51  |52  |53  |54  |55  |56  |57  |58  |59  |60  |----+----+----+----+----|----+----+----+----+----|722 |763 |776 |819 |833 |877 |891 |937 |952 |999 |61  |62  |63  |64  |65  |66  |67  |68  |69  |70  |----+----+----+----+----|----+----+----+----+----|1014|1063|1079|1129|1145|1197|1214|1267|1284|1339|71  |72  |73  |74  |75  |76  |77  |78  |79  |80  |----+----+----+----+----|----+----+----+----+----|1357|1413|1431|1489|1508|1567|1586|1647|1667|1729|81  |82  |83  |84  |85  |86  |87  |88  |89  |90  |----+----+----+----+----|----+----+----+----+----|1749|1813|1834|1899|1920|1987|2009|2077|2099|2169|91  |92  |93  |94  |95  |96  |97  |98  |99  |100 |----+----+----+----+----|----+----+----+----+----|2192|2263|2286|2359|2383|2457|2481|2557|2582|2659|

Share this post

Link to post
Share on other sites

Other extra tidbits...


Originally Posted By: TM
There are 63 lines of text in the box below the main view. In case, for whatever reason, you'd want to clear the party's text box.


Originally Posted By: TM
Note on party_size()


It does NOT count joined NPCs. If you want to count joined NPCs, set a flag when they join and unset it when they leave/die. (Use the START_STATE of the scenario to check for their deaths if you must.)


Originally Posted By: Nioca
On a species-related note, Giants (species 4) are not considered humanoid by the game engine.


Originally Posted By: TM


It's not listed in the appendices, so:

lvl*3 + (MAG+INT)/2


(lvl being, obviously, that of Unlock Doors)


Originally Posted By: Lazarus
Some spell formulas that aren't in the manual.


Divine Restoration:Full healing, +40 HP over the maximum for each spell level above 1.


Arcane Shield:*

(3 + ((Spell level + 1) / 2) + Bonus/10) Levels of resistance

(8 + Spell Level + Bonus/6) Levels of shielding

(3 + ((Spell level + 1) / 2) + Bonus/10) Levels of martyr's shield (Starts at spell level 2)

(Spell Level - 2) Levels of invulnerability (Starts at spell level 3)


*Exact formulas for status levels could be off. These are the formulas I came up with to most closely fit the data I gathered. They didn't come out too pretty.


Originally Posted By: Nioca
Okay, I was curious about the effects of the skill Luck. I was noticing that a moderately-armored character that I had pumped luck into was taking less damage than my heavily-armored bruiser. So, I decided to run a little test on luck.


The effects per point of Luck are:

+5% to Elemental, Poison, and Magic Resistances

+0-2% Physical Damage Resistance

+5% Chance of Saving Character from a Fatal Blow (maxing out at 90%, which requires 18 luck)


In other news, I am now putting a lot of luck into my fighters.

Share this post

Link to post
Share on other sites

Originally posted by Niemand:


Node counting in Avernumscript:


As we are all well aware, there is a strict upper limit to how many 'nodes' of Avernumscript the game will execute before it assume that the script has entered an infinite loop and kills it. The question which had always bothered me was: What is a 'node' in Avernumscript? The following is derived from the script interpreter code contained in the editor, but I have found no relevant differences in behavior between that code and the code actually used in the game.


From reading the code, I found that each of the following objects costs one node:

  • if(...){ or if(...)
  • while(...){
  • foo(...)
  • var=...; where var is some variable
  • ; (an extra not associated with any other statement
  • }

This shows that, unlike what one might guess, 'nodes' do not correspond at all directly to tokens, since the items in the list above range from 'if(...){' which contains a minimum of 5 tokens to '}' which is a single token. Happily, they aren't totally incomprehensible, as they will tend to correspond pretty much one-to-one with complete statements. The weirdest one, and something of a surprise, is '}' which counts even though it is typically not thought of as actually doing anything (especially in the case of an if statement, where it merely serves to hint to the interpreter which statements are inside and which aren't, and really does do nothing at run time).


I tested this by testing each of the little block below, and found them to all have the node counts that the above rules predict:

	i=10000+(5+j)/(1+j); //counts as a single node		i=5; //counts as 17	while(i>0){		i = i - 1;	}		i=5; //counts as 3	if(i<10)		j=1;		i=5; //counts as 4	if(i<10){		j=1;	}		i=5; //counts as 3	if(i>10)		j=1;	else		j=2;


(note that there is a separate limit on the length/complexity of arithmetic expression: they may not contain more than 100 tokens.)


So, from this we see that is probably advantageous to pack as much work into fewer statements as possible when trying to fit within the node limit. This could take the form of refactoring code like:

a=(get_health(target)-get_energy(ME))/2;if(a<10)	//do one thingelse if(a<20)	//do something elseelse	//sit down and cry

into a form more like:

if(((get_health(target)-get_energy(ME))/2)<10)	//do one thingelse if(((get_health(target)-get_energy(ME))/2)<20)	//do something elseelse	//sit down and cry

Basically manually inlining computations that are reused, rather than storing them in an intermediate variable. This will make the code execute slower, but, if I'm correct, trick the game into believing that there's less of it.


Also, I wasn't sure if I had ever seen a specific, actual value for the games limit on the number of nodes. In testing, I found that I could execute 32000 'nodes' according to the above criteria before the script was cut off. The code I used was:

beginstate 24;	x=10666;	while(x>0){		x = x - 1;	}break;


The variable initialization takes one node, the loop takes 10666*3, the final, failing check of the loop condition takes one, for a total of exactly 32000. Any further added code caused the script to be killed.

Share this post

Link to post
Share on other sites

Also originally posted by Niemand:


A tricky engine detail related to scripting: It appears, although I haven't been able to completely verfiy this, that Avernumscript does NOT utilize short circuit evaluation of binary operators.


For persons not familiar with the jargon, this means that in an example like

if(call_1() && call_2())    //do stuff


call_2 will be executed even if call_1 evaluates to false. This is unlike more sophisticated systems in which the evaluation of call_2 would be skipped in this situation if call_1 proves to be false, since if call_1 is false no possible value of call_2 could make the && evaluate to true.


This has two effects: (1)lack of speed and (2)lack of safety:

(1) is fairly simple: if you write

if(A && B && C && . . . && Z)    //do stuff


the avernumscript interpreter will ploddingly evaluate A, B, C and so on all the way to Z, even if B turns out to be false and most of the work could have been skipped.


(2) is more complicated and rarer, but often the more serious; as an example I have found the the char_attitude_to_char call doesn't like having being asked to evaluate a character's attitde toward an invalid character number like -1. But what if you wanted to do something if character i hates the character to its north? It's then natural to write:

if(char_attitude_to_char(i, char_on_loc(char_loc_x(i),char_loc_y(i)  - 1) == 2)    //do stuff


However, char_on_loc may return -1 if there is no character at the specified location, which would make char_attitude_to_char unhappy. Unfortunately, trying


if((char_on_loc(char_loc_x(i),char_loc_y(i)  - 1) > -1)  && (char_attitude_to_char(i, char_on_loc(char_loc_x(i),char_loc_y(i) - 1) == 2))    //do stuff

won't cut it; the game discovers that, by golly, there's nobody at that location, and then tries the attitude call anyway. The safe way to do this check is:

if(char_on_loc(char_loc_x(i),char_loc_y(i)  - 1) > -1){    if(char_attitude_to_char(i, char_on_loc(char_loc_x(i),char_loc_y(i) - 1) == 2)        //do stuff}



Although I haven't been able to think of a clear test for this, the chunk of the interpreter code which is in the 3D Edior supports this theory, and is likely equivalent to the game's own code. I have also observed the problems described in the last example, so I'm reasonably certain that all this is accurate.


In conclusion, try to avoid writing really long chains of &&'s and ||'s because they will always be slow, and be aware that every bit of code you write in a condition will run if any of it runs.

Share this post

Link to post
Share on other sites

Nioca did some work with the base classes:


Originally Posted By: Nioca
The base classes. You know, the ones you click by before settling on 'Custom'. Out of curiosity, I decided to gather data on the base classes, to see if any of them had certain advantages over the others. And this is what I found.


Skill Points for base classes in comparison to Custom (this includes the 8 extra skill points the player gets in each base class).

Soldier = +7 Skill Points (72 Total)

Berserker = +8 Skill Points (73 Total)

Cleric = +12 Skill Points (77 Total)

Sorcerer = +10 Skill Points (75 Total)

Rogue = +8 Skill Points (73 Total)

Archer = +9 Skill Points (74 Total)

Rebel = +13 Skill Points (78 Total)

Hedge Wizard = +13 Skill Points (78 Total)

Shaman = +8 Skill Points (73 Total)


And, a table of skills each base class other than custom.

             +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+CLASS SKILLS |STR|DEX|INT|END|MEL|POL|BOW|THR|HRD|DEF|ASS|MAG|PRI|ARC|POT|TUS|NLO|AID|LCK|+------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+|Soldier     |*4*| 4 | 2 | 5 | 4 |*3*| 1 | 0 |*2*|*2*| 0 | 0 | 0 | 1 | 0 | 2 |*2*| 2 | 0 |+------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+|Berserker   |*4*| 4 | 2 |*6*|*5*| 0 | 1 | 1 |*2*|*2*| 0 | 0 | 0 | 1 | 0 | 2 |*2*| 1 | 0 |+------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+|Cleric      | 2 | 2 | 5 | 5 | 3 | 0 | 0 | 1 | 0 |*2*| 0 | 0 |*4*| 5 | 4 | 1 | 1 |*3*| 0 |+------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+|Sorcerer    | 2 | 2 |*6*| 5 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |*5*| 0 |*6*| 2 | 1 | 1 | 1 | 0 |+------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+|Rogue       | 3 | 4 | 2 |*6*| 3 | 0 | 3 | 0 |*2*|*2*|*2*| 0 | 0 | 1 | 0 |*6*|*2*| 0 | 0 |+------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+|Archer      | 2 |*5*| 2 |*6*| 2 | 1 |*6*| 1 |*2*|*2*| 0 | 0 | 0 | 1 | 0 | 4 | 1 | 0 | 0 |+------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+|Rebel       |*4*| 4 | 2 | 5 | 2 | 2 | 2 |*2*|*2*|*2*| 1 | 0 | 0 | 3 | 2 | 4 | 1 | 2 |*1*|+------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+|Hedge Wizard| 2 | 2 | 5 | 5 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 3 | 3 | 5 |*5*| 2 | 1 | 1 | 0 |+------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+|Shaman      | 3 | 3 | 4 | 5 | 3 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 5 |*5*| 2 | 1 | 1 | 0 |+------------+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+


From this, we can discern a few things about each class.


Soldier: A decent melee class. Spreads its points around a bit too much, negating its skill point advantage, but is extremely useful for acquiring Blademaster.


Berserker: A very powerful melee class, with very little spread and a healthy skill point advantage.


Cleric: As an overall priest character, this class falls a bit short. As a dedicated healer character, though, this class rises to the occasion. It's capable of running every sort of healing available, and even has passable weapon skills. The luxurious skill point advantage is an added bonus.


Sorcerer: A magnificent glass-cannon style mage character, with a large skill point advantage and a little extra endurance.


Rogue: Not one of the better classes unless you have a very specific character in mind that works with this class. If you do, than this class, with its decent combat and lockpicking skills, might work out well with a little added advantage in skill points.


Archer: A masterful archer template with a cushy skill point advantage. Its low strength is a potential drawback, though.


Rebel: While it might have a massive skill point advantage, this class is really just awful. Points are spread so thin into every niche that it has no actual power. On the plus side, it is the only class to invest in a point of Luck.


Hedge Wizard: Has a identical skill point advantage to the Rebel, but lacks most of the ridiculous spreading of skill points. Decent with all kinds of magic, including potion making.


Shaman: Similar to Hedge Wizard, but with Melee instead of Mage spells. Also has a smaller skill point advantage and lackluster defensive capabilities, meaning that engaging in melee with this template might not be a good idea until it gets a few levels behind it.

Share this post

Link to post
Share on other sites

More from Lazarus:


Forcing Dialog W/ Names/Faces

By passing a flag to a creature script and then checking that flag in the creature's start_state, you can 'force' dialog (That is to say not initiated by actually talking to someone) but still have a creature's name/dialog pic displayed, and still be in normal talking mode. Flag should be reset somewhere in the dialog, so that it doesn't run every turn.

You can see this technique in any of the Tales, specifically talker.txt

(Ed. note: Also utilized in Adrift)


Marking Characters

This is a way to mark PCs, so that the player can't switch party order and throw you off. Some practical uses would be to keep track of the 'main' PC that is the story's protagonist, or to keep track of characters for special spells.

It is done by giving each PC an ability at the start of the scenario. This can be a simple ability, like "The Way Out" or "Set Cutscene Speed". Give each PC a different number of charges of that ability, so that PC 0 has 1 charge, PC 1 has 2 etc. So even if the player switches party order you can always tell what order the PCs were in when they first entered by checking how many ability charges they have.


Freezing the Party

set_mobility() works on the party-- which is just something kind of weird that I wasn't expecting. Since block_entry() in the start_state won't actually keep your party from moving around, you can use set_mobility(1000,0) to imobilize the party.

Practical Applications: I've never used this, but one use might be if you don't want the party to proceed until they equip an item. You could freeze them and then check in the start_state until that item is equipped, then unfreeze them. And refreeze them if they take it off.


The ever-running Start State

If you set a terrain script to run every turn, it runs every single turn. This means that even between combat turns it will run, unlike the town script start_state which only runs at the start of each combat round.

I was once toying with a way to make 'scripted' weapons using this, but it became too convoluted. Still, it can be used for something as simple as checking a monster's health all the time, instead of waiting until the end of a turn.


Booting the party from town

It isn't supposed to be possible to force a party to exit a town via scripts. Usually designers would simply relocate the party to a location where their only option is to walk out of town. However, if you use relocate_character() to relocate the party outside of the town boundaries, they are instantly placed outdoors. Kind of nifty.

(This only works when called from a special rectangle, like the limitations of move_to_new_town.)


Setting a Party's EXP

Unfortunately, there is no call to check character experience, only to add/subtract to it. You can set a PC's experience, though, by dropping their EXP by a massive number (So that it winds up at 0. You can't have negative EXP) and then moving it back up to the amount you want to set it to. Useful for prefabs.

(This one was Nikki's)


Weird Functions of Kill_char

Kill_char with 0 for death type erases the character. With 1 for death type the creature goes through it's death poses, dumps his items, but doesn't actually die. 5 kills the character, but changes his face to the 'flee' graphic. 6 kills the character but changes his face to the 'blank portrait' graphic. 7 and 8 will kill the character, not play any death sound, and set their portrait to blank.

The different death types correspond with the char_status types. (Thanks to Niemand for telling me this.)

Share this post

Link to post
Share on other sites

Other miscellaneous tricks:


Originally Posted By: Niemand
One of my favorite tricks is storing a 16 bit number using a pair of SDFs:


z = 5280;set_flag(1,1,z/256);set_flag(1,2,z%256); //Note that the %256 operation is implicitly performed every                //time you call set_flag, but it is clearer if stated explicitly.


(Clearly any pair of SDFs will do.)

You can the retrieve the value using:

z = (256 * get_flag(1,1)) + get_flag(1,2);

By doing this, you can do things like store time values needed, say, by a town script, so that they will preserved even if the party leaves and re-enters the town. It allows you to store a value up to 32767, even though flags can only hold values up to 255.


Originally Posted By: Nioca
Here's the shortest, simplest, and smallest way possible (that I know of) to have a message display only once depending on a flag.

if (get_flag(x,y) == 0) {    message_dialog("I'm a message!","With two paragraphs!");    set_flag(x,y,250); }


Originally Posted By: Nioca
Increasing Health and Energy over Maximum

It's impossible to increase Health and Energy over the maximum amount for a character using ordinary health and energy modification calls. However, the alter_stat(char,stat) call can be used to boost Intelligence or Endurance, thus increasing the maximum amount can have at anyone time. Health and energy modification calls can then be used to increase the health or energy of the character to the desired amount, and then alter_stat(char,stat) can again be used to drop the character's Intelligence and/or Endurance back down to their original state whilst retaining the adjusted amount of health and/or energy. This could be used in encounters that grant a blessing of some sort, or other situations where you want a character, or even the party to have higher-than-maximum health.


Originally Posted By: Arancaytar
I've changed ambient sounds in ED. It's not really an advanced trick, but more of an easy workaround - still, here it is:


beginstate INIT_STATE;    if (should change music?)    {        set_incidental_sound(1); // turn off the normal music        play_sound(-150); // and play new music        ticks=0;    }    else set_incidental_sound(0);    // turn on normal ambiencebreak;beginstate START_STATE;    if (should change music?)    {        ticks=ticks+1;        if (get_ran(3,1,6)==18 && ticks>200)        {                play_sound(-150);            ticks=0;        }    }break;

The added check for rolling a triple-six on three dice randomizes the result somewhat, because it was too clockwork-like otherwise. Note that the timing requires a lot of experimentation, as your timer will run on game time, while the music is played in real time. You may end up with too long gaps of silence, or cutting off music early.


Originally Posted By: Dintiradan
The move_to_loc function is adequate for most cases, but it lacks the within_dist parameter that approach_char, approach_ter_script, and approach_waypoint have. If you try to make a monster move to a spot too close to itself, it won't move at all. Since you can't create a waypoint or terrain script at runtime, you need to create a creature at or near the destination, move, then erase the spawned creature.

must_remove = 0;dest_char = char_on_loc(x, y);if (dest_char == -1) {    must_remove = 1;    place_monster(x, y, WAYPOINT_MONST, 1);    dest_char = char_on_loc(x, y);}approach_char(ME, dest_char, WITHIN_DIST);if (must_remove) {    erase_char(dest_char);}

Blades Invaders gives WAYPOINT_MONST an empty graphic, but this doesn't seem necessary; if a creature needs to be spawned, it doesn't appear in gameplay.

Share this post

Link to post
Share on other sites

But wait, there's more!


Originally Posted By: Lazarus
More Strings to Fiddle With

message_dialog("","") when used in the 'code' part of a dialog node will not display the text in a popup box as it usually does, but rather will display them as text1 and text2 for that dialog node. Useful for if you have more than 8 strings for a specific node. Note that when you use this call that is the only text that will display. So if you use message_dialog("Hey","there"); and text3 = "adventurers"; only "Hey there" will display (with a return obviously) not "Hey there adventurers." All strings are erased. For this reason this is only useful for responses of 2 or less strings. Still, with this you have an unlimited number of responses for a node as long as no response has to be over 2 strings.


Originally Posted By: Niemand
In my above post in this thread I outlined a method for storing large numbers in the SDF matrix. I have stated before that it cannot be used to store negative values. However, here's one that can:

Assuming that you want to store the value of a variable named z to SDFs 1,1 and 1,2

set_flag(1,1,(1 + -2 * (z < 0)) * z);            set_flag(1,2,(z / (256 * (1 + -2 * (z < 0)))) + (128 * (z < 0)));


You can then retrieve that value with

z = (1 + -2 * (get_flag(1,2) > 128)) * (get_flag(1,1) + 256 * (get_flag(1,2) - (128 * (get_flag(1,2) > 128))));


I've tested this and it seems to work as expected for numbers in the range [-32767,32767]. Note that you have to be careful about using the right coordinates in the numerous get and set sdf calls for the retrieval. Call the two SDFs A and B, and if the two set calls store to A and B respectively, then the order in the retrieval line is BABB.


Originally Posted By: Lazarus
Picking the First Party Member

A pretty straightforward task. Most people know that

i = 0;while(char_ok(i) == 0){    i = i + 1;}

will do this just fine, but I was trying to think of a way to do this in one line of code and came up with a few simpler alternatives. Firstly, first_group_member(0) will always return the first living party member, and so will random_party_member() if you have a singleton (The docs make it sound like this call is basically just get_ran(1,0,6), but it picks out only living party members, which is what I expected but wasn't really spelled out. Totally off topic-- thinking about this brought me to the realization that dead party members aren't part of group 1000, which wasn't what I'd expect.)

Anyways, this isn't really useful to most of you, but I figured I'd throw it out there since most people seem to use the loop option, but the first_group_member option is slightly easier.

Share this post

Link to post
Share on other sites

This was not in Shadowvale forums:

Adding a boat or horse to an existing save game.

If you add a boat or a horse to the Load Scen State, all details about the boat or horse will be reset every time a save game is loaded. The details will be read from Load Scen State, not the relevant part of the save game file. If the party is not in a boat, all boats will revert to the places specified in the State. If it is in a boat, that boat will revert when the party lands on some island or beach. This could leave the party stranded.

Clearly boats should be listed in Start Scen State not Load Scen. Trouble is that you can't add anything to Start Scen State after you start a scenario. If late in playtesting a scenario you realize that you really need a boat or a horse in a given area, you will normally need to start all over again.

Solution is to:

create the boat or horse in the Load Scen State

reload a save game to create the boat or horse

save the game, the boat or horse is now added to the save game file

delete the relevant entry from the Load Scen State.

When you next reload the save game the boat or horse should still be there.

Share this post

Link to post
Share on other sites

Modifying Custom Abilities:

I'm not aware of anyone using this trick, and while the documentation doesn't imply that it is impossible it also doesn't go out of its way to say that it is allowed: Calling init_special_abil more than once with the same ability index appears to redefine the ability in a perfectly sensible way. Also, init_special_abil can be used at any time (not just in the scenario script's LOAD_SCEN_STATE), so one can dynamically alter custom abilities. An obvious use for this would be a case in which a scenario wants to have more than four defined abilities (as long as no more than four are defined at any one time). Here's an amusing if dumb example of an ability which actually alternates what it does:

beginscenarioscript;variables;body;beginstate LOAD_SCEN_STATE;	init_special_abil(0,"Ability 1",10);break;beginstate START_SCEN_STATE;	change_custom_abil_uses(0,0,1);break;beginstate START_STATE;break;beginstate 10;	print_str("ABILITY 1!");	change_custom_abil_uses(who_used_custom_abil(),0,1);	init_special_abil(0,"Ability 2",11);break;beginstate 11;	print_str("ABILITY 2!!");	change_custom_abil_uses(who_used_custom_abil(),0,1);	init_special_abil(0,"Ability 1",10);break;

Note that since the game doesn't store ability definitions in save files (which is exactly why init_special_abil is recommended to be placed in the LOAD_SCEN_STATE) when doing something like this it would be adivable to store the state of the currently defined abilities using flags so that the LOAD_SCEN_STATE can properly restore it.


This technique doesn't actually accomplish anything that couldn't have been done already by writing more complex logic in the state which a special ability invokes, except changing the displayed ability name, but that may be useful sometimes in and of itself, and this technique may make it easier to write simpler code in some cases.

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this