1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

- town events implemented

- merged CustomImagecComponent into SComponent
- moved some subID-related code from CastleInterface
This commit is contained in:
Ivan Savenko 2010-08-18 14:24:30 +00:00
parent 3f31f6d33d
commit 8319e5e703
15 changed files with 204 additions and 186 deletions

View File

@ -392,36 +392,6 @@ void CHeroGSlot::setHighlight( bool on )
}
}
static std::string getBgName(int type) //TODO - co z tym zrobi�?
{
switch (type)
{
case 0:
return "TBCSBACK.bmp";
case 1:
return "TBRMBACK.bmp";
case 2:
return "TBTWBACK.bmp";
case 3:
return "TBINBACK.bmp";
case 4:
return "TBNCBACK.bmp";
case 5:
return "TBDNBACK.bmp";
case 6:
return "TBSTBACK.bmp";
case 7:
return "TBFRBACK.bmp";
case 8:
return "TBELBACK.bmp";
default:
#ifndef __GNUC__
throw new std::exception("std::string getBgName(int type): invalid type");
#else
throw new std::exception();
#endif
}
}
class SORTHELP
{
public:
@ -444,7 +414,6 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, int listPos)
fort = NULL;
market = NULL;
townInt = BitmapHandler::loadBitmap("TOWNSCRN.bmp");
cityBg = BitmapHandler::loadBitmap(getBgName(Town->subID));
pos.x = screen->w/2 - 400;
pos.y = screen->h/2 - 300;
hslotup.pos.x += pos.x;
@ -483,51 +452,9 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, int listPos)
//growth icons and buildings
recreateBuildings();
recreateIcons();
std::string defname;
switch (town->subID)
{
case 0:
defname = "HALLCSTL.DEF";
musicID = musicBase::castleTown;
break;
case 1:
defname = "HALLRAMP.DEF";
musicID = musicBase::rampartTown;
break;
case 2:
defname = "HALLTOWR.DEF";
musicID = musicBase::towerTown;
break;
case 3:
defname = "HALLINFR.DEF";
musicID = musicBase::infernoTown;
break;
case 4:
defname = "HALLNECR.DEF";
musicID = musicBase::necroTown;
break;
case 5:
defname = "HALLDUNG.DEF";
musicID = musicBase::dungeonTown;
break;
case 6:
defname = "HALLSTRN.DEF";
musicID = musicBase::strongHoldTown;
break;
case 7:
defname = "HALLFORT.DEF";
musicID = musicBase::fortressTown;
break;
case 8:
defname = "HALLELEM.DEF";
musicID = musicBase::elemTown;
break;
default:
throw new std::string("Wrong town subID");
}
bicons = CDefHandler::giveDefEss(defname);
CGI->musich->playMusic(musicID, -1);
cityBg = BitmapHandler::loadBitmap(graphics->townBgs[town->subID]);
bicons = CDefHandler::giveDefEss(graphics->buildingPics[town->subID]);
CGI->musich->playMusic(CGI->musich->townMusics[town->subID], -1);
}
CCastleInterface::~CCastleInterface()
@ -796,7 +723,7 @@ void CCastleInterface::castleTeleport(int where)
void CCastleInterface::defaultBuildingClicked(int building)
{
std::vector<SComponent*> comps(1,
new CCustomImgComponent(SComponent::building,town->subID,building,bicons->ourImages[building].bitmap,false));
new SComponent(SComponent::building,town->subID,building,bicons->ourImages[building].bitmap,false));
LOCPLINT->showInfoDialog(
CGI->buildh->buildings[town->subID].find(building)->second->Description(),
@ -806,7 +733,7 @@ void CCastleInterface::defaultBuildingClicked(int building)
void CCastleInterface::enterFountain(int building)
{
std::vector<SComponent*> comps(1,
new CCustomImgComponent(SComponent::building,town->subID,building,bicons->ourImages[building].bitmap,false));
new SComponent(SComponent::building,town->subID,building,bicons->ourImages[building].bitmap,false));
std::string descr = CGI->buildh->buildings[town->subID].find(building)->second->Description();
if ( building == 21)//we need description for mystic pond as well
@ -2051,7 +1978,7 @@ void CMageGuildScreen::Scroll::clickLeft(tribool down, bool previousState)
if(down)
{
std::vector<SComponent*> comps(1,
new CCustomImgComponent(SComponent::spell,spell->id,0,graphics->spellscr->ourImages[spell->id].bitmap,false)
new SComponent(SComponent::spell,spell->id,0)
);
LOCPLINT->showInfoDialog(spell->descriptions[0],comps, soundBase::sound_todo);
}

View File

@ -2329,7 +2329,7 @@ void CBonusSelection::showAll( SDL_Surface * to )
void CBonusSelection::loadPositionsOfGraphics()
{
std::ifstream is((GVCMIDirs.UserPath + "/config/campaign_regions.txt").c_str(), std::ios_base::binary | std::ios_base::in);
std::ifstream is(DATA_DIR "/config/campaign_regions.txt", std::ios_base::binary | std::ios_base::in);
assert(is.is_open());

View File

@ -896,6 +896,8 @@ void SComponent::init(Etype Type, int Subtype, int Val)
subtitle = CGI->generaltexth->capColors[Subtype];
break;
}
img = NULL;
free = false;
type = Type;
subtype = Subtype;
val = Val;
@ -908,7 +910,7 @@ void SComponent::init(Etype Type, int Subtype, int Val)
pos.w = temp->w;
pos.h = temp->h;
}
SComponent::SComponent(Etype Type, int Subtype, int Val)
SComponent::SComponent(Etype Type, int Subtype, int Val, SDL_Surface *sur, bool freeSur):img(sur),free(freeSur)
{
init(Type,Subtype,Val);
}
@ -925,44 +927,58 @@ SComponent::SComponent(const Component &c)
if(c.id==2 && c.when==-1)
subtitle += CGI->generaltexth->allTexts[3].substr(2,CGI->generaltexth->allTexts[3].length()-2);
}
SComponent::~SComponent()
{
if (free && img)
SDL_FreeSurface(img);
}
SDL_Surface * SComponent::setSurface(std:: string defname, int imagepos)
{
if (img)
tlog1<<"SComponent::setSurface: Warning - surface is already set!\n";
CDefEssential * def = CDefHandler::giveDefEss(defname);
free = true;
img = def->ourImages[imagepos].bitmap;
img->refcount++;//to preserve surface whed def is deleted
delete def;
}
void SComponent::show(SDL_Surface * to)
{
blitAt(getImg(),pos.x,pos.y,to);
}
SDL_Surface * SComponent::getImg()
{
if (img)
return img;
switch (type)
{
case artifact:
return graphics->artDefs->ourImages[subtype].bitmap;
break;
case primskill:
return graphics->pskillsb->ourImages[subtype].bitmap;
break;
case secskill44:
return graphics->abils44->ourImages[subtype*3 + 3 + val - 1].bitmap;
break;
case secskill:
return graphics->abils82->ourImages[subtype*3 + 3 + val - 1].bitmap;
break;
case resource:
return graphics->resources->ourImages[subtype].bitmap;
break;
case experience:
return graphics->pskillsb->ourImages[4].bitmap;
break;
case morale:
return graphics->morale82->ourImages[val+3].bitmap;
break;
case luck:
return graphics->luck82->ourImages[val+3].bitmap;
break;
case spell:
return graphics->spellscr->ourImages[subtype].bitmap;
break;
case building:
return setSurface(graphics->buildingPics[subtype],val);
case creature:
return graphics->bigImgs[subtype];
break;
case hero:
return graphics->portraitLarge[subtype];
case flag:
@ -2544,23 +2560,6 @@ CMinorResDataBar::~CMinorResDataBar()
SDL_FreeSurface(bg);
}
SDL_Surface * CCustomImgComponent::getImg()
{
return bmp;
}
CCustomImgComponent::CCustomImgComponent( Etype Type, int Subtype, int Val, SDL_Surface *sur, bool freeSur )
:bmp(sur), free(freeSur)
{
init(Type,Subtype,Val);
}
CCustomImgComponent::~CCustomImgComponent()
{
if(free)
SDL_FreeSurface(bmp);
}
CObjectListWindow::CObjectListWindow(const std::vector<int> &_items, CPicture * titlePic, std::string _title, std::string _descr,
boost::function<void(int)> Callback, int initState):items(_items), title(_title), descr(_descr),selected(initState)
{

View File

@ -159,11 +159,16 @@ public:
std::string description; //r-click
std::string subtitle; //TODO: comment me
SDL_Surface *img; //our image
bool free; //should surface be freed on delete
SDL_Surface * setSurface(std::string defName, int imgPos);
void init(Etype Type, int Subtype, int Val);
SComponent(Etype Type, int Subtype, int Val); //c-tor
SComponent(Etype Type, int Subtype, int Val, SDL_Surface *sur=NULL, bool freeSur=false); //c-tor
SComponent(const Component &c); //c-tor
SComponent(){}; //c-tor
virtual ~SComponent(){}; //d-tor
virtual ~SComponent(); //d-tor
void clickRight(tribool down, bool previousState); //call-in
SDL_Surface * getImg();
@ -172,16 +177,6 @@ public:
virtual void deactivate();
};
class CCustomImgComponent : public SComponent
{
public:
SDL_Surface *bmp; //our image
bool free; //should surface be freed on delete
SDL_Surface * getImg();
CCustomImgComponent(Etype Type, int Subtype, int Val, SDL_Surface *sur, bool freeSur); //c-tor
~CCustomImgComponent(); //d-tor
};
class CSelectableComponent : public SComponent, public KeyShortcut
{
public:

View File

@ -198,13 +198,18 @@ void Graphics::loadPaletteAndColors()
}
neutralColor->r = 0x84; neutralColor->g = 0x84; neutralColor->b = 0x84; neutralColor->unused = 0x0;//gray
std::ifstream bback(DATA_DIR "/config/mageBg.txt");
while(!bback.eof())
std::ifstream tpics(DATA_DIR "/config/townPics.txt");
assert(tpics.is_open());
while(!tpics.eof())
{
bback >> pals;
tpics >> pals;
townBgs.push_back(pals);
tpics >> pals;
guildBgs.push_back(pals);
tpics >> pals;
buildingPics.push_back(pals);
}
bback.close();
tpics.close();
}
void Graphics::initializeBattleGraphics()

View File

@ -67,12 +67,15 @@ public:
std::map<int,SDL_Surface*> bigImgs; //creature ID -> big 58x64 img of creature; //ID=-2 is for blank (black) img; -1 for the border
std::map<int,SDL_Surface*> backgrounds; //castle ID -> 100x130 background creature image // -1 is for neutral
std::map<int,SDL_Surface*> backgroundsm; //castle ID -> 100x120 background creature image // -1 is for neutral
//towns
std::vector< std::string > buildingPics;//filenames of def with building images (used rarely, too big to keep them loaded)
std::vector< std::string > townBgs;//backgrounds of town
std::vector< std::string > guildBgs;// name of bitmaps with imgs for mage guild screen
//for battles
std::vector< std::vector< std::string > > battleBacks; //battleBacks[terType] - vector of possible names for certain terrain type
std::vector< std::string > battleHeroes; //battleHeroes[hero type] - name of def that has hero animation for battle
std::map< int, std::vector < std::string > > battleACToDef; //maps AC format to vector of appropriate def names
CDefEssential * spellEffectsPics; //bitmaps representing spells affecting a stack in battle
std::vector<std::string> guildBgs;// name of bitmaps with imgs for mage guild screen
std::vector< Point > wallPositions[F_NUMBER]; //positions of different pieces of wall <x, y>
//abilities
CDefEssential * abils32, * abils44, * abils82;

View File

@ -1,9 +0,0 @@
TPMAGECS.bmp
TPMAGERM.bmp
TPMAGETW.bmp
TPMAGEIN.bmp
TPMAGENC.bmp
TPMAGEDN.bmp
TPMAGEST.bmp
TPMAGEFR.bmp
TPMAGEEL.bmp

10
config/townPics.txt Normal file
View File

@ -0,0 +1,10 @@
TBCSBACK.bmp TPMAGECS.bmp HALLCSTL.DEF
TBRMBACK.bmp TPMAGERM.bmp HALLRAMP.DEF
TBTWBACK.bmp TPMAGETW.bmp HALLTOWR.DEF
TBINBACK.bmp TPMAGEIN.bmp HALLINFR.DEF
TBNCBACK.bmp TPMAGENC.bmp HALLNECR.DEF
TBDNBACK.bmp TPMAGEDN.bmp HALLDUNG.DEF
TBSTBACK.bmp TPMAGEST.bmp HALLSTRN.DEF
TPMAGEFR.bmp TBFRBACK.bmp HALLFORT.DEF
TBELBACK.bmp TPMAGEEL.bmp HALLELEM.DEF

View File

@ -303,9 +303,15 @@ CMusicHandler::CMusicHandler(): currentMusic(NULL), nextMusic(NULL)
#undef VCMI_MUSIC_NAME
#undef VCMI_MUSIC_FILE
// Vector for helper
// Vectors for helper
battleMusics += musicBase::combat1, musicBase::combat2,
musicBase::combat3, musicBase::combat4;
townMusics += musicBase::castleTown, musicBase::rampartTown,
musicBase::towerTown, musicBase::infernoTown,
musicBase::necroTown, musicBase::dungeonTown,
musicBase::strongHoldTown, musicBase::fortressTown,
musicBase::elemTown;
}
void CMusicHandler::init()

View File

@ -120,6 +120,7 @@ public:
// Musics
std::map<musicBase::musicID, std::string> musics;
std::vector<musicBase::musicID> battleMusics;
std::vector<musicBase::musicID> townMusics;
void playMusic(musicBase::musicID musicID, int loop=1);
void playMusicFromSet(std::vector<musicBase::musicID> &music_vec, int loop=1);

View File

@ -41,6 +41,7 @@ class CGTownBuilding;
class CArtifact;
class CGDefInfo;
class CSpecObjInfo;
class CCastleEvent;
struct TerrainTile;
struct InfoWindow;
struct Component;
@ -48,30 +49,6 @@ struct BankConfig;
struct UpdateHeroSpeciality;
class CGBoat;
class DLL_EXPORT CCastleEvent
{
public:
std::string name, message;
std::vector<si32> resources; //gain / loss of resources
ui8 players; //players for whom this event can be applied
ui8 forHuman, forComputer;
ui32 firstShow; //postpone of first encounter time in days
ui32 forEvery; //every n days this event will occure
ui8 bytes[6]; //build specific buildings (raw format, similar to town's)
si32 gen[7]; //additional creatures in i-th level dwelling
bool operator<(const CCastleEvent &drugie) const
{
return firstShow<drugie.firstShow;
}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & name & message & resources & players & forHuman & forComputer & firstShow
& forEvery & bytes & gen;
}
};
class DLL_EXPORT CQuest
{
public:
@ -527,7 +504,7 @@ public:
std::vector<CGTownBuilding*> bonusingBuildings;
std::vector<ui32> possibleSpells, obligatorySpells;
std::vector<std::vector<ui32> > spells; //spells[level] -> vector of spells, first will be available in guild
std::set<CCastleEvent> events;
std::list<CCastleEvent*> events;
std::pair<si32, si32> bonusValue;//var to store town bonuses (rampart = resources from mystic pond);
//////////////////////////////////////////////////////////////////////////

View File

@ -721,41 +721,48 @@ void Mapa::loadTown( CGObjectInstance * &nobj, const unsigned char * bufor, int
for(int gh = 0; gh<numberOfEvent; ++gh)
{
CCastleEvent nce;
nce.name = readString(bufor,i);
nce.message = readString(bufor,i);
nce.resources.resize(RESOURCE_QUANTITY);
CCastleEvent *nce = new CCastleEvent();
nce->town = nt;
nce->name = readString(bufor,i);
nce->message = readString(bufor,i);
nce->resources.resize(RESOURCE_QUANTITY);
for(int x=0; x < 7; x++)
{
nce.resources[x] = readNormalNr(bufor,i);
nce->resources[x] = readNormalNr(bufor,i);
i+=4;
}
nce.players = bufor[i]; ++i;
nce->players = bufor[i]; ++i;
if(version > AB)
{
nce.forHuman = bufor[i]; ++i;
nce->humanAffected = bufor[i]; ++i;
}
else
nce.forHuman = true;
nce->humanAffected = true;
nce.forComputer = bufor[i]; ++i;
nce.firstShow = readNormalNr(bufor,i, 2); i+=2;
nce.forEvery = bufor[i]; ++i;
nce->computerAffected = bufor[i]; ++i;
nce->firstOccurence = readNormalNr(bufor,i, 2); i+=2;
nce->nextOccurence = bufor[i]; ++i;
i+=17;
for(int kk=0; kk<6; ++kk)
//new buildings
for(int byte=0;byte<6;byte++)
{
nce.bytes[kk] = bufor[i]; ++i;
for(int bit=0;bit<8;bit++)
if(bufor[i] & (1<<bit))
nce->buildings.insert(byte*8+bit);
i++;
}
nce->buildings = convertBuildings(nce->buildings,subid);
nce->creatures.resize(7);
for(int vv=0; vv<7; ++vv)
{
nce.gen[vv] = readNormalNr(bufor,i, 2); i+=2;
nce->creatures[vv] = readNormalNr(bufor,i, 2);i+=2;
}
i+=4;
nt->events.insert(nce);
nt->events.push_back(nce);
}//castle events have been read
if(version > AB)

View File

@ -177,6 +177,7 @@ public:
ui8 computerAffected;
ui32 firstOccurence;
ui32 nextOccurence; //after nextOccurance day event will occur; if it it 0, event occures only one time;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & name & message & resources
@ -187,6 +188,21 @@ public:
return firstOccurence < b.firstOccurence;
}
};
class DLL_EXPORT CCastleEvent: public CMapEvent
{
public:
std::set<si32> buildings;//build specific buildings
std::vector<si32> creatures;//additional creatures in i-th level dwelling
CGTownInstance * town;//owner of this event
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CMapEvent&>(*this);
h & buildings & creatures;
}
};
class DLL_EXPORT CMapHeader
{
public:

View File

@ -1123,6 +1123,7 @@ void CGameHandler::newTurn()
}
n.res[player][6] += (**j).dailyIncome();
}
handleTownEvents(*j, n);
if ((**j).subID == 2 && vstd::contains((**j).builtBuildings, 26)) // Skyship, probably easier to handle same as Veil of darkness
{ //do it every new day after veils apply
FoWChange fw;
@ -2604,18 +2605,18 @@ bool CGameHandler::disbandCreature( si32 id, ui8 pos )
return true;
}
bool CGameHandler::buildStructure( si32 tid, si32 bid )
bool CGameHandler::buildStructure( si32 tid, si32 bid, bool force /*=false*/ )
{
CGTownInstance * t = static_cast<CGTownInstance*>(gs->map->objects[tid]);
CBuilding * b = VLC->buildh->buildings[t->subID][bid];
if(gs->canBuildStructure(t,bid) != 7)
if( !force && gs->canBuildStructure(t,bid) != 7)
{
complain("Cannot build that building!");
return false;
}
if(bid == 26) //grail
if( !force && bid == 26) //grail
{
if(!t->visitingHero || !t->visitingHero->hasArt(2))
{
@ -2688,12 +2689,15 @@ bool CGameHandler::buildStructure( si32 tid, si32 bid )
getTilesInRange(fw.tiles,t->pos,t->getSightRadious(),t->tempOwner,1);
sendAndApply(&fw);
SetResources sr;
sr.player = t->tempOwner;
sr.res = gs->getPlayer(t->tempOwner)->resources;
for(int i=0;i<b->resources.size();i++)
sr.res[i]-=b->resources[i];
sendAndApply(&sr);
if (!force)
{
SetResources sr;
sr.player = t->tempOwner;
sr.res = gs->getPlayer(t->tempOwner)->resources;
for(int i=0;i<b->resources.size();i++)
sr.res[i]-=b->resources[i];
sendAndApply(&sr);
}
if(bid<5) //it's mage guild
{
@ -4380,6 +4384,81 @@ void CGameHandler::handleTimeEvents()
}
}
void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
{
town->events.sort(evntCmp);
while(town->events.size() && town->events.front()->firstOccurence == gs->day)
{
ui8 player = town->tempOwner;
CCastleEvent *ev = town->events.front();
PlayerState *pinfo = gs->getPlayer(player);
if( pinfo //player exists
&& (ev->players & 1<<player) //event is enabled to this player
&& ((ev->computerAffected && !pinfo->human)
|| (ev->humanAffected && pinfo->human) ) )
{
// dialog
InfoWindow iw;
iw.player = player;
iw.text << ev->message;
for (int i=0; i<ev->resources.size(); i++)
if(ev->resources[i]) //if resource had changed, we add it to the dialog
{
int was = n.res[player][i];
n.res[player][i] += ev->resources[i];
n.res[player][i] = std::max(n.res[player][i], 0);
if(pinfo->resources[i] != n.res[player][i]) //if non-zero res change
iw.components.push_back(Component(Component::RESOURCE,i,n.res[player][i]-was,0));
}
for(std::set<si32>::iterator i = ev->buildings.begin(); i!=ev->buildings.end();i++)
if ( !vstd::contains(town->builtBuildings, *i))
{
buildStructure(town->id, *i, true);
iw.components.push_back(Component(Component::BUILDING, town->subID, *i, 0));
}
SetAvailableCreatures sac;
if (n.cres.empty() || n.cres.back().tid != town->id)
{
sac.tid = town->id;
sac.creatures = town->creatures;
}
else
{
sac = n.cres.back();
n.cres.pop_back();
}
for(int i=0;i<ev->creatures.size();i++) //creature growths
{
if(town->creatureDwelling(i) && ev->creatures[i])//there is dwelling
{
sac.creatures[i].first += ev->creatures[i];
iw.components.push_back(Component(Component::CREATURE,
town->creatures[i].second.back(), ev->creatures[i], 0));
}
}
n.cres.push_back(sac);
sendAndApply(&iw); //show dialog
}
if(ev->nextOccurence)
{
ev->firstOccurence += ev->nextOccurence;
town->events.sort(evntCmp);
}
else
{
delete ev;
town->events.pop_front();
}
}
}
bool CGameHandler::complain( const std::string &problem )
{
sendMessageToAll("Server encountered a problem: " + problem);

View File

@ -8,6 +8,7 @@
#include "../lib/Connection.h"
#include "../lib/IGameCallback.h"
#include "../lib/BattleAction.h"
#include "../lib/NetPacks.h"
#include <boost/function.hpp>
#include <boost/thread.hpp>
@ -186,13 +187,14 @@ public:
bool garrisonSwap(si32 tid);
bool upgradeCreature( ui32 objid, ui8 pos, ui32 upgID );
bool recruitCreatures(si32 objid, ui32 crid, ui32 cram, si32 level);
bool buildStructure(si32 tid, si32 bid);
bool buildStructure(si32 tid, si32 bid, bool force=false);//force - for events: no cost, no checkings
bool razeStructure(si32 tid, si32 bid);
bool disbandCreature( si32 id, ui8 pos );
bool arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, si32 val, ui8 player);
void save(const std::string &fname);
void close();
void handleTimeEvents();
void handleTownEvents(CGTownInstance *town, NewTurn &n);
bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true
void objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h );
void engageIntoBattle( ui8 player );