1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Merge pull request #385 from Chocimier/altar

Fixed "Altar of Sacrifice only sacrifices creatures one kind at a time"
* https://bugs.vcmi.eu/view.php?id=2607
This commit is contained in:
Alexander Shishkin 2017-10-28 14:04:34 +03:00 committed by GitHub
commit fd4ecbd40b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 136 additions and 46 deletions

View File

@ -212,7 +212,19 @@ void CCallback::buyArtifact(const CGHeroInstance *hero, ArtifactID aid)
sendRequest(&pack);
}
void CCallback::trade(const CGObjectInstance *market, EMarketMode::EMarketMode mode, int id1, int id2, int val1, const CGHeroInstance *hero)
void CCallback::trade(const CGObjectInstance * market, EMarketMode::EMarketMode mode, ui32 id1, ui32 id2, ui32 val1, const CGHeroInstance * hero)
{
TradeOnMarketplace pack;
pack.market = market;
pack.hero = hero;
pack.mode = mode;
pack.r1 = {id1};
pack.r2 = {id2};
pack.val = {val1};
sendRequest(&pack);
}
void CCallback::trade(const CGObjectInstance * market, EMarketMode::EMarketMode mode, const std::vector<ui32> & id1, const std::vector<ui32> & id2, const std::vector<ui32> & val1, const CGHeroInstance * hero)
{
TradeOnMarketplace pack;
pack.market = market;

View File

@ -56,7 +56,8 @@ public:
virtual bool upgradeCreature(const CArmedInstance *obj, SlotID stackPos, CreatureID newID=CreatureID::NONE)=0; //if newID==-1 then best possible upgrade will be made
virtual void swapGarrisonHero(const CGTownInstance *town)=0;
virtual void trade(const CGObjectInstance *market, EMarketMode::EMarketMode mode, int id1, int id2, int val1, const CGHeroInstance *hero = nullptr)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce
virtual void trade(const CGObjectInstance * market, EMarketMode::EMarketMode mode, ui32 id1, ui32 id2, ui32 val1, const CGHeroInstance * hero = nullptr)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce
virtual void trade(const CGObjectInstance * market, EMarketMode::EMarketMode mode, const std::vector<ui32> & id1, const std::vector<ui32> & id2, const std::vector<ui32> & val1, const CGHeroInstance * hero = nullptr)=0;
virtual int selectionMade(int selection, QueryID queryID) =0;
virtual int sendQueryReply(const JsonNode & reply, QueryID queryID) =0;
@ -138,7 +139,8 @@ public:
void endTurn() override;
void swapGarrisonHero(const CGTownInstance *town) override;
void buyArtifact(const CGHeroInstance *hero, ArtifactID aid) override;
void trade(const CGObjectInstance *market, EMarketMode::EMarketMode mode, int id1, int id2, int val1, const CGHeroInstance *hero = nullptr) override;
void trade(const CGObjectInstance * market, EMarketMode::EMarketMode mode, ui32 id1, ui32 id2, ui32 val1, const CGHeroInstance * hero = nullptr) override;
void trade(const CGObjectInstance * market, EMarketMode::EMarketMode mode, const std::vector<ui32> & id1, const std::vector<ui32> & id2, const std::vector<ui32> & val1, const CGHeroInstance * hero = nullptr) override;
void setFormation(const CGHeroInstance * hero, bool tight) override;
void recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero) override;
void save(const std::string &fname) override;

View File

@ -1231,13 +1231,20 @@ void CAltarWindow::makeDeal()
blockTrade();
slider->moveTo(0);
std::vector<int> toSacrifice = sacrificedUnits;
for (int i = 0; i < toSacrifice.size(); i++)
std::vector<ui32> ids;
std::vector<ui32> toSacrifice;
for(int i = 0; i < sacrificedUnits.size(); i++)
{
if(toSacrifice[i])
LOCPLINT->cb->trade(market->o, mode, i, 0, toSacrifice[i], hero);
if(sacrificedUnits[i])
{
ids.push_back(i);
toSacrifice.push_back(sacrificedUnits[i]);
}
}
LOCPLINT->cb->trade(market->o, mode, ids, {}, toSacrifice, hero);
for(int& val : sacrificedUnits)
val = 0;
@ -1249,10 +1256,13 @@ void CAltarWindow::makeDeal()
}
else
{
std::vector<ui32> positions;
for(const CArtifactInstance *art : arts->artifactsOnAltar) //sacrifice each artifact on the list
{
LOCPLINT->cb->trade(market->o, mode, hero->getArtPos(art), -1, 1, hero);
positions.push_back(hero->getArtPos(art));
}
LOCPLINT->cb->trade(market->o, mode, positions, {}, {}, hero);
arts->artifactsOnAltar.clear();
for(CTradeableItem *t : items[0])
@ -1440,7 +1450,7 @@ void CAltarWindow::updateRight(CTradeableItem *toUpdate)
{
int val = sacrificedUnits[toUpdate->serial];
toUpdate->setType(val ? CREATURE : CREATURE_PLACEHOLDER);
toUpdate->subtitle = val ? boost::str(boost::format(CGI->generaltexth->allTexts[122]) % boost::lexical_cast<std::string>(val * expPerUnit[toUpdate->serial])) : ""; //%s exp
toUpdate->subtitle = val ? boost::str(boost::format(CGI->generaltexth->allTexts[122]) % boost::lexical_cast<std::string>(hero->calculateXp(val * expPerUnit[toUpdate->serial]))) : ""; //%s exp
}
int CAltarWindow::firstFreeSlot()
@ -1485,6 +1495,7 @@ void CAltarWindow::showAll(SDL_Surface * to)
int dmp, val;
market->getOffer(arts->commonInfo->src.art->artType->id, 0, dmp, val, EMarketMode::ARTIFACT_EXP);
val = hero->calculateXp(val);
printAtMiddleLoc(boost::lexical_cast<std::string>(val), 304, 498, FONT_SMALL, Colors::WHITE, to);
}
}
@ -1510,6 +1521,7 @@ bool CAltarWindow::putOnAltar(CTradeableItem* altarSlot, const CArtifactInstance
int dmp, val;
market->getOffer(art->artType->id, 0, dmp, val, EMarketMode::ARTIFACT_EXP);
val = hero->calculateXp(val);
arts->artifactsOnAltar.insert(art);
altarSlot->setArtInstance(art);

View File

@ -2199,14 +2199,14 @@ struct BuyArtifact : public CPackForServer
struct TradeOnMarketplace : public CPackForServer
{
TradeOnMarketplace()
:market(nullptr), hero(nullptr), mode(EMarketMode::RESOURCE_RESOURCE), r1(0), r2(0), val(0)
:market(nullptr), hero(nullptr), mode(EMarketMode::RESOURCE_RESOURCE)
{};
const CGObjectInstance *market; //todo: replace with ObjectInstanceID
const CGHeroInstance *hero; //needed when trading artifacts / creatures
EMarketMode::EMarketMode mode;
ui32 r1, r2; //mode 0: r1 - sold resource, r2 - bought res (exception: when sacrificing art r1 is art id [todo: make r2 preferred slot?]
ui32 val; //units of sold resource
std::vector<ui32> r1, r2; //mode 0: r1 - sold resource, r2 - bought res (exception: when sacrificing art r1 is art id [todo: make r2 preferred slot?]
std::vector<ui32> val; //units of sold resource
bool applyGh(CGameHandler *gh);
template <typename Handler> void serialize(Handler &h, const int version)

View File

@ -5420,50 +5420,89 @@ void CGameHandler::visitObjectOnTile(const TerrainTile &t, const CGHeroInstance
}
}
bool CGameHandler::sacrificeCreatures(const IMarket *market, const CGHeroInstance *hero, SlotID slot, ui32 count)
bool CGameHandler::sacrificeCreatures(const IMarket * market, const CGHeroInstance * hero, const std::vector<SlotID> & slot, const std::vector<ui32> & count)
{
if (!hero)
COMPLAIN_RET("You need hero to sacrifice creature!");
int oldCount = hero->getStackCount(slot);
int expSum = 0;
auto finish = [this, &hero, &expSum]()
{
changePrimSkill(hero, PrimarySkill::EXPERIENCE, hero->calculateXp(expSum));
};
if (oldCount < count)
COMPLAIN_RET("Not enough creatures to sacrifice!")
else if (oldCount == count && hero->stacksCount() == 1 && hero->needsLastStack())
COMPLAIN_RET("Cannot sacrifice last creature!");
for(int i = 0; i < slot.size(); ++i)
{
int oldCount = hero->getStackCount(slot[i]);
int crid = hero->getStack(slot).type->idNumber;
if(oldCount < count[i])
{
finish();
COMPLAIN_RET("Not enough creatures to sacrifice!")
}
else if(oldCount == count[i] && hero->stacksCount() == 1 && hero->needsLastStack())
{
finish();
COMPLAIN_RET("Cannot sacrifice last creature!");
}
changeStackCount(StackLocation(hero, slot), -count);
int crid = hero->getStack(slot[i]).type->idNumber;
int dump, exp;
market->getOffer(crid, 0, dump, exp, EMarketMode::CREATURE_EXP);
exp *= count;
changePrimSkill(hero, PrimarySkill::EXPERIENCE, hero->calculateXp(exp));
changeStackCount(StackLocation(hero, slot[i]), -count[i]);
int dump, exp;
market->getOffer(crid, 0, dump, exp, EMarketMode::CREATURE_EXP);
exp *= count[i];
expSum += exp;
}
finish();
return true;
}
bool CGameHandler::sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, ArtifactPosition slot)
bool CGameHandler::sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, const std::vector<ArtifactPosition> & slot)
{
if (!hero)
COMPLAIN_RET("You need hero to sacrifice artifact!");
ArtifactLocation al(hero, slot);
const CArtifactInstance *a = al.getArt();
int expSum = 0;
auto finish = [this, &hero, &expSum]()
{
changePrimSkill(hero, PrimarySkill::EXPERIENCE, hero->calculateXp(expSum));
};
COMPLAIN_RET_FALSE_IF(!a,"Cannot find artifact to sacrifice!");
for(int i = 0; i < slot.size(); ++i)
{
ArtifactLocation al(hero, slot[i]);
const CArtifactInstance * a = al.getArt();
int dmp, expToGive;
const CArtifactInstance * art = hero->getArt(slot);
COMPLAIN_RET_FALSE_IF((!art), "No artifact at position to sacrifice!");
if(!a)
{
finish();
COMPLAIN_RET("Cannot find artifact to sacrifice!");
}
si32 typId = art->artType->id;
const CArtifactInstance * art = hero->getArt(slot[i]);
m->getOffer(typId, 0, dmp, expToGive, EMarketMode::ARTIFACT_EXP);
if(!art)
{
finish();
COMPLAIN_RET("No artifact at position to sacrifice!");
}
si32 typId = art->artType->id;
int dmp, expToGive;
m->getOffer(typId, 0, dmp, expToGive, EMarketMode::ARTIFACT_EXP);
expSum += expToGive;
removeArtifact(al);
}
finish();
removeArtifact(al);
changePrimSkill(hero, PrimarySkill::EXPERIENCE, expToGive);
return true;
}

View File

@ -204,7 +204,7 @@ public:
bool buildBoat( ObjectInstanceID objid );
bool setFormation( ObjectInstanceID hid, ui8 formation );
bool tradeResources(const IMarket *market, ui32 val, PlayerColor player, ui32 id1, ui32 id2);
bool sacrificeCreatures(const IMarket *market, const CGHeroInstance *hero, SlotID slot, ui32 count);
bool sacrificeCreatures(const IMarket * market, const CGHeroInstance * hero, const std::vector<SlotID> & slot, const std::vector<ui32> & count);
bool sendResources(ui32 val, PlayerColor player, Res::ERes r1, PlayerColor r2);
bool sellCreatures(ui32 count, const IMarket *market, const CGHeroInstance * hero, SlotID slot, Res::ERes resourceID);
bool transformInUndead(const IMarket *market, const CGHeroInstance * hero, SlotID slot);
@ -287,7 +287,7 @@ public:
void handleAttackBeforeCasting(BattleAttack *bat);
void handleAfterAttackCasting (const BattleAttack & bat);
void attackCasting(const BattleAttack & bat, Bonus::BonusType attackMode, const CStack * attacker);
bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, ArtifactPosition slot);
bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, const std::vector<ArtifactPosition> & slot);
void spawnWanderingMonsters(CreatureID creatureID);
void handleCheatCode(std::string & cheat, PlayerColor player, const CGHeroInstance * hero, const CGTownInstance * town, bool & cheated);
friend class CVCMIServer;

View File

@ -178,29 +178,54 @@ bool TradeOnMarketplace::applyGh( CGameHandler *gh )
ERROR_IF_NOT(player);
bool result = true;
switch(mode)
{
case EMarketMode::RESOURCE_RESOURCE:
return gh->tradeResources(m, val, player, r1, r2);
for(int i = 0; i < r1.size(); ++i)
result &= gh->tradeResources(m, val[i], player, r1[i], r2[i]);
break;
case EMarketMode::RESOURCE_PLAYER:
return gh->sendResources(val, player, static_cast<Res::ERes>(r1), PlayerColor(r2));
for(int i = 0; i < r1.size(); ++i)
result &= gh->sendResources(val[i], player, static_cast<Res::ERes>(r1[i]), PlayerColor(r2[i]));
break;
case EMarketMode::CREATURE_RESOURCE:
return gh->sellCreatures(val, m, hero, SlotID(r1), static_cast<Res::ERes>(r2));
for(int i = 0; i < r1.size(); ++i)
result &= gh->sellCreatures(val[i], m, hero, SlotID(r1[i]), static_cast<Res::ERes>(r2[i]));
break;
case EMarketMode::RESOURCE_ARTIFACT:
return gh->buyArtifact(m, hero, static_cast<Res::ERes>(r1), ArtifactID(r2));
for(int i = 0; i < r1.size(); ++i)
result &= gh->buyArtifact(m, hero, static_cast<Res::ERes>(r1[i]), ArtifactID(r2[i]));
break;
case EMarketMode::ARTIFACT_RESOURCE:
return gh->sellArtifact(m, hero, ArtifactInstanceID(r1), static_cast<Res::ERes>(r2));
for(int i = 0; i < r1.size(); ++i)
result &= gh->sellArtifact(m, hero, ArtifactInstanceID(r1[i]), static_cast<Res::ERes>(r2[i]));
break;
case EMarketMode::CREATURE_UNDEAD:
return gh->transformInUndead(m, hero, SlotID(r1));
for(int i = 0; i < r1.size(); ++i)
result &= gh->transformInUndead(m, hero, SlotID(r1[i]));
break;
case EMarketMode::RESOURCE_SKILL:
return gh->buySecSkill(m, hero, SecondarySkill(r2));
for(int i = 0; i < r2.size(); ++i)
result &= gh->buySecSkill(m, hero, SecondarySkill(r2[i]));
break;
case EMarketMode::CREATURE_EXP:
return gh->sacrificeCreatures(m, hero, SlotID(r1), val);
{
std::vector<SlotID> slotIDs(r1.begin(), r1.end());
std::vector<ui32> count(val.begin(), val.end());
return gh->sacrificeCreatures(m, hero, slotIDs, count);
}
case EMarketMode::ARTIFACT_EXP:
return gh->sacrificeArtifact(m, hero, ArtifactPosition(r1));
{
std::vector<ArtifactPosition> positions(r1.begin(), r1.end());
return gh->sacrificeArtifact(m, hero, positions);
}
default:
COMPLAIN_AND_RETURN("Unknown exchange mode!");
}
return result;
}
bool SetFormation::applyGh( CGameHandler *gh )