浏览代码

Fixed #730:
* crash on +5 growth week
* crash on spawning wandering creatures on double growth months
(how come that has not been found in previous build?)

More logging for #729-like issues.

Michał W. Urbańczyk 14 年之前
父节点
当前提交
3ca95ef5ed

+ 0 - 1
client/Client.h

@@ -106,7 +106,6 @@ public:
 	void setBlockVis(int objid, bool bv) OVERRIDE {};
 	void setOwner(int objid, ui8 owner) OVERRIDE {};
 	void setHoverName(int objid, MetaString * name) OVERRIDE {};
-	void setObjProperty(int objid, int prop, si64 val) OVERRIDE {};
 	void changePrimSkill(int ID, int which, si64 val, bool abs=false) OVERRIDE {};
 	void changeSecSkill(int ID, int which, int val, bool abs=false) OVERRIDE {}; 
 	void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback) OVERRIDE {};

+ 4 - 1
lib/CCreatureSet.cpp

@@ -509,7 +509,10 @@ void CStackInstance::giveStackExp(expType exp)
 
 void CStackInstance::setType(int creID)
 {
-	setType(VLC->creh->creatures[creID]);
+	if(creID >= 0 && creID < VLC->creh->creatures.size())
+		setType(VLC->creh->creatures[creID]);
+	else
+		setType(NULL);
 }
 
 void CStackInstance::setType(const CCreature *c)

+ 11 - 1
lib/CGameState.cpp

@@ -271,8 +271,18 @@ void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst
 		case COLOR:
 			vec = &VLC->generaltexth->capColors;
 			break;
+		default:
+			tlog1 << "Failed string substitution because type is " << type << std::endl;
+			dst = "#@#";
+			return;
 		}
-		dst = (*vec)[ser];
+		if(vec->size() <= ser)
+		{
+			tlog1 << "Failed string substitution with type " << type << " because index " << ser << " is out of bounds!\n";
+			dst = "#!#";
+		}
+		else
+			dst = (*vec)[ser];
 	}
 }
 

+ 6 - 6
lib/CObjectHandler.cpp

@@ -3008,23 +3008,23 @@ void CGCreature::newTurn() const
 	if (stacks.begin()->second->count < CREEP_SIZE && cb->getDate(1) == 1 && cb->getDate(0) > 1)
 	{
 		ui32 power = temppower * (100 + WEEKLY_GROWTH)/100;
-		cb->setObjProperty(id, 10, std::min (power/1000 , (ui32)CREEP_SIZE)); //set new amount
-		cb->setObjProperty(id, 11, power); //increase temppower
+		cb->setObjProperty(id, ObjProperty::MONSTER_COUNT, std::min (power/1000 , (ui32)CREEP_SIZE)); //set new amount
+		cb->setObjProperty(id, ObjProperty::MONSTER_POWER, power); //increase temppower
 	}
 	if (STACK_EXP)
-		cb->setObjProperty(id, 12, 10000); //for testing purpose
+		cb->setObjProperty(id, ObjProperty::MONSTER_EXP, 10000); //for testing purpose
 }
 void CGCreature::setPropertyDer(ui8 what, ui32 val)
 {
 	switch (what)
 	{
-		case 10:
+		case ObjProperty::MONSTER_COUNT:
 			stacks[0]->count = val;
 			break;
-		case 11:
+		case ObjProperty::MONSTER_POWER:
 			temppower = val;
 			break;
-		case 12:
+		case ObjProperty::MONSTER_EXP:
 			giveStackExp(val);
 			break;
 		case 13:

+ 27 - 0
lib/IGameCallback.cpp

@@ -1184,3 +1184,30 @@ void IGameEventRealizer::showInfoDialog( InfoWindow *iw )
 {
 	commitPackage(iw);
 }
+
+void IGameEventRealizer::setObjProperty(int objid, int prop, si64 val)
+{
+	SetObjectProperty sob;
+	sob.id = objid;
+	sob.what = prop;
+	sob.val = val;
+	commitPackage(&sob);
+}
+
+const CGObjectInstance * IGameCallback::putNewObject(int ID, int subID, int3 pos)
+{
+	NewObject no;
+	no.ID = ID; //creature
+	no.subID= subID;
+	no.pos = pos;
+	commitPackage(&no);
+	return getObj(no.id); //id field will be filled during applaying on gs
+}
+
+const CGCreature * IGameCallback::putNewMonster(int creID, int count, int3 pos)
+{
+	const CGObjectInstance *m = putNewObject(54, creID, pos);
+	setObjProperty(m->id, ObjProperty::MONSTER_COUNT, count);
+	setObjProperty(m->id, ObjProperty::MONSTER_POWER, (si64)1000*count);
+	return dynamic_cast<const CGCreature*>(m);
+}

+ 5 - 2
lib/IGameCallback.h

@@ -55,6 +55,8 @@ class CCreatureSet;
 class CCreature;
 class CStackBasicDescriptor;
 class TeamState;
+class CGCreature;
+
 
 typedef std::vector<const CStack*> TStacks;
 
@@ -246,6 +248,7 @@ public:
 	virtual void commitPackage(CPackForClient *pack) = 0;
 
 	virtual void showInfoDialog(InfoWindow *iw);
+	virtual void setObjProperty(int objid, int prop, si64 val);
 };
 
 class DLL_EXPORT IGameEventCallback : public IGameEventRealizer
@@ -256,7 +259,6 @@ public:
 	virtual void setBlockVis(int objid, bool bv)=0;
 	virtual void setOwner(int objid, ui8 owner)=0;
 	virtual void setHoverName(int objid, MetaString * name)=0;
-	virtual void setObjProperty(int objid, int prop, si64 val)=0;
 	virtual void changePrimSkill(int ID, int which, si64 val, bool abs=false)=0;
 	virtual void changeSecSkill(int ID, int which, int val, bool abs=false)=0; 
 	virtual void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback)=0;
@@ -306,7 +308,8 @@ public:
 	virtual ~IGameCallback(){};
 
 	//do sth
-
+	const CGObjectInstance *putNewObject(int ID, int subID, int3 pos);
+	const CGCreature *putNewMonster(int creID, int count, int3 pos);
 
 	friend struct CPack;
 	friend struct CPackForClient;

+ 8 - 3
lib/NetPacks.h

@@ -677,14 +677,18 @@ struct OpenWindow : public CPackForClient //517
 
 struct NewObject  : public CPackForClient //518
 {
-	NewObject(){type = 518;};
+	NewObject()
+	{
+		type = 518;
+		id = -1;
+	}
 	void applyCl(CClient *cl);
 	DLL_EXPORT void applyGs(CGameState *gs);
 
 	ui32 ID, subID;
 	int3 pos;
 
-	int id; //used internally
+	int id; //used locally, filled during applyGs
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
@@ -1022,7 +1026,8 @@ struct InfoWindow : public CPackForClient //103  - displays simple info window
 namespace ObjProperty
 {
 	//TODO: move non general properties out to the appropriate objs classes
-	enum {OWNER = 1, BLOCKVIS = 2, PRIMARY_STACK_COUNT = 3, VISITORS = 4, VISITED = 5, ID = 6, AVAILABLE_CREATURE = 7, SUBID = 8};
+	enum {OWNER = 1, BLOCKVIS = 2, PRIMARY_STACK_COUNT = 3, VISITORS = 4, VISITED = 5, ID = 6, AVAILABLE_CREATURE = 7, SUBID = 8,
+		MONSTER_COUNT = 10, MONSTER_POWER = 11, MONSTER_EXP = 12};
 }
 
 struct SetObjectProperty : public CPackForClient//1001

+ 2 - 0
lib/NetPacksLib.cpp

@@ -476,6 +476,8 @@ DLL_EXPORT void NewObject::applyGs( CGameState *gs )
 			cre->notGrowingTeam = cre->neverFlees = 0;
 			cre->character = 2;
 			cre->gainedArtifact = -1;
+			cre->identifier = -1;
+			cre->addToSlot(0, new CStackInstance(-1, -1)); //add placeholder stack
 		}
 		break;
 	default:

+ 2 - 16
server/CGameHandler.cpp

@@ -811,7 +811,6 @@ void CGameHandler::newTurn()
 
 	if (getDate(1) == 7 && getDate(0)>1) //new week (day numbers are confusing, as day was not yet switched)
 	{
-		int monsterid;
 		int monthType = rand()%100;
 		if(getDate(4) == 28) //new month
 		{
@@ -843,7 +842,7 @@ void CGameHandler::newTurn()
 			{
 				n.specialWeek = NewTurn::BONUS_GROWTH; //+5
 				std::pair<int,int> newMonster (54, VLC->creh->pickRandomMonster(boost::ref(rand)));
-				monsterid = newMonster.second;
+				n.creatureid = newMonster.second;
 			}
 			else
 				n.specialWeek = NewTurn::NORMAL;
@@ -1006,11 +1005,7 @@ void CGameHandler::newTurn()
 			for (int i = 0; i < amount; ++i)
 			{
 				tile = tiles.begin();
-				NewObject no;
-				no.ID = 54; //creature
-				no.subID= n.creatureid;
-				no.pos = *tile;
-				sendAndApply(&no);
+				putNewMonster(n.creatureid, VLC->creh->creatures[n.creatureid]->getRandomAmount(std::rand), *tile);
 				tiles.erase(tile); //not use it again
 			}
 		}
@@ -1704,15 +1699,6 @@ void CGameHandler::changeSpells( int hid, bool give, const std::set<ui32> &spell
 	sendAndApply(&cs);
 }
 
-void CGameHandler::setObjProperty( int objid, int prop, si64 val )
-{
-	SetObjectProperty sob;
-	sob.id = objid;
-	sob.what = prop;
-	sob.val = val;
-	sendAndApply(&sob);
-}
-
 void CGameHandler::sendMessageTo( CConnection &c, const std::string &message )
 {
 	SystemMessage sm;

+ 0 - 1
server/CGameHandler.h

@@ -133,7 +133,6 @@ public:
 	void setBlockVis(int objid, bool bv) OVERRIDE;
 	void setOwner(int objid, ui8 owner) OVERRIDE;
 	void setHoverName(int objid, MetaString * name) OVERRIDE;
-	void setObjProperty(int objid, int prop, si64 val) OVERRIDE;
 	void changePrimSkill(int ID, int which, si64 val, bool abs=false) OVERRIDE;
 	void changeSecSkill(int ID, int which, int val, bool abs=false) OVERRIDE; 
 	//void showInfoDialog(InfoWindow *iw) OVERRIDE;

+ 17 - 7
server/NetPacksServer.cpp

@@ -13,7 +13,14 @@
 #define ERROR_AND_RETURN	do {if(c) *c << &SystemMessage("You are not allowed to perform this action!");	\
 							tlog1<<"Player is not allowed to perform this action!\n";	\
 							return false;} while(0)
-#define ERROR_IF_NOT_OWNS(id)	if(!PLAYER_OWNS(id)) ERROR_AND_RETURN
+
+#define WRONG_PLAYER_MSG(expectedplayer) do {std::ostringstream oss;\
+			oss << "You were identified as player " << (int)gh->getPlayerAt(c) << " while expecting " << (int)expectedplayer;\
+			tlog1 << oss.str() << std::endl; \
+			if(c) *c << &SystemMessage(oss.str());} while(0)
+
+#define ERROR_IF_NOT_OWNS(id)	do{if(!PLAYER_OWNS(id)){WRONG_PLAYER_MSG(gh->getOwner(id)); ERROR_AND_RETURN; }}while(0)
+#define ERROR_IF_NOT(player)	do{if(player != gh->getPlayerAt(c)){WRONG_PLAYER_MSG(player); ERROR_AND_RETURN; }}while(0)
 #define COMPLAIN_AND_RETURN(txt)	{ gh->complain(txt); ERROR_AND_RETURN; }
 
 /*
@@ -54,8 +61,7 @@ bool CloseServer::applyGh( CGameHandler *gh )
 
 bool EndTurn::applyGh( CGameHandler *gh )
 {
-	if(gh->getPlayerAt(c) != GS(gh)->currentPlayer)
-		ERROR_AND_RETURN;
+	ERROR_IF_NOT(GS(gh)->currentPlayer);
 	gh->states.setFlag(GS(gh)->currentPlayer,&PlayerStatus::makingTurn,false);
 	return true;
 }
@@ -153,8 +159,7 @@ bool TradeOnMarketplace::applyGh( CGameHandler *gh )
 	if(hero && (player != hero->tempOwner || hero->visitablePos() != market->visitablePos()))
 		COMPLAIN_AND_RETURN("This hero can't use this marketplace!");
 
-	if(gh->getPlayerAt(c) != player) 
-		ERROR_AND_RETURN;
+	ERROR_IF_NOT(player);
 
 	switch(mode)
 	{
@@ -255,6 +260,7 @@ bool CastAdvSpell::applyGh( CGameHandler *gh )
 
 bool PlayerMessage::applyGh( CGameHandler *gh )
 {
+	ERROR_IF_NOT(player);
 	if(gh->getPlayerAt(c) != player) ERROR_AND_RETURN;
 	gh->playerMessage(player,text);
 	return true;
@@ -262,8 +268,12 @@ bool PlayerMessage::applyGh( CGameHandler *gh )
 
 bool SetSelection::applyGh( CGameHandler *gh )
 {
-	if(gh->getPlayerAt(c) != player) ERROR_AND_RETURN;
-	if(!gh->getObj(id)) ERROR_AND_RETURN;
+	ERROR_IF_NOT(player);
+	if(!gh->getObj(id))
+	{
+		tlog1 << "No such object...\n";
+		ERROR_AND_RETURN;
+	}
 	gh->sendAndApply(this);
 	return true;
 }