Add two new special nodes for cutscenes

- Node to change a monster's location (also works on party members)
- Node to temporarily place text on the map
- Fix the "lift fog" node
- Remove the optimization of only redrawing a terrain space if it has changed
This commit is contained in:
2015-06-03 19:50:00 -04:00
parent 1b754619dc
commit a51ab021f4
16 changed files with 233 additions and 66 deletions

View File

@@ -1616,7 +1616,9 @@ reset to centre on the active character.</dd></dd>
of sight become fully visible. The fog is automatically restored at the end of the current
turn (after monsters make their move).
<dl>
<dt>Extra 1a:</dt><dd>If 1, lift the fog. If 0, restore it.</dd></dd>
<dt>Extra 1a:</dt><dd>If 1, lift the fog. If 0, restore it.</dd>
<dt>Note:</dt><dd>If needed, you can also use this to force the screen to be redrawn (just
specify the current fog setting).</dd></dd>
<dt>Type 200: Initiate Targeting Mode</dt><dd>This advanced node hooks into the native
Blades of Exile targeting engine to allow the player to select one or more targets. The
@@ -1681,6 +1683,39 @@ calculate the damage.</dd>
similar to what happens when fields are placed and creatures take damage as a result. If
1, all damage will be animated simultaneously using fully-animated explosions, similar to
what happens when casting spells such as Fireball or Divine Thud.</dd></dd>
<dt>Type 203: Relocate Creature</dt><dd>This node forces a single creature to relocate to
a different space. Useful for cutscenes. It can handle either absolute or relative
movement.
However, it does not currently check that it is legal for the creature to be on that
space.
This can split the party into its individual members temporarily, similar to combat mode,
but they return to the party's original location once the node sequence ends.
<dl>
<dt>Extra 1a, Extra 1b:</dt><dd>The x and y coordinates or differentials.</dd>
<dt>Extra 2a:</dt><dd>The creature to relocate - 0-5 for party members, 100+x for a
specific monster, -1 for the currently selected target.</dd>
<dt>Extra 2b:</dt><dd>If 0, Extra 1a and 1b are taken as absolute coordinates. If 1, they
are added to the x and y coordinates, respectively. 2 or 3 means the x coordinate is
instead subtracted, while 3 or 4 means the y coordinate is instead subtracted.</dd>
<dt>Extra 2c:</dt><dd>If positive, this specifies a delay in milliseconds after the
creature
is repositioned.</dd></dd>
<dt>Type 204:</dt><dd>This node places a text label on the terrain screen, for example to
indicate someone speaking. The label lasts only until the screen is next updated, but you
can optionally specify a delay to ensure there is time to read it.
<dl>
<dt>Mess 1:</dt><dd>The number of the message to display.</dd>
<dt>Extra 1a, Extra 1b:</dt><dd>The X and Y coordinates of the location to place the
message. If Extra 1b is left at -1, Extra 1a instead specifies the number of a creature at
whose location the message should be placed (0-5 for party members, 6 for party location,
100+x for other creatures). If both are left at -1, the current targeted PC from the
Select PC node is used.</dd>
<dt>Extra 2a:</dt><dd>If 1, the text is centred vertically on the space. If 0, it appears
at the top of the space.</dd>
<dt>Extra 2b:</dt><dd>If positive, this specifies a delay in seconds after the label is
placed.</dd></dd>
</dl>
<h4>Rectangle Specials:</h4>

View File

@@ -65,8 +65,8 @@ Your spell points are what you expend to cast spells. Each spell drains away som
Some doors can't be opened no matter what you try. For example, portcullises can almost never be opened by picking locks or bashing.
A special node just triggered, and since you previously enabled it, you are now in step-through mode. Take a look at the transcript - it gives you the node that is about to execute, together with the type and number (useful if you need to locate it in the editor).
To execute that node, simply press any key (or click the mouse button). After the node has executed, if it calls another one, you will see it in the transcript. Keep pressing a key to step through the nodes. If you wish to exit step-through mode in the middle of a node sequence, simply press Escape.

View File

@@ -200,8 +200,8 @@ lift-fog
start-target
spell-pat-field
spell-pat-boom
relocate
label

View File

@@ -526,3 +526,35 @@ How many dice? (calculated in d6's)
0 - sequential simple booms, 1 - simultaneous animated booms
Special to Jump To
--------------------
Relocate Creature
Unused
Unused
First part of message
Second part of message
Unused
Unused
Unused
X destination or differential
Y destination or differential
Unused
Which creature
Positioning mode
Delay
Special to Jump To
--------------------
Place Label
Unused
Unused
Label text
Unused
Unused
Unused
Unused
X coordinate, or which creature
Y coordinate, or -1 for creature
Unused
0 - Align top, 1 - align centre
Delay
Unused
Special to Jump To
--------------------

View File

@@ -61,6 +61,7 @@ short num_chirps_played = 0;
extern rectangle startup_button[6];
extern bool flushingInput;
extern bool fog_lifted;
extern bool cartoon_happening;
bool ghost_mode;
rectangle startup_top;
@@ -1446,7 +1447,9 @@ bool handle_action(sf::Event event) {
// MARK: Handle non-PC stuff (like monsters) if the party actually did something
if(did_something) handle_monster_actions(need_redraw, need_reprint);
if(fog_lifted) need_redraw = true;
if(cartoon_happening) need_redraw = true;
fog_lifted = false;
cartoon_happening = false;
if(need_redraw) draw_terrain();
if(need_reprint || need_redraw) print_buf();

View File

@@ -1,6 +1,7 @@
#include <cstring>
#include <cstdio>
#include <list>
#include "boe.global.h"
@@ -35,6 +36,7 @@ extern eGameMode overall_mode;
extern short current_spell_range;
extern bool anim_onscreen,play_sounds,frills_on,startup_loaded,party_in_memory;
extern bool flushingInput;
extern bool cartoon_happening, fog_lifted;
extern short anim_step;
extern effect_pat_type current_pat;
extern location ul;
@@ -67,12 +69,6 @@ extern std::string save_talk_str1, save_talk_str2;
rectangle menuBarRect;
Region originalGrayRgn, newGrayRgn, underBarRgn;
short terrain_there[9][9]; // this is an optimization variabel. Keeps track of what terrain
// is in the terrain spot, so things don't get redrawn.
// 0 - 299 just terrain graphic in place
// 300 - blackness
// -1 - nothign worth saving
long anim_ticks = 0;
// 0 - terrain 1 - buttons 2 - pc stats
@@ -214,9 +210,6 @@ void plop_fancy_startup() {
// for(i = 0;i < 8; i++)
// OffsetRect(&trim_rects[i],61,37);
for(i = 0; i < 9; i++)
for(j = 0; j < 9; j++)
terrain_there[i][j] = -1;
win_to_rects[5].offset(TEXT_WIN_UL_X,TEXT_WIN_UL_Y);
win_to_rects[2].offset(PC_WIN_UL_X,PC_WIN_UL_Y);
@@ -764,6 +757,7 @@ bool is_nature(short x, short y, unsigned short ground_t) {
}
std::vector<location> forcecage_locs;
extern std::list<text_label_t> posted_labels;
//mode ... if 1, don't place on screen after redoing
// if 2, only redraw over active monst
@@ -886,6 +880,8 @@ void draw_terrain(short mode) {
}
spot_seen[q][r] = can_draw;
if(fog_lifted) can_draw = true;
if((can_draw != 0) && (overall_mode != MODE_RESTING)) { // if can see, not a pit, and not resting
if(is_combat()) anim_ticks = 0;
@@ -987,6 +983,12 @@ void draw_terrain(short mode) {
// TODO: Move into the above loop to eliminate global variable
for(location fc_loc : forcecage_locs)
Draw_Some_Item(fields_gworld,calc_rect(2,0),terrain_screen_gworld,fc_loc,1,0);
// Draw any posted labels, then clear them out
clip_rect(terrain_screen_gworld, {13, 13, 337, 265});
for(text_label_t lbl : posted_labels)
draw_text_label(lbl);
undo_clip(terrain_screen_gworld);
posted_labels.clear();
// Now do the light mask thing
apply_light_mask(false);
@@ -1207,8 +1209,6 @@ void draw_trim(short q,short r,short which_trim,ter_num_t ground_ter) {
if(!frills_on)
return;
terrain_there[q][r] = -1;
unsigned short pic = univ.scenario.ter_types[ground_ter].picture;
if(pic < 960){
from_gworld = &terrain_gworld[pic / 50];
@@ -1327,8 +1327,6 @@ void place_road(short q,short r,location where, bool here) {
draw_loc.x = q;
draw_loc.y = r;
terrain_there[q][r] = -1;
if(here){
if(where.y > 0)
ter = coord_to_ter(where.x,where.y - 1);

View File

@@ -23,6 +23,7 @@ extern sf::RenderWindow mainPtr;
extern rectangle windRect;
extern short stat_window;
extern bool give_delays;
extern bool cartoon_happening;
extern eGameMode overall_mode;
extern short current_spell_range;
extern bool anim_onscreen,play_sounds,frills_on,startup_loaded;
@@ -34,7 +35,6 @@ extern short combat_posing_monster , current_working_monster ; // 0-5 PC 100 + x
extern sf::RenderTexture terrain_screen_gworld;
extern sf::Texture items_gworld,tiny_obj_gworld,pc_gworld,monst_gworld[NUM_MONST_SHEETS];
extern sf::Texture fields_gworld,anim_gworld,vehicle_gworld,terrain_gworld[NUM_TER_SHEETS];
extern short terrain_there[9][9];
extern std::queue<pending_special_type> special_queue;
extern location ul;
@@ -77,20 +77,13 @@ void draw_one_terrain_spot (short i,short j,short terrain_to_draw) {
where_draw = calc_rect(i,j);
where_draw.offset(13,13);
if(terrain_to_draw == -1) {
if(terrain_there[i][j] == 300) {
return;
}
terrain_there[i][j] = 300;
fill_rect(terrain_screen_gworld, where_draw, sf::Color::Black);
return;
}
if(terrain_to_draw >= 10000) { // force using a specific graphic
terrain_to_draw -= 10000;
if(terrain_there[i][j] == terrain_to_draw)
return;
source_gworld = &terrain_gworld[terrain_to_draw / 50];
terrain_there[i][j] = terrain_to_draw;
terrain_to_draw %= 50;
source_rect = calc_rect(terrain_to_draw % 10, terrain_to_draw / 10);
anim_type = -1;
@@ -98,25 +91,19 @@ void draw_one_terrain_spot (short i,short j,short terrain_to_draw) {
else if(univ.scenario.ter_types[terrain_to_draw].picture >= 2000) { // custom
graf_pos_ref(source_gworld, source_rect) = spec_scen_g.find_graphic(univ.scenario.ter_types[terrain_to_draw].picture - 2000 + (anim_ticks % 4));
anim_type = 0;
terrain_there[i][j] = -1;
}
else if(univ.scenario.ter_types[terrain_to_draw].picture >= 1000) { // custom
graf_pos_ref(source_gworld, source_rect) = spec_scen_g.find_graphic(univ.scenario.ter_types[terrain_to_draw].picture - 1000);
terrain_there[i][j] = -1;
}
else if(univ.scenario.ter_types[terrain_to_draw].picture >= 960) { // animated
source_gworld = &anim_gworld;
terrain_to_draw = univ.scenario.ter_types[terrain_to_draw].picture;
source_rect = calc_rect(4 * ((terrain_to_draw - 960) / 5) + (anim_ticks % 4),(terrain_to_draw - 960) % 5);
terrain_there[i][j] = -1;
anim_type = 0;
}
else {
if(terrain_there[i][j] == univ.scenario.ter_types[terrain_to_draw].picture) return;
terrain_there[i][j] = univ.scenario.ter_types[terrain_to_draw].picture;
terrain_to_draw = univ.scenario.ter_types[terrain_to_draw].picture;
source_gworld = &terrain_gworld[terrain_to_draw / 50];
terrain_there[i][j] = terrain_to_draw;
terrain_to_draw %= 50;
source_rect = calc_rect(terrain_to_draw % 10, terrain_to_draw / 10);
anim_type = -1;
@@ -152,7 +139,6 @@ void draw_monsters() {
(can_see_light(univ.party.p_loc, univ.party.out_c[i].m_loc,sight_obscurity) < 5)) {
where_draw.x = univ.party.out_c[i].m_loc.x - univ.party.p_loc.x + 4;
where_draw.y = univ.party.out_c[i].m_loc.y - univ.party.p_loc.y + 4;
terrain_there[where_draw.x][where_draw.y] = -1;
for(j = 0; univ.party.out_c[i].what_monst.monst[j] == 0 && j < 7; j++);
@@ -250,7 +236,7 @@ void draw_pcs(location center,short mode) {
for(i = 0; i < 6; i++)
if(univ.party[i].main_status == eMainStatus::ALIVE)
if(point_onscreen(center, univ.party[i].combat_pos) &&
(/*cartoon_happening ||*/ party_can_see(univ.party[i].combat_pos) < 6)){
(cartoon_happening || party_can_see(univ.party[i].combat_pos) < 6)){
where_draw.x = univ.party[i].combat_pos.x - center.x + 4;
where_draw.y = univ.party[i].combat_pos.y - center.y + 4;
sf::Texture* from_gw;
@@ -315,18 +301,15 @@ void draw_items(location where){
sf::Texture* src_gw;
graf_pos_ref(src_gw, from_rect) = spec_scen_g.find_graphic(univ.town.items[i].graphic_num - 10000, true);
to_rect = coord_to_rect(where_draw.x,where_draw.y);
terrain_there[where_draw.x][where_draw.y] = -1;
rect_draw_some_item(*src_gw,from_rect,terrain_screen_gworld,to_rect,sf::BlendAlpha);
}else if(univ.town.items[i].graphic_num >= 1000){
sf::Texture* src_gw;
graf_pos_ref(src_gw, from_rect) = spec_scen_g.find_graphic(univ.town.items[i].graphic_num - 1000);
to_rect = coord_to_rect(where_draw.x,where_draw.y);
terrain_there[where_draw.x][where_draw.y] = -1;
rect_draw_some_item(*src_gw,from_rect,terrain_screen_gworld,to_rect,sf::BlendAlpha);
}else{
from_rect = get_item_template_rect(univ.town.items[i].graphic_num);
to_rect = coord_to_rect(where_draw.x,where_draw.y);
terrain_there[where_draw.x][where_draw.y] = -1;
if(univ.town.items[i].graphic_num >= 55) {
to_rect.inset(5,9);
rect_draw_some_item(tiny_obj_gworld, from_rect, terrain_screen_gworld, to_rect,sf::BlendAlpha);
@@ -458,7 +441,7 @@ void draw_party_symbol(location center) {
return;
if((is_town()) && (univ.town.p_loc.x > 70))
return;
if(overall_mode == MODE_LOOK_TOWN) {
if(overall_mode == MODE_LOOK_TOWN || cartoon_happening) {
target.x += univ.town.p_loc.x - center.x;
target.y += univ.town.p_loc.y - center.y;
}

View File

@@ -16,6 +16,7 @@ extern eGameMode overall_mode;
extern eGameMode store_pre_shop_mode, store_pre_talk_mode;
extern location center;
extern cUniverse univ;
extern bool cartoon_happening;
location light_locs[40];
short num_lights = 0;
@@ -56,7 +57,7 @@ bool is_out() {
}
bool is_town() {
if(((overall_mode > MODE_OUTDOORS) && (overall_mode < MODE_COMBAT)) || (overall_mode == MODE_LOOK_TOWN))
if((overall_mode > MODE_OUTDOORS && overall_mode < MODE_COMBAT) || overall_mode == MODE_LOOK_TOWN || cartoon_happening)
return true;
else if(overall_mode == MODE_SHOPPING) {
std::swap(overall_mode, store_pre_shop_mode);

View File

@@ -62,7 +62,6 @@ extern std::shared_ptr<cButton> done_btn, help_btn;
extern location center;
extern location store_anim_ul;
extern char light_area[13][13];
extern short terrain_there[9][9];
extern char unexplored_area[13][13];
extern tessel_ref_t bw_pats[6];
extern short combat_posing_monster , current_working_monster ; // 0-5 PC 100 + x - monster x
@@ -95,7 +94,6 @@ extern rectangle shop_frame ;
extern rectangle shop_done_rect;
extern char *heal_types[];
extern short heal_costs[8];
extern short terrain_there[9][9];
extern short shop_array[30];
// Missile anim vars
@@ -146,11 +144,6 @@ void apply_unseen_mask() {
to_rect.offset(-28 + i * 28,-36 + 36 * j);
to_rect |= big_to;
tileImage(terrain_screen_gworld, to_rect, bw_pats[3], sf::BlendAlpha);
for(k = i - 2; k < i + 1; k++)
for(l = j - 2; l < j + 1; l++)
if((k >= 0) && (l >= 0) && (k < 9) && (l < 9) && ((k != i - 1) || (l != j - 1)))
terrain_there[k][l] = -1;
}
}
@@ -200,11 +193,6 @@ void apply_light_mask(bool onWindow) {
light_area[i][j] = 3;
}
for(i = 2; i < 11; i++)
for(j = 2; j < 11; j++) {
if(light_area[i][j] == 1)
terrain_there[i - 2][j - 2] = -1;
}
for(i = 0; i < 13; i++)
for(j = 0; j < 13; j++)
if(last_light_mask[i][j] != light_area[i][j])

View File

@@ -51,6 +51,7 @@ extern short combat_posing_monster;
bool can_draw_pcs = true;
bool fog_lifted = false;
bool cartoon_happening = false;
std::map<eDamageType,int> boom_gr = {
{eDamageType::WEAPON, 3},
@@ -70,6 +71,14 @@ iLiving* current_pc_picked_in_spec_enc = nullptr;
extern std::map<eSkill,short> skill_max;
bool special_in_progress = false;
static void start_cartoon() {
if(!cartoon_happening && !is_combat()) {
for(int i = 0; i < 6; i++)
univ.party[i].combat_pos = univ.town.p_loc;
}
cartoon_happening = true;
}
// 0 - can't use 1 - combat only 2 - town only 3 - town & combat only 4 - everywhere 5 - outdoor
// + 10 - mag. inept can use
std::map<eItemAbil, short> abil_chart = {
@@ -4116,6 +4125,7 @@ void townmode_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
case eSpecType::TOWN_SET_CENTER:
if(l.x >= 0 && l.y >= 0) center = l;
else center = is_combat() ? univ.party[current_pc].combat_pos : univ.town.p_loc;
start_cartoon();
redraw_screen(REFRESH_TERRAIN);
break;
case eSpecType::TOWN_LIFT_FOG:
@@ -4188,6 +4198,65 @@ void townmode_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
end_missile_anim();
}
break;
case eSpecType::TOWN_RELOCATE_CREATURE:
if(spec.ex2b > 4) {
giveError("Invalid positioning mode (0-4)");
break;
}
if(spec.ex2a < 0)
i = univ.get_target_i(*current_pc_picked_in_spec_enc);
else i = spec.ex2a;
if(spec.ex2b > 1) {
if(spec.ex2b <= 3) l.x *= -1;
if(spec.ex2b >= 3) l.y *= -1;
}
if(i < 6) {
start_cartoon();
if(spec.ex2b == 0)
univ.party[i].combat_pos = l;
else {
univ.party[i].combat_pos.x += l.x;
univ.party[i].combat_pos.y += l.y;
}
} else if(i >= 100) {
i -= 100;
if(spec.ex2b == 0)
univ.town.monst[i].cur_loc = l;
else {
univ.town.monst[i].cur_loc.x += l.x;
univ.town.monst[i].cur_loc.y += l.y;
}
} else {
giveError("Invalid positioning target!");
break;
}
redraw_screen(REFRESH_TERRAIN);
if(spec.ex2c > 0)
sf::sleep(sf::milliseconds(spec.ex2c));
*redraw = 1;
break;
case eSpecType::TOWN_PLACE_LABEL:
check_mess = false;
if(l.y < 0) {
if(l.x < 0)
l.x = univ.get_target_i(*current_pc_picked_in_spec_enc);
if(l.x < 6)
l = (is_combat() || cartoon_happening) ? univ.party[l.x].combat_pos : univ.town.p_loc;
else if(l.x == 6)
l = univ.town.p_loc;
else if(l.x >= 100 && l.x - 100 < univ.town.monst.size())
l = univ.town.monst[l.x - 100].cur_loc;
else {
giveError("Invalid label target!");
break;
}
}
get_strs(strs[0], strs[1], cur_spec_type, spec.m1, spec.m1);
place_text_label(strs[0], l, spec.ex2a);
redraw_screen(REFRESH_TERRAIN);
if(spec.ex2b > 0) // TODO: Add preferences setting to increase this delay, for slow readers
sf::sleep(sf::seconds(spec.ex2b));
break;
default:
giveError("Special node type \"" + (*cur_node.type).name() + "\" is either miscategorized or unimplemented!");
break;

View File

@@ -2,6 +2,7 @@
#define TEXT_BUF_LEN 70
#include <sstream>
#include <list>
#include "boe.global.h"
@@ -52,12 +53,13 @@ extern tessel_ref_t bg[];
extern short dest_personalities[40];
extern location source_locs[6];
extern location dest_locs[40] ;
extern location center;
extern sf::Texture tiny_obj_gworld,invenbtn_gworld,status_gworld;
extern cCustomGraphics spec_scen_g;
extern sf::Texture pc_gworld;
extern sf::RenderTexture pc_stats_gworld, item_stats_gworld, text_area_gworld;
extern short terrain_there[9][9];
extern sf::RenderTexture terrain_screen_gworld;
// game globals
extern location ul;
@@ -1117,7 +1119,6 @@ void Draw_Some_Item (sf::Texture& src_gworld, rectangle src_rect, sf::RenderTarg
if((supressing_some_spaces) && (target != ok_space[0]) &&
(target != ok_space[1]) && (target != ok_space[2]) && (target != ok_space[3]))
return;
terrain_there[target.x][target.y] = -1;
destrec = coord_to_rect(target.x,target.y);
if(main_win == 1) destrec.offset(ul.x + 5,ul.y + 5);
@@ -1133,6 +1134,49 @@ void Draw_Some_Item (sf::Texture& src_gworld, rectangle src_rect, sf::RenderTarg
}
}
std::list<text_label_t> posted_labels;
void place_text_label(std::string string, location at, bool centred) {
TextStyle style;
style.font = FONT_PLAIN;
short height = 0;
short width = string_length(string, style, &height);
at.x -= center.x - 4;
at.x *= 28;
at.x += 14;
at.x -= width / 2;
at.y -= center.y - 4;
at.y *= 36;
if(centred)
at.y += 18;
if(at.y == 0) at.y = 36;
else at.y -= height;
rectangle text_rect(at, loc(at.x + width, at.y + height));
text_rect.offset(-min(at.x,0),-min(at.y,0)); // If it's longer, make it off-centre to keep it onscreen.
text_rect.offset(13,13);
posted_labels.push_back({text_rect, string});
}
void draw_text_label(const text_label_t& label) {
sf::Color back_clr = {64, 64, 64, 42};
TextStyle style;
style.font = FONT_PLAIN;
style.colour = sf::Color::White;
rectangle back_rect = label.text_rect, text_rect = label.text_rect;
back_rect.inset(-7,-7);
back_rect.offset(0,-2);
for(int i = 0; i <= 3; i++) {
fill_roundrect(terrain_screen_gworld, back_rect, 7, back_clr);
back_rect.inset(2,2);
back_clr.a *= 1.5;
}
//text_rect.offset(0, -text_rect.height() + 1);
text_rect.offset(0, -5);
win_draw_string(terrain_screen_gworld, text_rect, label.str, eTextMode::LEFT_TOP, style);
}
// TODO: This seems to duplicate logic found in graphtool to get a rect from a picture index
rectangle coord_to_rect(short i,short j) {
rectangle to_return;

View File

@@ -37,3 +37,10 @@ bool day_reached(unsigned short which_day, unsigned short which_event);
void Draw_Some_Item (sf::Texture& src_gworld, rectangle src_rect, sf::RenderTarget& targ_gworld, location target, char masked, short main_win);
rectangle get_stat_effect_rect(int which_effect);
struct text_label_t {
rectangle text_rect;
std::string str;
};
void place_text_label(std::string string, location at, bool centred);
void draw_text_label(const text_label_t& label);

View File

@@ -687,6 +687,8 @@ enum class eSpecType {
TOWN_START_TARGETING = 200,
TOWN_SPELL_PAT_FIELD = 201,
TOWN_SPELL_PAT_BOOM = 202,
TOWN_RELOCATE_CREATURE = 203,
TOWN_PLACE_LABEL = 204,
RECT_PLACE_FIELD = 210,
RECT_SET_EXPLORED = 211,
RECT_MOVE_ITEMS = 212,
@@ -717,7 +719,7 @@ inline eSpecCat getNodeCategory(eSpecType node) {
return eSpecCat::AFFECT;
if(code >= 130 && code <= 160)
return eSpecCat::IF_THEN;
if(code >= 170 && code <= 202)
if(code >= 170 && code <= 204)
return eSpecCat::TOWN;
if(code >= 210 && code <= 218)
return eSpecCat::RECT;

View File

@@ -390,6 +390,7 @@ std::istream& operator >> (std::istream& in, eSpecType& e) {
// % - Choose button to select shop cost adjustment
// { - Choose button to select a spell pattern
// } - As above, but allows you to select which version of the rotateable field
// ^ - Choose button to select a positioning mode
// e - Choose button to select a status effect
// E - Choose button to select a party status effect
// w - Choose button to select main party status effect
@@ -447,17 +448,17 @@ static const char*const button_dict[7][11] = {
"s ss s + s==+s = ", // ex2b
" = s ", // ex2c
}, { // town nodes
"mmmmmmmmmmmmmmm dddmmmmmmmmmmmm", // msg1
" ", // msg2
" ", // msg3
" 8 ppp ", // pic
" ??? ", // pictype
" c L { ", // ex1a
" s s s s @ ", // ex1b
" }}", // ex1c
"@ 7 ! c T T i FD", // ex2a
" DD / ", // ex2b
" x x : : ", // ex2c
"mmmmmmmmmmmmmmm dddmmmmmmmmmmmmmM", // msg1
" ", // msg2
" ", // msg3
" 8 ppp ", // pic
" ??? ", // pictype
" c L { ", // ex1a
" s s s s @ ", // ex1b
" }} ", // ex1c
"@ 7 ! c T T i FD ", // ex2a
" DD / ^ ", // ex2b
" x x : : ", // ex2c
}, { // rectangle nodes
"mmmmmmmmm", // msg1
" ", // msg2

View File

@@ -343,6 +343,9 @@ short choose_text(eStrType list, unsigned short cur_choice, cDialog* parent, std
"Magic Resistance", "Fire Resistance", "Cold Resistance", "Poison Resistance",
};
break;
case STRT_POS_MODE:
strings = {"Absolute Position", "Move Southeast", "Move Southwest", "Move Northwest", "Move Northeast"};
break;
}
if(cur_choice < 0 || cur_choice >= strings.size())
cur_choice = -1;
@@ -807,6 +810,7 @@ static bool edit_spec_enc_value(cDialog& me, std::string item_hit, node_stack_t&
case '&': strt = STRT_SHOP; title = "Which shop?"; break;
case '%': strt = STRT_COST_ADJ; title = "What cost adjust?"; break;
case '*': strt = STRT_CONTEXT; title = "What context?"; break;
case '^': strt = STRT_POS_MODE; title = "Select positioning mode:"; break;
case ':': strt = STRT_STAIR_MODE; title = "Select trigger limitations:"; break;
case 'w': strt = STRT_STATUS; title = "Select status:"; str_adj = 1; break;
case 'j': strt = STRT_QUEST; title = "Select a quest:"; break;

View File

@@ -12,7 +12,7 @@ enum eStrType {
STRT_SHOP, STRT_COST_ADJ, STRT_STAIR_MODE, STRT_TALK_NODE,
STRT_STATUS, STRT_SPELL_PAT, STRT_SUMMON, STRT_TALK,
STRT_ENCHANT, STRT_DIR, STRT_QUEST, STRT_QUEST_STATUS,
STRT_HEALING, STRT_TREASURE, STRT_MONST_STAT,
STRT_HEALING, STRT_TREASURE, STRT_MONST_STAT, STRT_POS_MODE,
};
bool cre(short val,short min,short max,std::string text1,std::string text2,cDialog* parent) ;