Rewrite shops system to be more general

- Shops can now contain more than one type of item (for example, both mage and priest spells)
- Shops can now specify any talking portrait
- Healing options in a shop now have an info button giving a brief explanation (partly because it was easier than maintaining the exception)
- Additional healing option (not present in default healing shops): cure acid
- Acid is also no longer removed when you leave town or end combat (unless it's about to wear off)
- Always start shop mode with the scrollbar scrolled to the top
- Fix crash when entering an outdoor shop (and outdoor dialogue for that matter)
- Treasure generation system can now return junk items (treasure type 0), but only if explicitly requested; this is possible in shops but not with monsters since 0 means no loot

Dialog Engine:
- When setting a scrollbar's maximum, it now ensures the current position doesn't end up greater than the maximum
This commit is contained in:
2015-02-03 10:22:28 -05:00
parent 559663dd35
commit 008248a947
20 changed files with 435 additions and 238 deletions

View File

@@ -681,7 +681,7 @@ static void handle_switch_pc(short which_pc, bool& need_redraw) {
set_stat_window(current_pc);
put_pc_screen();
} else add_string_to_buf("Set active: PC has no APs.");
} else if(univ.party[which_pc].main_status != eMainStatus::ALIVE && (overall_mode != MODE_SHOPPING || active_shop.getType() != eShopType::HEALING))
} else if(univ.party[which_pc].main_status != eMainStatus::ALIVE && (overall_mode != MODE_SHOPPING || active_shop.getType() != eShopType::ALLOW_DEAD))
add_string_to_buf("Set active: PC must be here & active.");
else {
current_pc = which_pc;
@@ -697,7 +697,7 @@ static void handle_switch_pc_items(short which_pc, bool& need_redraw) {
add_string_to_buf("Set active: Finish what you're doing first.");
else {
if(!is_combat()) {
if(univ.party[which_pc].main_status != eMainStatus::ALIVE && (overall_mode != MODE_SHOPPING || active_shop.getType() != eShopType::ALCHEMY))
if(univ.party[which_pc].main_status != eMainStatus::ALIVE && (overall_mode != MODE_SHOPPING || active_shop.getType() != eShopType::ALLOW_DEAD))
add_string_to_buf("Set active: PC must be here & active.");
else {
current_pc = which_pc;
@@ -708,8 +708,7 @@ static void handle_switch_pc_items(short which_pc, bool& need_redraw) {
}
set_stat_window(which_pc);
if(overall_mode == MODE_SHOPPING) {
if(active_shop.getType() == eShopType::HEALING)
set_up_shop_array(eShopType::HEALING, 0, 0);
set_up_shop_array();
draw_shop_graphics(0,item_screen_button_rects[which_pc]); // rect is dummy
}
}
@@ -1330,8 +1329,7 @@ bool handle_action(sf::Event event) {
put_pc_screen();
put_item_screen(stat_window,0);
if(overall_mode == MODE_SHOPPING) {
if(active_shop.getType() == eShopType::HEALING)
set_up_shop_array(eShopType::HEALING, 0, 0);
set_up_shop_array();
draw_shop_graphics(0,pc_buttons[0][0]);
}
}

View File

@@ -97,29 +97,26 @@ rectangle bottom_help_rects[4] = {rectangle{356,6,368,250},rectangle{374,6,386,2
rectangle shop_name_str = {44,6,56,200};
rectangle shop_frame = {62,10,352,269};
rectangle shop_done_rect = {388,212,411,275};
short shop_array[30];
short store_scen_page_on,store_num_scen;
cShop active_shop;
short active_shop_num;
/*
shop_type:
0 - weapon shop
1 - armor shop
2 - misc shop
3 - healer
4 - food no longer used!!!
5-9 - magic shop
10 - mage spells
11 - priest spells
12 alchemy
*/
void start_shop_mode(eShopType shop_type,short shop_min,short shop_max,short cost_adj,std::string store_name) {
void start_shop_mode(short which,short cost_adj,std::string store_name) {
rectangle area_rect;
if(which < 0 || which >= univ.scenario.shops.size()) {
giveError("The scenario tried to place you in a nonexistent shop!");
return;
}
// This would be a place to hide the text box, if I add it.
active_shop = cShop(shop_type, cost_adj, store_name);
active_shop_num = which;
active_shop = univ.scenario.shops[which];
active_shop.setCostAdjust(cost_adj);
active_shop.setName(store_name);
area_rect = talk_area_rect;
talk_gworld.create(area_rect.width(), area_rect.height());
@@ -127,8 +124,9 @@ void start_shop_mode(eShopType shop_type,short shop_min,short shop_max,short cos
store_pre_shop_mode = overall_mode;
overall_mode = MODE_SHOPPING;
stat_screen_mode = MODE_SHOP;
shop_sbar->setPosition(0);
set_up_shop_array(shop_type, shop_min, std::max(shop_min, shop_max));
set_up_shop_array();
put_background();
draw_shop_graphics(0,area_rect);
@@ -174,17 +172,14 @@ void end_shop_mode() {
// TODO: I suspect REFRESH_NONE will suffice here
redraw_screen(REFRESH_TERRAIN | REFRESH_BAR);
// If it was a magic shop, we need to update the stored list of items so that bought items don't reappear
if(active_shop.getType() >= eShopType::MAGIC_JUNK && active_shop.getType() <= eShopType::MAGIC_GREAT) {
int which_shop = int(active_shop.getType()) - int(eShopType::MAGIC_JUNK);
int j = 0;
for(int i = 0; i < 30 && j < 10; i++) {
// If it was a random shop, we need to update the stored list of items so that bought items don't reappear
if(active_shop.getType() == eShopType::RANDOM) {
for(int i = 0; i < 30; i++) {
cShopItem item = active_shop.getItem(i);
if(item.type != eShopItemType::EMPTY)
univ.party.magic_store_items[which_shop][j++] = item.item;
if(item.type != eShopItemType::EMPTY && univ.party.magic_store_items[active_shop_num][i].variety != eItemType::NO_ITEM)
univ.party.magic_store_items[active_shop_num][i] = item.item;
else univ.party.magic_store_items[active_shop_num][i].variety = eItemType::NO_ITEM;
}
for(int i = j; i < 10; i++)
univ.party.magic_store_items[which_shop][i].variety = eItemType::NO_ITEM;
}
}
@@ -212,12 +207,16 @@ void handle_shop_event(location p) {
p.y -= 5;
for(i = 0; i < 8; i++) {
store_what_picked = i + shop_sbar->getPosition();
if(store_what_picked >= active_shop.size()) break;
store_what_picked = shop_array[i + shop_sbar->getPosition()];
if(store_what_picked >= 30) break;
if(active_shop.getItem(store_what_picked).type == eShopItemType::EMPTY)
break;
if(p.in(shopping_rects[i][SHOPRECT_ACTIVE_AREA])) {
click_shop_rect(shopping_rects[i][SHOPRECT_ACTIVE_AREA]);
handle_sale(active_shop.getItem(store_what_picked), store_what_picked);
} else if(p.in(shopping_rects[i][SHOPRECT_ITEM_HELP]) && active_shop.getType() != eShopType::HEALING){
set_up_shop_array();
draw_shop_graphics(false, {});
} else if(p.in(shopping_rects[i][SHOPRECT_ITEM_HELP])){
click_shop_rect(shopping_rects[i][SHOPRECT_ITEM_HELP]);
handle_info_request(active_shop.getItem(store_what_picked));
}
@@ -226,12 +225,13 @@ void handle_shop_event(location p) {
void handle_sale(cShopItem item, int i) {
cItem base_item = item.item;
short cost = item.cost;
short cost = item.getCost(active_shop.getCostAdjust());
rectangle dummy_rect = {0,0,0,0};
size_t size_before = active_shop.size();
switch(item.type) {
case eShopItemType::EMPTY: break; // Invalid
case eShopItemType::TREASURE: break; // Also invalid
case eShopItemType::ITEM:
switch(univ.party[current_pc].ok_to_buy(cost,base_item)) {
case eBuyStatus::OK:
@@ -267,6 +267,7 @@ void handle_sale(cShopItem item, int i) {
case eShopItemType::HEAL_WOUNDS: case eShopItemType::REMOVE_CURSE: case eShopItemType::CURE_DUMBFOUNDING:
case eShopItemType::CURE_POISON: case eShopItemType::CURE_DISEASE: case eShopItemType::CURE_PARALYSIS:
case eShopItemType::DESTONE: case eShopItemType::RAISE_DEAD: case eShopItemType::RESURRECT:
case eShopItemType::CURE_ACID:
if(!take_gold(cost,false))
ASB("Not enough gold.");
else {
@@ -282,6 +283,9 @@ void handle_sale(cShopItem item, int i) {
case eShopItemType::CURE_DISEASE:
univ.party[current_pc].status[eStatus::DISEASE] = 0;
break;
case eShopItemType::CURE_ACID:
univ.party[current_pc].status[eStatus::ACID] = 0;
break;
case eShopItemType::CURE_PARALYSIS:
univ.party[current_pc].status[eStatus::PARALYZED] = 0;
break;
@@ -299,8 +303,6 @@ void handle_sale(cShopItem item, int i) {
break;
default: break; // Silence compiler warning
}
// Once you've been healed, of course you're no longer eligible for that form of healing.
active_shop.clearItem(i);
}
break;
case eShopItemType::MAGE_SPELL:
@@ -378,6 +380,7 @@ void handle_info_request(cShopItem item) {
switch(item.type) {
case eShopItemType::EMPTY: break;
case eShopItemType::TREASURE: break;
case eShopItemType::ITEM:
display_pc_item(6,0, base_item,0);
break;
@@ -394,77 +397,110 @@ void handle_info_request(cShopItem item) {
case eShopItemType::SKILL:
display_skills(eSkill(base_item.item_level), nullptr);
break;
case eShopItemType::HEAL_WOUNDS: case eShopItemType::REMOVE_CURSE: case eShopItemType::CURE_DUMBFOUNDING:
case eShopItemType::CURE_POISON: case eShopItemType::CURE_DISEASE: case eShopItemType::CURE_PARALYSIS:
case eShopItemType::DESTONE: case eShopItemType::RAISE_DEAD: case eShopItemType::RESURRECT:
case eShopItemType::HEAL_WOUNDS:
cStrDlog("Select this option to restore the current PC to full health.", "", "Heal Wounds", 15, PIC_DLOG).show();
break;
case eShopItemType::REMOVE_CURSE:
cStrDlog("Select this option to remove any curses on any items the PC is wearing.", "", "Remove Curse", 15, PIC_DLOG).show();
break;
case eShopItemType::CURE_DUMBFOUNDING:
cStrDlog("Select this option to restore the PC's mind from dumbfounding.", "", "Cure Dumbfounding", 15, PIC_DLOG).show();
break;
case eShopItemType::CURE_POISON:
cStrDlog("Select this option purge all poison from the current PC.", "", "Cure Poison", 15, PIC_DLOG).show();
break;
case eShopItemType::CURE_DISEASE:
cStrDlog("Select this option purge all disease from the current PC.", "", "Cure Disease", 15, PIC_DLOG).show();
break;
case eShopItemType::CURE_ACID:
cStrDlog("Select this option purge all acid from the current PC.", "", "Cure Acid", 15, PIC_DLOG).show();
break;
case eShopItemType::CURE_PARALYSIS:
cStrDlog("Select this option to cure the current PC's paralysis.", "", "Cure Paralysis", 15, PIC_DLOG).show();
break;
case eShopItemType::DESTONE:
cStrDlog("Select this option to restore a PC that has been turned to stone.", "", "Destone", 15, PIC_DLOG).show();
break;
case eShopItemType::RAISE_DEAD:
cStrDlog("Select this option to resurrect a PC.", "", "Raise Dead", 15, PIC_DLOG).show();
break;
case eShopItemType::RESURRECT:
cStrDlog("Select this option to resurrect a PC that has been turned to dust.", "", "Resurrect", 15, PIC_DLOG).show();
break;
}
}
void set_up_shop_array(eShopType store_shop_type, short store_shop_min, short store_shop_max) {
bool cursed_item = false;
active_shop.clear();
switch(store_shop_type) {
case eShopType::ITEMS:
for(int i = store_shop_min; i <= store_shop_max; i++)
active_shop.addItem(get_stored_item(i), cShop::INFINITE);
break;
case eShopType::HEALING:
if(univ.party[current_pc].cur_health < univ.party[current_pc].max_health)
active_shop.addSpecial(eShopItemType::HEAL_WOUNDS);
if(univ.party[current_pc].status[eStatus::POISON] > 0)
active_shop.addSpecial(eShopItemType::CURE_POISON);
if(univ.party[current_pc].status[eStatus::DISEASE] > 0)
active_shop.addSpecial(eShopItemType::CURE_DISEASE);
if(univ.party[current_pc].status[eStatus::PARALYZED] > 0)
active_shop.addSpecial(eShopItemType::CURE_PARALYSIS);
if(univ.party[current_pc].status[eStatus::DUMB] > 0)
active_shop.addSpecial(eShopItemType::CURE_DUMBFOUNDING);
for(int i = 0; i < 24; i++)
if((univ.party[current_pc].equip[i]) && (univ.party[current_pc].items[i].cursed))
cursed_item = true;
if(cursed_item) active_shop.addSpecial(eShopItemType::REMOVE_CURSE);
if(univ.party[current_pc].main_status == eMainStatus::STONE)
active_shop.addSpecial(eShopItemType::DESTONE);
if(univ.party[current_pc].main_status == eMainStatus::DEAD)
active_shop.addSpecial(eShopItemType::RAISE_DEAD);
if(univ.party[current_pc].main_status == eMainStatus::DUST)
active_shop.addSpecial(eShopItemType::RESURRECT);
break;
case eShopType::MAGIC_JUNK:
active_shop.addItems(univ.party.magic_store_items[0].begin(), univ.party.magic_store_items[0].end(), 1);
break;
case eShopType::MAGIC_LOUSY:
active_shop.addItems(univ.party.magic_store_items[1].begin(), univ.party.magic_store_items[1].end(), 1);
break;
case eShopType::MAGIC_SO_SO:
active_shop.addItems(univ.party.magic_store_items[2].begin(), univ.party.magic_store_items[2].end(), 1);
break;
case eShopType::MAGIC_GOOD:
active_shop.addItems(univ.party.magic_store_items[3].begin(), univ.party.magic_store_items[3].end(), 1);
break;
case eShopType::MAGIC_GREAT:
active_shop.addItems(univ.party.magic_store_items[4].begin(), univ.party.magic_store_items[4].end(), 1);
break;
case eShopType::MAGE:
for(int i = store_shop_min; i <= store_shop_max && i < 62; i++)
active_shop.addSpecial(eShopItemType::MAGE_SPELL, i);
break;
case eShopType::PRIEST:
for(int i = store_shop_min; i <= store_shop_max && i < 62; i++)
active_shop.addSpecial(eShopItemType::PRIEST_SPELL, i);
break;
case eShopType::ALCHEMY:
for(int i = store_shop_min; i <= store_shop_max && i < 20; i++)
active_shop.addSpecial(eShopItemType::ALCHEMY, i);
break;
case eShopType::SKILLS:
for(int i = max(0,store_shop_min); i <= min(18,store_shop_max); i++)
active_shop.addSpecial(eShopItemType::SKILL, i);
break;
void set_up_shop_array() {
int i = 0;
for(int j = 0; i < 30 && j < 30; j++) {
cShopItem entry = active_shop.getItem(j);
switch(entry.type) {
case eShopItemType::ITEM:
case eShopItemType::MAGE_SPELL:
case eShopItemType::PRIEST_SPELL:
case eShopItemType::ALCHEMY:
case eShopItemType::SKILL:
shop_array[i++] = j;
break;
case eShopItemType::HEAL_WOUNDS:
if(univ.party[current_pc].cur_health < univ.party[current_pc].max_health)
shop_array[i++] = j;
break;
case eShopItemType::CURE_POISON:
if(univ.party[current_pc].status[eStatus::POISON] > 0)
shop_array[i++] = j;
break;
case eShopItemType::CURE_DISEASE:
if(univ.party[current_pc].status[eStatus::DISEASE] > 0)
shop_array[i++] = j;
break;
case eShopItemType::CURE_ACID:
if(univ.party[current_pc].status[eStatus::ACID] > 0)
shop_array[i++] = j;
break;
case eShopItemType::CURE_PARALYSIS:
if(univ.party[current_pc].status[eStatus::PARALYZED] > 0)
shop_array[i++] = j;
break;
case eShopItemType::CURE_DUMBFOUNDING:
if(univ.party[current_pc].status[eStatus::DUMB] > 0)
shop_array[i++] = j;
break;
case eShopItemType::DESTONE:
if(univ.party[current_pc].main_status == eMainStatus::STONE)
shop_array[i++] = j;
break;
case eShopItemType::RAISE_DEAD:
if(univ.party[current_pc].main_status == eMainStatus::DEAD)
shop_array[i++] = j;
break;
case eShopItemType::RESURRECT:
if(univ.party[current_pc].main_status == eMainStatus::DUST)
shop_array[i++] = j;
break;
case eShopItemType::REMOVE_CURSE:
for(int i = 0; i < 24; i++) {
if((univ.party[current_pc].equip[i]) && (univ.party[current_pc].items[i].cursed)) {
shop_array[i++] = j;
break;
}
}
break;
case eShopItemType::TREASURE:
entry.type = eShopItemType::ITEM;
entry.item = univ.party.magic_store_items[active_shop_num][j];
if(entry.item.variety == eItemType::NO_ITEM)
entry.type = eShopItemType::EMPTY;
else shop_array[i++] = j;
entry.quantity = 1;
active_shop.replaceItem(j, entry);
break;
case eShopItemType::EMPTY:
break;
}
}
shop_sbar->setMaximum(active_shop.size() - 8);
shop_sbar->setMaximum(i - 8);
std::fill(shop_array + i, shop_array + 30, -1);
}
void start_talk_mode(short m_num,short personality,mon_num_t monst_type,short store_face_pic) {
@@ -704,8 +740,6 @@ void handle_talk_event(location p) {
oldstrnum1 = strnum1; oldstrnum2 = strnum2;
strnum1 = 40 + which_talk_entry * 2; strnum2 = 40 + which_talk_entry * 2 + 1;
eShopType shop;
switch(ttype) {
case eTalkNode::REGULAR:
break;
@@ -774,18 +808,7 @@ void handle_talk_event(location p) {
giveError("Invalid shop type!");
return;
}
shop = eShopType(d);
switch(shop) {
case eShopType::ITEMS: case eShopType::MAGE: case eShopType::PRIEST:
c = minmax(1,30,c);
break;
case eShopType::ALCHEMY: c = minmax(1,20,c); break;
case eShopType::SKILLS: c = minmax(1,19,c); break;
case eShopType::HEALING: case eShopType::MAGIC_JUNK: case eShopType::MAGIC_LOUSY:
case eShopType::MAGIC_SO_SO: case eShopType::MAGIC_GOOD: case eShopType::MAGIC_GREAT:
break;
}
start_shop_mode(shop,b,b + c - 1,a,save_talk_str1.c_str());
start_shop_mode(b,a,save_talk_str1);
strnum1 = -1;
return;
case eTalkNode::JOB_BANK:

View File

@@ -6,12 +6,12 @@
#include "simpletypes.h"
#include "shop.hpp"
void start_shop_mode(eShopType shop_type,short shop_min,short shop_max,short cost_adj,std::string store_name);
void start_shop_mode(short which,short cost_adj,std::string store_name);
void end_shop_mode();
void handle_shop_event(location p);
void handle_sale(cShopItem item, int i);
void handle_info_request(cShopItem item);
void set_up_shop_array(eShopType shop_type, short shop_min, short shop_max);
void set_up_shop_array();
void start_talk_mode(short m_num,short personality,mon_num_t monst_type,short store_face_pic);
void end_talk_mode();
void handle_talk_event(location p);

View File

@@ -8,6 +8,7 @@
#include "boe.itemdata.h"
#include "mathutil.hpp"
bool allow_junk_treasure = false;
short loot_min[5] = {0,0,5,50,400};
short loot_max[5] = {3,8,40,800,4000};
extern cUniverse univ;
@@ -50,12 +51,12 @@ cItem pull_item_of_type(unsigned int loot_max,short min_val,short max_val,eItemT
max_val += 2000;
}
for(i = 0; i < 80; i++) {
j = get_ran(1,0,399);
j = get_ran(1,0,univ.scenario.scen_items.size() - 1);
temp_i = get_stored_item(j);
if(temp_i.variety == eItemType::NO_ITEM) continue;
if((temp_i.variety == t1) || (temp_i.variety == t2) || (temp_i.variety == t3)) {
val = (temp_i.charges > 0) ? temp_i.charges * temp_i.value : temp_i.value;
if((val >= min_val) && (val <= max_val) && (temp_i.treas_class != 0) &&
if((val >= min_val) && (val <= max_val) && (temp_i.treas_class != 0 || allow_junk_treasure) &&
(temp_i.treas_class <= loot_max))
return temp_i;
}

View File

@@ -31,6 +31,7 @@ extern short stat_window,which_combat_type,current_pc;
extern eGameMode overall_mode;
extern sf::RenderWindow mainPtr;
extern bool boom_anim_active;
extern bool allow_junk_treasure;
extern rectangle d_rects[80];
extern short d_rect_index[80];
@@ -934,21 +935,30 @@ void generate_job_bank(int which, job_bank_t& bank) {
}
}
static cItem get_random_store_item(int loot_type) {
cItem item = return_treasure(loot_type);
if(item.variety == eItemType::GOLD || item.variety == eItemType::SPECIAL || item.variety == eItemType::FOOD)
item = cItem();
item.ident = true;
return item;
}
void refresh_store_items() {
short i,j;
short loot_index[10] = {1,1,1,1,2,2,2,3,3,4};
for(i = 0; i < 5; i++)
for(j = 0; j < 10; j++) {
univ.party.magic_store_items[i][j] = return_treasure(loot_index[j]);
if(univ.party.magic_store_items[i][j].variety == eItemType::GOLD ||
univ.party.magic_store_items[i][j].variety == eItemType::SPECIAL ||
univ.party.magic_store_items[i][j].variety == eItemType::FOOD)
univ.party.magic_store_items[i][j] = cItem();
univ.party.magic_store_items[i][j].ident = true;
for(size_t i = 0; i < univ.scenario.shops.size(); i++) {
if(univ.scenario.shops[i].getType() != eShopType::RANDOM)
continue;
for(int j = 0; j < 30; j++) {
cShopItem entry = univ.scenario.shops[i].getItem(j);
if(entry.type == eShopItemType::TREASURE) {
if(entry.item.item_level == 0)
allow_junk_treasure = true;
univ.party.magic_store_items[i][j] = get_random_store_item(entry.item.item_level);
allow_junk_treasure = false;
} else univ.party.magic_store_items[i][j] = cItem();
}
}
for(i = 0; i < univ.party.job_banks.size(); i++) {
for(int i = 0; i < univ.party.job_banks.size(); i++) {
generate_job_bank(i, univ.party.job_banks[i]);
}
}

View File

@@ -13,6 +13,7 @@ location which_party_sec;
extern short which_combat_type,current_pc;
extern eGameMode overall_mode;
extern eGameMode store_pre_shop_mode, store_pre_talk_mode;
extern location center;
extern cUniverse univ;
@@ -41,13 +42,33 @@ void take_explored(short i,short j) {
bool is_out() {
if((overall_mode == MODE_OUTDOORS) || (overall_mode == MODE_LOOK_OUTDOORS))
return true;
else return false;
else if(overall_mode == MODE_SHOPPING) {
std::swap(overall_mode, store_pre_shop_mode);
bool ret = is_out();
std::swap(overall_mode, store_pre_shop_mode);
return ret;
} else if(overall_mode == MODE_TALKING) {
std::swap(overall_mode, store_pre_talk_mode);
bool ret = is_out();
std::swap(overall_mode, store_pre_talk_mode);
return ret;
} else return false;
}
bool is_town() {
if(((overall_mode > MODE_OUTDOORS) && (overall_mode < MODE_COMBAT)) || (overall_mode == MODE_LOOK_TOWN))
return true;
else return false;
else if(overall_mode == MODE_SHOPPING) {
std::swap(overall_mode, store_pre_shop_mode);
bool ret = is_town();
std::swap(overall_mode, store_pre_shop_mode);
return ret;
} else if(overall_mode == MODE_TALKING) {
std::swap(overall_mode, store_pre_talk_mode);
bool ret = is_town();
std::swap(overall_mode, store_pre_talk_mode);
return ret;
} else return false;
}
bool is_combat() {

View File

@@ -96,6 +96,7 @@ 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
struct store_missile_type {
@@ -624,18 +625,6 @@ void do_explosion_anim(short /*sound_num*/,short special_draw) {
store_booms[i].boom_type = -1;
}
/*
shop_type:
0 - weapon shop
1 - armor shop
2 - misc shop
3 - healer
4 - food
5-9 - magic shop
10 - mage spells
11 - priest spells
12 alchemy
*/
void click_shop_rect(rectangle area_rect) {
draw_shop_graphics(1,area_rect);
@@ -707,11 +696,7 @@ void draw_shop_graphics(bool pressed,rectangle clip_area_rect) {
// Place store icon
if(!pressed) {
i = 0;
eShopType type = active_shop.getType();
if(type == eShopType::HEALING) i = 41;
else if(type == eShopType::MAGE || type == eShopType::PRIEST || type == eShopType::ALCHEMY)
i = 43;
i = active_shop.getFace();
rectangle from_rect = {0,0,32,32};
from_rect.offset(32 * (i % 10),32 * (i / 10));
rect_draw_some_item(talkfaces_gworld, from_rect, talk_gworld, face_rect);
@@ -733,20 +718,26 @@ void draw_shop_graphics(bool pressed,rectangle clip_area_rect) {
style.colour = c[3];
std::ostringstream title;
switch(active_shop.getType()) {
case eShopType::HEALING:
switch(active_shop.getPrompt()) {
case eShopPrompt::HEALING:
title << "Healing for " << univ.party[current_pc].name << '.';
break;
case eShopType::MAGE:
case eShopPrompt::MAGE:
title << "Mage Spells for " << univ.party[current_pc].name << '.';
break;
case eShopType::PRIEST:
case eShopPrompt::PRIEST:
title << "Priest Spells for " << univ.party[current_pc].name << '.';
break;
case eShopType::ALCHEMY:
case eShopPrompt::SPELLS:
title << "Spells for " << univ.party[current_pc].name << '.';
break;
case eShopPrompt::TRAINING:
title << "Training for " << univ.party[current_pc].name << '.';
break;
case eShopPrompt::ALCHEMY:
title << "Buying Alchemy.";
break;
default:
case eShopPrompt::SHOPPING:
title << "Shopping for " << univ.party[current_pc].name << '.';
break;
}
@@ -759,11 +750,11 @@ void draw_shop_graphics(bool pressed,rectangle clip_area_rect) {
// Place all the items
for(i = 0; i < 8; i++) {
current_pos = i + shop_sbar->getPosition();
cShopItem item = active_shop.getItem(i);
if(shop_array[current_pos] < 0)
break; // theoretically, this shouldn't happen
cShopItem item = active_shop.getItem(shop_array[current_pos]);
eSpell spell; eSkill skill;
if(item.type == eShopItemType::EMPTY)
continue; // theoretically, this shouldn't happen
cur_cost = item.cost;
cur_cost = item.getCost(active_shop.getCostAdjust());
base_item = item.item;
std::string cur_name = base_item.full_name, cur_info_str;
rectangle from_rect, to_rect = shopping_rects[i][SHOPRECT_GRAPHIC];
@@ -805,8 +796,7 @@ void draw_shop_graphics(bool pressed,rectangle clip_area_rect) {
win_draw_string(talk_gworld,shopping_rects[i][SHOPRECT_ITEM_COST],cur_name,eTextMode::WRAP,style);
style.pointSize = 10;
win_draw_string(talk_gworld,shopping_rects[i][SHOPRECT_ITEM_EXTRA],cur_info_str,eTextMode::WRAP,style);
if(active_shop.getType() != eShopType::HEALING) // Draw info button
rect_draw_some_item(invenbtn_gworld,item_info_from,talk_gworld,shopping_rects[i][SHOPRECT_ITEM_HELP],pressed ? sf::BlendNone : sf::BlendAlpha);
rect_draw_some_item(invenbtn_gworld,item_info_from,talk_gworld,shopping_rects[i][SHOPRECT_ITEM_HELP],pressed ? sf::BlendNone : sf::BlendAlpha);
}
@@ -818,8 +808,7 @@ void draw_shop_graphics(bool pressed,rectangle clip_area_rect) {
win_draw_string(talk_gworld,bottom_help_rects[0],title.str(),eTextMode::WRAP,style);
win_draw_string(talk_gworld,bottom_help_rects[1],"Click on item name (or type 'a'-'h') to buy.",eTextMode::WRAP,style);
win_draw_string(talk_gworld,bottom_help_rects[2],"Hit done button (or Esc.) to quit.",eTextMode::WRAP,style);
if(active_shop.getType() != eShopType::HEALING)
win_draw_string(talk_gworld,bottom_help_rects[3],"'I' button brings up description.",eTextMode::WRAP,style);
win_draw_string(talk_gworld,bottom_help_rects[3],"'I' button brings up description.",eTextMode::WRAP,style);
undo_clip(talk_gworld);
talk_gworld.display();

View File

@@ -2359,12 +2359,8 @@ void general_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type,
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);
spec.ex1b = minmax(0,6,spec.ex2b);
start_shop_mode(spec.ex1a, spec.ex1b, str1);
*next_spec = -1;
break;
case eSpecType::STORY_DIALOG:

View File

@@ -649,10 +649,11 @@ location end_town_mode(short switching_level,location destination) { // returns
univ.party.status[ePartyStatus::DETECT_LIFE] = 0; // TODO: Yes? No? Maybe?
for(i = 0; i < 6; i++)
erase_if(univ.party[i].status, [](std::pair<const eStatus, short> kv) -> bool {
// TODO: These were the only statuses kept in the original code, but what about acid? Should it be kept too?
if(kv.first == eStatus::POISON) return false;
if(kv.first == eStatus::DISEASE) return false;
if(kv.first == eStatus::DUMB) return false;
if(kv.first == eStatus::ACID && kv.second > 2)
return false;
return true;
});

View File

@@ -580,13 +580,14 @@ void cParty::writeTo(std::ostream& file) const {
}
}
file << '\f';
for(int i = 0; i < 5; i++)
for(auto& p : magic_store_items) {
for(int j = 0; j < 10; j++)
if(magic_store_items[i][j].variety != eItemType::NO_ITEM){
file << "MAGICSTORE " << i << ' ' << j << '\n';
magic_store_items[i][j].writeTo(file);
if(p.second[j].variety != eItemType::NO_ITEM){
file << "MAGICSTORE " << p.first << ' ' << j << '\n';
p.second[j].writeTo(file);
file << '\f';
}
}
file << '\f';
for(int i = 0; i < job_banks.size(); i++) {
file << "JOBBANK " << i << ' ' << job_banks[i].anger << '\n';
@@ -805,6 +806,7 @@ void cParty::readFrom(std::istream& file){
} else if(cur == "MAGICSTORE") {
int i,j;
bin >> i >> j;
if(j < 0 || j >= 30) continue;
magic_store_items[i][j].readFrom(bin);
} else if(cur == "ENCOUNTER") {
int i;

View File

@@ -93,7 +93,7 @@ public:
short in_boat;
short in_horse;
cOutdoors::cCreature out_c[10];
std::array<std::array<cItem,10>,5> magic_store_items;
std::map<int,std::array<cItem,30>> magic_store_items;
std::vector<job_bank_t> job_banks;
mon_num_t imprisoned_monst[4]; // Soul Crystal
char m_noted[256]; // has the monster been scried?

View File

@@ -176,6 +176,11 @@ void cScenario::append(legacy::scen_item_data_type& old){
}
for(i = 0; i < 256; i++)
ter_types[i].name = old.ter_names[i];
// Some default shops - the five magic shops and the healing shop.
cShop magic_shop('junk');
for(i = 0; i < 5; i++)
shops.push_back(magic_shop);
shops.push_back(cShop('heal'));
}
static std::string format_version(const unsigned char(& ver)[3]) {

View File

@@ -20,6 +20,7 @@
#include "outdoors.h"
#include "town.h"
#include "vector2d.hpp"
#include "shop.hpp"
namespace fs = boost::filesystem; // TODO: Centralize this namespace alias?
@@ -70,6 +71,7 @@ public:
short store_item_towns[3];
std::array<cSpecItem,50> special_items;
std::vector<cQuest> quests;
std::vector<cShop> shops;
short rating,uses_custom_graphics;
std::vector<ePicType> custom_graphics;
std::array<cMonster,256> scen_monsters;

View File

@@ -47,7 +47,38 @@ static long cost_mult[7] = {5,7,10,13,16,20,25};
cShop::cShop() {}
cShop::cShop(eShopType type, int adj, std::string name) : type(type), cost_adj(adj), name(name) {}
cShop::cShop(eShopType type, eShopPrompt prompt, pic_num_t pic, int adj, std::string name):
cost_adj(adj),
name(name),
type(type),
prompt(prompt),
face(pic)
{}
cShop::cShop(long preset) {
const short loot_index[10] = {1,1,1,1,2,2,2,3,3,4};
if(preset == 'junk') {
type = eShopType::RANDOM;
prompt = eShopPrompt::SHOPPING;
face = 0;
for(int i = 0; i < 10; i++)
addSpecial(eShopItemType::TREASURE, loot_index[i]);
} else if(preset == 'heal') {
type = eShopType::ALLOW_DEAD;
prompt = eShopPrompt::HEALING;
face = 41;
addSpecial(eShopItemType::HEAL_WOUNDS);
addSpecial(eShopItemType::CURE_POISON);
addSpecial(eShopItemType::CURE_DISEASE);
addSpecial(eShopItemType::CURE_PARALYSIS);
addSpecial(eShopItemType::CURE_DUMBFOUNDING);
addSpecial(eShopItemType::REMOVE_CURSE);
addSpecial(eShopItemType::DESTONE);
addSpecial(eShopItemType::RAISE_DEAD);
addSpecial(eShopItemType::RESURRECT);
}
}
size_t cShop::firstEmpty() {
for(size_t i = 0; i < items.size(); i++) {
@@ -70,11 +101,6 @@ void cShop::addItem(cItem item, size_t quantity) {
items[i].type = eShopItemType::ITEM;
items[i].item = item;
items[i].item.ident = true;
items[i].cost = item.value;
if(item.charges > 0)
items[i].cost *= item.charges;
items[i].cost *= cost_mult[cost_adj];
items[i].cost /= 10;
items[i].quantity = quantity;
}
@@ -139,9 +165,9 @@ static cItem store_alchemy(short which_s) {
void cShop::addSpecial(eShopItemType type, int n) {
// TODO: Make this a std::map instead
static const short heal_costs[9] = {50,30,80,100,250,500,1000,3000,100};
static const short heal_costs[10] = {50,30,80,90,100,250,500,1000,3000,100};
static const char*const heal_types[] = {
"Heal Damage","Cure Poison","Cure Disease","Cure Paralysis",
"Heal Damage","Cure Poison","Cure Disease","Cure Acid","Cure Paralysis",
"Uncurse Items","Cure Stoned Character","Raise Dead","Resurrection","Cure Dumbfounding"
};
if(type == eShopItemType::EMPTY) return;
@@ -158,17 +184,16 @@ void cShop::addSpecial(eShopItemType type, int n) {
else if(type == eShopItemType::SKILL) {
items[i].item.graphic_num = 108;
items[i].item.full_name = get_str("skills", n * 2 + 1);
} else if(type == eShopItemType::TREASURE) {
items[i].item.item_level = n;
} else {
items[i].item.graphic_num = 109;
items[i].item.full_name = heal_types[int(type) - 700];
items[i].item.full_name = heal_types[int(type) - int(eShopItemType::HEAL_WOUNDS)];
}
if(type == eShopItemType::MAGE_SPELL || type == eShopItemType::PRIEST_SPELL || type == eShopItemType::ALCHEMY)
items[i].cost = items[i].item.value;
else if(type == eShopItemType::SKILL)
items[i].cost = skill_g_cost[eSkill(n)] * 1.5;
else items[i].cost = heal_costs[int(type) - 700];
items[i].cost *= cost_mult[cost_adj];
items[i].cost /= 10;
if(type == eShopItemType::SKILL)
items[i].item.value = skill_g_cost[eSkill(n)] * 1.5;
else if(type >= eShopItemType::HEAL_WOUNDS)
items[i].item.value = heal_costs[int(type) - int(eShopItemType::HEAL_WOUNDS)];
items[i].quantity = 0;
}
@@ -188,6 +213,22 @@ std::string cShop::getName() const {
return name;
}
eShopPrompt cShop::getPrompt() const {
return prompt;
}
pic_num_t cShop::getFace() const {
return face;
}
void cShop::setName(std::string newName) {
name = newName;
}
void cShop::setCostAdjust(int adj) {
cost_adj = adj;
}
void cShop::takeOne(size_t i) {
if(items[i].quantity == 1)
clearItem(i);
@@ -195,6 +236,11 @@ void cShop::takeOne(size_t i) {
items[i].quantity--;
}
void cShop::replaceItem(size_t i, cShopItem newItem) {
if(i >= 30) return;
items[i] = newItem;
}
void cShop::clearItem(size_t i) {
std::copy(items.begin() + i + 1, items.end(), items.begin() + i);
items.back().type = eShopItemType::EMPTY;
@@ -203,3 +249,12 @@ void cShop::clearItem(size_t i) {
void cShop::clear() {
std::fill(items.begin(), items.end(), cShopItem());
}
int cShopItem::getCost(int adj) {
int cost = item.value;
if(item.charges > 0)
cost *= item.charges;
cost *= cost_mult[adj];
cost /= 10;
return cost;
}

View File

@@ -12,30 +12,38 @@
#include <array>
#include <string>
#include "item.h"
#include "pictypes.hpp" // for pic_num_t
enum class eShopType {NORMAL, ALLOW_DEAD, RANDOM};
enum class eShopPrompt {SHOPPING, HEALING, MAGE, PRIEST, SPELLS, ALCHEMY, TRAINING};
enum class eShopItemType {
EMPTY = 0,
EMPTY,
// These ones must have these numbers in order for old scenarios to be ported correctly
ITEM = 1,
HEAL_WOUNDS = 700,
CURE_POISON = 701,
CURE_DISEASE = 702,
CURE_PARALYSIS = 703,
CURE_DUMBFOUNDING = 708,
REMOVE_CURSE = 704,
DESTONE = 705,
RAISE_DEAD = 706,
RESURRECT = 707,
MAGE_SPELL = 800,
PRIEST_SPELL = 900,
ALCHEMY = 500,
SKILL = 1000,
MAGE_SPELL = 2,
PRIEST_SPELL = 3,
ALCHEMY = 4,
SKILL,
TREASURE,
HEAL_WOUNDS,
CURE_POISON,
CURE_DISEASE,
CURE_ACID,
CURE_PARALYSIS,
REMOVE_CURSE,
DESTONE,
RAISE_DEAD,
RESURRECT,
CURE_DUMBFOUNDING,
};
struct cShopItem {
eShopItemType type = eShopItemType::EMPTY;
int cost;
size_t quantity;
cItem item;
int getCost(int adj);
};
class cShop {
@@ -43,21 +51,29 @@ class cShop {
int cost_adj;
std::string name;
eShopType type;
eShopPrompt prompt;
pic_num_t face;
size_t firstEmpty();
public:
static const size_t INFINITE = 0;
cShop();
cShop(eShopType type, int adj, std::string name);
cShop(eShopType type, eShopPrompt prompt, pic_num_t pic, int adj, std::string name);
explicit cShop(long preset);
void addItem(cItem item, size_t quantity);
void addSpecial(eShopItemType type, int n = 0);
template<typename Iter> void addItems(Iter begin, Iter end, size_t quantity) {
while(begin != end) addItem(*begin++, quantity);
}
void replaceItem(size_t i, cShopItem newItem);
size_t size();
cShopItem getItem(size_t i) const;
eShopType getType() const;
int getCostAdjust() const;
std::string getName() const;
pic_num_t getFace() const;
eShopPrompt getPrompt() const;
void setCostAdjust(int adj);
void setName(std::string name);
void takeOne(size_t i);
void clearItem(size_t i);
void clear();

View File

@@ -1010,20 +1010,6 @@ inline bool isPriest(eSpell spell) {
return code >= 100 && code < 162;
}
enum class eShopType {
ITEMS = 0,
MAGE = 1,
PRIEST = 2,
ALCHEMY = 3,
HEALING = 4,
MAGIC_JUNK = 5,
MAGIC_LOUSY = 6,
MAGIC_SO_SO = 7,
MAGIC_GOOD = 8,
MAGIC_GREAT = 9,
SKILLS = 10,
};
enum class eAlchemy {
NONE = -1,
CURE_WEAK = 0,

View File

@@ -15,7 +15,7 @@
#include "oldstructs.h"
void cSpeech::append(legacy::talking_record_type& old){
void cSpeech::append(legacy::talking_record_type& old, std::vector<shop_info_t>& shops){
int i,j;
for(i = 0; i < 200; i++)
strlens[i] = old.strlens[i];
@@ -51,26 +51,34 @@ void cSpeech::append(legacy::talking_record_type& old){
break;
case 7: // Item shop
talk_nodes[i].type = eTalkNode::SHOP;
talk_nodes[i].extras[3] = int(eShopType::ITEMS);
shops.push_back({eShopItemType::ITEM, talk_nodes[i].extras[1], talk_nodes[i].extras[2]});
talk_nodes[i].extras[1] = shops.size() + 5;
talk_nodes[i].extras[2] = 0;
break;
case 8: // Training
talk_nodes[i].type = eTalkNode::TRAINING;
break;
case 9: // Spell shops
talk_nodes[i].extras[3] = int(eShopType::MAGE);
if(false) // Intentional fallthrough, but suppress first line
case 10:
talk_nodes[i].extras[3] = int(eShopType::PRIEST);
talk_nodes[i].type = eTalkNode::SHOP;
talk_nodes[i].extras[1] += 30;
shops.push_back({
old.talk_nodes[i].type == 9 ? eShopItemType::MAGE_SPELL : eShopItemType::PRIEST_SPELL,
talk_nodes[i].extras[1] + 30,
talk_nodes[i].extras[2]
});
talk_nodes[i].extras[1] = shops.size() + 5;
talk_nodes[i].extras[2] = 0;
break;
case 11: // Alchemy shop
talk_nodes[i].type = eTalkNode::SHOP;
talk_nodes[i].extras[3] = int(eShopType::ALCHEMY);
shops.push_back({eShopItemType::ALCHEMY, talk_nodes[i].extras[1], talk_nodes[i].extras[2]});
talk_nodes[i].extras[1] = shops.size() + 5;
talk_nodes[i].extras[2] = 0;
break;
case 12: // Healer
talk_nodes[i].type = eTalkNode::SHOP;
talk_nodes[i].extras[3] = int(eShopType::HEALING);
talk_nodes[i].extras[1] = 5;
talk_nodes[i].extras[2] = 0;
break;
case 13: // Sell weapons
talk_nodes[i].type = eTalkNode::SELL_WEAPONS;
@@ -104,8 +112,7 @@ void cSpeech::append(legacy::talking_record_type& old){
break;
case 23: // Junk shop
talk_nodes[i].type = eTalkNode::SHOP;
talk_nodes[i].extras[3] = talk_nodes[i].extras[1] + int(eShopType::MAGIC_JUNK);
talk_nodes[i].extras[1] = 0;
talk_nodes[i].extras[2] = 0;
break;
case 24: // buy town location
talk_nodes[i].type = eTalkNode::BUY_TOWN_LOC;

View File

@@ -12,6 +12,7 @@
#include <iosfwd>
#include <string>
#include "simpletypes.h"
#include "shop.hpp"
namespace legacy {
struct talking_record_type;
@@ -24,6 +25,12 @@ public:
std::string look, name, job, dunno;
};
// This is used solely for porting old shops
struct shop_info_t {
eShopItemType type;
int first, count;
};
class cSpeech { // formerly talking_record_type
public:
class cNode { // formerly talking_node_type
@@ -39,7 +46,7 @@ public:
cPersonality people[10];
cNode talk_nodes[60];
void append(legacy::talking_record_type& old);
void append(legacy::talking_record_type& old, std::vector<shop_info_t>& shops);
void writeTo(std::ostream& file) const;
};

View File

@@ -36,6 +36,7 @@ void cScrollbar::setPosition(long newPos) {
void cScrollbar::setMaximum(long newMax) {
max = ::max(1,newMax);
setPosition(pos);
}
void cScrollbar::setPageSize(long newSize) {

View File

@@ -17,6 +17,7 @@
#include "regtown.h"
#include "map_parse.hpp"
#include "graphtool.hpp"
#include "mathutil.hpp"
#include "porting.hpp"
#include "restypes.hpp"
@@ -32,7 +33,7 @@ void load_spec_graphics(fs::path scen_file);
// Load old scenarios (town talk is handled by the town loading function)
static bool load_scenario_v1(fs::path file_to_load, cScenario& scenario);
static bool load_outdoors_v1(fs::path scen_file, location which_out,cOutdoors& the_out, legacy::scenario_data_type& scenario);
static bool load_town_v1(fs::path scen_file, short which_town, cTown& the_town, legacy::scenario_data_type& scenario);
static bool load_town_v1(fs::path scen_file,short which_town,cTown& the_town,legacy::scenario_data_type& scenario,std::vector<shop_info_t>& shops);
// Load new scenarios
static bool load_outdoors(fs::path out_base, location which_out, cOutdoors& the_out);
static bool load_town(fs::path town_base, short which_town, cTown*& the_town);
@@ -44,6 +45,20 @@ bool load_scenario(fs::path file_to_load, cScenario& scenario) {
return load_scenario_v1(file_to_load, scenario);
}
static void port_shop_spec_node(cSpecial& spec, std::vector<shop_info_t>& shops) {
int which_shop;
if(spec.ex1b < 4) {
shops.push_back({eShopItemType(spec.ex1b + 1), spec.ex1a, spec.ex2a});
which_shop = shops.size() + 5;
} else if(spec.ex1b == 4)
which_shop = 5;
else which_shop = spec.ex1b - 5;
spec.ex1a = which_shop;
spec.ex1b = spec.ex2b;
spec.ex2a = spec.ex2b = -1;
}
bool load_scenario_v1(fs::path file_to_load, cScenario& scenario){
short i,n;
bool file_ok = false;
@@ -140,6 +155,9 @@ bool load_scenario_v1(fs::path file_to_load, cScenario& scenario){
}
}
// Need to build a list of shops used in the scenario
std::vector<shop_info_t> shops;
// Then load all the towns
scenario.towns.resize(scenario.format.num_towns);
for(int i = 0; i < scenario.format.num_towns; i++) {
@@ -148,11 +166,70 @@ bool load_scenario_v1(fs::path file_to_load, cScenario& scenario){
case 1: scenario.towns[i] = new cMedTown(scenario); break;
case 2: scenario.towns[i] = new cTinyTown(scenario); break;
}
load_town_v1(scenario.scen_file, i, *scenario.towns[i], *temp_scenario);
load_town_v1(scenario.scen_file, i, *scenario.towns[i], *temp_scenario, shops);
}
// Enable character creation in starting town
scenario.towns[scenario.which_town_start]->has_tavern = true;
// Check special nodes in case there were outdoor shops
for(cSpecial& spec : scenario.scen_specials) {
if(spec.type == eSpecType::ENTER_SHOP)
port_shop_spec_node(spec, shops);
}
for(cOutdoors* out : scenario.outdoors) {
for(cSpecial& spec : out->specials) {
if(spec.type == eSpecType::ENTER_SHOP)
port_shop_spec_node(spec, shops);
}
}
// We'll check town nodes too, just in case.
for(cTown* town : scenario.towns) {
for(cSpecial& spec : town->specials) {
if(spec.type == eSpecType::ENTER_SHOP)
port_shop_spec_node(spec, shops);
}
}
// Now we have to build all those shops
for(shop_info_t info : shops) {
pic_num_t face = 0;
if(info.type == eShopItemType::MAGE_SPELL || info.type == eShopItemType::PRIEST_SPELL || info.type == eShopItemType::ALCHEMY)
face = 43;
else if(info.type == eShopItemType::ITEM) {
bool is_food_shop = true;
for(int i = info.first; i < info.first + info.count && i < scenario.scen_items.size(); i++) {
if(scenario.scen_items[i].variety != eItemType::FOOD)
is_food_shop = false;
}
if(is_food_shop)
face = 42;
}
eShopType type = eShopType::NORMAL;
eShopPrompt prompt = eShopPrompt::SHOPPING;
if(info.type == eShopItemType::MAGE_SPELL)
prompt = eShopPrompt::MAGE;
else if(info.type == eShopItemType::PRIEST_SPELL)
prompt = eShopPrompt::PRIEST;
else if(info.type == eShopItemType::ALCHEMY) {
prompt = eShopPrompt::ALCHEMY;
type = eShopType::ALLOW_DEAD;
}
cShop shop(type, prompt, face, 0, "");
if(info.type == eShopItemType::ITEM) {
int end = info.first + info.count;
end = min(end, scenario.scen_items.size());
shop.addItems(scenario.scen_items.begin() + info.first, scenario.scen_items.begin() + end, cShop::INFINITE);
} else {
int max = 62;
if(info.type == eShopItemType::ALCHEMY)
max = 20;
int end = min(max, info.first + info.count);
for(int i = info.first; i < end; i++)
shop.addSpecial(info.type, i);
}
scenario.shops.push_back(shop);
}
delete temp_scenario;
delete item_data;
return true;
@@ -179,7 +256,7 @@ static long get_town_offset(short which_town, legacy::scenario_data_type& scenar
return len_to_jump;
}
bool load_town_v1(fs::path scen_file, short which_town, cTown& the_town, legacy::scenario_data_type& scenario) {
bool load_town_v1(fs::path scen_file, short which_town, cTown& the_town, legacy::scenario_data_type& scenario, std::vector<shop_info_t>& shops) {
short i,n;
long len,len_to_jump = 0;
char temp_str[256];
@@ -261,7 +338,7 @@ bool load_town_v1(fs::path scen_file, short which_town, cTown& the_town, legacy:
return false;
}
port_talk_nodes(&store_talk);
the_town.talking.append(store_talk);
the_town.talking.append(store_talk, shops);
for(i = 0; i < 170; i++) {
len = (long) (the_town.talking.strlens[i]);