diff --git a/osx/BoE.xcodeproj/project.pbxproj b/osx/BoE.xcodeproj/project.pbxproj index c4f1531c..59ae81c3 100644 --- a/osx/BoE.xcodeproj/project.pbxproj +++ b/osx/BoE.xcodeproj/project.pbxproj @@ -286,6 +286,8 @@ 91FCC8F118FEEDC6007026CE /* winutil.mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 919145FF18E63B70005CF3A4 /* winutil.mac.mm */; }; 91FCC8F218FEEFE0007026CE /* pc.editors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B3EF070F969BD300BF5B67 /* pc.editors.cpp */; }; 91FCC8F418FF0866007026CE /* pc.appleevents.mm in Sources */ = {isa = PBXBuildFile; fileRef = 91FCC8F318FF069A007026CE /* pc.appleevents.mm */; }; + 91FDB57B1A4E77CA00DE5983 /* shop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91FDB5791A4E774E00DE5983 /* shop.cpp */; }; + 91FDB57C1A4E77CA00DE5983 /* shop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91FDB5791A4E774E00DE5983 /* shop.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -780,6 +782,8 @@ 91FCC8DA18FE2CCA007026CE /* pc.menus.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pc.menus.h; sourceTree = ""; }; 91FCC8DB18FE2CE8007026CE /* pc.menus.mac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = pc.menus.mac.mm; sourceTree = ""; }; 91FCC8F318FF069A007026CE /* pc.appleevents.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = pc.appleevents.mm; sourceTree = ""; }; + 91FDB5771A4E71A900DE5983 /* shop.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = shop.hpp; sourceTree = ""; }; + 91FDB5791A4E774E00DE5983 /* shop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = shop.cpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -948,6 +952,7 @@ 913D05BB0FA1EA0A00184C18 /* pc.cpp */, 91AC607F0FA26A3B00EEAE67 /* regtown.cpp */, 91279C580F9D1253007B0D52 /* scenario.cpp */, + 91FDB5791A4E774E00DE5983 /* shop.cpp */, 91279CC60F9D1A02007B0D52 /* special.cpp */, 91597A6E1A3BEDC700BE7BF9 /* spell.cpp */, 91E5C7B70F9F619D00C21460 /* talking.cpp */, @@ -973,6 +978,7 @@ 91AC607E0FA26A3B00EEAE67 /* regtown.h */, 91279C570F9D1253007B0D52 /* scenario.h */, 912287850FD41A2300B21642 /* simpletypes.h */, + 91FDB5771A4E71A900DE5983 /* shop.hpp */, 91279CC50F9D1A02007B0D52 /* special.h */, 91597A6C1A3BED2D00BE7BF9 /* spell.hpp */, 91E5C7B60F9F619D00C21460 /* talking.h */, @@ -1606,6 +1612,7 @@ 915E090A1A316EE3008BDF00 /* map_parse.cpp in Sources */, 91597A6F1A3C021400BE7BF9 /* spell.cpp in Sources */, 9179A4671A48683100FEF872 /* stack.cpp in Sources */, + 91FDB57B1A4E77CA00DE5983 /* shop.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1721,6 +1728,7 @@ 915E090B1A316EE4008BDF00 /* map_parse.cpp in Sources */, 91597A701A3C021600BE7BF9 /* spell.cpp in Sources */, 9179A4651A48683100FEF872 /* stack.cpp in Sources */, + 91FDB57C1A4E77CA00DE5983 /* shop.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/osx/boe.actions.cpp b/osx/boe.actions.cpp index abea2f98..bbfebf62 100644 --- a/osx/boe.actions.cpp +++ b/osx/boe.actions.cpp @@ -35,6 +35,7 @@ #include "winutil.h" #include "cursors.h" #include "spell.hpp" +#include "shop.hpp" rectangle bottom_buttons[7]; rectangle town_buttons[10]; @@ -76,9 +77,9 @@ short door_pc,store_drop_item; short current_switch = 6; cOutdoors::cWandering store_wandering_special; long dummy; -short store_shop_type; short store_selling_values[8] = {0,0,0,0,0,0,0,0}; +extern cShop active_shop; extern short cen_x, cen_y, stat_window,give_delays;//,pc_moves[6]; extern eGameMode overall_mode; @@ -655,7 +656,7 @@ static void handle_switch_pc(short which_pc) { else if(is_combat()) // TODO: Allow this, provided the chosen PC has APs; it would be equivalent to pressing space until reaching that PC add_string_to_buf("Set active: Can't set this in combat."); - else if(univ.party[which_pc].main_status != eMainStatus::ALIVE && (overall_mode != MODE_SHOPPING || store_shop_type != 3)) + else if(univ.party[which_pc].main_status != eMainStatus::ALIVE && (overall_mode != MODE_SHOPPING || active_shop.getType() != eShopType::HEALING)) add_string_to_buf("Set active: PC must be here & active."); else { current_pc = which_pc; @@ -675,7 +676,7 @@ static void handle_switch_pc_items(short which_pc, bool& need_redraw) { else { if(!is_combat()) { // TODO: Maybe allow this in combat, as per the above TODO note? - if(univ.party[which_pc].main_status != eMainStatus::ALIVE && (overall_mode != MODE_SHOPPING || store_shop_type != 12)) + if(univ.party[which_pc].main_status != eMainStatus::ALIVE && (overall_mode != MODE_SHOPPING || active_shop.getType() != eShopType::ALCHEMY)) add_string_to_buf("Set active: PC must be here & active."); else { current_pc = which_pc; @@ -687,7 +688,8 @@ static void handle_switch_pc_items(short which_pc, bool& need_redraw) { } set_stat_window(which_pc); if(overall_mode == MODE_SHOPPING) { - set_up_shop_array(); + if(active_shop.getType() == eShopType::HEALING) + set_up_shop_array(eShopType::HEALING, 0, 0); draw_shop_graphics(0,item_screen_button_rects[which_pc]); // rect is dummy } } @@ -1274,7 +1276,8 @@ bool handle_action(sf::Event event) { put_pc_screen(); put_item_screen(stat_window,0); if(overall_mode == MODE_SHOPPING) { - set_up_shop_array(); + if(active_shop.getType() == eShopType::HEALING) + set_up_shop_array(eShopType::HEALING, 0, 0); draw_shop_graphics(0,pc_buttons[0][0]); } } diff --git a/osx/boe.dlgutil.cpp b/osx/boe.dlgutil.cpp index bb682132..524444fb 100644 --- a/osx/boe.dlgutil.cpp +++ b/osx/boe.dlgutil.cpp @@ -34,6 +34,7 @@ #include "pict.hpp" #include #include "prefs.hpp" +#include "shop.hpp" #define NUM_HINTS 30 //extern big_tr_type t_d; @@ -93,11 +94,8 @@ extern std::vector talk_words; // 800 + - mage spells // 900 + - priest spells // n000 + i - magic store n item i -short store_shop_items[30],store_shop_costs[30]; // talk_area_rect and talk_help_rect used for this too -short store_shop_min,store_shop_max,store_cost_mult; eGameMode store_pre_shop_mode; -char store_store_name[256]; // 0 - whole area, 1 - active area 2 - graphic 3 - item name // 4 - item cost 5 - item extra str 6 - item help button extern rectangle shopping_rects[8][7]; @@ -107,16 +105,10 @@ rectangle shop_name_str = {44,6,56,200}; rectangle shop_frame = {62,10,352,269}; rectangle shop_done_rect = {388,212,411,275}; -extern short store_shop_type; - -const char* heal_types[] = { - "Heal Damage","Cure Poison","Cure Disease","Cure Paralysis", - "Uncurse Items","Cure Stoned Character","Raise Dead","Resurrection","Cure Dumbfounding"}; -short heal_costs[9] = {50,30,80,100,250,500,1000,3000,100}; -long cost_mult[7] = {5,7,10,13,16,20,25}; - short store_scen_page_on,store_num_scen; +cShop active_shop; + /* shop_type: 0 - weapon shop @@ -129,30 +121,21 @@ shop_type: 11 - priest spells 12 alchemy */ -void start_shop_mode(short shop_type,short shop_min,short shop_max,short cost_adj,const char* store_name) { +void start_shop_mode(eShopType shop_type,short shop_min,short shop_max,short cost_adj,std::string store_name) { rectangle area_rect; // This would be a place to hide the text box, if I add it. - if(shop_max < shop_min) - shop_max = shop_min; //// - store_cost_mult = cost_adj; - if(store_cost_mult > 6) - store_cost_mult = 6; - store_shop_type = shop_type; - store_shop_min = shop_min; - store_shop_max = shop_max; + active_shop = cShop(shop_type, cost_adj, store_name); area_rect = talk_area_rect; - strcpy((char *) store_store_name,store_name); - talk_gworld.create(area_rect.width(), area_rect.height()); store_pre_shop_mode = overall_mode; overall_mode = MODE_SHOPPING; stat_screen_mode = 1; - set_up_shop_array(); + set_up_shop_array(shop_type, shop_min, std::max(shop_min, shop_max)); put_background(); draw_shop_graphics(0,area_rect); @@ -217,39 +200,42 @@ void handle_shop_event(location p) { } for(i = 0; i < 8; i++) { - store_what_picked = i; - if((p.in(shopping_rects[i][1])) && (store_shop_items[store_what_picked] >= 0)) { + store_what_picked = i + shop_sbar->getPosition(); + if(store_what_picked >= active_shop.size()) break; + if(p.in(shopping_rects[i][1])) { click_shop_rect(shopping_rects[i][1]); - handle_sale(store_shop_items[store_what_picked],store_shop_costs[store_what_picked]); - } - if((p.in(shopping_rects[i][6])) && (store_shop_items[store_what_picked] >= 0) - && (store_shop_type != 3) && (store_shop_type != 4)){ + handle_sale(active_shop.getItem(store_what_picked), store_what_picked); + } else if(p.in(shopping_rects[i][6]) && active_shop.getType() != eShopType::HEALING){ click_shop_rect(shopping_rects[i][6]); - handle_info_request(store_shop_items[store_what_picked]); + handle_info_request(active_shop.getItem(store_what_picked)); } } } -void handle_sale(short what_chosen,short cost) { - cItemRec base_item; - short what_magic_shop,what_magic_shop_item,i; +void handle_sale(cShopItem item, int i) { + cItemRec base_item = item.item; + short cost = item.cost; rectangle dummy_rect = {0,0,0,0}; - switch(what_chosen / 100) { - case 0: case 1: case 2: case 3: case 4: - base_item = get_stored_item(what_chosen); - base_item.ident = true; - //cost = (base_item.charges == 0) ? base_item.value : base_item.value * base_item.charges; + switch(item.type) { + case eShopItemType::ITEM: switch(pc_ok_to_buy(current_pc,cost,base_item)) { - case 1: play_sound(-38); give_to_pc(current_pc,base_item,true); break; + case 1: + play_sound(-38); + give_to_pc(current_pc,base_item,true); + if(active_shop.getType() != eShopType::ITEMS) { + // Magic shops have limited stock + active_shop.clearItem(i); + shop_sbar->setMaximum(shop_sbar->getMaximum() - 1); + } + break; case 2: ASB("Can't carry any more items."); break; case 3: ASB("Not enough cash."); break; case 4: ASB("Item is too heavy."); break; case 5: ASB("You own too many of this."); break; } break; - case 5: - base_item = store_alchemy(what_chosen - 500); + case eShopItemType::ALCHEMY: if(univ.party.alchemy[base_item.item_level]) ASB("You already know that recipe."); else if(!take_gold(cost,false)) @@ -261,52 +247,53 @@ void handle_sale(short what_chosen,short cost) { univ.party.alchemy[base_item.item_level] = true; } break; - case 6: - //base_item = food_types[what_chosen - 600]; - //if(!take_gold(cost,false)) - // ASB("Not enough gold."); - //else { - // play_sound(-38); ASB("You buy food."); - // univ.party.food += base_item.item_level; - //} + case eShopItemType::FOOD: + // TODO: This shop type is never actually used. Should it be deleted or restored? + if(!take_gold(cost,false)) + ASB("Not enough gold."); + else { + play_sound(-38); + ASB("You buy food."); + univ.party.food += base_item.item_level; + } break; - case 7: - what_chosen -= 700; + default: if(!take_gold(cost,false)) ASB("Not enough gold."); else { ASB("You pay the healer."); play_sound(68); - switch(what_chosen) { - case 0: + switch(item.type) { + case eShopItemType::HEAL_WOUNDS: univ.party[current_pc].cur_health = univ.party[current_pc].max_health; break; - case 1: + case eShopItemType::CURE_POISON: univ.party[current_pc].status[eStatus::POISON] = 0; break; - case 2: + case eShopItemType::CURE_DISEASE: univ.party[current_pc].status[eStatus::DISEASE] = 0; break; - case 3: + case eShopItemType::CURE_PARALYSIS: univ.party[current_pc].status[eStatus::PARALYZED] = 0; break; - case 4: - for(i = 0; i < 24; i++) + 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)) univ.party[current_pc].items[i].cursed = univ.party[current_pc].items[i].unsellable = false; break; - case 5: case 6: case 7: + case eShopItemType::DESTONE: case eShopItemType::RAISE_DEAD: case eShopItemType::RESURRECT: univ.party[current_pc].main_status = eMainStatus::ALIVE; break; - case 8: + case eShopItemType::CURE_DUMBFOUNDING: univ.party[current_pc].status[eStatus::DUMB] = 0; break; } + // Once you've been healed, of course you're no longer eligible for that form of healing. + active_shop.clearItem(i); } break; - case 8: - base_item = store_mage_spells(what_chosen - 800 - 30); + case eShopItemType::MAGE_SPELL: if((base_item.item_level < 0) || (base_item.item_level > 61)) { beep(); giveError("Error: The scenario tried to sell you an invalid mage spell!"); @@ -324,8 +311,7 @@ void handle_sale(short what_chosen,short cost) { give_help(41,0); } break; - case 9: - base_item = store_priest_spells(what_chosen - 900 - 30); + case eShopItemType::PRIEST_SPELL: if((base_item.item_level < 0) || (base_item.item_level > 61)) { beep(); giveError("Error: The scenario tried to sell you an invalid priest spell!"); @@ -343,22 +329,7 @@ void handle_sale(short what_chosen,short cost) { give_help(41,0); } break; - default: - what_magic_shop = (what_chosen / 1000) - 1; - what_magic_shop_item = what_chosen % 1000; - base_item = univ.party.magic_store_items[what_magic_shop][what_magic_shop_item]; - base_item.ident = true; - switch(pc_ok_to_buy(current_pc,cost,base_item)) { - case 1: play_sound(-38); give_to_pc(current_pc,base_item,true); - univ.party.magic_store_items[what_magic_shop][what_magic_shop_item].variety = eItemType::NO_ITEM; - break; - case 2: ASB("Can't carry any more items."); break; - case 3: ASB("Not enough cash."); break; - case 4: ASB("Item is too heavy."); break; - } - break; } - set_up_shop_array(); if(overall_mode != MODE_SHOPPING) { beep(); @@ -371,159 +342,92 @@ void handle_sale(short what_chosen,short cost) { } -void handle_info_request(short what_chosen) { - cItemRec base_item; - short what_magic_shop,what_magic_shop_item; +void handle_info_request(cShopItem item) { + cItemRec base_item = item.item; - switch(what_chosen / 100) { - case 0: case 1: case 2: case 3: case 4: - base_item = get_stored_item(what_chosen); - base_item.ident = true; + switch(item.type) { + case eShopItemType::ITEM: + case eShopItemType::FOOD: display_pc_item(6,0, base_item,0); break; - case 5: + case eShopItemType::ALCHEMY: // TODO: Create a dedicated dialog for alchemy info display_alchemy(); break; - case 8: - base_item = store_mage_spells(what_chosen - 800 - 30); - display_spells(eSkill::MAGE_SPELLS,base_item.item_level,0); + case eShopItemType::MAGE_SPELL: + display_spells(eSkill::MAGE_SPELLS,base_item.item_level - 800 - 30,0); break; - case 9: - base_item = store_priest_spells(what_chosen - 900 - 30); - display_spells(eSkill::PRIEST_SPELLS,base_item.item_level,0); - break; - default: - what_magic_shop = (what_chosen / 1000) - 1; - what_magic_shop_item = what_chosen % 1000; - base_item = univ.party.magic_store_items[what_magic_shop][what_magic_shop_item]; - base_item.ident = true; - display_pc_item(6,0, base_item,0); + case eShopItemType::PRIEST_SPELL: + display_spells(eSkill::PRIEST_SPELLS,base_item.item_level - 900 - 30,0); break; } } -void set_up_shop_array() { - short i,shop_pos = 0; +void set_up_shop_array(eShopType store_shop_type, short store_shop_min, short store_shop_max) { bool cursed_item = false; - cItemRec store_i; - long store_l; + active_shop.clear(); - for(i = 0; i < 30; i++) - store_shop_items[i] = -1; switch(store_shop_type) { - case 0: case 1: case 2: - for(i = store_shop_min; i < store_shop_max + 1; i++) { - store_shop_items[shop_pos] = i; - store_i = get_stored_item(store_shop_items[shop_pos]); - store_shop_costs[shop_pos] = (store_i.charges == 0) ? - store_i.value : store_i.value * store_i.charges; - shop_pos++; - } + case eShopType::ITEMS: + for(int i = store_shop_min; i <= store_shop_max; i++) + active_shop.addItem(get_stored_item(i)); break; - case 3: - if(univ.party[current_pc].cur_health < univ.party[current_pc].max_health) { - store_shop_items[shop_pos] = 700; - store_shop_costs[shop_pos] = heal_costs[0]; - shop_pos++; - } - if(univ.party[current_pc].status[eStatus::POISON] > 0) { - store_shop_items[shop_pos] = 701; - store_shop_costs[shop_pos] = heal_costs[1]; - shop_pos++; - } - if(univ.party[current_pc].status[eStatus::DISEASE] > 0) { - store_shop_items[shop_pos] = 702; - store_shop_costs[shop_pos] = heal_costs[2]; - shop_pos++; - } - if(univ.party[current_pc].status[eStatus::PARALYZED] > 0) { - store_shop_items[shop_pos] = 703; - store_shop_costs[shop_pos] = heal_costs[3]; - shop_pos++; - } - if(univ.party[current_pc].status[eStatus::DUMB] > 0) { - store_shop_items[shop_pos] = 708; - store_shop_costs[shop_pos] = heal_costs[8]; - shop_pos++; - } - for(i = 0; i < 24; i++) + 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) { - store_shop_items[shop_pos] = 704; - store_shop_costs[shop_pos] = heal_costs[4]; - shop_pos++; - } - if(univ.party[current_pc].main_status == eMainStatus::STONE) { - store_shop_items[shop_pos] = 705; - store_shop_costs[shop_pos] = heal_costs[5]; - shop_pos++; - } - if(univ.party[current_pc].main_status == eMainStatus::DEAD){ - store_shop_items[shop_pos] = 706; - store_shop_costs[shop_pos] = heal_costs[6]; - shop_pos++; - } - if(univ.party[current_pc].main_status == eMainStatus::DUST){ - store_shop_items[shop_pos] = 707; - store_shop_costs[shop_pos] = heal_costs[7]; - shop_pos++; - } + 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 4: - //for(i = store_shop_min; i < store_shop_max + 1; i++) { - // store_shop_items[shop_pos] = 600 + i; - // store_shop_costs[shop_pos] = food_types[i].value; - // shop_pos++; - //} + case eShopType::FOOD: + // TODO: This shop type is never actually used. Should it be deleted or resurrected? + for(int i = store_shop_min; i <= store_shop_max; i++) + active_shop.addSpecial(eShopItemType::FOOD, i); break; - case 5: case 6: case 7: case 8: case 9: - for(i = 0; i < 10; i++) - if(univ.party.magic_store_items[store_shop_type - 5][i].variety != eItemType::NO_ITEM) { - store_shop_items[shop_pos] = (store_shop_type - 4) * 1000 + i; - store_i = univ.party.magic_store_items[store_shop_type - 5][i]; - store_shop_costs[shop_pos] = (store_i.charges == 0) ? - store_i.value : store_i.value * store_i.charges; - shop_pos++; - } + case eShopType::MAGIC_JUNK: + active_shop.addItems(univ.party.magic_store_items[0].begin(), univ.party.magic_store_items[0].end()); break; - case 10: - for(i = store_shop_min; i < store_shop_max + 1; i++) - if(i == minmax(0,31,i)) { - store_i = store_mage_spells(i); - store_shop_costs[shop_pos] = store_i.value; - store_shop_items[shop_pos] = 800 + i; - shop_pos++; - } + case eShopType::MAGIC_LOUSY: + active_shop.addItems(univ.party.magic_store_items[1].begin(), univ.party.magic_store_items[1].end()); break; - case 11: - for(i = store_shop_min; i < store_shop_max + 1; i++) - if(i == minmax(0,31,i)) { - store_i = store_priest_spells(i); - store_shop_costs[shop_pos] = store_i.value; - store_shop_items[shop_pos] = 900 + i; - shop_pos++; - } + case eShopType::MAGIC_SO_SO: + active_shop.addItems(univ.party.magic_store_items[2].begin(), univ.party.magic_store_items[2].end()); break; - case 12: - for(i = store_shop_min; i < store_shop_max + 1; i++) - if(i == minmax(0,19,i)) { - store_i = store_alchemy(i); - store_shop_costs[shop_pos] = store_i.value; - store_shop_items[shop_pos] = 500 + i; - shop_pos++; - } + case eShopType::MAGIC_GOOD: + active_shop.addItems(univ.party.magic_store_items[3].begin(), univ.party.magic_store_items[3].end()); + break; + case eShopType::MAGIC_GREAT: + active_shop.addItems(univ.party.magic_store_items[4].begin(), univ.party.magic_store_items[4].end()); + 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; } - for(i = 0; i < 30; i++) - if(store_shop_items[i] >= 0) { - store_l = store_shop_costs[i]; - store_l = (store_l * cost_mult[store_cost_mult]) / 10; - store_shop_costs[i] = (short) store_l; - } - i = max(0,shop_pos - 8); - shop_sbar->setMaximum(i); + shop_sbar->setMaximum(active_shop.size() - 8); } void start_talk_mode(short m_num,short personality,m_num_t monst_type,short store_face_pic) { @@ -754,7 +658,7 @@ void handle_talk_event(location p) { break; case 7: c = minmax(1,30,c); - start_shop_mode(2,b,b + c - 1,a,save_talk_str1.c_str()); + start_shop_mode(eShopType::ITEMS,b,b + c - 1,a,save_talk_str1.c_str()); strnum1 = -1; return; case 8: @@ -765,14 +669,24 @@ void handle_talk_event(location p) { save_talk_str1 = "You conclude your training."; return; - case 9: case 10: case 11: - c = minmax(1,30,c); - start_shop_mode(ttype + 1,b,b + c - 1,a,save_talk_str1.c_str()); + case 9: + c = minmax(1,61,c); + start_shop_mode(eShopType::MAGE,b,b + c - 1,a,save_talk_str1.c_str()); + strnum1 = -1; + return; + case 10: + c = minmax(1,61,c); + start_shop_mode(eShopType::PRIEST,b,b + c - 1,a,save_talk_str1.c_str()); + strnum1 = -1; + return; + case 11: + c = minmax(1,19,c); + start_shop_mode(eShopType::ALCHEMY,b,b + c - 1,a,save_talk_str1.c_str()); strnum1 = -1; return; case 12: //healer // TODO: extra1 and extra2 are actually never used! So remove them. - start_shop_mode(3,univ.town.monst[store_m_num].extra1, + start_shop_mode(eShopType::HEALING,univ.town.monst[store_m_num].extra1, univ.town.monst[store_m_num].extra2,a,save_talk_str1.c_str()); strnum1 = -1; return; @@ -904,7 +818,7 @@ void handle_talk_event(location p) { save_talk_str2 = ""; break; case 23: - start_shop_mode(5 + b,0, + start_shop_mode(eShopType(5 + b),0, 9,a,save_talk_str1.c_str()); strnum1 = -1; return; diff --git a/osx/boe.dlgutil.h b/osx/boe.dlgutil.h index d28e6eef..1982e21b 100644 --- a/osx/boe.dlgutil.h +++ b/osx/boe.dlgutil.h @@ -1,15 +1,17 @@ #ifndef BOE_GAME_DLGUTIL_H +#include #include "dialog.hpp" #include "simpletypes.h" +#include "shop.hpp" -void start_shop_mode(short shop_type,short shop_min,short shop_max,short cost_adj,const char* store_name); +void start_shop_mode(eShopType shop_type,short shop_min,short shop_max,short cost_adj,std::string store_name); void end_shop_mode(); void handle_shop_event(location p); -void handle_sale(short what_chosen,short cost); -void handle_info_request(short what_chosen); -void set_up_shop_array(); +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 start_talk_mode(short m_num,short personality,m_num_t monst_type,short store_face_pic); void end_talk_mode(); void handle_talk_event(location p); diff --git a/osx/boe.items.cpp b/osx/boe.items.cpp index 2ddd9033..00e1acae 100644 --- a/osx/boe.items.cpp +++ b/osx/boe.items.cpp @@ -919,8 +919,7 @@ static void put_item_graphics(cDialog& me, size_t& first_item_shown, short& curr csp(987,20 + i * 4,/*3000 + 2000 + */item.graphic_num - 1000,PICT_CUSTOM + PICT_ITEM); else csp(987,20 + i * 4,/*4800 + */item.graphic_num,PICT_ITEM); #endif - get_item_interesting_string(item,(char *) message); - me[detail].setText(message); + me[detail].setText(get_item_interesting_string(item)); storage = item.item_weight(); sprintf ((char *) message, "Weight: %d",storage); me[weight].setText(message); diff --git a/osx/boe.newgraph.cpp b/osx/boe.newgraph.cpp index a6840d57..e958341e 100644 --- a/osx/boe.newgraph.cpp +++ b/osx/boe.newgraph.cpp @@ -22,6 +22,7 @@ #include "scrollbar.hpp" #include #include "location.h" +#include "shop.hpp" short monsters_faces[190] = { 0,1,2,3,4,5,6,7,8,9, @@ -86,10 +87,8 @@ extern m_num_t store_monst_type; std::vector talk_words; // Shop vars -extern short store_shop_items[30],store_shop_costs[30]; -extern short store_shop_type,store_shop_min,store_shop_max,store_cost_mult; +extern cShop active_shop; extern eGameMode store_pre_shop_mode; -extern char store_store_name[256]; extern rectangle shopping_rects[8][7]; extern rectangle bottom_help_rects[4]; extern rectangle shop_name_str; @@ -673,9 +672,8 @@ void draw_shop_graphics(bool pressed,rectangle clip_area_rect) { rectangle face_rect = {6,6,38,38}; rectangle title_rect = {15,48,42,260}; rectangle dest_rect,help_from = {85,36,101,54}; - short faces[13] = {1,1,1,42,43, 1,1,1,1,1, 44,44,44}; - short i,what_chosen; + short i; // In the 0..65535 range, these blue components were: 0, 32767, 14535, 26623, 59391 // The green components on the second line were 40959 and 24575 // TODO: The duplication of sf::Color here shouldn't be necessary... @@ -685,9 +683,7 @@ void draw_shop_graphics(bool pressed,rectangle clip_area_rect) { rectangle shopper_name = {44,6,56,260}; short current_pos; - short cur_cost,what_magic_shop,what_magic_shop_item; - char cur_name[60]; - char cur_info_str[60]; + short cur_cost; static const char*const cost_strs[] = { "Extremely Cheap","Very Reasonable","Pretty Average","Somewhat Pricey", "Expensive","Exorbitant","Utterly Ridiculous"}; @@ -716,7 +712,12 @@ void draw_shop_graphics(bool pressed,rectangle clip_area_rect) { // Place store icon if(!pressed) { - i = faces[store_shop_type]; + i = 0; + eShopType type = active_shop.getType(); + if(type == eShopType::HEALING) i = 41; + else if(type == eShopType::FOOD) i = 42; + else if(type == eShopType::MAGE || type == eShopType::PRIEST || type == eShopType::ALCHEMY) + i = 43; 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); @@ -728,24 +729,34 @@ void draw_shop_graphics(bool pressed,rectangle clip_area_rect) { style.lineHeight = 18; dest_rect = title_rect; dest_rect.offset(1,1); - win_draw_string(talk_gworld,dest_rect,store_store_name,eTextMode::LEFT_TOP,style); + win_draw_string(talk_gworld,dest_rect,active_shop.getName(),eTextMode::LEFT_TOP,style); dest_rect.offset(-1,-1); style.colour = c[4]; - win_draw_string(talk_gworld,dest_rect,store_store_name,eTextMode::LEFT_TOP,style); + win_draw_string(talk_gworld,dest_rect,active_shop.getName(),eTextMode::LEFT_TOP,style); style.font = FONT_BOLD; style.pointSize = 12; style.colour = c[3]; - switch(store_shop_type) { - case 3: sprintf(cur_name,"Healing for %s.",univ.party[current_pc].name.c_str()); break; - case 10: sprintf(cur_name,"Mage Spells for %s.",univ.party[current_pc].name.c_str());break; - case 11: sprintf(cur_name,"Priest Spells for %s.",univ.party[current_pc].name.c_str()); break; - case 12: sprintf(cur_name,"Buying Alchemy.");break; - case 4: sprintf(cur_name,"Buying Food.");break; - default:sprintf(cur_name,"Shopping for %s.",univ.party[current_pc].name.c_str()); break; + std::ostringstream title; + switch(active_shop.getType()) { + case eShopType::HEALING: + title << "Healing for " << univ.party[current_pc].name << '.'; + break; + case eShopType::MAGE: + title << "Mage Spells for " << univ.party[current_pc].name << '.'; + break; + case eShopType::PRIEST: + title << "Priest Spells for " << univ.party[current_pc].name << '.'; + break; + case eShopType::ALCHEMY: + title << "Buying Alchemy."; + break; + default: + title << "Shopping for " << univ.party[current_pc].name << '.'; + break; } - win_draw_string(talk_gworld,shopper_name,cur_name,eTextMode::LEFT_TOP,style); + win_draw_string(talk_gworld,shopper_name,title.str(),eTextMode::LEFT_TOP,style); // Place help and done buttons // TODO: Reimplement these with a cButton @@ -767,67 +778,34 @@ 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(); - if(store_shop_items[current_pos] < 0) - break; // theoretically, this shouldn't happen - cur_cost = store_shop_costs[current_pos]; - what_chosen = store_shop_items[current_pos]; + cShopItem item = active_shop.getItem(i); + if(item.type == eShopItemType::EMPTY) + continue; // theoretically, this shouldn't happen + cur_cost = item.cost; + base_item = item.item; + std::string cur_name = base_item.full_name, cur_info_str; rectangle from_rect, to_rect = shopping_rects[i][2]; sf::Texture* from_gw; - switch(what_chosen / 100) { - case 0: case 1: case 2: case 3: case 4: - base_item = get_stored_item(what_chosen); + switch(item.type) { + case eShopItemType::ITEM: base_item.ident = true; - graf_pos_ref(from_gw, from_rect) = calc_item_rect(base_item.graphic_num,to_rect); - rect_draw_some_item(*from_gw, from_rect, talk_gworld, to_rect, sf::BlendAlpha); - strcpy(cur_name,base_item.full_name.c_str()); - get_item_interesting_string(base_item,cur_info_str); + cur_info_str = get_item_interesting_string(base_item); break; - case 5: - base_item = store_alchemy(what_chosen - 500); - graf_pos_ref(from_gw, from_rect) = calc_item_rect(53,to_rect); - rect_draw_some_item(*from_gw, from_rect, talk_gworld, to_rect, sf::BlendAlpha); - strcpy(cur_name,base_item.full_name.c_str()); - strcpy(cur_info_str,""); + case eShopItemType::ALCHEMY: + cur_info_str = ""; break; - case 6: - //base_item = food_types[what_chosen - 600]; - //draw_dialog_graphic( talk_gworld, shopping_rects[i][2],633, false,1); - //strcpy(cur_name,base_item.full_name); - //get_item_interesting_string(base_item,cur_info_str); + case eShopItemType::MAGE_SPELL: + cur_info_str = ""; break; - case 7: - what_chosen -= 700; - graf_pos_ref(from_gw, from_rect) = calc_item_rect(99,to_rect); - rect_draw_some_item(*from_gw, from_rect, talk_gworld, to_rect, sf::BlendAlpha); - strcpy(cur_name,heal_types[what_chosen]); - strcpy(cur_info_str,""); + case eShopItemType::PRIEST_SPELL: + cur_info_str = ""; break; - case 8: - base_item = store_mage_spells(what_chosen - 800 - 30); - graf_pos_ref(from_gw, from_rect) = calc_item_rect(base_item.graphic_num,to_rect); - rect_draw_some_item(*from_gw, from_rect, talk_gworld, to_rect, sf::BlendAlpha); - - strcpy(cur_name,base_item.full_name.c_str()); - strcpy(cur_info_str,""); - break; - case 9: - base_item = store_priest_spells(what_chosen - 900 - 30); - graf_pos_ref(from_gw, from_rect) = calc_item_rect(base_item.graphic_num,to_rect); - rect_draw_some_item(*from_gw, from_rect, talk_gworld, to_rect, sf::BlendAlpha); - strcpy(cur_name,base_item.full_name.c_str()); - strcpy(cur_info_str,""); - break; - default: - what_magic_shop = (what_chosen / 1000) - 1; - what_magic_shop_item = what_chosen % 1000; - base_item = univ.party.magic_store_items[what_magic_shop][what_magic_shop_item]; - base_item.ident = true; - graf_pos_ref(from_gw, from_rect) = calc_item_rect(base_item.graphic_num,to_rect); - rect_draw_some_item(*from_gw, from_rect, talk_gworld, to_rect, sf::BlendAlpha); - strcpy(cur_name,base_item.full_name.c_str()); - get_item_interesting_string(base_item,cur_info_str); + default: // Healing + cur_info_str = ""; break; } + graf_pos_ref(from_gw, from_rect) = calc_item_rect(base_item.graphic_num,to_rect); + rect_draw_some_item(*from_gw, from_rect, talk_gworld, to_rect, sf::BlendAlpha); // Now draw item shopping_rects[i][7] // 0 - whole area, 1 - active area 2 - graphic 3 - item name @@ -835,44 +813,41 @@ void draw_shop_graphics(bool pressed,rectangle clip_area_rect) { style.pointSize = 12; style.lineHeight = 12; win_draw_string(talk_gworld,shopping_rects[i][3],cur_name,eTextMode::WRAP,style); - sprintf(cur_name,"Cost: %d",cur_cost); + cur_name = "Cost: " + std::to_string(cur_cost); win_draw_string(talk_gworld,shopping_rects[i][4],cur_name,eTextMode::WRAP,style); style.pointSize = 10; win_draw_string(talk_gworld,shopping_rects[i][5],cur_info_str,eTextMode::WRAP,style); - if((store_shop_type != 3) && (store_shop_type != 4)) + if(active_shop.getType() != eShopType::HEALING) // Draw info button rect_draw_some_item(invenbtn_gworld,item_info_from,talk_gworld,shopping_rects[i][6],pressed ? sf::BlendNone : sf::BlendAlpha); } // Finally, cost info and help strs - sprintf(cur_name,"Prices here are %s.",cost_strs[store_cost_mult]); + title.str(""); + title << "Prices here are " << cost_strs[active_shop.getCostAdjust()] << '.'; style.pointSize = 10; style.lineHeight = 12; - win_draw_string(talk_gworld,bottom_help_rects[0],cur_name,eTextMode::WRAP,style); + 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((store_shop_type != 3) && (store_shop_type != 4)) + if(active_shop.getType() != eShopType::HEALING) win_draw_string(talk_gworld,bottom_help_rects[3],"'I' button brings up description.",eTextMode::WRAP,style); undo_clip(talk_gworld); talk_gworld.display(); refresh_shopping(); - shop_sbar->show(); - shop_sbar->draw(); + if(shop_sbar->getMaximum() > 1) + shop_sbar->show(); + else shop_sbar->hide(); } void refresh_shopping() { - // TODO: The duplication of rectangle here shouldn't be necessary... - rectangle from_rects[4] = {rectangle{0,0,62,279},rectangle{62,0,352,253},rectangle{62,269,352,279},rectangle{352,0,415,279}}; - rectangle to_rect; - short i; - - for(i = 0; i < 4; i++) { - to_rect = from_rects[i]; - to_rect.offset(5,5); - rect_draw_some_item(talk_gworld.getTexture(),from_rects[i],to_rect,ul); - } + rectangle from_rect(talk_gworld); + rectangle to_rect = from_rect; + to_rect.offset(5,5); + rect_draw_some_item(talk_gworld.getTexture(),from_rect,to_rect,ul); + shop_sbar->draw(); } static void place_talk_face() { @@ -914,84 +889,17 @@ void click_talk_rect(word_rect_t word) { place_talk_face(); } -cItemRec store_mage_spells(short which_s) { - cItemRec spell('spel');// = {21,0, 0,0,0,0,0,0, 53,0,0,0,0, 0, 0,0, {0,0},"", "",0,0,0,0}; - static const short cost[62] = { - // TODO: Costs for the level 1-3 spells - 5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5, - 150,200,150,1000,1200,400,300,200, - 200,250,500,1500,300, 250,125,150, - 400,450, 800,600,700,600,7500, 500, - 5000,3000,3500,4000,4000,4500,7000,5000 - }; - - std::string str; - - if(which_s != minmax(0,61,which_s)) - which_s = 0; - spell.item_level = which_s; - spell.value = cost[which_s]; - str = get_str("magic-names",which_s + 1); - spell.full_name = str.c_str(); - return spell; -} - -cItemRec store_priest_spells(short which_s) { - cItemRec spell('spel');// = {21,0, 0,0,0,0,0,0, 53,0,0,0,0, 0, 0,0, {0,0},"", "",0,0,0,0}; - static const short cost[62] = { - // TODO: Costs for the level 1-3 spells - 5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5, - 100,150,75,400,200, 100,80,250, - 400,400,1200,600,300, 600,350,250, - 500,500,600,800, 1000,900,400,600, - 2500,2000,4500,4500,3000,3000,2000,2000 - }; - std::string str; - - if(which_s != minmax(0,61,which_s)) - which_s = 0; - spell.item_level = which_s; - spell.value = cost[which_s]; - str = get_str("magic-names",which_s + 101); - spell.full_name = str.c_str(); - return spell; -} -cItemRec store_alchemy(short which_s) { - cItemRec spell('spel');// = {21,0, 0,0,0,0,0,0, 53,0,0,0,0, 0, 0,0, {0,0},"", "",0,0,0,0}; - static const short val[20] = { - 50,75,30,130,100, - 150, 200,200,300,250, - 300, 500,600,750,700, - 1000,10000,5000,7000,12000 - }; - std::string str; - - if(which_s != minmax(0,19,which_s)) - which_s = 0; - spell.item_level = which_s; - spell.value = val[which_s]; - str = get_str("magic-names",which_s + 200); - spell.full_name = str.c_str(); - return spell; -} - -void get_item_interesting_string(cItemRec item,char *message) { +std::string get_item_interesting_string(cItemRec item) { if(item.property) { - strcpy(message,"Not yours."); - return; + return "Not yours."; } if(!item.ident) { - strcpy(message,""); - return; + return ""; } if(item.cursed) { - strcpy(message,"Cursed item."); - return; + return "Cursed item."; } + char message[256]; switch(item.variety) { case eItemType::ONE_HANDED: case eItemType::TWO_HANDED: @@ -1033,6 +941,7 @@ void get_item_interesting_string(cItemRec item,char *message) { } if(item.charges > 0) sprintf(message,"Uses: %d",item.charges); + return message; } // color 0 - regular 1 - darker diff --git a/osx/boe.newgraph.h b/osx/boe.newgraph.h index 7dffb321..71fc0a54 100644 --- a/osx/boe.newgraph.h +++ b/osx/boe.newgraph.h @@ -58,10 +58,7 @@ void do_explosion_anim(short sound_num,short expand); void click_shop_rect(rectangle area_rect); void draw_shop_graphics(bool pressed,rectangle clip_area_rect); void refresh_shopping(); -cItemRec store_mage_spells(short which_s) ; -cItemRec store_priest_spells(short which_s); -cItemRec store_alchemy(short which_s); -void get_item_interesting_string(cItemRec item,char *message); +std::string get_item_interesting_string(cItemRec item); void click_talk_rect(word_rect_t word); void place_talk_str(std::string str_to_place,std::string str_to_place2,short color,rectangle c_rect); short scan_for_response(const char *str); diff --git a/osx/boe.specials.cpp b/osx/boe.specials.cpp index 90257d37..2f1103c4 100644 --- a/osx/boe.specials.cpp +++ b/osx/boe.specials.cpp @@ -3942,19 +3942,13 @@ void outdoor_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, *a = 1; break; case eSpecType::OUT_STORE: - get_strs(str1,str2,1,spec.m1 + 10,-1); + 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); - switch(spec.ex1b) { - case 0: start_shop_mode(0,spec.ex1a,spec.ex1a + spec.ex2a - 1,spec.ex2b,str1.c_str()); break; - case 1: start_shop_mode(10,spec.ex1a,spec.ex1a + spec.ex2a - 1,spec.ex2b,str1.c_str()); break; - case 2: start_shop_mode(11,spec.ex1a,spec.ex1a + spec.ex2a - 1 ,spec.ex2b,str1.c_str()); break; - case 3: start_shop_mode(12,spec.ex1a,spec.ex1a + spec.ex2a - 1,spec.ex2b,str1.c_str()); break; - case 4: start_shop_mode(3,spec.ex1a,spec.ex1a + spec.ex2a - 1,spec.ex2b,str1.c_str()); break; - } + start_shop_mode(eShopType(spec.ex1b), spec.ex1a, spec.ex1a + spec.ex2a - 1, spec.ex2b, str1); *next_spec = -1; break; } diff --git a/osx/classes/party.h b/osx/classes/party.h index 2f0a960d..a30162b0 100644 --- a/osx/classes/party.h +++ b/osx/classes/party.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include "vehicle.h" @@ -82,7 +83,7 @@ public: short in_boat; short in_horse; cOutdoors::cCreature out_c[10]; - cItemRec magic_store_items[5][10]; + std::array,5> magic_store_items; short imprisoned_monst[4]; // Soul Crystal? char m_noted[256]; // has the monster been scried? char m_seen[256]; // has the monster ever been seen? (this used to have the above meaning) diff --git a/osx/classes/shop.cpp b/osx/classes/shop.cpp new file mode 100644 index 00000000..d7642841 --- /dev/null +++ b/osx/classes/shop.cpp @@ -0,0 +1,159 @@ +// +// shop.cpp +// BoE +// +// Created by Celtic Minstrel on 14-12-27. +// +// + +#include "shop.hpp" +#include +#include "mathutil.h" +#include "graphtool.h" // for get_str + +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) {} + +size_t cShop::firstEmpty() { + for(size_t i = 0; i < items.size(); i++) { + if(items[i].type == eShopItemType::EMPTY) + return i; + } + return items.size(); +} + +size_t cShop::size() { + return std::count_if(items.begin(), items.end(), [](cShopItem& item) { + return item.type != eShopItemType::EMPTY; + }); +} + +void cShop::addItem(cItemRec item) { + size_t i = firstEmpty(); + if(i >= items.size()) return; + if(item.variety == eItemType::NO_ITEM) return; + 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; +} + +static cItemRec store_mage_spells(short which_s) { + cItemRec spell('spel'); + static const short cost[62] = { + // TODO: Costs for the level 1-3 spells + 5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5, + 150,200,150,1000,1200,400,300,200, + 200,250,500,1500,300, 250,125,150, + 400,450, 800,600,700,600,7500, 500, + 5000,3000,3500,4000,4000,4500,7000,5000 + }; + + if(which_s != minmax(0,61,which_s)) + which_s = 0; + spell.item_level = which_s; + spell.value = cost[which_s]; + spell.full_name = get_str("magic-names",which_s + 1); + return spell; +} + +static cItemRec store_priest_spells(short which_s) { + cItemRec spell('spel'); + static const short cost[62] = { + // TODO: Costs for the level 1-3 spells + 5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5, + 100,150,75,400,200, 100,80,250, + 400,400,1200,600,300, 600,350,250, + 500,500,600,800, 1000,900,400,600, + 2500,2000,4500,4500,3000,3000,2000,2000 + }; + + if(which_s != minmax(0,61,which_s)) + which_s = 0; + spell.item_level = which_s; + spell.value = cost[which_s]; + spell.full_name = get_str("magic-names",which_s + 101); + return spell; +} + +static cItemRec store_alchemy(short which_s) { + cItemRec spell('spel'); + static const short val[20] = { + 50,75,30,130,100, + 150, 200,200,300,250, + 300, 500,600,750,700, + 1000,10000,5000,7000,12000 + }; + + if(which_s != minmax(0,19,which_s)) + which_s = 0; + spell.item_level = which_s; + spell.value = val[which_s]; + spell.full_name = get_str("magic-names",which_s + 200); + return spell; +} + +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 char*const heal_types[] = { + "Heal Damage","Cure Poison","Cure Disease","Cure Paralysis", + "Uncurse Items","Cure Stoned Character","Raise Dead","Resurrection","Cure Dumbfounding" + }; + if(type == eShopItemType::EMPTY) return; + if(type == eShopItemType::ITEM) return; + size_t i = firstEmpty(); + if(i >= items.size()) return; + items[i].type = type; + if(type == eShopItemType::MAGE_SPELL) + items[i].item = store_mage_spells(n); + else if(type == eShopItemType::PRIEST_SPELL) + items[i].item = store_priest_spells(n); + else if(type == eShopItemType::ALCHEMY) + items[i].item = store_alchemy(n); + else { + items[i].item.graphic_num = 109; + items[i].item.full_name = heal_types[int(type) - 700]; + } + if(type == eShopItemType::MAGE_SPELL || type == eShopItemType::PRIEST_SPELL || type == eShopItemType::ALCHEMY) + items[i].cost = items[i].item.value; + else items[i].cost = heal_costs[int(type) - 700]; + items[i].cost *= cost_mult[cost_adj]; + items[i].cost /= 10; +} + +cShopItem cShop::getItem(size_t i) const { + return items[i]; +} + +eShopType cShop::getType() const { + return type; +} + +int cShop::getCostAdjust() const { + return cost_adj; +} + +std::string cShop::getName() const { + return name; +} + +void cShop::clearItem(size_t i) { + std::copy(items.begin() + i + 1, items.end(), items.begin() + i); + items.back().type = eShopItemType::EMPTY; +} + +void cShop::clear() { + std::fill(items.begin(), items.end(), cShopItem()); +} diff --git a/osx/classes/shop.hpp b/osx/classes/shop.hpp new file mode 100644 index 00000000..6c330363 --- /dev/null +++ b/osx/classes/shop.hpp @@ -0,0 +1,63 @@ +// +// shop.hpp +// BoE +// +// Created by Celtic Minstrel on 14-12-26. +// +// + +#ifndef BoE_DATA_SHOP_HPP +#define BoE_DATA_SHOP_HPP + +#include +#include +#include "item.h" + +enum class eShopItemType { + EMPTY = 0, + 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, + FOOD = 600, +}; + +struct cShopItem { + eShopItemType type = eShopItemType::EMPTY; + int cost; + cItemRec item; +}; + +class cShop { + std::array items; + int cost_adj; + std::string name; + eShopType type; + size_t firstEmpty(); +public: + cShop(); + cShop(eShopType type, int adj, std::string name); + void addItem(cItemRec item); + void addSpecial(eShopItemType type, int n = 0); + template void addItems(Iter begin, Iter end) { + while(begin != end) addItem(*begin++); + } + size_t size(); + cShopItem getItem(size_t i) const; + eShopType getType() const; + int getCostAdjust() const; + std::string getName() const; + void clearItem(size_t i); + void clear(); +}; + +#endif diff --git a/osx/classes/simpletypes.h b/osx/classes/simpletypes.h index 546a7339..dd6b814c 100644 --- a/osx/classes/simpletypes.h +++ b/osx/classes/simpletypes.h @@ -1035,4 +1035,18 @@ 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, + FOOD = 10, +}; + #endif diff --git a/osx/scenedit/scen.keydlgs.cpp b/osx/scenedit/scen.keydlgs.cpp index 272124b8..74cab19a 100644 --- a/osx/scenedit/scen.keydlgs.cpp +++ b/osx/scenedit/scen.keydlgs.cpp @@ -249,8 +249,7 @@ short choose_text(eStrType list, unsigned short cur_choice, cDialog* parent, con // TODO: Generate a list of special node contexts break; case STRT_SHOP: - // TODO: There are actually a few more shop types than this (like junk shops) - strings = {"Items", "Mage Spells", "Priest Spells", "Alchemy", "Healing"}; + strings = {"Items", "Mage Spells", "Priest Spells", "Alchemy", "Healing", "Magic Shop: Junk", "Magic Shop: Lousy", "Magic Shop: So-so", "Magic Shop: Good", "Magic Shop: Great"}; break; case STRT_COST_ADJ: strings = {"Extremely Cheap", "Very Reasonable", "Pretty Average", "Somewhat Pricey", "Expensive", "Exorbitant", "Utterly Ridiculous"}; @@ -612,11 +611,11 @@ static bool edit_spec_enc_value(cDialog& me, std::string item_hit, node_stack_t& } if(btn == '#') { // TODO: Enumify the shop types - switch(me["x1b"].getTextAsNum()) { - case 0: btn = 'i'; break; - case 1: btn = 'A'; break; - case 2: btn = 'P'; break; - case 3: btn = 'a'; break; + switch(eShopType(me["x1b"].getTextAsNum())) { + case eShopType::ITEMS: btn = 'i'; break; + case eShopType::MAGE: btn = 'A'; break; + case eShopType::PRIEST: btn = 'P'; break; + case eShopType::ALCHEMY: btn = 'a'; break; } } short val = me[field].getTextAsNum(), mode = (btn == 'S' || btn == '$') ? 0 : edit_stack.top().mode, store; diff --git a/osx/tools/graphtool.cpp b/osx/tools/graphtool.cpp index 7f40b1f1..e1a79141 100644 --- a/osx/tools/graphtool.cpp +++ b/osx/tools/graphtool.cpp @@ -1002,7 +1002,7 @@ static void frame_shape(sf::RenderTarget& target, sf::Shape& shape, int x, int y shape.setOutlineColor(colour); shape.setFillColor(sf::Color::Transparent); // TODO: Determine the correct outline value; should be one pixel, not sure if it should be negative - shape.setOutlineThickness(1.0); + shape.setOutlineThickness(-1.0); target.draw(shape); }