mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Implemented Summon Boat spell.
This commit is contained in:
		| @@ -121,7 +121,7 @@ int CCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) co | ||||
| 		return gs->curB->getSpellCost(sp, caster); | ||||
|  | ||||
| 	//if there is no battle | ||||
| 	return sp->costs[caster->getSpellSchoolLevel(sp)]; | ||||
| 	return caster->getSpellCost(sp); | ||||
| } | ||||
|  | ||||
| int CCallback::estimateSpellDamage(const CSpell * sp) const | ||||
| @@ -954,6 +954,15 @@ si8 CCallback::battleGetStackLuck( int stackID ) | ||||
| 	return gs->curB->Luck( gs->curB->getStack(stackID) ); | ||||
| } | ||||
|  | ||||
| void CCallback::castSpell(const CGHeroInstance *hero, int spellID, const int3 &pos) | ||||
| { | ||||
| 	CastAdvSpell cas; | ||||
| 	cas.hid = hero->id; | ||||
| 	cas.sid = spellID; | ||||
| 	cas.pos = pos; | ||||
| 	sendRequest(&cas); | ||||
| } | ||||
|  | ||||
| InfoAboutTown::InfoAboutTown() | ||||
| { | ||||
| 	tType = NULL; | ||||
|   | ||||
| @@ -128,6 +128,7 @@ public: | ||||
| 	virtual void calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int3 src = int3(-1,-1,-1), int movement = -1) =0; | ||||
| 	virtual void recalculatePaths()=0; //updates main, client pathfinder info (should be called when moving hero is over) | ||||
| 	virtual void dig(const CGObjectInstance *hero)=0;  | ||||
| 	virtual void castSpell(const CGHeroInstance *hero, int spellID, const int3 &pos = int3(-1, -1, -1))=0; //cast adventure map spell | ||||
| 	 | ||||
| 	//map | ||||
| 	virtual std::vector < const CGObjectInstance * > getBlockingObjs(int3 pos)const =0; | ||||
| @@ -227,6 +228,7 @@ public: | ||||
| 	void sendMessage(const std::string &mess); | ||||
| 	void buildBoat(const IShipyard *obj); | ||||
| 	void dig(const CGObjectInstance *hero);  | ||||
| 	void castSpell(const CGHeroInstance *hero, int spellID, const int3 &pos = int3(-1, -1, -1)); | ||||
|  | ||||
| //get info | ||||
| 	bool verifyPath(CPath * path, bool blockSea) const; | ||||
|   | ||||
| @@ -668,7 +668,8 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState) | ||||
| { | ||||
| 	if(!down && mySpell!=-1) | ||||
| 	{ | ||||
| 		int spellCost = owner->myInt->cb->getSpellCost(&CGI->spellh->spells[mySpell], owner->myHero); | ||||
| 		const CSpell *sp = &CGI->spellh->spells[mySpell]; | ||||
| 		int spellCost = owner->myInt->cb->getSpellCost(sp, owner->myHero); | ||||
| 		//we will cast a spell | ||||
| 		if(owner->myInt->battleInt && owner->myInt->cb->battleCanCastSpell() && spellCost <= owner->myHero->mana) //if battle window is open | ||||
| 		{ | ||||
| @@ -676,15 +677,35 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState) | ||||
| 			owner->fexitb(); | ||||
| 			owner->myInt->battleInt->castThisSpell(spell); | ||||
| 		} | ||||
| 		else | ||||
| 		else //adventure spell | ||||
| 		{ | ||||
| 			//insufficient mana | ||||
| 			if(spellCost > owner->myHero->mana) | ||||
| 			{ | ||||
| 				std::vector<SComponent*> comps; | ||||
| 				char msgBuf[500]; | ||||
| 				sprintf(msgBuf, CGI->generaltexth->allTexts[206].c_str(), spellCost, owner->myHero->mana); | ||||
| 				owner->myInt->showInfoDialog(std::string(msgBuf), comps); | ||||
| 				owner->myInt->showInfoDialog(std::string(msgBuf)); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				int spell = mySpell; | ||||
| 				const CGHeroInstance *h = owner->myHero; | ||||
| 				owner->fexitb(); | ||||
|  | ||||
| 				switch(spell) | ||||
| 				{ | ||||
| 				case 0: //summon boat | ||||
| 					{ | ||||
| 						int3 pos = h->bestLocation(); | ||||
| 						if(pos.x < 0) | ||||
| 						{ | ||||
| 							LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[334]); //There is no place to put the boat. | ||||
| 							return; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				LOCPLINT->cb->castSpell(h, spell); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -511,5 +511,11 @@ void CClient::handlePack( CPack * pack ) | ||||
| 	delete pack; | ||||
| } | ||||
|  | ||||
| void CClient::updatePaths() | ||||
| {	 | ||||
| 	const CGHeroInstance *h = getHero(getSelectedHero()); | ||||
| 	if (h)//if we have selected hero... | ||||
| 		gs->calculatePaths(h, *pathInfo); | ||||
| } | ||||
| template void CClient::serialize( CISer<CLoadFile> &h, const int version ); | ||||
| template void CClient::serialize( COSer<CSaveFile> &h, const int version ); | ||||
|   | ||||
| @@ -113,6 +113,7 @@ public: | ||||
| 	void waitForServer(); | ||||
| 	CPack * retreivePack(); //gets from server next pack (allocates it with new) | ||||
| 	void handlePack( CPack * pack ); //applies the given pack and deletes it | ||||
| 	void updatePaths(); | ||||
|  | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|   | ||||
| @@ -107,8 +107,7 @@ void FoWChange::applyCl( CClient *cl ) | ||||
| 	else | ||||
| 		cl->playerint[player]->tileHidden(tiles); | ||||
|  | ||||
| 	if (cl->IGameCallback::getSelectedHero(player))//if we have selected hero... | ||||
| 		GS(cl)->calculatePaths(cl->IGameCallback::getSelectedHero(player), *cl->pathInfo); | ||||
| 	cl->updatePaths(); | ||||
| } | ||||
|  | ||||
| void SetAvailableHeroes::applyCl( CClient *cl ) | ||||
| @@ -146,6 +145,8 @@ void ChangeObjPos::applyCl( CClient *cl ) | ||||
| 	CGObjectInstance *obj = GS(cl)->map->objects[objid]; | ||||
| 	if(flags & 1) | ||||
| 		CGI->mh->printObject(obj); | ||||
|  | ||||
| 	cl->updatePaths(); | ||||
| } | ||||
|  | ||||
| void PlayerEndsGame::applyCl( CClient *cl ) | ||||
|   | ||||
| @@ -47,7 +47,6 @@ BankConfig CGPyramid::pyramidConfig; | ||||
| ui8 CGObelisk::obeliskCount; //how many obelisks are on map | ||||
| std::map<ui8, ui8> CGObelisk::visited; //map: color_id => how many obelisks has been visited | ||||
|  | ||||
|  | ||||
| void IObjectInterface::onHeroVisit(const CGHeroInstance * h) const  | ||||
| {}; | ||||
|  | ||||
| @@ -687,6 +686,7 @@ int CGHeroInstance::getSpellSecLevel(int spell) const | ||||
| } | ||||
|  | ||||
| CGHeroInstance::CGHeroInstance() | ||||
|  : IBoatGenerator(this) | ||||
| { | ||||
| 	ID = HEROI_TYPE; | ||||
| 	tacticFormationEnabled = inTownGarrison = false; | ||||
| @@ -1226,6 +1226,34 @@ const BonusList * CGHeroInstance::ownerBonuses() const | ||||
| 		return &p->bonuses; | ||||
| } | ||||
|  | ||||
| int CGHeroInstance::getBoatType() const | ||||
| { | ||||
| 	int alignment = type->heroType / 6;  | ||||
| 	switch(alignment) | ||||
| 	{ | ||||
| 	case 0: | ||||
| 		return 1; //good | ||||
| 	case 1: | ||||
| 		return 0; //evil | ||||
| 	case 2: | ||||
| 		return 2; | ||||
| 	default: | ||||
| 		assert(0); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CGHeroInstance::getOutOffsets(std::vector<int3> &offsets) const | ||||
| { | ||||
| 	static int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0), int3(1,1,0),int3(-1,1,0),int3(1,-1,0),int3(-1,-1,0) }; | ||||
| 	for (size_t i = 0; i < ARRAY_COUNT(dirs); i++) | ||||
| 		offsets += dirs[i]; | ||||
| } | ||||
|  | ||||
| int CGHeroInstance::getSpellCost(const CSpell *sp) const | ||||
| { | ||||
| 	return sp->costs[getSpellSchoolLevel(sp)]; | ||||
| } | ||||
|  | ||||
| void CGDwelling::initObj() | ||||
| { | ||||
| 	switch(ID) | ||||
| @@ -5308,13 +5336,6 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const | ||||
| 	cb->showInfoDialog(&iw); | ||||
| } | ||||
|  | ||||
| void IShipyard::getBoatCost( std::vector<si32> &cost ) const | ||||
| { | ||||
| 	cost.resize(RESOURCE_QUANTITY); | ||||
| 	cost[0] = 10; | ||||
| 	cost[6] = 1000; | ||||
| } | ||||
|  | ||||
| //bool IShipyard::validLocation() const | ||||
| //{ | ||||
| //	std::vector<int3> offsets; | ||||
| @@ -5327,7 +5348,7 @@ void IShipyard::getBoatCost( std::vector<si32> &cost ) const | ||||
| //	return false; | ||||
| //} | ||||
|  | ||||
| int3 IShipyard::bestLocation() const | ||||
| int3 IBoatGenerator::bestLocation() const | ||||
| { | ||||
| 	std::vector<int3> offsets; | ||||
| 	getOutOffsets(offsets); | ||||
| @@ -5339,12 +5360,7 @@ int3 IShipyard::bestLocation() const | ||||
| 	return int3(-1,-1,-1); | ||||
| } | ||||
|  | ||||
| IShipyard::IShipyard(const CGObjectInstance *O)  | ||||
| 	: o(O) | ||||
| { | ||||
| } | ||||
|  | ||||
| int IShipyard::state() const | ||||
| int IBoatGenerator::state() const | ||||
| { | ||||
| 	int3 tile = bestLocation(); | ||||
| 	TerrainTile *t = IObjectInterface::cb->getTile(tile); | ||||
| @@ -5358,6 +5374,30 @@ int IShipyard::state() const | ||||
| 		return 2; //blocked | ||||
| } | ||||
|  | ||||
| int IBoatGenerator::getBoatType() const | ||||
| { | ||||
| 	//We make good ships by default | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| IBoatGenerator::IBoatGenerator(const CGObjectInstance *O)  | ||||
| : o(O) | ||||
| { | ||||
| } | ||||
|  | ||||
| void IShipyard::getBoatCost( std::vector<si32> &cost ) const | ||||
| { | ||||
| 	cost.resize(RESOURCE_QUANTITY); | ||||
| 	cost[0] = 10; | ||||
| 	cost[6] = 1000; | ||||
| } | ||||
|  | ||||
| IShipyard::IShipyard(const CGObjectInstance *O)  | ||||
| 	: IBoatGenerator(O) | ||||
| { | ||||
| } | ||||
|  | ||||
| IShipyard * IShipyard::castFrom( CGObjectInstance *obj ) | ||||
| { | ||||
| 	if(obj->ID == TOWNI_TYPE) | ||||
| @@ -5380,12 +5420,6 @@ const IShipyard * IShipyard::castFrom( const CGObjectInstance *obj ) | ||||
| 	return castFrom(const_cast<CGObjectInstance*>(obj)); | ||||
| } | ||||
|  | ||||
| int IShipyard::getBoatType() const | ||||
| { | ||||
| 	//We make good ships by default | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| CGShipyard::CGShipyard() | ||||
| 	:IShipyard(this) | ||||
| { | ||||
|   | ||||
| @@ -115,18 +115,23 @@ public: | ||||
| 	static void postInit();//caleed after objs receive their initObj | ||||
| }; | ||||
|  | ||||
| class DLL_EXPORT IShipyard | ||||
| class DLL_EXPORT IBoatGenerator | ||||
| { | ||||
| public: | ||||
| 	const CGObjectInstance *o; | ||||
|  | ||||
| 	IShipyard(const CGObjectInstance *O); | ||||
| 	virtual void getBoatCost(std::vector<si32> &cost) const; | ||||
| 	IBoatGenerator(const CGObjectInstance *O); | ||||
| 	virtual int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral | ||||
| 	virtual void getOutOffsets(std::vector<int3> &offsets) const =0; //offsets to obj pos when we boat can be placed | ||||
| 	//virtual bool validLocation() const; //returns true if there is a water tile near where boat can be placed | ||||
| 	int3 bestLocation() const; //returns location when the boat should be placed | ||||
| 	int state() const; //0 - can buid, 1 - there is already a boat at dest tile, 2 - dest tile is blocked, 3 - no water | ||||
| }; | ||||
|  | ||||
| class DLL_EXPORT IShipyard : public IBoatGenerator | ||||
| { | ||||
| public: | ||||
| 	IShipyard(const CGObjectInstance *O); | ||||
| 	virtual void getBoatCost(std::vector<si32> &cost) const; | ||||
|  | ||||
| 	static const IShipyard *castFrom(const CGObjectInstance *obj); | ||||
| 	static IShipyard *castFrom(CGObjectInstance *obj); | ||||
| @@ -227,7 +232,7 @@ public: | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_EXPORT CGHeroInstance : public CArmedInstance | ||||
| class DLL_EXPORT CGHeroInstance : public CArmedInstance, public IBoatGenerator | ||||
| { | ||||
| public: | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
| @@ -287,6 +292,12 @@ public: | ||||
| 	int3 getSightCenter() const; //"center" tile from which the sight distance is calculated | ||||
| 	int getSightRadious() const; //sight distance (should be used if player-owned structure) | ||||
|  | ||||
|  | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| 	int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral | ||||
| 	void getOutOffsets(std::vector<int3> &offsets) const; //offsets to obj pos when we boat can be placed | ||||
|  | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| 	const std::string &getBiography() const; | ||||
| @@ -298,6 +309,7 @@ public: | ||||
| 	si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day | ||||
| 	bool canWalkOnSea() const; | ||||
| 	int getCurrentLuck(int stack=-1, bool town=false) const; | ||||
| 	int getSpellCost(const CSpell *sp) const; //do not use during battles -> bonuses from army would be ignored | ||||
|  | ||||
| 	const BonusList *ownerBonuses() const; | ||||
| 	const HeroBonus *getBonus(int from, int id) const; | ||||
|   | ||||
| @@ -2740,7 +2740,7 @@ CStack * BattleInfo::generateNewStack(const CGHeroInstance * owner, int creature | ||||
|  | ||||
| ui32 BattleInfo::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const | ||||
| { | ||||
| 	ui32 ret = VLC->spellh->spells[sp->id].costs[caster->getSpellSchoolLevel(sp)]; | ||||
| 	ui32 ret = caster->getSpellCost(sp); | ||||
|  | ||||
| 	//checking for friendly stacks reducing cost of the spell and | ||||
| 	//enemy stacks increasing it | ||||
|   | ||||
| @@ -380,7 +380,11 @@ struct GiveBonus :  public CPackForClient //115 | ||||
|  | ||||
| struct ChangeObjPos : public CPackForClient //116 | ||||
| { | ||||
| 	ChangeObjPos(){type = 116;}; | ||||
| 	ChangeObjPos() | ||||
| 	{ | ||||
| 		type = 116;  | ||||
| 		flags = 0; | ||||
| 	} | ||||
| 	void applyFirstCl(CClient *cl); | ||||
| 	void applyCl(CClient *cl); | ||||
| 	DLL_EXPORT void applyGs(CGameState *gs); | ||||
| @@ -692,10 +696,11 @@ struct InfoWindow : public CPackForClient //103  - displays simple info window | ||||
| 	{ | ||||
| 		h & text & components & player & soundID; | ||||
| 	} | ||||
| 	InfoWindow() {  | ||||
| 	InfoWindow()  | ||||
| 	{  | ||||
| 		type = 103; | ||||
| 		soundID = 0;  | ||||
| 	}; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct SetObjectProperty : public CPackForClient//1001 | ||||
| @@ -1424,6 +1429,20 @@ struct DigWithHero : public CPackForServer | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct CastAdvSpell : public CPackForServer | ||||
| { | ||||
| 	CastAdvSpell(){} | ||||
| 	si32 hid; //hero id | ||||
| 	ui32 sid; //spell id | ||||
| 	int3 pos; //selected tile (not always used) | ||||
|  | ||||
| 	bool applyGh(CGameHandler *gh); | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & hid & sid & pos; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| /***********************************************************************************************************/ | ||||
|  | ||||
| struct SaveGame : public CPackForClient, public CPackForServer | ||||
|   | ||||
| @@ -153,6 +153,7 @@ void registerTypes3(Serializer &s) | ||||
| 	s.template registerType<MakeAction>(); | ||||
| 	s.template registerType<MakeCustomAction>(); | ||||
| 	s.template registerType<DigWithHero>(); | ||||
| 	s.template registerType<CastAdvSpell>(); | ||||
|  | ||||
| 	s.template registerType<SaveGame>(); | ||||
| 	s.template registerType<SetSelection>(); | ||||
|   | ||||
| @@ -46,6 +46,8 @@ extern bool end2; | ||||
| #ifdef max | ||||
| #undef max | ||||
| #endif | ||||
|  | ||||
| #define COMPLAIN_RET(txt) {complain(txt); return false;} | ||||
| #define NEW_ROUND 		BattleNextRound bnr;\ | ||||
| 		bnr.round = gs->curB->round + 1;\ | ||||
| 		sendAndApply(&bnr); | ||||
| @@ -4197,3 +4199,101 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat ) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool CGameHandler::castSpell(const CGHeroInstance *h, int spellID, const int3 &pos) | ||||
| { | ||||
| 	const CSpell *s = &VLC->spellh->spells[spellID]; | ||||
| 	int cost = h->getSpellCost(s); | ||||
| 	int schoolLevel = h->getSpellSchoolLevel(s); | ||||
|  | ||||
| 	if(!h->canCastThisSpell(s)) | ||||
| 		COMPLAIN_RET("Hero cannot cast this spell!"); | ||||
| 	if(h->mana < cost)  | ||||
| 		COMPLAIN_RET("Hero doesn't have enough spell points to cast this spell!"); | ||||
| 	if(s->combatSpell) | ||||
| 		COMPLAIN_RET("This function can be used only for adventure map spells!"); | ||||
|  | ||||
| 	switch(spellID) | ||||
| 	{ | ||||
| 	case 0: //Summon Boat  | ||||
| 		{ | ||||
| 			//check if spell works at all | ||||
| 			if(rand() % 100 >= s->powers[schoolLevel]) //power is % chance of success | ||||
| 			{ | ||||
| 				InfoWindow iw; | ||||
| 				iw.player = h->tempOwner; | ||||
| 				iw.text.addTxt(MetaString::GENERAL_TXT, 336); //%s tried to summon a boat, but failed. | ||||
| 				iw.text.addReplacement(h->name); | ||||
| 				sendAndApply(&iw); | ||||
| 				return true; //TODO? or should it be false? request was correct and realized, but spell failed... | ||||
| 			} | ||||
|  | ||||
| 			//try to find unoccupied boat to summon | ||||
| 			const CGBoat *nearest = NULL; | ||||
| 			double dist = 0; | ||||
| 			int3 summonPos = h->bestLocation(); | ||||
| 			if(summonPos.x < 0) | ||||
| 				COMPLAIN_RET("There is no water tile available!"); | ||||
|  | ||||
| 			BOOST_FOREACH(const CGObjectInstance *obj, gs->map->objects) | ||||
| 			{ | ||||
| 				if(obj && obj->ID == 8) | ||||
| 				{ | ||||
| 					const CGBoat *b = static_cast<const CGBoat*>(obj); | ||||
| 					if(b->hero) continue; //we're looking for unoccupied boat | ||||
|  | ||||
| 					double nDist = distance(b->pos, h->getPosition()); | ||||
| 					if(!nearest || nDist < dist) //it's first boat or closer than previous | ||||
| 					{ | ||||
| 						nearest = b; | ||||
| 						dist = nDist; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if(nearest) //we found boat to summon | ||||
| 			{ | ||||
| 				ChangeObjPos cop; | ||||
| 				cop.objid = nearest->id; | ||||
| 				cop.nPos = summonPos + int3(1,0,0);; | ||||
| 				cop.flags = 1; | ||||
| 				sendAndApply(&cop); | ||||
| 			} | ||||
| 			else if(schoolLevel < 2) //none or basic level -> cannot create boat :( | ||||
| 			{ | ||||
| 				InfoWindow iw; | ||||
| 				iw.player = h->tempOwner; | ||||
| 				iw.text.addTxt(MetaString::GENERAL_TXT, 335); //There are no boats to summon. | ||||
| 				sendAndApply(&iw); | ||||
| 			} | ||||
| 			else //create boat | ||||
| 			{ | ||||
| 				NewObject no; | ||||
| 				no.ID = 8; | ||||
| 				no.subID = h->getBoatType(); | ||||
| 				no.pos = summonPos + int3(1,0,0);; | ||||
| 				sendAndApply(&no); | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 	case 1: //Scuttle Boat  | ||||
| 	case 2: //Visions  | ||||
| 	case 3: //View Earth  | ||||
| 	case 4: //Disguise  | ||||
| 	case 5: //View Air  | ||||
| 	case 6: //Fly  | ||||
| 	case 7: //Water Walk  | ||||
| 	case 8: //Dimension Door | ||||
| 	case 9: //Town Portal  | ||||
| 	default: | ||||
| 		COMPLAIN_RET("This spell is not implemented yet!"); | ||||
| 	} | ||||
|  | ||||
| 	SetMana sm; | ||||
| 	sm.hid = h->id; | ||||
| 	sm.val = h->mana - cost; | ||||
| 	sendAndApply(&sm); | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
| @@ -181,6 +181,7 @@ public: | ||||
| 	void objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h ); | ||||
| 	void engageIntoBattle( ui8 player ); | ||||
| 	bool dig(const CGHeroInstance *h); | ||||
| 	bool castSpell(const CGHeroInstance *h, int spellID, const int3 &pos); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
|   | ||||
| @@ -160,6 +160,12 @@ bool DigWithHero::applyGh( CGameHandler *gh ) | ||||
| 	return gh->dig(gh->getHero(id)); | ||||
| } | ||||
|  | ||||
| bool CastAdvSpell::applyGh( CGameHandler *gh ) | ||||
| { | ||||
| 	ERROR_IF_NOT_OWNS(hid); | ||||
| 	return gh->castSpell(gh->getHero(hid), sid, pos); | ||||
| } | ||||
|  | ||||
| bool PlayerMessage::applyGh( CGameHandler *gh ) | ||||
| { | ||||
| 	if(gh->getPlayerAt(c) != player) ERROR_AND_RETURN; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user