Playing character control in Blades of Avernum
Apprentice
Member # 13238
written Saturday, January 19 2008 15:10
Profile
#12
Code update... Part 1 : the scenario script parts --------// SCENARIO SCRIPT beginscenarioscript; variables; short count, result, done, pos_x, pos_y; short i, j, k; body; // ************************************************************************************************* // START_SCEN_STATE // ************************************************************************************************* beginstate START_SCEN_STATE; // init unique stats for switching, to avoid switching effects on scenario start // uses flags (pos_x to pos_x+4, pos_y) = (30 to 30+4, 29) // uses flags (pos_x to pos_x+7(+4 for joined-NPCs), pos_y) = (10 to 10+7(+4 for joined-NPCs), 29) // take switch flags pos_x = 30; pos_y = 29; i = 0; while (i <= 3) { if (char_status(i) != 0) { done = 0; j = 0; // try stat from Strength (0) to Pathfinder (24), use bought levels while (j <= 24 && done == 0) { result = get_stat_levels_bought(i, j) % 10; done = 0; k = 0; while (k <= 3 && done < 3) { // don't check against himself if (k != i) { if (char_status(k) == 0) done = done + 1; else if (result != (get_stat_levels_bought(k, j) % 10)) done = done + 1; } k = k + 1; } if (done == 3) done = 1; else done = 0; j = j + 1; } j = j - 1; // can't get a unique stat for char (i), drop it if (done == 0) set_flag(pos_x + i, pos_y, 250); // got a unique stat for char (i) else set_flag(pos_x + i, pos_y, (j * 10) + result); } // set to default value for non-existing char (i) else set_flag(pos_x + i, pos_y, 250); i = i + 1; } // set switching difficulty level to 'reordering + lost a turn' (3), this can be changed at any time // uses flags (pos_x to pos_x+4, pos_y) = (30 to 30+4, 29) // uses flags (pos_x to pos_x+7(+4 for joined-NPCs), pos_y) = (10 to 10+7(+4 for joined-NPCs), 29) // take switch flags pos_x = 30; pos_y = 29; set_flag(pos_x + 4, pos_y, 3); break; // ************************************************************************************************* // LOAD_SCEN_STATE // ************************************************************************************************* beginstate LOAD_SCEN_STATE; break; // ************************************************************************************************* // START_STATE // ************************************************************************************************* beginstate START_STATE; // relocation ************************************************************************************** // check current game mode for relocation on combat end (0 : outdoor) (1 : town) (2 : combat) // uses flags (pos_x to pos_x+7(+4 for joined-NPCs), pos_y) = (10 to 10+7(+4 for joined-NPCs), 29) // and flag (pos_x+12, pos_y) = (10+12, 29) (last turn mode flag) // take position and last turn mode flags pos_x = 10; pos_y = 29; // outdoor mode : just record if (is_outdoor() == 1) { set_flag(pos_x + 12, pos_y, 0); } // town mode : check for last turn mode, if it was combat relocate all chars else if (is_town() == 1) { // on combat end, in town mode only, relocate all chars to their last positions during the last combat turn // and center screen on the first living, present, non joined-NPC character (the leader) if (get_flag(pos_x + 12, pos_y) == 2) { done = 0; i = 0; // while (i <= 3) { // if joined-NPCs relocation is not needed while (i <= 5) { if (char_status(i) == 1 && get_flag(pos_x + (2 * i), pos_y) != 250) { relocate_character(i, get_flag(pos_x + (2 * i), pos_y), get_flag(pos_x + (2 * i) + 1, pos_y)); if (done == 0) { force_view_center(get_flag(pos_x + (2 * i), pos_y), get_flag(pos_x + (2 * i) + 1, pos_y)); done = 1; } } i = i + 1; } force_instant_terrain_redraw(); print_str_color("End combat.", 4); } set_flag(pos_x + 12, pos_y, 1); } // combat mode : just record else if (is_combat() == 1) { set_flag(pos_x + 12, pos_y, 2); } // update chars positions ************************************************************************** // update all chars positions between turns // uses flags (pos_x to pos_x+7(+4 for joined-NPCs), pos_y) = (10 to 10+7(+4 for joined-NPCs), 29) // take position flags pos_x = 10; pos_y = 29; i = 0; // while (i <= 3) { // if joined-NPCs relocation is not needed while (i <= 5) { if (char_status(i) == 1) { set_flag(pos_x + (2 * i), pos_y, char_loc_x(i)); set_flag(pos_x + (2 * i) + 1, pos_y, char_loc_y(i)); } else { set_flag(pos_x + (2 * i), pos_y, 250); set_flag(pos_x + (2 * i) + 1, pos_y, 250); } i = i + 1; } // switching *************************************************************************************** // switching party order is prevented and/or paralyses whole party for one turn, not outdoor // switching difficulty level : 0 = normal, 1 = reordering, 2 = lost a turn, 3 = reordering + lost a turn // uses flags (pos_x to pos_x+4, pos_y) = (30 to 30+4, 29) // uses flags (pos_x to pos_x+7(+4 for joined-NPCs), pos_y) = (10 to 10+7(+4 for joined-NPCs), 29) // take switch flags (beware pos_x, pos_y will be swapped to position flags) pos_x = 30; pos_y = 29; // check stats for switching if (is_outdoor != 1) { j = 0; i = 0; while (i <= 3 && j <= 2) { count = get_flag(pos_x + i, pos_y); // check all existing chars with their unique stat, if stats modulus 10 are !=, stats are != if (char_status(i) != 0 && count != 250) { result = count % 10; done = (count - result) / 10; // if stat mismatch increase j by 1 if (get_stat_levels_bought(i, done) != result) j = j + 1; } i = i + 1; } // switching means at least two characters having their identification stat changed if (j >= 2) { // if flag(pos_x + 4, pos_y) = 1 or 3 // physical reordering is prevented (reversed to last chars positions) if (get_flag(pos_x + 4, pos_y) == 1 || get_flag(pos_x + 4, pos_y) == 3) { print_str_color("Reordering party...", 2); i = 0; while (i <= 3) { if (char_status(i) == 1) { count = get_flag(pos_x + i, pos_y); result = count % 10; done = (count - result) / 10; // find the position the char had and relocate it there j = 0; while (j <= 3 && get_flag(pos_x + (2 * j), pos_y) != 250) { if (get_stat_levels_bought(j, done) == result) { // take positions flags (this heavy but used only when switching occurs) pos_x = 10; pos_y = 29; relocate_character(i, get_flag(pos_x + (2 * j), pos_y), get_flag(pos_x + (2 * j) + 1, pos_y)); // take switch flags (this heavy but used only when switching occurs) pos_x = 30; pos_y = 29; } j = j + 1; } } i = i + 1; } // center screen on the first living, present, non joined-NPC character (the leader) done = 0; i = 0; while (i <= 3 && done == 0) { if (char_status(i) == 1) { // take positions flags (this heavy but used only when switching occurs) pos_x = 10; pos_y = 29; force_view_center(get_flag(pos_x + (2 * i), pos_y), get_flag(pos_x + (2 * i) + 1, pos_y)); // take switch flags (this heavy but used only when switching occurs) pos_x = 30; pos_y = 29; done = 1; } i = i + 1; } force_instant_terrain_redraw(); } // if flag(pos_x + 4, pos_y) = 2 or 3, paralyse all chars, and joined-NPCs, one turn, unblockable if (get_flag(pos_x + 4, pos_y) == 2 || get_flag(pos_x + 4, pos_y) == 3) { if ((get_flag(pos_x + 4, pos_y) == 2) || is_town() == 1) { print_str_color("You spend a turn reordering your party...", 3); } else { print_str_color("You lost a turn trying to reorder your party...", 1); } i = 0; while (i <= 5) { if (char_status(i) != 0) set_char_status(i, 11, 1, 1, 0); i = i + 1; } } } } // refresh unique stats for switching i = 0; while (i <= 3) { if (char_status(i) != 0) { done = 0; j = 0; // try stat from Strength (0) to Pathfinder (24), use bought levels while (j <= 24 && done == 0) { result = get_stat_levels_bought(i, j) % 10; done = 0; k = 0; while (k <= 3 && done < 3) { // don't check against himself if (k != i) { if (char_status(k) == 0) done = done + 1; else if (result != (get_stat_levels_bought(k, j) % 10)) done = done + 1; } k = k + 1; } if (done == 3) done = 1; else done = 0; j = j + 1; } j = j - 1; // can't get a unique stat for char (i), drop it if (done == 0) set_flag(pos_x + i, pos_y, 250); // got a unique stat for char (i) else set_flag(pos_x + i, pos_y, (j * 10) + result); } // set to default value for non-existing char (i) else set_flag(pos_x + i, pos_y, 250); i = i + 1; } break;
Part 2 : the terrain script to place once in each town --------// TERRAIN SCRIPT // Script for updating characters positions in combat mode (to place on one terrain in each town) // uses flags (pos_x to pos_x+7(+4 for joined-NPCs), pos_y) = (10 to 10+7(+4 for joined-NPCs), 29) beginterrainscript; variables; short pos_x, pos_y, i; body; beginstate INIT_STATE; // run script every move even if party is far set_script_mode(3); break; beginstate START_STATE; // update all chars positions on each individual step during combat // uses flags (pos_x to pos_x+7(+4 for joined-NPCs), pos_y) = (10 to 10+7(+4 for joined-NPCs), 29) // take position flags pos_x = 10; pos_y = 29; if (is_combat() == 1) { i = 0; // while (i <= 3) { // if joined-NPCs relocation is not needed while (i <= 5) { if (char_status(i) == 1) { set_flag(pos_x + (2 * i), pos_y, char_loc_x(i)); set_flag(pos_x + (2 * i) + 1, pos_y, char_loc_y(i)); } else { set_flag(pos_x + (2 * i), pos_y, 250); set_flag(pos_x + (2 * i) + 1, pos_y, 250); } i = i + 1; } } break;
Posts: 7 |
Registered: Monday, January 14 2008 08:00
Playing character control in Blades of Avernum
Apprentice
Member # 13238
written Friday, January 18 2008 20:48
Profile
#11
Lazarus : just tested your ever-running terrain script (did a script saying "hello" from a terrain), now I understand your previous answer... It says "hello" 7 times per town mode move, and once per individual move in combat mode. The recording of each character position could be put in one script terrain in each town... with INIT_STATE 'set_script_mode(3)' (every turn) Tried that : both functions (especially end combat relocation) work. For the cpu load, I run a Sempron 2400 (very basic) and I tested with and without my script it makes no difference (I made my party run around a filled town with the mouse left click down). The reason is that it is not graphic operations but simple mathematical operations (should be nothing for a computer if BOE engine works normally) I saw the marking character trick with a special ability and I could use it. The advantage of my system is that it is more self-contained and can be inserted in a scenario without interfering (however it needs temporary variables and 4 flags for skills marking)
Posts: 7 |
Registered: Monday, January 14 2008 08:00
Playing character control in Blades of Avernum
Apprentice
Member # 13238
written Friday, January 18 2008 19:38
Profile
#9
A more complete scenario script to control how playing characters move some may find that very useful, others very superfluous, at least it should be funny to look at when working so it's a script for the scenario START_STATE (or a town state run each turn), and a bit of code for the scenario START_SCEN_STATE it allow to control how characters are positioned on combat end, and how they get positioned when the player uses the 'switch' buttons (under the portraits) it's probably difficult to read but it can be tested directly inside a scenario by temporarily replacing thescenario.txt with this code// ************************************************************************************************* // Scenario script with two indepandant functions (one or both can be used) // I. // relocate characters at the end of a combat to the position they had at the beginning of the last turn // of this combat, to avoid having them progressing and skipping a special encounter by repetitively // starting-ending combat mode // II. // make switching party order by using the 'switch' buttons (under the portraits) // - cost a turn without acting (monsters will act !) // and/or // - prevent this operation from physically reordering of the party // (usual switch by moving on town ground is still possible, but then it's a real move) // Uses flags (10 to 18, 29) for chars positions // Uses flags (20 to 23, 29) for chars stat identification // Uses flags (24, 29) for switching difficulty level : (it can be changed at any time during the game) // 0 = normal, 1 = reordering, 2 = lost a turn, 3 = reordering + lost a turn // ************************************************************************************************* // the constraint is that the start_state of the scenario script must be run each turn // the code could also be executed from all (or some) town scripts in a state that is run each turn // ************************************************************************************************* // SCENARIO SCRIPT beginscenarioscript; variables; short result, done, count; short i, j, k; body; // ************************************************************************************************* // START_SCEN_STATE // ************************************************************************************************* beginstate START_SCEN_STATE; // ************************************************************************************************* // init unique stats for switching, uses flags (20-23, 29) (not vital but avoid switch effects on scenario start) // ************************************************************************************************* i = 0; while (i <= 3) { if (char_status(i) != 0) { done = 0; j = 0; // try stat from Strength (0) to Pathfinder (24), use bought levels while (j <= 24 && done == 0) { result = get_stat_levels_bought(i, j) % 10; done = 0; k = 0; while (k <= 3 && done < 3) { // don't check against himself if (k != i) { if (char_status(k) == 0) done = done + 1; else if (result != (get_stat_levels_bought(k, j) % 10)) done = done + 1; } k = k + 1; } if (done == 3) done = 1; else done = 0; j = j + 1; } j = j - 1; // can't get a unique stat for char (i), drop it if (done == 0) set_flag(20 + i, 29, 250); // got a unique stat for char (i) else set_flag(20 + i, 29, (j * 10) + result); } // set to default value for non-existing char (i) else set_flag(20 + i, 29, 250); i = i + 1; } // ************************************************************************************************* break; // ************************************************************************************************* // LOAD_SCEN_STATE // ************************************************************************************************* beginstate LOAD_SCEN_STATE; break; // ************************************************************************************************* // START_STATE // ************************************************************************************************* beginstate START_STATE; // this state has to be run each turn otherwise there will be no effect // ************************************************************************************************* // first the code for relocating characters on combat end // if used must be placed before the [refresh all chars positions] block, so in first place // ************************************************************************************************* // check mode for relocation on combat end (0 : outdoor) (1 : town) (2 : combat) uses flags (10-18, 29) // outdoor mode : just record if (is_outdoor() == 1) { set_flag(18, 29, 0); } // town mode : check for last turn mode, if it was combat relocate all chars else if (is_town() == 1) { // on combat end, in town mode only, relocate all chars to their position at the beginning of the last combat turn // cannot easily get chars positions in the middle of a turn (except with all terrains checking in STEP_INTO_SPOT_STATE with char_on_me()) if (get_flag(18, 29) == 2) { i = 0; while (i <= 3) { relocate_character(i, get_flag(10 + (2 * i), 29), get_flag(10 + (2 * i) + 1, 29)); i = i + 1; } // center screen on the first living, present, non-joined NPC character (the leader) done = 0; i = 0; while (i <= 3 && done == 0) { if (char_status(i) == 1) { force_view_center(get_flag(10 + (2 * i), 29), get_flag(10 + (2 * i) + 1, 29)); done = 1; } i = i + 1; } force_instant_terrain_redraw(); print_str_color("End combat.", 4); } set_flag(18, 29, 1); } // combat mode : just record else if (is_combat() == 1) { set_flag(18, 29, 2); } // ************************************************************************************************* // ************************************************************************************************* // this code is common to both functions and must be between them // ************************************************************************************************* // refresh all chars positions i = 0; while (i <= 3) { set_flag(10 + (2 * i), 29, char_loc_x(i)); set_flag(10 + (2 * i) + 1, 29, char_loc_y(i)); i = i + 1; } // ************************************************************************************************* // ************************************************************************************************* // now the code for the 'switch' buttons control // if used must be placed after the [refresh all chars positions] block, so in third place // ************************************************************************************************* // the following flag can be set from anywhere to fit the situation (possible values 0 to 3) set_flag(24, 29, 3); // switching party order is reversed and/or paralyses whole party for one turn, not outdoor // switching difficulty level : 0 = normal, 1 = reordering, 2 = lost a turn, 3 = reordering + lost a turn // check stats for switching, uses flags (20-23, 29) if (is_outdoor != 1) { j = 0; i = 0; while (i <= 3 && j <= 2) { count = get_flag(20 + i, 29); // check all existing chars with their unique stat, if stats modulus 10 are !=, stats are != if (char_status(i) != 0 && count != 250) { result = count % 10; done = (count - result) / 10; // if stat mismatch increase j by 1 if (get_stat_levels_bought(i, done) != result) j = j + 1; } i = i + 1; } // switching means at least two characters having their identification stat changed if (j >= 2) { // if flag(24, 29) = 1 or 3, physical reordering is not possible (reversed to last chars position) if (get_flag(24, 29) == 1 || get_flag(24, 29) == 3) { print_str_color("Reordering party...", 2); i = 0; while (i <= 3) { if (char_status(i) == 1) { count = get_flag(20 + i, 29); result = count % 10; done = (count - result) / 10; // find the place the char had and replace it there j = 0; while (j <= 3) { if (get_stat_levels_bought(j, done) == result) { relocate_character(i, get_flag(10 + (2 * j), 29), get_flag(10 + (2 * j) + 1, 29)); } j = j + 1; } } i = i + 1; } // center screen on the first living, present, non-joined NPC character (the leader) done = 0; i = 0; while (i <= 3 && done == 0) { if (char_status(i) == 1) { force_view_center(get_flag(10 + (2 * i), 29), get_flag(10 + (2 * i) + 1, 29)); done = 1; } i = i + 1; } force_instant_terrain_redraw(); } // if flag(24, 29) = 2 or 3, paralyse all chars, and joined NPCs, one turn, unblockable if (get_flag(24, 29) == 2 || get_flag(24, 29) == 3) { if ((get_flag(24, 29) == 2) || is_town() == 1) { print_str_color("You spend a turn reordering your party...", 3); } else { print_str_color("You lost a turn trying to reorder your party...", 1); } i = 0; while (i <= 5) { set_char_status(i, 11, 1, 1, 0); i = i + 1; } } } } // refresh unique stats for switching, uses flags (20-23, 29) i = 0; while (i <= 3) { if (char_status(i) != 0) { done = 0; j = 0; // try stat from Strength (0) to Pathfinder (24), use bought levels while (j <= 24 && done == 0) { result = get_stat_levels_bought(i, j) % 10; done = 0; k = 0; while (k <= 3 && done < 3) { // don't check against himself if (k != i) { if (char_status(k) == 0) done = done + 1; else if (result != (get_stat_levels_bought(k, j) % 10)) done = done + 1; } k = k + 1; } if (done == 3) done = 1; else done = 0; j = j + 1; } j = j - 1; // can't get a unique stat for char (i), drop it if (done == 0) set_flag(20 + i, 29, 250); // got a unique stat for char (i) else set_flag(20 + i, 29, (j * 10) + result); } // set to default value for non-existing char (i) else set_flag(20 + i, 29, 250); i = i + 1; } // ************************************************************************************************* break;
Posts: 7 |
Registered: Monday, January 14 2008 08:00
Playing character control in Blades of Avernum
Apprentice
Member # 13238
written Monday, January 14 2008 13:23
Profile
#6
Thank you for renaming I found the edit button...
Posts: 7 |
Registered: Monday, January 14 2008 08:00
Playing character control in Blades of Avernum
Apprentice
Member # 13238
written Monday, January 14 2008 12:44
Profile
#4
This thread should be renamed but I don't known who can do that, to 'End Combat bug workaround' probably. Also a possible problem : (leader = in slot order (0 to 3) the first living present character) first the good : in fact the leader can change during combat... if he dies. But if the previous leader didn't cross a given special encounter, the others, following him in town mode, shouldn't have either. second, the problem : if the terrain on which a playing character was sitting at the beginning of the turn has been swapped in the middle of this turn to a blocked terrain, and the combat ends, the leader at this moment and thus the party could remain stuck inside this spot when relocated. this might be possible if terrain swapping is triggered by a creature script, or by a character walking on this spot for example. so when swapping/flipping a terrain/floor to a blocked one it should be checked if char_on_me() == -1, but, in addition in combat mode, the script would have to check, with the flags used to record positions, if ANY character (since the leader may have changed since the beginning of the turn) was not upon this spot at the beginning of the current turn, and if so do not swap. the problem is to avoid trapping the party in a position one of the characters had at the beginning of the last combat turn. the modification is not to the script I gave, but to all scripts that swap/flip terrains/floors from a non-blocked one to a blocked one (set as blocked in scendata.txt).
Posts: 7 |
Registered: Monday, January 14 2008 08:00
Playing character control in Blades of Avernum
Apprentice
Member # 13238
written Monday, January 14 2008 10:28
Profile
#2
End Combat bug workaround ------------------------- If no one has already written this, a piece of script to avoid the end-combat bug (the party moving one step forward and skipping encounters). This is a piece of script to place in the Scenario Script, START_STATE (I don't know if START_STATE in the Scenario Script is run each turn in any situation but I think so). It requires 9 stuff done flags, I used (0 to 8, 1) To notice : since characters cannot be 'switched' in combat mode the leader remains the same and no encounter should be skipped (it would have been walked upon by the leader either before combat in town mode, or during the combat)#!/usr/bin/perl // ************************************************************************************************* // SCENARIO SCRIPT // ************************************************************************************************* beginscenarioscript; variables; short done, i; body; beginstate LOAD_SCEN_STATE; break; beginstate START_SCEN_STATE; break; // ************************************************************************************************* // START_STATE // ************************************************************************************************* // This state is called every tick wherever the party is in the scenario. // You can use the set_state beginstate START_STATE; // check mode for relocation on combat end (0 : outdoor) (1 : town) (2 : combat) uses flags (0-8, 1) // outdoor mode : just record if (is_outdoor() == 1) { set_flag(0, 1, 0); } // town mode : check for last turn mode, if it was combat relocate all chars else if (is_town() == 1) { if (get_flag(0, 1) == 2) { // on combat end, in town mode only, relocate all chars to their position at the beginning of the last combat turn // cannot easily get chars positions in the middle of a turn (except with all terrains checking in STEP_INTO_SPOT_STATE with char_on_me()) print_str_color("End combat.", 4); i = 0; while (i <= 3) { relocate_character(i, get_flag((2 * i) + 1, 1), get_flag((2 * i) + 2, 1)); i = i + 1; } // center screen on the first living, present, non-NPC character (the leader) i = 0; done = 0; while (i <= 3 && done == 0) { if (char_status(i) == 1) { force_view_center(get_flag((2 * i) + 1, 1), get_flag((2 * i) + 2, 1)); done = 1; } i = i + 1; } } set_flag(0, 1, 1); } // combat mode : get all chars positions // don't need party NPCs (slots 4-5) positions since they don't trigger scripts (probably...), but could be added else if (is_combat() == 1) { i = 0; while (i <= 3) { set_flag((2 * i) + 1, 1, char_loc_x(i)); set_flag((2 * i) + 2, 1, char_loc_y(i)); i = i + 1; } set_flag(0, 1, 2); } break;
Posts: 7 |
Registered: Monday, January 14 2008 08:00
Playing character control in Blades of Avernum
Apprentice
Member # 13238
written Monday, January 14 2008 10:18
Profile
#0
I'm trying to post a piece of script that may be useful to some people but I get : 'Sorry, we do not permit this HTML tag:Parenthesis in HTML tag' is the // used for script comments that create a problem ? if this post get through probably not... or is it the () parenthesis as stated? this is a script to solve (work-around) the combat end bug, if any interested... thanks for any help.
Posts: 7 |
Registered: Monday, January 14 2008 08:00