Lots of special node changes

- Moved change/swap/transform terrain to the General section
- Merge change outdoor terrain into general change terrain
- Merge if town/outdoor terrain nodes
- Merge the if+take nodes with the equivalent base nodes
- Merge secret passage node into the can't enter node
- Move outdoor shop to the General section since it's not restricted to outdoors
- New story dialog node displays a sequence of strings one at a time, like the Exile 2 intro dialog
- New town nodes for animations: run missile, animate monster attack, draw simple boom with optional damage number
- If fields node expanded - now checks if the count of the desired field type existing within a specified rectangle falls within a given range
- Place items and move items nodes can now set the items as contained, provided there's a container on the destination space
- All rectangle nodes can now be restricted to just the boundary, as per the documentation
This commit is contained in:
2015-01-15 23:30:07 -05:00
parent 96f14d3a38
commit aaa3cde16b
13 changed files with 422 additions and 288 deletions

View File

@@ -1,13 +1,13 @@
set-sdf
inc-sdf
disp-msg
secret-pass
start-shop
disp-sm-msg
flip-sdf
sdf-rand
sdf-add
sdf-diff
story-dlog
block-move
change-time
start-timer-scen
@@ -31,9 +31,9 @@ print-nums
sdf-times
sdf-divide
sdf-power
change-ter
swap-ter
trans-ter
@@ -58,8 +58,8 @@ once-dlog
once-give-dlog
once-encounter
once-out-encounter
once-town-encounter
once-trap
@@ -134,16 +134,16 @@ if-spec-item
if-sdf-compare
if-ter
if-gold
if-food
if-item-class-at
if-item-class
if-item-class-equip
if-day
if-field
if-party-size
@@ -168,9 +168,9 @@ if-num-response
town-attitude
change-ter
swap-ter
trans-ter
anim-missile
anim-attack
anim-splat
move-party
hit-space
explode-space
@@ -225,5 +225,3 @@ rect-unlock
make-out-monst
start-shop

View File

@@ -62,19 +62,19 @@ Unused
Unused
Special to Jump To
--------------------
Secret Passage
Unused
Unused
First part of message
Second part of message
Unused
Start Shopping
Unused
Unused
Name of Store
Unused
Unused
Unused
Unused
Number of first item in store
Store type (see docs. for list)
Unused
Number of items in store (1 .. 40)
Cost adjust (0 .. 6, lower = cheaper)
Unused
Special to Jump To
--------------------
@@ -158,21 +158,21 @@ Second SDF part B, or -1 for literal number
Unused
Special to Jump To
--------------------
Unused Node
Unused
Unused
Unused
Unused
Unused
Unused
Unused
Unused
Story Dialog
Unused
Unused
Dialog title string
First string in dialog
Last string in dialog
Picture number
Picture type
Unused
Unused
Unused
Unused
Unused
Unused
Special to Jump To
--------------------
Can't Enter
Unused
@@ -185,7 +185,7 @@ Unused
0 - can enter, 1 - no enter
Unused
Unused
Unused
0 - don't force, 1 - force if blocked
Unused
Unused
Special to Jump To
@@ -542,3 +542,67 @@ Second SDF part B, or -1 for literal number
Unused
Special to Jump To
--------------------
Change Terrain
Unused
Unused
First part of message
Second part of message
Unused
Unused
Unused
X coordinate of space
Y coordinate of space
Unused
Terrain to change to
Unused
Unused
Special to Jump To
--------------------
Swap Terrain
Unused
Unused
First part of message
Second part of message
Unused
Unused
Unused
X coordinate of space
Y coordinate of space
Unused
Swap this terrain ...
With this terrain ...
Unused
Special to Jump To
--------------------
Transform Terrain
Unused
Unused
First part of message
Second part of message
Unused
Unused
Unused
X coordinate of space
Y coordinate of space
Unused
Unused
Unused
Unused
Special to Jump To
--------------------
Special Name
sdf1
sdf2
message1
message2
message3
pic
pictype
extra 1a
extra 1b
extra 1c
extra 2a
extra 2b
extra 2c
Special to Jump To
--------------------

View File

@@ -121,7 +121,7 @@ Unused
If party has this much gold ...
Call this special ...
Unused
Unused
If 1, take gold
Unused
Unused
Otherwise call this special
@@ -137,7 +137,7 @@ Unused
If party has this much food ...
Call this special ...
Unused
Unused
If 1, take food
Unused
Unused
Otherwise call this special
@@ -155,7 +155,7 @@ Y coordinate of space
Unused
If item of this class on space ...
Call this special ...
Unused
If 1, take item
Otherwise call this special
--------------------
Have Item With Class?
@@ -169,7 +169,7 @@ Unused
If has item of this special class ...
Call this special ...
Unused
Unused
If 1, take item
Unused
Unused
Otherwise call this special
@@ -185,28 +185,12 @@ Unused
If has equipped item of this special ...
Call this special ...
Unused
Unused
Unused
Unused
Otherwise call this special
--------------------
Has Gold? (+ take)
Unused
Unused
Unused
Unused
Unused
Unused
Unused
If party has this much gold ...
Call this special ...
Unused
Unused
If 1, take item
Unused
Unused
Otherwise call this special
--------------------
Has Food? (+ take)
Unused Node
Unused
Unused
Unused
@@ -214,15 +198,15 @@ Unused
Unused
Unused
Unused
If party has this much food ...
Call this special ...
Unused
Unused
Unused
Unused
Otherwise call this special
Unused
Unused
Special to Jump To
--------------------
Item Class on Space? (+ take)
Unused Node
Unused
Unused
Unused
@@ -230,15 +214,15 @@ Unused
Unused
Unused
Unused
X coordinate of space
Y coordinate of space
Unused
If item of this class on space ...
Call this special ...
Unused
Otherwise call this special
Unused
Unused
Unused
Unused
Special to Jump To
--------------------
Have Item W. Class? (+ take)
Unused Node
Unused
Unused
Unused
@@ -246,15 +230,15 @@ Unused
Unused
Unused
Unused
If has item of this special class ...
Call this special ...
Unused
Unused
Unused
Unused
Otherwise call this special
Unused
Unused
Special to Jump To
--------------------
Equip Item W. Class? (+ take)
Unused Node
Unused
Unused
Unused
@@ -262,13 +246,29 @@ Unused
Unused
Unused
Unused
If has equipped item of this class ...
Call this special ...
Unused
Unused
eUnused
Unused
Otherwise call this special
Unused
Unused
Unused
Special to Jump To
--------------------
Unused Node
Unused
Unused
Unused
Unused
Unused
Unused
Unused
Unused
Unused
Unused
Unused
Unused
Unused
Special to Jump To
--------------------
Day Reached?
Unused

View File

@@ -62,19 +62,4 @@ Unused
Unused
Special to Jump To
--------------------
Outdoor Store
Unused
Unused
Name of Store
Unused
Unused
Unused
Unused
Number of first item in store
Store type (see docs. for list)
Unused
Number of items in store (1 .. 40)
Cost adjust (0 .. 6, lower = cheaper)
Unused
Special to Jump To
--------------------

View File

@@ -4,7 +4,7 @@ Which field type
First part of message
Second part of message
Unused
Unused
0 - entire rectangle, 1 - just borders
Unused
Top of rectangle
Left of rectangle
@@ -195,8 +195,8 @@ X of space to move to
Y of space to move to
First part of message
Second part of message
Unused
Unused
Set to 1 to place in container, if present
0 - entire rectangle, 1 - just borders
Unused
Top of rectangle
Left of rectangle
@@ -212,7 +212,7 @@ Unused
First part of message
Second part of message
Unused
Unused
0 - entire rectangle, 1 - just borders
Unused
Top of rectangle
Left of rectangle
@@ -228,7 +228,7 @@ Chance of changing (0 - 100)
First part of message
Second part of message
Unused
Unused
0 - entire rectangle, 1 - just borders
Unused
Top of rectangle
Left of rectangle
@@ -244,7 +244,7 @@ with this ter. type
First part of message
Second part of message
Unused
Unused
0 - entire rectangle, 1 - just borders
Unused
Top of rectangle
Left of rectangle
@@ -260,7 +260,7 @@ Unused
First part of message
Second part of message
Unused
Unused
0 - entire rectangle, 1 - just borders
Unused
Top of rectangle
Left of rectangle
@@ -276,7 +276,7 @@ Unused
First part of message
Second part of message
Unused
Unused
0 - entire rectangle, 1 - just borders
Unused
Top of rectangle
Left of rectangle
@@ -292,7 +292,7 @@ Unused
First part of message
Second part of message
Unused
Unused
0 - entire rectangle, 1 - just borders
Unused
Top of rectangle
Left of rectangle

View File

@@ -14,7 +14,23 @@ Unused
Unused
Special to Jump To
--------------------
Change Terrain
Do Missile Animation
Unused
Unused
First part of message
Second part of message
Unused
Which missile animation?
Unused
X coordinate of start space
Y coordinate of start space
Path type
X coordinate of end space
Y coordinate of end space
Sound to play
Special to Jump To
--------------------
Animate Monster Attack
Unused
Unused
First part of message
@@ -22,44 +38,28 @@ Second part of message
Unused
Unused
Unused
X coordinate of space
Y coordinate of space
X coordinate of monster (or monster ID)
Y coordinate of monster (or -1 to use X as ID)
Unused
Unused
Terrain to change to
Unused
Unused
Special to Jump To
--------------------
Swap Terrain
Animate Fake Damage
Unused
Unused
First part of message
Second part of message
Unused
Unused
Unused
pic
pictype
X coordinate of space
Y coordinate of space
Unused
Swap this terrain ...
With this terrain ...
Unused
Special to Jump To
--------------------
Transform Terrain
Unused
Unused
First part of message
Second part of message
Unused
Unused
Unused
X coordinate of space
Y coordinate of space
Unused
Unused
Unused
Unused
extra 1c
Boom type
Number to print (0 means print no number)
Sound to play
Special to Jump To
--------------------
Move Party
@@ -362,7 +362,7 @@ X coordinate to place at
Y coordinate to place at
Unused
Item to place
Unused
Set to 1 to place in container, if present
Unused
Special to Jump To
--------------------

View File

@@ -1472,9 +1472,10 @@ void boom_space(location where,short mode,short type,short damage,short sound) {
rectangle source_rect = {0,0,36,28},text_rect,dest_rect = {13,13,49,41},big_to = {13,13,337,265},store_rect;
short del_len;
short x_adj = 0,y_adj = 0,which_m;
short sound_to_play[20] = {
short sound_lookup[20] = {
97,69,70,71,72, 73,55,75,42,86,
87,88,89,98,0, 0,0,0,0,0};
short sound_to_play = sound < 0 ? -sound : sound_lookup[sound];
//sound_key = type / 10;
//type = type % 10;
@@ -1495,7 +1496,7 @@ void boom_space(location where,short mode,short type,short damage,short sound) {
// Redraw terrain in proper position
if(((!point_onscreen(center,where) && (overall_mode >= MODE_COMBAT)) || (overall_mode == MODE_OUTDOORS))
) {
play_sound(sound_to_play[sound]);
play_sound(sound_to_play);
return;
}
@@ -1532,7 +1533,7 @@ void boom_space(location where,short mode,short type,short damage,short sound) {
source_rect.offset(-store_rect.left + 28 * type,-store_rect.top);
rect_draw_some_item(boom_gworld,source_rect,dest_rect,ul,sf::BlendAlpha);
if((dest_rect.right - dest_rect.left >= 28) && (dest_rect.bottom - dest_rect.top >= 36)) {
if(damage > 0 && dest_rect.right - dest_rect.left >= 28 && dest_rect.bottom - dest_rect.top >= 36) {
TextStyle style;
style.lineHeight = 10;
//text_rect = coord_to_rect(where_draw.x,where_draw.y);
@@ -1544,7 +1545,7 @@ void boom_space(location where,short mode,short type,short damage,short sound) {
text_rect.offset(-4,-5);
win_draw_string(mainPtr,text_rect,std::to_string(damage),eTextMode::CENTRE,style,ul);
}
play_sound((skip_boom_delay?-1:1)*sound_to_play[sound]);
play_sound((skip_boom_delay?-1:1)*sound_to_play);
mainPtr.display();
if((sound == 6) && (fast_bang == 0) && (!skip_boom_delay))
sf::sleep(time_in_ticks(12));

View File

@@ -603,13 +603,17 @@ void drop_item(short pc_num,short item_num,location where_drop) {
}
}
bool place_item(cItem item,location where,bool forced) {
bool place_item(cItem item,location where,bool forced,bool contained) {
short i;
if(contained && !is_container(where))
contained = false;
for(i = 0; i < NUM_TOWN_ITEMS; i++)
if(univ.town.items[i].variety == eItemType::NO_ITEM) {
univ.town.items[i] = item;
univ.town.items[i].item_loc = where;
univ.town.items[i].contained = contained;
reset_item_max();
return true;
}
@@ -620,6 +624,7 @@ bool place_item(cItem item,location where,bool forced) {
if(univ.town.items[i].variety == eItemType::NO_ITEM) {
univ.town.items[i] = item;
univ.town.items[i].item_loc = where;
univ.town.items[i].contained = contained;
reset_item_max();
return true;
}
@@ -1120,6 +1125,32 @@ void custom_pic_dialog(std::string title, pic_num_t bigpic) {
pic_dlg.run();
}
void story_dialog(std::string title, str_num_t first, str_num_t last, int which_str_type, pic_num_t pic, ePicType pt) {
cDialog story_dlg("many-str");
dynamic_cast<cPict&>(story_dlg["pict"]).setPict(pic, pt);
str_num_t cur = first;
story_dlg.attachClickHandlers([&cur,first,last,which_str_type](cDialog& me, std::string clicked, eKeyMod) -> bool {
if(clicked == "left") {
if(cur > first) cur--;
} else if(clicked == "done" || cur == last) {
me.toast(false);
return true;
} else if(clicked == "right") {
cur++;
}
if(which_str_type == 0)
me["str"].setText(univ.scenario.spec_strs[cur]);
else if(which_str_type == 1)
me["str"].setText(univ.out->spec_strs[cur]);
else if(which_str_type == 2)
me["str"].setText(univ.town->spec_strs[cur]);
return true;
}, {"left", "right", "done"});
story_dlg["left"].triggerClickHandler(story_dlg, "left", eKeyMod());
story_dlg["title"].setText(title);
story_dlg.run();
}
static bool get_num_of_items_event_filter(cDialog& me, std::string, eKeyMod) {
if(me.toast(true))
me.setResult<int>(me["number"].getTextAsNum());

View File

@@ -25,7 +25,7 @@ void remove_charge(short pc_num,short which_item);
void enchant_weapon(short pc_num,short item_hit,short enchant_type,short new_val);
void equip_item(short pc_num,short item_num);
void drop_item(short pc_num,short item_num,location where_drop);
bool place_item(cItem item,location where,bool forced);
bool place_item(cItem item,location where,bool forced,bool contained = false);
void destroy_an_item();
void give_thing(short pc_num, short item_num);
void combine_things(short pc_num);
@@ -40,6 +40,7 @@ bool show_get_items(std::string titleText, std::vector<cItem*>& itemRefs, short
bool display_item(location from_loc,short pc_num,short mode, bool check_container);
short custom_choice_dialog(std::array<std::string, 6>& strs,short pic_num,ePicType pic_type,std::array<short, 3>& buttons) ;
void custom_pic_dialog(std::string title, pic_num_t bigpic);
void story_dialog(std::string title, str_num_t first, str_num_t last, int which_str_type, pic_num_t pic, ePicType pt);
short get_num_of_items(short max_num);
void init_mini_map();
void put_pc_effects_on_dialog(cDialog& dialog,short item);

View File

@@ -44,6 +44,7 @@ extern short fast_bang;
extern bool end_scenario;
extern cUniverse univ;
extern std::queue<pending_special_type> special_queue;
extern short combat_posing_monster;
bool can_draw_pcs = true;
@@ -180,13 +181,12 @@ bool check_special_terrain(location where_check,eSpecCtx mode,short which_pc,sho
for(i = 0; i < 18; i++)
if(out_where == univ.out->special_locs[i]) {
*spec_num = univ.out->special_id[i];
if((*spec_num >= 0) &&
univ.out->specials[*spec_num].type == eSpecType::SECRET_PASSAGE)
*forced = true;
// call special
run_special(mode,1,univ.out->special_id[i],out_where,&s1,&s2,&s3);
if(s1 > 0)
can_enter = false;
else if(s2 > 0)
*forced = true;
erase_out_specials();
put_pc_screen();
put_item_screen(stat_window,0);
@@ -211,9 +211,6 @@ bool check_special_terrain(location where_check,eSpecCtx mode,short which_pc,sho
}
for(i = 0; i < 50; i++)
if(where_check == univ.town->special_locs[i]) {
if(univ.town->specials[univ.town->spec_id[i]].type == eSpecType::SECRET_PASSAGE) {
*forced = true;
}
*spec_num = univ.town->spec_id[i];
bool runSpecial = false;
if(!is_blocked(where_check)) runSpecial = true;
@@ -226,6 +223,8 @@ bool check_special_terrain(location where_check,eSpecCtx mode,short which_pc,sho
run_special(mode,2,univ.town->spec_id[i],where_check,&s1,&s2,&s3);
if(s1 > 0)
can_enter = false;
else if(s2 > 0)
*forced = true;
}
}
put_pc_screen();
@@ -2102,7 +2101,10 @@ void general_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
if(which_mode == eSpecCtx::OUT_MOVE || which_mode == eSpecCtx::TOWN_MOVE || which_mode == eSpecCtx::COMBAT_MOVE) {
if(spec.ex1a != 0)
*a = 1;
else *a = 0;
else {
*a = 0;
if(spec.ex2a != 0) *b = 1;
}
}
break;
case eSpecType::CHANGE_TIME:
@@ -2285,6 +2287,43 @@ void general_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
break;
}
break;
case eSpecType::CHANGE_TER:
set_terrain(loc(spec.ex1a,spec.ex1b),spec.ex2a);
*redraw = true;
draw_map(true);
check_mess = true;
break;
case eSpecType::SWAP_TER:
if(coord_to_ter(spec.ex1a,spec.ex1b) == spec.ex2a){
set_terrain(loc(spec.ex1a,spec.ex1b),spec.ex2b);
}
else if(coord_to_ter(spec.ex1a,spec.ex1b) == spec.ex2b){
set_terrain(loc(spec.ex1a,spec.ex1b),spec.ex2a);
}
*redraw = 1;
draw_map(true);
check_mess = true;
break;
case eSpecType::TRANS_TER:
set_terrain(loc(spec.ex1a,spec.ex1b),univ.scenario.ter_types[coord_to_ter(spec.ex1a,spec.ex1b)].trans_to_what);
*redraw = 1;
draw_map(true);
check_mess = true;
break;
case eSpecType::ENTER_SHOP:
get_strs(str1,str2,1,spec.m1,-1);
if(spec.ex2a >= 40)
spec.ex2a = 39;
if(spec.ex2a < 1)
spec.ex2a = 1;
spec.ex2b = minmax(0,6,spec.ex2b);
start_shop_mode(eShopType(spec.ex1b), spec.ex1a, spec.ex1a + spec.ex2a - 1, spec.ex2b, str1);
*next_spec = -1;
break;
case eSpecType::STORY_DIALOG:
get_strs(str1,str2,cur_spec_type,spec.m1,-1);
story_dialog(str1, spec.m2, spec.m3, cur_spec_type, spec.pic, ePicType(spec.pictype));
break;
}
if(check_mess) {
handle_message(which_mode,cur_spec_type,cur_node.m1,cur_node.m2,a,b);
@@ -2934,23 +2973,25 @@ void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
}
else giveError("A Stuff Done flag is out of range.");
break;
case eSpecType::IF_TOWN_TER_TYPE:
if(((is_town()) || (is_combat())) && (univ.town->terrain(spec.ex1a,spec.ex1b) == spec.ex2a))
*next_spec = spec.ex2b;
break;
case eSpecType::IF_OUT_TER_TYPE:
case eSpecType::IF_TER_TYPE:
l.x = spec.ex1a; l.y = spec.ex1b;
l = local_to_global(l);
if((is_out()) && (univ.out[l.x][l.y] == spec.ex2a))
if((is_town() || is_combat()) && univ.town->terrain(spec.ex1a,spec.ex1b) == spec.ex2a)
*next_spec = spec.ex2b;
else if(is_out() && univ.out[l.x][l.y] == spec.ex2a)
*next_spec = spec.ex2b;
break;
case eSpecType::IF_HAS_GOLD:
if(univ.party.gold >= spec.ex1a)
if(univ.party.gold >= spec.ex1a) {
if(spec.ex2a) take_gold(spec.ex1a,true);
*next_spec = spec.ex1b;
}
break;
case eSpecType::IF_HAS_FOOD:
if(univ.party.food >= spec.ex1a)
if(univ.party.food >= spec.ex1a) {
if(spec.ex2a) take_food(spec.ex1a,true);
*next_spec = spec.ex1b;
}
break;
case eSpecType::IF_ITEM_CLASS_ON_SPACE:
if(is_out())
@@ -2958,11 +2999,16 @@ void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
l.x = spec.ex1a; l.y = spec.ex1b;
for(i = 0; i < NUM_TOWN_ITEMS; i++)
if(univ.town.items[i].variety != eItemType::NO_ITEM && univ.town.items[i].special_class == (unsigned)spec.ex2a
&& (l == univ.town.items[i].item_loc))
&& l == univ.town.items[i].item_loc) {
*next_spec = spec.ex2b;
if(spec.ex2c) {
*redraw = 1;
univ.town.items[i].variety = eItemType::NO_ITEM;
}
}
break;
case eSpecType::IF_HAVE_ITEM_CLASS:
if(party_check_class(spec.ex1a,1))
if(party_check_class(spec.ex1a,!spec.ex2a))
*next_spec = spec.ex1b;
break;
case eSpecType::IF_EQUIP_ITEM_CLASS:
@@ -2970,46 +3016,12 @@ void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
if(univ.party[i].main_status == eMainStatus::ALIVE)
for(j = 0; j < 24; j++)
if(univ.party[i].items[j].variety != eItemType::NO_ITEM && univ.party[i].items[j].special_class == (unsigned)spec.ex1a
&& (univ.party[i].equip[j]))
&& univ.party[i].equip[j]) {
*next_spec = spec.ex1b;
break;
case eSpecType::IF_HAS_GOLD_AND_TAKE:
if(univ.party.gold >= spec.ex1a) {
take_gold(spec.ex1a,true);
*next_spec = spec.ex1b;
}
break;
case eSpecType::IF_HAS_FOOD_AND_TAKE:
if(univ.party.food >= spec.ex1a) {
take_food(spec.ex1a,true);
*next_spec = spec.ex1b;
}
break;
case eSpecType::IF_ITEM_CLASS_ON_SPACE_AND_TAKE:
if(is_out())
break;
l.x = spec.ex1a; l.y = spec.ex1b;
for(i = 0; i < NUM_TOWN_ITEMS; i++)
if(univ.town.items[i].variety != eItemType::NO_ITEM && univ.town.items[i].special_class == (unsigned)spec.ex2a
&& (l == univ.town.items[i].item_loc)) {
*next_spec = spec.ex2b;
*redraw = 1;
univ.town.items[i].variety = eItemType::NO_ITEM;
}
break;
case eSpecType::IF_HAVE_ITEM_CLASS_AND_TAKE:
if(party_check_class(spec.ex1a,0))
*next_spec = spec.ex1b;
break;
case eSpecType::IF_EQUIP_ITEM_CLASS_AND_TAKE:
for(i = 0; i < 6; i++)
if(univ.party[i].main_status == eMainStatus::ALIVE)
for(j = 0; j < 24; j++)
if(univ.party[i].items[j].variety != eItemType::NO_ITEM && univ.party[i].items[j].special_class == (unsigned)spec.ex1a
&& (univ.party[i].equip[j])) {
*next_spec = spec.ex1b;
*redraw = 1;
take_item(i,j);
if(spec.ex2c) {
*redraw = 1;
take_item(i,j);
}
}
break;
case eSpecType::IF_DAY_REACHED:
@@ -3017,14 +3029,14 @@ void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
*next_spec = spec.ex1b;
break;
case eSpecType::IF_FIELDS:
if(!isValidField(spec.ex1a, false)) {
if(!isValidField(spec.m1, false)) {
giveError("Scenario tried to check for invalid field type (1...24)");
break;
}
i = 0;
for(j = 0; j < univ.town->max_dim(); j++)
for(k = 0; k < univ.town->max_dim(); k++) {
switch(eFieldType(spec.ex1a)) {
for(j = spec.ex1b; j < std::min(spec.ex2b, univ.town->max_dim()); j++)
for(k = spec.ex1a; k < std::min(spec.ex2a, univ.town->max_dim()); k++) {
switch(eFieldType(spec.m1)) {
// These values are not allowed
case SPECIAL_EXPLORED: case SPECIAL_SPOT: case FIELD_DISPEL: case FIELD_SMASH: break;
// Walls
@@ -3057,11 +3069,8 @@ void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
case SFX_RUBBLE: i += univ.town.is_rubble(i,j); break;
}
}
if(i > 0)
*next_spec = spec.ex1b;
// TODO: Are there other object types to account for?
// TODO: Allow restricting to a specific rect
// TODO: Allow requiring a minimum and maximum number of objects
if(i >= spec.sd1 && i <= spec.sd2)
*next_spec = spec.m2;
break;
case eSpecType::IF_PARTY_SIZE:
if(spec.ex2a < 1) {
@@ -3337,14 +3346,19 @@ void ifthen_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
}
void set_terrain(location l, ter_num_t terrain_type) {
// TODO: Use dynamic size() instead of hard-coded limit
if(terrain_type >= 256) return;
ter_num_t former = univ.town->terrain(l.x,l.y);
univ.town->terrain(l.x,l.y) = terrain_type;
if(univ.scenario.ter_types[terrain_type].special == eTerSpec::CONVEYOR)
belt_present = true;
if(univ.scenario.ter_types[former].light_radius != univ.scenario.ter_types[terrain_type].light_radius)
univ.town->set_up_lights();
if(terrain_type >= univ.scenario.ter_types.size()) return;
if(is_out()) {
univ.out->terrain[l.x][l.y] = terrain_type;
l = local_to_global(l);
univ.out[l.x][l.y] = terrain_type;
} else {
ter_num_t former = univ.town->terrain(l.x,l.y);
univ.town->terrain(l.x,l.y) = terrain_type;
if(univ.scenario.ter_types[terrain_type].special == eTerSpec::CONVEYOR)
belt_present = true;
if(univ.scenario.ter_types[former].light_radius != univ.scenario.ter_types[terrain_type].light_radius)
univ.town->set_up_lights();
}
}
// TODO: What was next_spec_type for? Is it still needed?
@@ -3376,27 +3390,6 @@ void townmode_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
case eSpecType::MAKE_TOWN_HOSTILE:
set_town_attitude(spec.ex1a,spec.ex1b,spec.ex2a);
break;
case eSpecType::TOWN_CHANGE_TER:
set_terrain(l,spec.ex2a);
*redraw = true;
draw_map(true);
break;
case eSpecType::TOWN_SWAP_TER:
if(coord_to_ter(spec.ex1a,spec.ex1b) == spec.ex2a){
set_terrain(l,spec.ex2b);
}
else if(coord_to_ter(spec.ex1a,spec.ex1b) == spec.ex2b){
set_terrain(l,spec.ex2a);
}
*redraw = 1;
draw_map(true);
break;
case eSpecType::TOWN_TRANS_TER:
ter = coord_to_ter(spec.ex1a,spec.ex1b);
set_terrain(l,univ.scenario.ter_types[ter].trans_to_what);
*redraw = 1;
draw_map(true);
break;
case eSpecType::TOWN_MOVE_PARTY:
if(is_combat()) {
ASB("Not while in combat.");
@@ -3654,7 +3647,7 @@ void townmode_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
break;
case eSpecType::TOWN_PLACE_ITEM:
store_i = get_stored_item(spec.ex2a);
place_item(store_i,l,true);
place_item(store_i,l,true,spec.ex2b);
break;
case eSpecType::TOWN_SPLIT_PARTY:
if(which_mode == eSpecCtx::TALK)
@@ -3728,6 +3721,36 @@ void townmode_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
}
univ.town.monst[spec.ex1a].attitude = spec.ex1b;
break;
case eSpecType::TOWN_RUN_MISSILE:
if(which_mode == eSpecCtx::TALK)
break;
if((i = monst_there(loc(spec.ex2a, spec.ex2b))) < 90) {
cCreature& who = univ.town.monst[i];
i = 14 * who.x_width - 1;
r1 = 18 * who.y_width - 1;
} else i = r1 = 0;
run_a_missile(l, loc(spec.ex2a, spec.ex2b), spec.pic, spec.ex1c, spec.ex2c, i, r1, 100);
break;
case eSpecType::TOWN_BOOM_SPACE:
// TODO: This should work, but does it need a bit of extra logic?
if(which_mode == eSpecCtx::TALK)
break;
boom_space(l, 100, spec.ex2a, spec.ex2b, -spec.ex2c);
break;
case eSpecType::TOWN_MONST_ATTACK:
// TODO: I'm not certain if this will work.
if(which_mode == eSpecCtx::TALK)
break;
i = combat_posing_monster;
if(l.y >= 0) combat_posing_monster = monst_there(l);
else combat_posing_monster = spec.ex1a;
if(combat_posing_monster < 0 || combat_posing_monster >= univ.town->max_monst()) {
combat_posing_monster = i;
break;
}
redraw_screen(REFRESH_TERRAIN);
combat_posing_monster = i;
break;
}
if(check_mess) {
handle_message(which_mode,cur_spec_type,cur_node.m1,cur_node.m2,a,b);
@@ -3753,6 +3776,9 @@ void rect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
for(i = spec.ex1b;i <= spec.ex2b;i++)
for(j = spec.ex1a; j <= spec.ex2a; j++) {
l.x = i; l.y = j;
// If pict non-zero, exclude rectangle interior
if(spec.pic > 0 && i > spec.ex1b && i < spec.ex2b && j > spec.ex1a && j < spec.ex2a)
continue;
switch(cur_node.type) {
case eSpecType::RECT_PLACE_FIELD:
if(!isValidField(spec.sd2, true)) {
@@ -3802,10 +3828,13 @@ void rect_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
}
break;
case eSpecType::RECT_MOVE_ITEMS:
i = is_container(loc(spec.sd1,spec.sd2));
for(k = 0; k < NUM_TOWN_ITEMS; k++)
if(univ.town.items[k].variety != eItemType::NO_ITEM && univ.town.items[k].item_loc == l) {
univ.town.items[k].item_loc.x = spec.sd1;
univ.town.items[k].item_loc.y = spec.sd2;
if(i && spec.m3)
univ.town.items[k].contained = true;
}
break;
case eSpecType::RECT_DESTROY_ITEMS:
@@ -3881,16 +3910,6 @@ void outdoor_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
create_wand_monst();
*redraw = 1;
break;
case eSpecType::OUT_CHANGE_TER:
if(spec.ex2a < 0) break;
univ.out->terrain[spec.ex1a][spec.ex1b] = spec.ex2a;
l.x = spec.ex1a;
l.y = spec.ex1b;
l = local_to_global(l);
univ.out[l.x][l.y] = spec.ex2a;
*redraw = 1;
check_mess = true;
break;
case eSpecType::OUT_PLACE_ENCOUNTER:
if(spec.ex1a != minmax(0,3,spec.ex1a)) {
giveError("Special outdoor enc. is out of range. Must be 0-3.");
@@ -3908,16 +3927,6 @@ void outdoor_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
*redraw = 1;
*a = 1;
break;
case eSpecType::OUT_STORE:
get_strs(str1,str2,1,spec.m1,-1);
if(spec.ex2a >= 40)
spec.ex2a = 39;
if(spec.ex2a < 1)
spec.ex2a = 1;
spec.ex2b = minmax(0,6,spec.ex2b);
start_shop_mode(eShopType(spec.ex1b), spec.ex1a, spec.ex1a + spec.ex2a - 1, spec.ex2b, str1);
*next_spec = -1;
break;
}
if(check_mess) {

View File

@@ -58,10 +58,10 @@ public:
short store_item_towns[3];
cSpecItem special_items[50];
short rating,uses_custom_graphics;
cMonster scen_monsters[256];
std::array<cMonster,256> scen_monsters;
cVehicle boats[30];
cVehicle horses[30];
cTerrain ter_types[256];
std::array<cTerrain,256> ter_types;
short scenario_timer_times[20];
short scenario_timer_specs[20];
std::array<cSpecial,256> scen_specials;

View File

@@ -498,13 +498,13 @@ enum class eSpecType {
SET_SDF = 1,
INC_SDF = 2,
DISPLAY_MSG = 3,
SECRET_PASSAGE = 4,
ENTER_SHOP = 4,
DISPLAY_SM_MSG = 5,
FLIP_SDF = 6,
SDF_RANDOM = 7, // formerly OUT_BLOCK
SDF_ADD = 8, // formerly TOWN_BLOCK
SDF_DIFF = 9, // formerly FIGHT_BLOCK
UNUSED1 = 10, // formerly LOOK_BLOCK
SDF_RANDOM = 7,
SDF_ADD = 8,
SDF_DIFF = 9,
STORY_DIALOG = 10,
CANT_ENTER = 11,
CHANGE_TIME = 12,
SCEN_TIMER_START = 13,
@@ -518,7 +518,7 @@ enum class eSpecType {
CALL_GLOBAL = 21,
SET_SDF_ROW = 22,
COPY_SDF = 23,
DISPLAY_PICTURE = 24, // formerly SANCTIFY
DISPLAY_PICTURE = 24,
REST = 25,
WANDERING_WILL_FIGHT = 26,
END_SCENARIO = 27,
@@ -528,6 +528,9 @@ enum class eSpecType {
SDF_TIMES = 31,
SDF_DIVIDE = 32, // Computes both quotient and remainder
SDF_POWER = 33,
CHANGE_TER = 34,
SWAP_TER = 35,
TRANS_TER = 36,
ONCE_GIVE_ITEM = 50,
ONCE_GIVE_SPEC_ITEM = 51,
ONCE_NULL = 52,
@@ -574,18 +577,18 @@ enum class eSpecType {
IF_RANDOM = 132,
IF_HAVE_SPECIAL_ITEM = 133,
IF_SDF_COMPARE = 134,
IF_TOWN_TER_TYPE = 135,
IF_OUT_TER_TYPE = 136,
IF_TER_TYPE = 135,
UNUSED21 = 136,
IF_HAS_GOLD = 137,
IF_HAS_FOOD = 138,
IF_ITEM_CLASS_ON_SPACE = 139,
IF_HAVE_ITEM_CLASS = 140,
IF_EQUIP_ITEM_CLASS = 141,
IF_HAS_GOLD_AND_TAKE = 142,
IF_HAS_FOOD_AND_TAKE = 143,
IF_ITEM_CLASS_ON_SPACE_AND_TAKE = 144,
IF_HAVE_ITEM_CLASS_AND_TAKE = 145,
IF_EQUIP_ITEM_CLASS_AND_TAKE = 146,
UNUSED22 = 142,
UNUSED23 = 143,
UNUSED24 = 144,
UNUSED25 = 145,
UNUSED26 = 146,
IF_DAY_REACHED = 147,
IF_FIELDS = 148,
IF_PARTY_SIZE = 149,
@@ -598,9 +601,9 @@ enum class eSpecType {
IF_CONTEXT = 156,
IF_NUM_RESPONSE = 157,
MAKE_TOWN_HOSTILE = 170,
TOWN_CHANGE_TER = 171,
TOWN_SWAP_TER = 172,
TOWN_TRANS_TER = 173,
TOWN_RUN_MISSILE = 171,
TOWN_MONST_ATTACK = 172,
TOWN_BOOM_SPACE = 173,
TOWN_MOVE_PARTY = 174,
TOWN_HIT_SPACE = 175,
TOWN_EXPLODE_SPACE = 176,
@@ -645,10 +648,9 @@ enum class eSpecType {
RECT_LOCK = 217,
RECT_UNLOCK = 218,
OUT_MAKE_WANDER = 225,
OUT_CHANGE_TER = 226,
UNUSED20 = 226,
OUT_PLACE_ENCOUNTER = 227,
OUT_MOVE_PARTY = 228,
OUT_STORE = 229,
};
enum class eSpecCat {
@@ -658,7 +660,7 @@ enum class eSpecCat {
inline eSpecCat getNodeCategory(eSpecType node) {
int code = (int) node;
if(code >= 0 && code <= 33)
if(code >= 0 && code <= 36)
return eSpecCat::GENERAL;
if(code >= 50 && code <= 63)
return eSpecCat::ONCE;
@@ -670,7 +672,7 @@ inline eSpecCat getNodeCategory(eSpecType node) {
return eSpecCat::TOWN;
if(code >= 200 && code <= 218)
return eSpecCat::RECT;
if(code >= 225 && code <= 229)
if(code >= 225 && code <= 228)
return eSpecCat::OUTDOOR;
return eSpecCat::INVALID;
}

View File

@@ -107,7 +107,12 @@ void cSpecial::append(legacy::special_node_type& old){
break;
case 148: case 149: // if barrels or crates
type = eSpecType::IF_FIELDS;
ex1a = old.type == 148 ? OBJECT_BARREL : OBJECT_CRATE;
m1 = old.type == 148 ? OBJECT_BARREL : OBJECT_CRATE;
m2 = ex1b;
ex1a = ex1b = 0;
ex2a = ex2b = 64;
sd1 = 1;
sd2 = std::numeric_limits<short>::max();
break;
case 151: case 152: // if has cave lore or woodsman
type = eSpecType::IF_TRAIT;
@@ -132,9 +137,47 @@ void cSpecial::append(legacy::special_node_type& old){
ex1a -= 160;
break;
case 229: // Outdoor store - fix spell IDs
type = eSpecType::ENTER_SHOP;
if(ex1b == 1 || ex1b == 2)
ex1a += 30;
break;
case 4: // Secret passage
type = eSpecType::CANT_ENTER;
ex1a = 0;
ex2a = 1;
break;
case 171: case 226: // Change terrain (town/outdoor)
type = eSpecType::CHANGE_TER;
break;
case 172: // Swap terrain
type = eSpecType::SWAP_TER;
break;
case 173: // Transform terrain
type = eSpecType::TRANS_TER;
break;
case 135: case 136: // If terrain
type = eSpecType::IF_TER_TYPE;
break;
case 137: case 142: // If has gold (and maybe take)
type = eSpecType::IF_HAS_GOLD;
ex2a = (old.type - 137) / 5;
break;
case 138: case 143: // If has food (and maybe take)
type = eSpecType::IF_HAS_FOOD;
ex2a = (old.type - 138) / 5;
break;
case 139: case 144: // If item on space (and maybe take)
type = eSpecType::IF_ITEM_CLASS_ON_SPACE;
ex2c = (old.type - 139) / 5;
break;
case 140: case 145: // If have item class (and maybe take)
type = eSpecType::IF_HAVE_ITEM_CLASS;
ex2a = (old.type - 140) / 5;
break;
case 141: case 146: // If equip item class (and maybe take)
type = eSpecType::IF_EQUIP_ITEM_CLASS;
ex2a = (old.type - 131) / 5;
break;
// Place fields (twelve individual node types were collapsed into one)
case 200:
type = eSpecType::RECT_PLACE_FIELD;
@@ -264,17 +307,17 @@ std::istream& operator >> (std::istream& in, eSpecType& e) {
// % - Choose button to select shop cost adjustment
static const char*const button_dict[7][11] = {
{ // general nodes
" mmmmmmmmm mmm mmmmmm Mmm $ mmm", // msg1
" ", // msg2
" ", // msg3
" ", // pic
" ", // pictype
" x T i ", // ex1a
" S ss ", // ex1b
" ", // ex1c
" ", // ex2a
" ", // ex2b
" ", // ex2c
" mmmMMmmmm mmm mmmmmm Mmm $ mmmmmm", // msg1
" ", // msg2
" ", // msg3
" ", // pic
" ", // pictype
" # x T i ", // ex1a
" & S ss ", // ex1b
" ", // ex1c
" tt ", // ex2a
" % t ", // ex2b
" ", // ex2c
}, { // one-shot nodes
"mm mddddddmmm", // msg1
" ", // msg2
@@ -306,23 +349,23 @@ static const char*const button_dict[7][11] = {
" ", // pic
" ", // pictype
" f Qq $ * ", // ex1a
"ssss ss ssss sssss sssss =", // ex1b
"ssss ss ss sss sssss =", // ex1b
" ss", // ex1c
" K$ ", // ex2a
"s sss s s s==+s =", // ex2b
"s ss s s==+s =", // ex2b
" s", // ex2c
}, { // town nodes
"mmmmmmmmmmmmmmm dddmmmmmmm", // msg1
" ", // msg2
" ", // msg3
" ppp ", // pic
" ??? ", // pictype
" p ppp ", // pic
" ? ??? ", // pictype
" c L ", // ex1a
" s s s s @", // ex1b
" ", // ex1c
"@tt ! c T T i ", // ex2a
" t DD / ", // ex2b
" : : ", // ex2c
"@ D ! c T T i ", // ex2a
" DD / ", // ex2b
" x x : : ", // ex2c
}, { // rectangle nodes
"m mmmmmmm", // msg1
" ", // msg2