1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-25 22:42:04 +02:00

* server sends confirmation (given later to player interface) after applying request (will be needed for AI)

* created new package for injuring multiple units - needed for area spells (not tested)
* proper screen updating on garrison change
* spell effects will be removed when they time out
* Corpse (Skeleton) will be accessible from all directions
* new objects supported:
- Corpse
- Lean To
- Wagon
- Warrior's Tomb

* several minor improvements
This commit is contained in:
Michał W. Urbańczyk
2009-04-16 00:28:54 +00:00
parent f9ae91d88c
commit d80afb1902
20 changed files with 576 additions and 180 deletions

View File

@@ -55,16 +55,16 @@ CondSh<BattleResult *> battleResult(NULL);
class CBaseForGHApply
{
public:
virtual void applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const =0;
virtual bool applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const =0;
};
template <typename T> class CApplyOnGH : public CBaseForGHApply
{
public:
void applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const
bool applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const
{
T *ptr = static_cast<T*>(pack);
ptr->c = c;
ptr->applyGh(gh);
return ptr->applyGh(gh);
}
};
@@ -484,17 +484,32 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
{
while(!end2)
{
c >> pack;
tlog5 << "Received client message of type " << typeid(*pack).name() << std::endl;
CBaseForGHApply *apply = applier->apps[typeList.getTypeID(pack)];
{
boost::unique_lock<boost::mutex> lock(*c.rmx);
c >> pack; //get the package
tlog5 << "Received client message of type " << typeid(*pack).name() << std::endl;
}
int packType = typeList.getTypeID(pack); //get the id of type
CBaseForGHApply *apply = applier->apps[packType]; //and appropriae applier object
if(apply)
{
apply->applyOnGH(this,&c,pack);
tlog5 << "Message successfully applied!\n";
bool result = apply->applyOnGH(this,&c,pack);
tlog5 << "Message successfully applied (result=" << result << ")!\n";
//send confirmation that we've applied the package
PackageApplied applied;
applied.result = result;
applied.packType = packType;
{
boost::unique_lock<boost::mutex> lock(*c.wmx);
c << &applied;
}
}
else
{
tlog5 << "Message cannot be applied, cannot find applier!\n";
tlog1 << "Message cannot be applied, cannot find applier (unregistered type)!\n";
}
delete pack;
pack = NULL;
@@ -759,6 +774,7 @@ void CGameHandler::run(bool resume)
{
YourTurn yt;
yt.player = i->first;
boost::unique_lock<boost::mutex> lock(*connections[i->first]->wmx);
*connections[i->first] << &yt;
}
@@ -1063,11 +1079,19 @@ void CGameHandler::setBlockVis(int objid, bool bv)
SetObjectProperty sop(objid,2,bv);
sendAndApply(&sop);
}
void CGameHandler::removeObject(int objid)
bool CGameHandler::removeObject( int objid )
{
if(!getObj(objid))
{
tlog1 << "Something wrong, that object already has been removed or hasn't existed!\n";
return false;
}
RemoveObject ro;
ro.id = objid;
sendAndApply(&ro);
return true;
}
void CGameHandler::setAmount(int objid, ui32 val)
@@ -1076,7 +1100,7 @@ void CGameHandler::setAmount(int objid, ui32 val)
sendAndApply(&sop);
}
void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker)
bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*/ )
{
bool blockvis = false;
const CGHeroInstance *h = getHero(hid);
@@ -1085,7 +1109,7 @@ void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker)
)
{
tlog1 << "Illegal call to move hero!\n";
return;
return false;
}
tlog5 << "Player " <<int(asker) << " wants to move hero "<< hid << " from "<< h->pos << " to " << dst << std::endl;
@@ -1109,7 +1133,7 @@ void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker)
{
tlog2 << "Cannot move hero, destination tile is blocked!\n";
sendAndApply(&tmh);
return;
return false;
}
//checks for standard movement
@@ -1121,7 +1145,7 @@ void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker)
{
tlog2 << "Cannot move hero, not enough move points or tiles are not neighbouring!\n";
sendAndApply(&tmh);
return;
return false;
}
//check if there is blocking visitable object
@@ -1148,7 +1172,7 @@ void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker)
}
}
tlog5 << "Blocking visit at " << hmpos << std::endl;
return;
return true;
}
else //normal move
{
@@ -1169,6 +1193,7 @@ void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker)
}
}
tlog5 << "Movement end!\n";
return true;
}
else //instant move - teleportation
{
@@ -1177,16 +1202,17 @@ void CGameHandler::moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker)
if(obj->ID==HEROI_TYPE)
{
if(obj->tempOwner==h->tempOwner)
return;//TODO: exchange
return true;//TODO: exchange
//TODO: check for ally
CGHeroInstance *dh = static_cast<CGHeroInstance *>(obj);
startBattleI(&h->army,&dh->army,dst,h,dh,0);
return;
return true;
}
}
tmh.result = instant+1;
getTilesInRange(tmh.fowRevealed,h->getSightCenter()+(tmh.end-tmh.start),h->getSightRadious(),h->tempOwner,1);
sendAndApply(&tmh);
return true;
}
}
void CGameHandler::setOwner(int objid, ui8 owner)
@@ -1452,7 +1478,7 @@ void CGameHandler::close()
//exit(0);
}
void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, si32 val)
bool CGameHandler::arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, si32 val )
{
CArmedInstance *s1 = static_cast<CArmedInstance*>(gs->map->objects[id1]),
*s2 = static_cast<CArmedInstance*>(gs->map->objects[id2]);
@@ -1462,7 +1488,7 @@ void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, s
if(!isAllowedExchange(id1,id2))
{
complain("Cannot exchange stacks between these two objects!\n");
return;
return false;
}
if(what==1) //swap
@@ -1480,7 +1506,7 @@ void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, s
if(S1.slots[p1].first != S2.slots[p2].first) //not same creature
{
complain("Cannot merge different creatures stacks!");
return;
return false;
}
S2.slots[p2].second += S1.slots[p1].second;
@@ -1492,7 +1518,7 @@ void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, s
if((!vstd::contains(S1.slots,p1) && complain("no creatures to split"))
|| (val<1 && complain("no creatures to split")) )
{
return;
return false;
}
@@ -1503,7 +1529,7 @@ void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, s
|| (S2.slots[p2].first != S1.slots[p1].first && complain("Cannot rebalance different creatures stacks!"))
)
{
return;
return false;
}
S2.slots[p2].second = val;
@@ -1514,7 +1540,7 @@ void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, s
if(S1.slots[p1].second < val)//not enough creatures
{
complain("Cannot split that stack, not enough creatures!");
return;
return false;
}
S2.slots[p2].first = S1.slots[p1].first;
S2.slots[p2].second = val;
@@ -1529,7 +1555,7 @@ void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, s
)
{
complain("Cannot take the last stack!");
return; //leave without applying changes to garrison
return false; //leave without applying changes to garrison
}
//apply changes
@@ -1538,6 +1564,7 @@ void CGameHandler::arrangeStacks(si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, s
if(s1 != s2)
sg.garrs[id2] = S2;
sendAndApply(&sg);
return true;
}
int CGameHandler::getPlayerAt( CConnection *c ) const
@@ -1564,21 +1591,22 @@ int CGameHandler::getPlayerAt( CConnection *c ) const
}
}
void CGameHandler::disbandCreature(si32 id, ui8 pos)
bool CGameHandler::disbandCreature( si32 id, ui8 pos )
{
CArmedInstance *s1 = static_cast<CArmedInstance*>(gs->map->objects[id]);
if(!vstd::contains(s1->army.slots,pos))
{
complain("Illegal call to disbandCreature - no such stack in army!");
return;
return false;
}
s1->army.slots.erase(pos);
SetGarrisons sg;
sg.garrs[id] = s1->army;
sendAndApply(&sg);
return true;
}
void CGameHandler::buildStructure(si32 tid, si32 bid)
bool CGameHandler::buildStructure( si32 tid, si32 bid )
{
CGTownInstance * t = static_cast<CGTownInstance*>(gs->map->objects[tid]);
CBuilding * b = VLC->buildh->buildings[t->subID][bid];
@@ -1586,7 +1614,7 @@ void CGameHandler::buildStructure(si32 tid, si32 bid)
if(gs->canBuildStructure(t,bid) != 7)
{
complain("Cannot build that building!");
return;
return false;
}
NewStructures ns;
@@ -1625,6 +1653,8 @@ void CGameHandler::buildStructure(si32 tid, si32 bid)
if(t->garrisonHero)
giveSpells(t,t->garrisonHero);
}
return true;
}
void CGameHandler::sendMessageToAll( const std::string &message )
@@ -1634,7 +1664,7 @@ void CGameHandler::sendMessageToAll( const std::string &message )
sendToAllClients(&sm);
}
void CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram )
bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram )
{
si32 ser = -1;
CGTownInstance * t = static_cast<CGTownInstance*>(gs->map->objects[objid]);
@@ -1654,11 +1684,13 @@ void CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram )
}
int slot = t->army.getSlotFor(crid);
if(!found || //no such creature
cram > VLC->creh->creatures[crid].maxAmount(gs->getPlayer(t->tempOwner)->resources) || //lack of resources
cram<=0 ||
slot<0 )
return;
if(!found && complain("Cannot recruit: no such creatures!")
|| cram > VLC->creh->creatures[crid].maxAmount(gs->getPlayer(t->tempOwner)->resources) && complain("Cannot recruit: lack of resources!")
|| cram<=0 && complain("Cannot recruit: cram <= 0!")
|| slot<0 && complain("Cannot recruit: no available slot!"))
{
return false;
}
//recruit
SetResources sr;
@@ -1684,9 +1716,10 @@ void CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram )
sendAndApply(&sr);
sendAndApply(&sac);
sendAndApply(&sg);
return true;
}
void CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID )
bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID )
{
CArmedInstance *obj = static_cast<CArmedInstance*>(gs->map->objects[objid]);
UpgradeInfo ui = gs->getUpgradeInfo(obj,pos);
@@ -1694,8 +1727,10 @@ void CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID )
int crQuantity = obj->army.slots[pos].second;
//check if upgrade is possible
if(ui.oldID<0 || !vstd::contains(ui.newID,upgID))
return;
if((ui.oldID<0 || !vstd::contains(ui.newID,upgID)) && complain("That upgrade is not possible!"))
{
return false;
}
//check if player has enough resources
for(int i=0;i<ui.cost.size();i++)
@@ -1703,7 +1738,10 @@ void CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID )
for (std::set<std::pair<int,int> >::iterator j=ui.cost[i].begin(); j!=ui.cost[i].end(); j++)
{
if(gs->getPlayer(player)->resources[j->first] < j->second*crQuantity)
return;
{
complain("Cannot upgrade, not enough resources!");
return false;
}
}
}
@@ -1725,9 +1763,10 @@ void CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID )
sg.garrs[objid] = obj->army;
sg.garrs[objid].slots[pos].first = upgID;
sendAndApply(&sg);
return true;
}
void CGameHandler::garrisonSwap(si32 tid)
bool CGameHandler::garrisonSwap( si32 tid )
{
CGTownInstance *town = gs->getTown(tid);
if(!town->garrisonHero && town->visitingHero) //visiting => garrison, merge armies
@@ -1737,7 +1776,10 @@ void CGameHandler::garrisonSwap(si32 tid)
{
int pos = csn.getSlotFor(cso.slots.begin()->second.first);
if(pos<0)
return;
{
complain("Cannot make garrison swap, not enough free slots!");
return false;
}
if(csn.slots.find(pos)!=csn.slots.end()) //add creatures to the existing stack
{
csn.slots[pos].second += cso.slots.begin()->second.second;
@@ -1759,6 +1801,7 @@ void CGameHandler::garrisonSwap(si32 tid)
intown.visiting = -1;
intown.garrison = town->visitingHero->id;
sendAndApply(&intown);
return true;
}
else if (town->garrisonHero && !town->visitingHero) //move hero out of the garrison
{
@@ -1766,7 +1809,7 @@ void CGameHandler::garrisonSwap(si32 tid)
if(getHeroCount(town->garrisonHero->tempOwner,true) >= 8)
{
complain("Cannot move hero out of the garrison, there are already 8 wandering heroes!");
return;
return false;
}
SetHeroesInTown intown;
@@ -1779,6 +1822,7 @@ void CGameHandler::garrisonSwap(si32 tid)
SetGarrisons sg;
sg.garrs[tid] = CCreatureSet();
sendAndApply(&sg);
return true;
}
else if (town->garrisonHero && town->visitingHero) //swap visiting and garrison hero
{
@@ -1792,18 +1836,21 @@ void CGameHandler::garrisonSwap(si32 tid)
intown.visiting = town->garrisonHero->id;
sendAndApply(&intown);
sendAndApply(&sg);
return true;
}
else
{
complain("Cannot swap garrison hero!");
return false;
}
}
void CGameHandler::swapArtifacts( si32 hid1, si32 hid2, ui16 slot1, ui16 slot2 )
bool CGameHandler::swapArtifacts( si32 hid1, si32 hid2, ui16 slot1, ui16 slot2 )
{
CGHeroInstance *h1 = gs->getHero(hid1), *h2 = gs->getHero(hid2);
if((distance(h1->pos,h2->pos) > 1.0) || (h1->tempOwner != h2->tempOwner))
return;
return false;
const CArtifact *a1 = h1->getArt(slot1),
*a2=h2->getArt(slot2);
@@ -1813,7 +1860,7 @@ void CGameHandler::swapArtifacts( si32 hid1, si32 hid2, ui16 slot1, ui16 slot2 )
{
//artifact doesn't fit dst slot
complain("Cannot swap artifacts!");
return;
return false;
}
@@ -1832,9 +1879,11 @@ void CGameHandler::swapArtifacts( si32 hid1, si32 hid2, ui16 slot1, ui16 slot2 )
sha.setArtAtPos(slot2,h1->getArtAtPos(slot1));
sendAndApply(&sha);
}
return true;
}
void CGameHandler::buyArtifact( ui32 hid, si32 aid )
bool CGameHandler::buyArtifact( ui32 hid, si32 aid )
{
CGHeroInstance *hero = gs->getHero(hid);
CGTownInstance *town = hero->visitedTown;
@@ -1844,29 +1893,32 @@ void CGameHandler::buyArtifact( ui32 hid, si32 aid )
|| getResource(hero->getOwner(),6)<500 && complain("Cannot buy a spellbook, not enough gold!")
|| hero->getArt(17) && complain("Cannot buy a spellbook, hero already has a one!")
)
return;
return false;
giveResource(hero->getOwner(),6,-500);
giveHeroArtifact(0,hid,17);
giveSpells(town,hero);
return true;
}
else if(aid < 7 && aid > 3) //war machine
{
int price = VLC->arth->artifacts[aid].price;
if(vstd::contains(hero->artifWorn,ui16(9+aid)) //hero already has this machine
|| !vstd::contains(town->builtBuildings,si32(16)) //no blackismith
|| gs->getPlayer(hero->getOwner())->resources[6] < price //no gold
|| town->town->warMachine!= aid ) //this machine is not available here (//TODO: support ballista yard in stronghold)
if(vstd::contains(hero->artifWorn,ui16(9+aid)) && complain("Hero already has this machine!")
|| !vstd::contains(town->builtBuildings,si32(16)) && complain("No blackismith!")
|| gs->getPlayer(hero->getOwner())->resources[6] < price && complain("Not enough gold!") //no gold
|| town->town->warMachine!= aid && complain("This machine is unavailale here!") ) //TODO: ballista yard in Stronghold
{
return;
return false;
}
giveResource(hero->getOwner(),6,-price);
giveHeroArtifact(aid,hid,9+aid);
return true;
}
return false;
}
void CGameHandler::tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 )
bool CGameHandler::tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 )
{
val = std::min(si32(val),gs->getPlayer(player)->resources[id1]);
double uzysk = (double)gs->resVals[id1] * val * gs->getMarketEfficiency(player);
@@ -1880,22 +1932,25 @@ void CGameHandler::tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 )
sr.resid = id2;
sr.val = gs->getPlayer(player)->resources[id2] + (int)uzysk;
sendAndApply(&sr);
return true;
}
void CGameHandler::setFormation( si32 hid, ui8 formation )
bool CGameHandler::setFormation( si32 hid, ui8 formation )
{
gs->getHero(hid)->army.formation = formation;
return true;
}
void CGameHandler::hireHero( ui32 tid, ui8 hid )
bool CGameHandler::hireHero( ui32 tid, ui8 hid )
{
CGTownInstance *t = gs->getTown(tid);
if(!vstd::contains(t->builtBuildings,5) //no tavern in the town
|| gs->getPlayer(t->tempOwner)->resources[6]<2500 //not enough gold
|| t->visitingHero //there is visiting hero - no place
if(!vstd::contains(t->builtBuildings,5) && complain("No tavern!")
|| gs->getPlayer(t->tempOwner)->resources[6]<2500 && complain("Not enough gold for buying hero!")
|| t->visitingHero && complain("There is visiting hero - no place!")
|| getHeroCount(t->tempOwner,false) >= 8 && complain("Cannot hire hero, only 8 wandering heroes are allowed!")
)
return;
return false;
CGHeroInstance *nh = gs->getPlayer(t->tempOwner)->availableHeroes[hid];
HeroRecruited hr;
@@ -1919,9 +1974,10 @@ void CGameHandler::hireHero( ui32 tid, ui8 hid )
sendAndApply(&sr);
giveSpells(t,nh);
return true;
}
void CGameHandler::queryReply( ui32 qid, ui32 answer )
bool CGameHandler::queryReply( ui32 qid, ui32 answer )
{
boost::unique_lock<boost::recursive_mutex> lock(gsm);
if(vstd::contains(callbacks,qid))
@@ -1941,11 +1997,14 @@ void CGameHandler::queryReply( ui32 qid, ui32 answer )
else
{
tlog1 << "Unknown query reply...\n";
return false;
}
return true;
}
void CGameHandler::makeBattleAction( BattleAction &ba )
bool CGameHandler::makeBattleAction( BattleAction &ba )
{
bool ok = true;
switch(ba.actionType)
{
case 2: //walk
@@ -1985,11 +2044,13 @@ void CGameHandler::makeBattleAction( BattleAction &ba )
if(curStack->position != ba.destinationTile) //we wasn't able to reach destination tile
{
tlog3<<"We cannot move this stack to its destination "<<curStack->creature->namePl<<std::endl;
ok = false;
}
if(!stackAtEnd)
{
tlog3 << "There is no stack on " << ba.additionalInfo << " tile (no attack)!";
ok = false;
break;
}
@@ -2010,7 +2071,7 @@ void CGameHandler::makeBattleAction( BattleAction &ba )
{
tlog3 << "Attack cannot be performed!";
sendAndApply(&EndAction());
break;
ok = false;
}
//attack
@@ -2080,6 +2141,7 @@ void CGameHandler::makeBattleAction( BattleAction &ba )
}
}
battleMadeAction.setn(true);
return ok;
}
void CGameHandler::playerMessage( ui8 player, const std::string &message )
@@ -2182,7 +2244,7 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
}
}
void CGameHandler::makeCustomAction( BattleAction &ba )
bool CGameHandler::makeCustomAction( BattleAction &ba )
{
switch(ba.actionType)
{
@@ -2192,12 +2254,12 @@ void CGameHandler::makeCustomAction( BattleAction &ba )
if(!h)
{
tlog2 << "Wrong caster!\n";
return;
return false;
}
if(ba.additionalInfo >= VLC->spellh->spells.size())
{
tlog2 << "Wrong spell id (" << ba.additionalInfo << ")!\n";
return;
return false;
}
CSpell *s = &VLC->spellh->spells[ba.additionalInfo];
@@ -2210,7 +2272,7 @@ void CGameHandler::makeCustomAction( BattleAction &ba )
)
{
tlog2 << "Spell cannot be casted!\n";
return;
return false;
}
sendAndApply(&StartAction(ba)); //start spell casting
@@ -2343,8 +2405,10 @@ void CGameHandler::makeCustomAction( BattleAction &ba )
}
}
sendAndApply(&EndAction());
return true;
}
}
return false;
}
void CGameHandler::handleTimeEvents()