Browse Source

* stuff for battles
* Sprites/ folder works for h3sprite.lod same as Data/ for h3bitmap.lod
* randomization quantity of creatures on the map
* minor changes

Michał W. Urbańczyk 17 năm trước cách đây
mục cha
commit
9819bc86e2
19 tập tin đã thay đổi với 403 bổ sung76 xóa
  1. 11 0
      CBattleInterface.cpp
  2. 13 0
      CBattleInterface.h
  3. 10 1
      CCallback.cpp
  4. 10 0
      CCallback.h
  5. 24 0
      CGameInterface.h
  6. 82 0
      CGameState.cpp
  7. 17 1
      CGameState.h
  8. 82 0
      CLua.cpp
  9. 23 0
      CLua.h
  10. 23 1
      CMT.cpp
  11. 33 1
      CPlayerInterface.cpp
  12. 12 0
      CPlayerInterface.h
  13. 1 1
      global.h
  14. 2 2
      hch/CAmbarCendamo.cpp
  15. 24 0
      hch/CCreatureHandler.cpp
  16. 2 0
      hch/CCreatureHandler.h
  17. 18 65
      hch/CLodHandler.cpp
  18. 7 0
      hch/CObjectHandler.cpp
  19. 9 4
      hch/CObjectHandler.h

+ 11 - 0
CBattleInterface.cpp

@@ -0,0 +1,11 @@
+#include "CBattleInterface.h"
+
+CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2)
+{
+}
+void CBattleInterface::activate()
+{
+}
+void CBattleInterface::deactivate()
+{
+}

+ 13 - 0
CBattleInterface.h

@@ -0,0 +1,13 @@
+#pragma once
+#include "global.h"
+#include "CPlayerInterface.h"
+class CCreatureSet;
+class CGHeroInstance;
+class CBattleInterface : public IActivable
+{
+public:
+	CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2);
+	//napisz tu klase odpowiadajaca za wyswietlanie bitwy i obsluge uzytkownika, polecenia ma przekazywac callbackiem
+	void activate();
+	void deactivate();
+};

+ 10 - 1
CCallback.cpp

@@ -407,7 +407,7 @@ const CCreatureSet* CCallback::getGarrison(const CGObjectInstance *obj)
 	if(obj->ID == 34)
 		return &(dynamic_cast<const CGHeroInstance*>(obj))->army;
 	else if(obj->ID == 98)
-		return &(dynamic_cast<const CGTownInstance*>(obj)->garrison);
+		return &(dynamic_cast<const CGTownInstance*>(obj)->army);
 	else return NULL;
 }
 
@@ -651,6 +651,15 @@ void CScriptCallback::giveHeroArtifact(int artid, int hid, int position) //pos==
 	}
 }
 
+void CScriptCallback::startBattle(CCreatureSet * army1, CCreatureSet * army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2) //use hero=NULL for no hero
+{
+	gs->battle(army1,army2,tile,hero1,hero2);
+}
+void CScriptCallback::startBattle(int heroID, CCreatureSet * army, int3 tile) //for hero<=>neutral army
+{
+	CGHeroInstance* h = gs->getHero(heroID,0);
+	gs->battle(&h->army,army,tile,h,NULL);
+}
 void CLuaCallback::registerFuncs(lua_State * L)
 {
 	lua_newtable(L);

+ 10 - 0
CCallback.h

@@ -9,6 +9,7 @@ class CGObjectInstance;
 class SComponent;
 class IChosen;
 class CSelectableComponent;
+class Action;
 typedef struct lua_State lua_State;
 
 class ICallback
@@ -89,6 +90,13 @@ public:
 	bool dismissHero(const CGHeroInstance * hero);
 	const CCreatureSet* getGarrison(const CGObjectInstance *obj);
 	bool swapArifacts(const CGHeroInstance * hero1, bool worn1, int pos1, const CGHeroInstance * hero2, bool worn2, int pos2);
+	//battle
+	int battleGetBattlefieldType(); //   1. sand/shore   2. sand/mesas   3. dirt/birches   4. dirt/hills   5. dirt/pines   6. grass/hills   7. grass/pines   8. lava   9. magic plains   10. snow/mountains   11. snow/trees   12. subterranean   13. swamp/trees   14. fiery fields   15. rock lands   16. magic clouds   17. lucid pools   18. holy ground   19. clover field   20. evil fog   21. "favourable winds" text on magic plains background   22. cursed ground   23. rough   24. ship to ship   25. ship
+	int battleGetObstaclesAtTile(int tile); //returns bitfield 
+	int battleGetStack(int pos); //returns ID of stack on the tile
+	int battleGetPos(int stack); //returns position (tile ID) of stack
+	int battleMakeAction(Action* action);//perform action with an active stack (or custom action)
+	
 
 //friends
 	friend int _tmain(int argc, _TCHAR* argv[]);
@@ -113,6 +121,8 @@ public:
 	void heroVisitCastle(CGObjectInstance * ob, int heroID);
 	void stopHeroVisitCastle(CGObjectInstance * ob, int heroID);
 	void giveHeroArtifact(int artid, int hid, int position); //pos==-1 - first free slot in backpack
+	void startBattle(CCreatureSet * army1, CCreatureSet * army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2); //use hero=NULL for no hero
+	void startBattle(int heroID, CCreatureSet * army, int3 tile); //for hero<=>neutral army
 
 	//friends
 	friend void initGameState(CGameInfo * cgi);

+ 24 - 0
CGameInterface.h

@@ -9,6 +9,20 @@ class CCallback;
 class CGlobalAI;
 class CGHeroInstance;
 class CSelectableComponent;
+class CObstacle
+{
+	int ID;
+	int position;
+	//TODO: add some kind of the blockmap
+};
+struct Action
+{
+	bool side; //who made this action: false - left, true - right player
+	int stackNumber;//stack ID, -1 left hero, -2 right hero, 
+	int actionType; //    0 = Cancel Action   1 = Hero cast a spell   2 = Walk   3 = Defend   4 = Retreat from the battle   5 = Surrender   6 = Walk and Attack   7 = Shoot    8 = Wait   9 = Catapult 10 = Monster casts a spell (i.e. Faerie Dragons) 
+	int destinationTile; 
+	int additionalInfo; // e.g. spell number if type is 1 || 10
+};
 class CGameInterface
 {
 public:
@@ -27,6 +41,16 @@ public:
 	virtual void receivedResource(int type, int val){};
 	virtual void showSelDialog(std::string text, std::vector<CSelectableComponent*> & components, int askID)=0{};
 	virtual void garrisonChanged(const CGObjectInstance * obj){};
+	//battle call-ins 
+	virtual void battleStart(CCreatureSet * army1, CCreatureSet * army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
+	virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles){}; //called when battlefield is prepared, prior the battle beginning
+	virtual void battleNewRound(int round){}; //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
+	virtual void actionStarted(Action action){};//occurs BEFORE every action taken by any stack or by the hero
+	virtual void actionFinished(Action action){};//occurs AFTER every action taken by any stack or by the hero
+	virtual void activeStack(int stackID){}; //called when it's turn of that stack
+	virtual void battleEnd(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, std::vector<int> capturedArtifacts, int expForWinner, bool winner){};
+	//
+
 };
 class CAIHandler
 {

+ 82 - 0
CGameState.cpp

@@ -0,0 +1,82 @@
+#include "CGameState.h"
+#include "CGameInterface.h"
+#include <algorithm>
+class CStack
+{
+public:
+	int ID;
+	CCreature * creature;
+	int amount;
+	int owner;
+	int position;
+	bool alive;
+	CStack(CCreature * C, int A, int O, int I):creature(C),amount(A),owner(O), alive(true), position(-1), ID(I){};
+};
+class CMP_stack
+{
+public:
+	bool operator ()(const CStack* a, const CStack* b)
+	{
+		return (a->creature->speed)<(b->creature->speed);
+	}
+} cmpst ;
+
+void CGameState::battle(CCreatureSet * army1, CCreatureSet * army2, int3 tile, CArmedInstance *hero1, CArmedInstance *hero2)
+{
+	curB = new BattleInfo();
+	std::vector<CStack*> & stacks = (curB->stacks);
+
+	curB->army1=army1;
+	curB->army2=army2;
+	curB->hero1=dynamic_cast<CGHeroInstance*>(hero1);
+	curB->hero2=dynamic_cast<CGHeroInstance*>(hero2);
+	curB->side1=(hero1)?(hero1->tempOwner):(-1);
+	curB->side2=(hero2)?(hero2->tempOwner):(-1);
+	curB->round = -2;
+	for(std::map<int,std::pair<CCreature*,int> >::iterator i = army1->slots.begin(); i!=army1->slots.end(); i++)
+		stacks.push_back(new CStack(i->second.first,i->second.second,0, stacks.size()));
+	for(std::map<int,std::pair<CCreature*,int> >::iterator i = army2->slots.begin(); i!=army2->slots.end(); i++)
+		stacks.push_back(new CStack(i->second.first,i->second.second,1, stacks.size()));
+	std::stable_sort(stacks.begin(),stacks.end(),cmpst);
+
+	//for start inform players about battle
+	for(std::map<int, PlayerState>::iterator j=CGI->state->players.begin(); j!=CGI->state->players.end(); ++j)//CGI->state->players.size(); ++j) //for testing
+	{
+		if (j->first > PLAYER_LIMIT)
+			break;
+		if(j->second.fogOfWarMap[tile.x][tile.y][tile.z])
+		{ //player should be notified
+			tribool side = tribool::indeterminate_value;
+			if(j->first == curB->side1) //player is attacker
+				side = false;
+			else if(j->first == curB->side2) //player is defender
+				side = true;
+			else 
+				return; //no witnesses
+			CGI->playerint[j->second.serial]->battleStart(army1, army2, tile, curB->hero1, curB->hero2, side);
+		}
+	}
+
+	curB->round++;
+	if(curB->hero1->getSecSkillLevel(19)>=0 || curB->hero2->getSecSkillLevel(19)>=0) //someone has tactics
+	{
+		//TODO: wywolania dla rundy -1, ograniczenie pola ruchu, etc
+	}
+
+	curB->round++;
+	while(true) //do zwyciestwa jednej ze stron
+	{
+		for(int i=0;i<stacks.size();i++)
+		{
+			curB->activeStack = i;
+			if(stacks[i]->alive) //niech interfejs ruszy oddzialem
+				CGI->playerint[(stacks[i]->owner)?(hero2->tempOwner):(hero1->tempOwner)]->activeStack(stacks[i]->ID);
+			//sprawdzic czy po tej akcji ktoras strona nie wygrala bitwy
+		}
+	}
+
+	for(int i=0;i<stacks.size();i++)
+		delete stacks[i];
+	delete curB;
+	curB = NULL;
+}

+ 17 - 1
CGameState.h

@@ -2,10 +2,15 @@
 #define CGAMESTATE_H
 #include "mapHandler.h"
 #include <set>
+#include <tchar.h>
 class CScriptCallback;
 class CCallback;
 class CLuaCallback;
 class CCPPObjectScript;
+class CCreatureSet;
+class CStack;
+class CGHeroInstance;
+class CArmedInstance;
 struct PlayerState
 {
 public:
@@ -17,11 +22,21 @@ public:
 	std::vector<CGTownInstance *> towns;
 	PlayerState():color(-1){};
 };
-
+struct BattleInfo
+{
+	int side1, side2;
+	int round, activeStack;
+	int siege; //    = 0 ordinary battle    = 1 a siege with a Fort    = 2 a siege with a Citadel    = 3 a siege with a Castle
+	int3 tile; //for background and bonuses
+	CGHeroInstance *hero1, *hero2;
+	CCreatureSet * army1, * army2;
+	std::vector<CStack*> stacks;
+};
 class CGameState
 {
 private:
 	int currentPlayer;
+	BattleInfo *curB; //current battle
 	int day; //total number of days in game
 	std::map<int,PlayerState> players; //color <-> playerstate
 	std::set<CCPPObjectScript *> cppscripts;
@@ -53,6 +68,7 @@ private:
 		}
 		return NULL;
 	}
+	void battle(CCreatureSet * army1, CCreatureSet * army2, int3 tile, CArmedInstance *hero1, CArmedInstance *hero2);
 public:
 	friend CCallback;
 	friend CPathfinder;;

+ 82 - 0
CLua.cpp

@@ -620,3 +620,85 @@ std::vector<int> CTownScript::yourObjects() //returns IDs of objects which are h
 	ret.push_back(98); //town
 	return ret;
 }
+
+void CHeroScript::newObject(CGObjectInstance *os)
+{
+	os->blockVisit = true;
+	heroes.insert(std::pair<int,CGObjectInstance*>(os->subID,os));
+}
+
+void CHeroScript::onHeroVisit(CGObjectInstance *os, int heroID)
+{
+	//TODO: check for allies
+	cb->startBattle(
+		&(static_cast<CGHeroInstance*>(heroes[heroID]))->army,
+		&(static_cast<CGHeroInstance*>(os))->army,
+		os->pos,
+		static_cast<CGHeroInstance*>(heroes[heroID]),
+		static_cast<CGHeroInstance*>(os));
+}
+std::vector<int> CHeroScript::yourObjects() //returns IDs of objects which are handled by script
+{
+	std::vector<int> ret(1);
+	ret.push_back(34); //town
+	return ret;
+}
+
+void CMonsterS::newObject(CGObjectInstance *os)
+{
+	os->blockVisit = true;
+	switch(CGI->creh->creatures[os->subID].level)
+	{
+	case 1:
+		((CCreatureObjInfo*)os->info)->number = rand()%31+20;
+		break;
+	case 2:
+		((CCreatureObjInfo*)os->info)->number = rand()%16+15;
+		break;
+	case 3:
+		((CCreatureObjInfo*)os->info)->number = rand()%16+10;
+		break;
+	case 4:
+		((CCreatureObjInfo*)os->info)->number = rand()%11+10;
+		break;
+	case 5:
+		((CCreatureObjInfo*)os->info)->number = rand()%9+8;
+		break;
+	case 6:
+		((CCreatureObjInfo*)os->info)->number = rand()%8+5;
+		break;
+	case 7:
+		((CCreatureObjInfo*)os->info)->number = rand()%7+3;
+		break;
+	case 8:
+		((CCreatureObjInfo*)os->info)->number = rand()%4+2;
+		break;
+	case 9:
+		((CCreatureObjInfo*)os->info)->number = rand()%3+2;
+		break;
+	case 10:
+		((CCreatureObjInfo*)os->info)->number = rand()%3+1;
+		break;
+
+	}
+
+}
+std::string CMonsterS::hoverText(CGObjectInstance *os)
+{
+	int pom = CCreature::getQuantityID(((CCreatureObjInfo*)os->info)->number);
+	pom = 174 + 3*pom + 1;
+	return CGI->generaltexth->arraytxt[pom] + CGI->creh->creatures[os->subID].namePl;
+}
+void CMonsterS::onHeroVisit(CGObjectInstance *os, int heroID)
+{
+	CCreatureSet set;
+	//TODO: zrobic secik w sposob wyrafinowany
+	set.slots[0] = std::pair<CCreature*,int>(&CGI->creh->creatures[os->subID],((CCreatureObjInfo*)os->info)->number);
+	cb->startBattle(heroID,&set,os->pos);
+}
+std::vector<int> CMonsterS::yourObjects() //returns IDs of objects which are handled by script
+{
+	std::vector<int> ret(1);
+	ret.push_back(54); //town
+	return ret;
+}

+ 23 - 0
CLua.h

@@ -161,5 +161,28 @@ class CTownScript : public CCPPObjectScript  //pickable - resources, artifacts,
 	std::string hoverText(CGObjectInstance *os);
 	std::vector<int> yourObjects(); //returns IDs of objects which are handled by script
 
+	friend void initGameState(CGameInfo * cgi);
+};
+
+class CHeroScript : public CCPPObjectScript
+{
+	std::map<int, CGObjectInstance*> heroes;
+	CHeroScript(CScriptCallback * CB):CCPPObjectScript(CB){};
+	void newObject(CGObjectInstance *os);
+	void onHeroVisit(CGObjectInstance *os, int heroID);
+	std::vector<int> yourObjects(); //returns IDs of objects which are handled by script
+
+	friend void initGameState(CGameInfo * cgi);
+};
+
+class CMonsterS : public CCPPObjectScript
+{
+	std::map<int, CGObjectInstance*> heroes;
+	CMonsterS(CScriptCallback * CB):CCPPObjectScript(CB){};
+	void newObject(CGObjectInstance *os);
+	std::string hoverText(CGObjectInstance *os);
+	void onHeroVisit(CGObjectInstance *os, int heroID);
+	std::vector<int> yourObjects(); //returns IDs of objects which are handled by script
+
 	friend void initGameState(CGameInfo * cgi);
 };

+ 23 - 1
CMT.cpp

@@ -249,6 +249,8 @@ void initGameState(CGameInfo * cgi)
 	handleCPPObjS(&scripts,new CPickable(csc));
 	handleCPPObjS(&scripts,new CMines(csc));
 	handleCPPObjS(&scripts,new CTownScript(csc));
+	handleCPPObjS(&scripts,new CHeroScript(csc));
+	handleCPPObjS(&scripts,new CMonsterS(csc));
 	//created map
 
 	/****************************LUA OBJECT SCRIPTS************************************************/
@@ -388,7 +390,27 @@ int _tmain(int argc, _TCHAR* argv[])
 				}
 			}
 		}
-		THC std::cout<<"Scanning Data/: "<<tmh.getDif()<<std::endl;
+		if(boost::filesystem::exists("Sprites"))
+		{
+			for (boost::filesystem::directory_iterator dir("Sprites");dir!=enddir;dir++)
+			{
+				if(boost::filesystem::is_regular(dir->status()))
+				{
+					std::string name = dir->path().leaf();
+					std::transform(name.begin(), name.end(), name.begin(), (int(*)(int))toupper);
+					boost::algorithm::replace_all(name,".BMP",".PCX");
+					Entry * e = cgi->spriteh->entries.znajdz(name);
+					if(e)
+					{
+						e->offset = -1;
+						e->realSize = e->size = boost::filesystem::file_size(dir->path());
+					}
+				}
+			}
+		}
+		else
+			std::cout<<"Warning: No sprites/ folder!"<<std::endl;
+		THC std::cout<<"Scanning Data/ and Sprites/ folders: "<<tmh.getDif()<<std::endl;
 		cgi->curh->initCursor();
 		cgi->curh->showGraphicCursor();
 

+ 33 - 1
CPlayerInterface.cpp

@@ -22,6 +22,7 @@
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/replace.hpp>
 #include "hch\CPreGameTextHandler.h"
+#include "CBattleInterface.h"
 using namespace CSDL_Ext;
 
 extern TTF_Font * GEOR16;
@@ -1496,7 +1497,7 @@ SDL_Surface * CPlayerInterface::drawTownInfoWin(const CGTownInstance * curh)
 		blitAt(halls->ourImages[pom].bitmap,77,42,ret);
 	itoa(curh->dailyIncome(),buf,10);
 	printAtMiddle(buf,167,70,GEORM,zwykly,ret);
-	for (std::map<int,std::pair<CCreature*,int> >::const_iterator i=curh->garrison.slots.begin(); i!=curh->garrison.slots.end();i++)
+	for (std::map<int,std::pair<CCreature*,int> >::const_iterator i=curh->army.slots.begin(); i!=curh->army.slots.end();i++)
 	{
 		blitAt(CGI->creh->smallImgs[(*i).second.first->idNumber],slotsPos[(*i).first].first+1,slotsPos[(*i).first].second+1,ret);
 		itoa((*i).second.second,buf,10);
@@ -1845,6 +1846,37 @@ void CPlayerInterface::garrisonChanged(const CGObjectInstance * obj)
 		}
 	}
 }
+
+void CPlayerInterface::battleStart(CCreatureSet * army1, CCreatureSet * army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, tribool side) //called by engine when battle starts; side=0 - left, side=1 - right
+{
+	curint->deactivate();
+	curint = new CBattleInterface(army1,army2,tile,hero1,hero2);
+}
+
+void CPlayerInterface::battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles) //called when battlefield is prepared, prior the battle beginning
+{
+}
+
+void CPlayerInterface::battleNewRound(int round) //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
+{
+}
+
+void CPlayerInterface::actionStarted(Action action)//occurs BEFORE every action taken by any stack or by the hero
+{
+}
+
+void CPlayerInterface::actionFinished(Action action)//occurs AFTER every action taken by any stack or by the hero
+{
+}
+
+void CPlayerInterface::activeStack(int stackID) //called when it's turn of that stack
+{
+}
+
+void CPlayerInterface::battleEnd(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, std::vector<int> capturedArtifacts, int expForWinner, bool winner)
+{
+}
+
 void CPlayerInterface::showComp(SComponent comp)
 {
 	adventureInt->infoBar.showComp(&comp,4000);

+ 12 - 0
CPlayerInterface.h

@@ -302,6 +302,18 @@ public:
 	void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town);
 	void garrisonChanged(const CGObjectInstance * obj);
 
+	//battles
+	void battleStart(CCreatureSet * army1, CCreatureSet * army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, tribool side); //called by engine when battle starts; side=0 - left, side=1 - right
+	void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning
+	void battleNewRound(int round); //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
+	void actionStarted(Action action);//occurs BEFORE every action taken by any stack or by the hero
+	void actionFinished(Action action);//occurs AFTER every action taken by any stack or by the hero
+	void activeStack(int stackID); //called when it's turn of that stack
+	void battleEnd(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2, std::vector<int> capturedArtifacts, int expForWinner, bool winner);
+
+
+	//-------------//
+
 	void showComp(SComponent comp);
 
 	void openTownWindow(const CGTownInstance * town); //shows townscreen

+ 1 - 1
global.h

@@ -4,8 +4,8 @@
 #if CHECKTIME
 #include "timeHandler.h"
 #include <boost/logic/tribool.hpp>
-#include "int3.h"
 #include <iostream>
+#include "int3.h"
 #define THC
 #else 
 #define THC //

+ 2 - 2
hch/CAmbarCendamo.cpp

@@ -354,7 +354,7 @@ void CAmbarCendamo::deh3m()
 				((VicCona*)map.vicConDetails)->destinationPlace.x = bufor[i+3];
 				((VicCona*)map.vicConDetails)->destinationPlace.y = bufor[i+4];
 				((VicCona*)map.vicConDetails)->destinationPlace.z = bufor[i+5];				
-				nr=3;
+				nr=4;
 				break;
 			}
 		}
@@ -1747,7 +1747,7 @@ void CAmbarCendamo::deh3m()
 				nt->builded = 0;
 				nt->destroyed = 0;
 				nt->name = spec->name;
-				nt->garrison = spec->garrison;
+				nt->army = spec->garrison;
 				nt->garrisonHero = NULL;// spec->garnisonHero is not readed - TODO: readit
 				nt->pos = int3(spec->x, spec->y, spec->z);
 				nt->possibleSpells = spec->possibleSpells;

+ 24 - 0
hch/CCreatureHandler.cpp

@@ -7,6 +7,30 @@
 #include <boost/assign/std/vector.hpp>
 #include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/replace.hpp>
+
+int CCreature::getQuantityID(int quantity)
+{
+	if (quantity<5)
+		return 0;
+	if (quantity<10)
+		return 1;
+	if (quantity<20)
+		return 2;
+	if (quantity<50)
+		return 3;
+	if (quantity<100)
+		return 4;
+	if (quantity<250)
+		return 5;
+	if (quantity<500)
+		return 5;
+	if (quantity<1000)
+		return 6;
+	if (quantity<4000)
+		return 7;
+	return 8;
+}
+
 void CCreatureHandler::loadCreatures()
 {
 	std::string buf = CGameInfo::mainObj->bitmaph->getTextFile("ZCRTRAIT.TXT");

+ 2 - 0
hch/CCreatureHandler.h

@@ -35,6 +35,8 @@ public:
 	//end
 	CDefHandler * battleAnimation;
 	//TODO - zdolnoœci - na typie wyliczeniowym czy czymœ
+
+	static int getQuantityID(int quantity); //0 - a few, 1 - several, 2 - pack, 3 - lots, 4 - horde, 5 - throng, 6 - swarm, 7 - zounds, 8 - legion
 };
 
 class CCreatureSet //seven combined creatures

+ 18 - 65
hch/CLodHandler.cpp

@@ -380,7 +380,22 @@ CDefHandler * CLodHandler::giveDef(std::string defName)
 	CDefHandler * ret;
 	fseek(FLOD, ourEntry->offset, 0);
 	unsigned char * outp;
-	if (ourEntry->size==0) //file is not compressed
+	if (ourEntry->offset<0) //file in the sprites/ folder
+	{
+		char * outp = new char[ourEntry->realSize];
+		char name[120];for(int i=0;i<120;i++) name[i]='\0';
+		strcat(name,"Sprites/");
+		strcat(name,(char*)ourEntry->name);
+		FILE * f = fopen(name,"rb");
+		int result = fread(outp,1,ourEntry->realSize,f);
+		if(result<0) {std::cout<<"Error in file reading: "<<name<<std::endl;delete[] outp; return NULL;}
+		CDefHandler * nh = new CDefHandler();
+		nh->openFromMemory((unsigned char*)outp, ourEntry->realSize, std::string((char*)ourEntry->name));
+		nh->alphaTransformed = false;
+		ret = nh;
+		delete[] outp;
+	}
+	else if (ourEntry->size==0) //file is not compressed
 	{
 		outp = new unsigned char[ourEntry->realSize];
 		fread((char*)outp, 1, ourEntry->realSize, FLOD);
@@ -388,6 +403,7 @@ CDefHandler * CLodHandler::giveDef(std::string defName)
 		nh->openFromMemory(outp, ourEntry->realSize, std::string((char*)ourEntry->name));
 		nh->alphaTransformed = false;
 		ret = nh;
+		delete[] outp;
 	}
 	else //we will decompress file
 	{
@@ -401,8 +417,8 @@ CDefHandler * CLodHandler::giveDef(std::string defName)
 		nh->alphaTransformed = false;
 		ret = nh;
 		delete[] decomp;
+		delete[] outp;
 	}
-	delete[] outp;
 	return ret;
 }
 CDefEssential * CLodHandler::giveDefEss(std::string defName)
@@ -449,69 +465,6 @@ std::vector<CDefHandler *> CLodHandler::extractManyFiles(std::vector<std::string
 		}
 		delete[] outp;
 	}
-	//int i;
-	//std::vector<char> found(defNamesIn.size(), 0);
-	//for (int i=0;i<totalFiles;i++)
-	//{
-	//	//std::cout << "Reading def "<<i<<": "<<entries[i].name<<std::endl;
-	//	//std::cout<<'\r'<<"Reading defs: "<<(100.0*i)/((float)(totalFiles))<<"%      ";
-	//	//std::string buf1 = std::string((char*)entries[i].name);
-	//	//std::transform(buf1.begin(), buf1.end(), buf1.begin(), (int(*)(int))toupper);
-	//	bool exists = false;
-	//	int curDef;
-	//	for(int hh=0; hh<defNamesIn.size(); ++hh)
-	//	{
-	//		if(entries[i].nameStr==defNamesIn[hh])
-	//		{
-	//			exists = true;
-	//			found[hh] = '\1';
-	//			curDef = hh;
-	//			break;
-	//		}
-	//	}
-	//	if(!exists)
-	//		continue;
-	//	fseek(FLOD, entries[i].offset, 0);
-	//	unsigned char * outp;
-	//	if (entries[i].size==0) //file is not compressed
-	//	{
-	//		outp = new unsigned char[entries[i].realSize];
-	//		fread((char*)outp, 1, entries[i].realSize, FLOD);
-	//		CDefHandler * nh = new CDefHandler;
-	//		nh->openFromMemory(outp, entries[i].realSize, std::string((char*)entries[i].name));
-	//		nh->alphaTransformed = false;
-	//		ret[curDef] = nh;
-	//	}
-	//	else //we will decompressing file
-	//	{
-	//		outp = new unsigned char[entries[i].size];
-	//		fread((char*)outp, 1, entries[i].size, FLOD);
-	//		fseek(FLOD, 0, 0);
-	//		unsigned char * decomp = NULL;
-	//		int decRes = infs2(outp, entries[i].size, entries[i].realSize, decomp);
-	//		CDefHandler * nh = new CDefHandler;
-	//		nh->openFromMemory(decomp, entries[i].realSize, std::string((char*)entries[i].name));
-	//		nh->alphaTransformed = false;
-	//		delete [] decomp;
-	//		ret[curDef] = nh;
-	//	}
-	//	delete[] outp;
-	//}
-	////std::cout<<'\r'<<"Reading defs: 100%    "<<std::endl;
-	//for(int hh=0; hh<found.size(); ++hh)
-	//{
-	//	if(!found[hh])
-	//	{
-	//		for(int ff=0; ff<hh; ++ff)
-	//		{
-	//			if(defNamesIn[ff]==defNamesIn[hh])
-	//			{
-	//				ret[hh]=ret[ff];
-	//			}
-	//		}
-	//	}
-	//}
-	//std::cout<<"*** Archive: "+FName+" closed\n";
 	return ret;
 }
 int CLodHandler::infs(unsigned char * in, int size, int realSize, std::ofstream & out, int wBits)

+ 7 - 0
hch/CObjectHandler.cpp

@@ -222,6 +222,13 @@ int CGHeroInstance::getCurrentMorale() const
 	//TODO: write it
 	return 0;
 }
+int CGHeroInstance::getSecSkillLevel(int ID) const
+{
+	for(int i=0;i<secSkills.size();i++)
+		if(secSkills[i].first==ID)
+			return secSkills[i].second;
+	return -1;
+}
 
 
 int CGTownInstance::getSightDistance() const //returns sight distance

+ 9 - 4
hch/CObjectHandler.h

@@ -326,7 +326,13 @@ public:
 	CGObjectInstance& operator=(const CGObjectInstance & right);
 };
 
-class CGHeroInstance : public CGObjectInstance
+class  CArmedInstance: public CGObjectInstance
+{
+public:
+	CCreatureSet army; //army
+};
+
+class CGHeroInstance : public CArmedInstance
 {
 public:
 	int moveDir; //format:	123
@@ -340,7 +346,6 @@ public:
 	std::string name; //may be custom
 	std::string biography; //may be custom
 	int portrait; //may be custom
-	CCreatureSet army; //army
 	int mana; // remaining spell points
 	std::vector<int> primSkills; //0-attack, 1-defence, 2-spell power, 3-knowledge
 	std::vector<std::pair<int,int> > secSkills; //first - ID of skill, second - level of skill (0 - basic, 1 - adv., 2 - expert)
@@ -368,16 +373,16 @@ public:
 	bool canWalkOnSea() const;
 	int getCurrentLuck() const;
 	int getCurrentMorale() const;
+	int getSecSkillLevel(int ID) const; //-1 - no skill
 	CGHeroInstance();
 	virtual ~CGHeroInstance();
 };
 
-class CGTownInstance : public CGObjectInstance
+class CGTownInstance : public CArmedInstance
 {
 public:
 	CTown * town;
 	std::string name; // name of town
-	CCreatureSet garrison;
 	int builded; //how many buildings has been built this turn
 	int destroyed; //how many buildings has been destroyed this turn
 	int identifier;