Files
oboe/src/scenario/shop.cpp
Celtic Minstrel 7b93726383 Replace 4-character constants with enums
This covers only the places where they were used to indicate
a preset selection in constructors.

The usage in qdpict where they're actually passed to the Resource Manager,
as well as the 4-character constants representing file types and creator
codes, are still present.
2020-02-21 00:16:58 -05:00

331 lines
9.4 KiB
C++

//
// shop.cpp
// BoE
//
// Created by Celtic Minstrel on 14-12-27.
//
//
#include "shop.hpp"
#include <numeric>
#include <iostream>
#include "mathutil.hpp"
#include "utility.hpp"
std::map<eSkill,short> skill_cost = {
{eSkill::STRENGTH,3}, {eSkill::DEXTERITY,3}, {eSkill::INTELLIGENCE,3},
{eSkill::EDGED_WEAPONS,2}, {eSkill::BASHING_WEAPONS,2}, {eSkill::POLE_WEAPONS,2},
{eSkill::THROWN_MISSILES,1}, {eSkill::ARCHERY,2}, {eSkill::DEFENSE,2},
{eSkill::MAGE_SPELLS,6}, {eSkill::PRIEST_SPELLS,5}, {eSkill::MAGE_LORE,1},
{eSkill::ALCHEMY,2}, {eSkill::ITEM_LORE,4}, {eSkill::DISARM_TRAPS,2},
{eSkill::LOCKPICKING,1}, {eSkill::ASSASSINATION,4}, {eSkill::POISON,2},
{eSkill::LUCK,5},
};
std::map<eSkill,short> skill_max = {
{eSkill::STRENGTH,20}, {eSkill::DEXTERITY,20}, {eSkill::INTELLIGENCE,20},
{eSkill::EDGED_WEAPONS,20}, {eSkill::BASHING_WEAPONS,20}, {eSkill::POLE_WEAPONS,20},
{eSkill::THROWN_MISSILES,20}, {eSkill::ARCHERY,20}, {eSkill::DEFENSE,20},
{eSkill::MAGE_SPELLS,7}, {eSkill::PRIEST_SPELLS,7}, {eSkill::MAGE_LORE,20},
{eSkill::ALCHEMY,20}, {eSkill::ITEM_LORE,10}, {eSkill::DISARM_TRAPS,20},
{eSkill::LOCKPICKING,20}, {eSkill::ASSASSINATION,20}, {eSkill::POISON,20},
{eSkill::LUCK,20},
};
std::map<eSkill,short> skill_g_cost = {
{eSkill::STRENGTH,50}, {eSkill::DEXTERITY,50}, {eSkill::INTELLIGENCE,50},
{eSkill::EDGED_WEAPONS,40}, {eSkill::BASHING_WEAPONS,40}, {eSkill::POLE_WEAPONS,40},
{eSkill::THROWN_MISSILES,30}, {eSkill::ARCHERY,50}, {eSkill::DEFENSE,40},
{eSkill::MAGE_SPELLS,250}, {eSkill::PRIEST_SPELLS,250}, {eSkill::MAGE_LORE,25},
{eSkill::ALCHEMY,100}, {eSkill::ITEM_LORE,200}, {eSkill::DISARM_TRAPS,30},
{eSkill::LOCKPICKING,20}, {eSkill::ASSASSINATION,100}, {eSkill::POISON,80},
{eSkill::LUCK,0},
};
// The index here is the skill's level, not the skill itself; thus 20 is the max index since no skill can go above 20.
short skill_bonus[21] = {
-3,-3,-2,-1,0,0,1,1,1,2,
2,2,3,3,3,3,4,4,4,5,5};
static long cost_mult[7] = {5,7,10,13,16,20,25};
cShop::cShop() {}
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(std::string name) : cShop(eShopType::NORMAL, eShopPrompt::SHOPPING, 0, 0, name) {}
cShop::cShop(eShopPreset preset) {
const short loot_index[10] = {1,1,1,1,2,2,2,3,3,4};
if(preset == SHOP_JUNK) {
type = eShopType::RANDOM;
prompt = eShopPrompt::SHOPPING;
face = 0;
name = "Magic Shop";
for(int i = 0; i < 10; i++)
addSpecial(eShopItemType::TREASURE, loot_index[i]);
} else if(preset == SHOP_HEALING) {
type = eShopType::ALLOW_DEAD;
prompt = eShopPrompt::HEALING;
face = 41;
name = "Healing";
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++) {
if(items[i].type == eShopItemType::EMPTY)
return i;
}
return items.size();
}
size_t cShop::size() const {
return items.size();
}
size_t cShop::num_items() const {
return std::count_if(items.begin(), items.end(), [](const cShopItem& item) {
return item.type != eShopItemType::EMPTY;
});
}
void cShop::addItem(size_t n, cItem item, size_t quantity, int chance) {
size_t i = firstEmpty();
if(i >= items.size()) {
items.resize(i + 1);
}
if(item.variety == eItemType::NO_ITEM) return;
items[i].type = chance == 100 ? eShopItemType::ITEM : eShopItemType::OPT_ITEM;
items[i].item = item;
items[i].quantity = quantity;
items[i].index = n;
if(chance < 100)
items[i].quantity = min(999,quantity) + chance * 1000;
}
void cShop::refreshItems(std::vector<cItem>& fromList) {
// The purpose of this is to load in the actual item data from the scenario list
for(size_t i = 0; i < items.size(); i++) {
if(items[i].type == eShopItemType::ITEM || items[i].type == eShopItemType::OPT_ITEM)
items[i].item = fromList[items[i].index];
// Prevent shops from selling unidentified items
items[i].item.ident = true;
}
}
static cItem store_mage_spells(short which_s) {
cItem spell(ITEM_SPELL);
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 cItem store_priest_spells(short which_s) {
cItem spell(ITEM_SPELL);
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 cItem store_alchemy(short which_s) {
cItem spell(ITEM_SPELL);
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) {
if(type == eShopItemType::EMPTY || type == eShopItemType::CALL_SPECIAL) return;
if(type == eShopItemType::OPT_ITEM || type == eShopItemType::ITEM) return;
replaceSpecial(firstEmpty(), type, n);
}
void cShop::replaceSpecial(size_t i, eShopItemType type, int n) {
// TODO: Make this a std::map instead
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 Acid","Cure Paralysis",
"Uncurse Items","Cure Stoned Character","Raise Dead","Resurrection","Cure Dumbfounding"
};
if(type == eShopItemType::EMPTY) return;
if(type == eShopItemType::ITEM) return;
if(type == eShopItemType::OPT_ITEM) return;
if(type == eShopItemType::CALL_SPECIAL) return;
if(i >= items.size()) {
items.resize(i + 1);
}
items[i].type = type;
if(type >= eShopItemType::HEAL_WOUNDS)
items[i].index = int(type) - int(eShopItemType::HEAL_WOUNDS);
else items[i].index = n;
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 if(type == eShopItemType::SKILL) {
items[i].item.graphic_num = 108;
items[i].item.item_level = n;
items[i].item.full_name = get_str("skills", n * 2 + 1);
} else if(type == eShopItemType::TREASURE) {
items[i].item.graphic_num = 17;
items[i].item.item_level = n;
items[i].item.full_name = "Treasure (type " + std::to_string(n) + ")";
} else if(type == eShopItemType::CLASS) {
items[i].item.graphic_num = 105;
items[i].item.special_class = n;
items[i].item.full_name = "Item of special class " + std::to_string(n);
} else {
items[i].item.graphic_num = 109;
items[i].item.full_name = heal_types[items[i].index];
}
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[items[i].index];
items[i].quantity = 0;
}
void cShop::addSpecial(std::string name, std::string descr, pic_num_t pic, int node, int cost, int quantity) {
size_t i = firstEmpty();
if(i >= items.size()) {
items.resize(i + 1);
}
items[i].type = eShopItemType::CALL_SPECIAL;
items[i].quantity = quantity;
items[i].item.full_name = name;
items[i].item.desc = descr;
items[i].item.graphic_num = pic;
items[i].item.item_level = node;
items[i].item.value = cost;
}
cShopItem cShop::getItem(size_t i) const {
if(i >= items.size()) return cShopItem();
return items[i];
}
eShopType cShop::getType() const {
return type;
}
int cShop::getCostAdjust() const {
return cost_adj;
}
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::setFace(pic_num_t pic) {
face = pic;
}
void cShop::setType(eShopType t) {
type = t;
}
void cShop::setPrompt(eShopPrompt p) {
prompt = p;
}
void cShop::takeOne(size_t i) {
if(items[i].quantity == 1) {
items[i].type = eShopItemType::EMPTY;
} else if(items[i].quantity > 0)
items[i].quantity--;
}
void cShop::replaceItem(size_t i, cShopItem newItem) {
if(i >= items.size()) {
items.resize(i + 1);
}
items[i] = newItem;
}
void cShop::clearItem(size_t i) {
items.erase(items.begin() + i);
}
void cShop::clear() {
items.clear();
}
int cShopItem::getCost(int adj) {
int cost = item.value;
if(item.charges > 0)
cost *= item.charges;
cost *= cost_mult[adj];
cost /= 10;
return cost;
}