1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

- reorganized hero classes

- artifact iconIndex should work
- new file with hardcoded string constants: lib/StringConstants.h

Note: some minor bugs, will fix soon:
- slow to open hero window
- hero adventure map images serialization is broken\incorrect
This commit is contained in:
Ivan Savenko 2012-12-14 15:32:53 +00:00
parent afe3f77a59
commit ffe8b99369
31 changed files with 2786 additions and 1355 deletions

View File

@ -12,6 +12,7 @@
#include "../lib/CTownHandler.h"
#include "../lib/NetPacks.h"
#include "../lib/CHeroHandler.h"
#include "../lib/StringConstants.h"
#include "CAdvmapInterface.h"
#include "CAnimation.h"
#include "CGameInfo.h"

View File

@ -239,7 +239,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
//loading hero animations
if(hero1) // attacking hero
{
int type = hero1->type->heroType;
int type = hero1->type->heroClass->id;
if ( type % 2 ) type--;
if ( hero1->sex ) type++;
attackingHero = new CBattleHero(graphics->battleHeroes[type], false, hero1->tempOwner, hero1->tempOwner == curInt->playerID ? hero1 : NULL, this);
@ -251,7 +251,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
}
if(hero2) // defending hero
{
int type = hero2->type->heroType;
int type = hero2->type->heroClass->id;
if ( type % 2 ) type--;
if ( hero2->sex ) type++;
defendingHero = new CBattleHero(graphics->battleHeroes[type ], true, hero2->tempOwner, hero2->tempOwner == curInt->playerID ? hero2 : NULL, this);
@ -1142,7 +1142,7 @@ void CBattleInterface::setBattleCursor(const int myNumber)
while (sectorCursor[(cursorIndex + i)%sectorCursor.size()] == -1) //Why hast thou forsaken me?
i = i <= 0 ? 1 - i : -i; // 0, 1, -1, 2, -2, 3, -3 etc..
int index = (cursorIndex + i)%sectorCursor.size(); //hopefully we get elements from sectorCursor
cursor->changeGraphic(1, sectorCursor[index]);
cursor->changeGraphic(ECursor::COMBAT, sectorCursor[index]);
switch (index)
{
case 0:
@ -1182,7 +1182,7 @@ void CBattleInterface::bOptionsf()
if(spellDestSelectMode) //we are casting a spell
return;
CCS->curh->changeGraphic(0,0);
CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
Rect tempRect = genRect(431, 481, 160, 84);
tempRect += pos.topLeft();
@ -1238,7 +1238,7 @@ void CBattleInterface::bFleef()
void CBattleInterface::reallyFlee()
{
giveCommand(BattleAction::RETREAT,0,0);
CCS->curh->changeGraphic(0, 0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
}
void CBattleInterface::reallySurrender()
@ -1250,7 +1250,7 @@ void CBattleInterface::reallySurrender()
else
{
giveCommand(BattleAction::SURRENDER,0,0);
CCS->curh->changeGraphic(0, 0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
}
}
@ -1265,7 +1265,7 @@ void CBattleInterface::bSpellf()
if(spellDestSelectMode) //we are casting a spell
return;
CCS->curh->changeGraphic(0,0);
CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
if(!myTurn)
return;
@ -1585,7 +1585,7 @@ void CBattleInterface::battleFinished(const BattleResult& br)
void CBattleInterface::displayBattleFinished()
{
CCS->curh->changeGraphic(0,0);
CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
SDL_Rect temp_rect = genRect(561, 470, (screen->w - 800)/2 + 165, (screen->h - 600)/2 + 19);
resWindow = new CBattleResultWindow(*bresult, temp_rect, this);
@ -2076,7 +2076,7 @@ void CBattleInterface::endCastingSpell()
spellToCast = NULL;
sp = NULL;
spellDestSelectMode = false;
CCS->curh->changeGraphic(1, 6);
CCS->curh->changeGraphic(ECursor::COMBAT, ECursor::COMBAT_POINTER);
if (activeStack)
{
@ -2762,7 +2762,8 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
//used when hovering -> tooltip message and cursor to be set
std::string consoleMsg;
bool setCursor = true; //if we want to suppress setting cursor
int cursorType = ECursor::COMBAT, cursorFrame = ECursor::COMBAT_POINTER; //TODO: is this line used?
ECursor::ECursorTypes cursorType = ECursor::COMBAT;
int cursorFrame = ECursor::COMBAT_POINTER; //TODO: is this line used?
//used when l-clicking -> action to be called upon the click
std::function<void()> realizeAction;
@ -3256,7 +3257,7 @@ BattleHex CBattleInterface::fromWhichHexAttack(BattleHex myNumber)
{
//TODO far too much repeating code
BattleHex destHex = -1;
switch(CCS->curh->number)
switch(CCS->curh->frame)
{
case 12: //from bottom right
{

View File

@ -173,7 +173,7 @@ void CBattleHero::clickLeft(tribool down, bool previousState)
if(myOwner->bfield[it]->hovered && myOwner->bfield[it]->strictHovered)
return;
}
CCS->curh->changeGraphic(0,0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
CSpellWindow * spellWindow = new CSpellWindow(genRect(595, 620, (screen->w - 620)/2, (screen->h - 595)/2), myHero, myOwner->curInt);
GH.pushInt(spellWindow);

View File

@ -100,7 +100,7 @@ void CTerrainRect::mouseMoved (const SDL_MouseMotionEvent & sEvent)
if(tHovered != pom) //tile outside the map
{
CCS->curh->changeGraphic(0, 0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
return;
}
@ -116,7 +116,7 @@ void CTerrainRect::hover(bool on)
if (!on)
{
adventureInt->statusbar.clear();
CCS->curh->changeGraphic(0,0);
CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
}
//Hoverable::hover(on);
}
@ -634,7 +634,7 @@ void CAdvMapInt::deactivate()
{
scrollingDir = 0;
CCS->curh->changeGraphic(0,0);
CCS->curh->changeGraphic(ECursor::ADVENTURE,0);
kingOverview.deactivate();
underground.deactivate();
questlog.deactivate();
@ -1213,7 +1213,7 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
{
if(!LOCPLINT->cb->isVisible(mapPos))
{
CCS->curh->changeGraphic(0, 0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
statusbar.clear();
return;
}
@ -1247,18 +1247,18 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
{
case Spells::SCUTTLE_BOAT:
if(objAtTile && objAtTile->ID == Obj::BOAT)
CCS->curh->changeGraphic(0, 42);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 42);
else
CCS->curh->changeGraphic(0, 0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
return;
case Spells::DIMENSION_DOOR:
{
const TerrainTile *t = LOCPLINT->cb->getTile(mapPos, false);
int3 hpos = selection->getSightCenter();
if((!t || t->isClear(LOCPLINT->cb->getTile(hpos))) && isInScreenRange(hpos, mapPos))
CCS->curh->changeGraphic(0, 41);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 41);
else
CCS->curh->changeGraphic(0, 0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
return;
}
}
@ -1271,14 +1271,14 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
if(objAtTile)
{
if(objAtTile->ID == Obj::TOWN && LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, objAtTile->tempOwner))
CCS->curh->changeGraphic(0, 3);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 3);
else if(objAtTile->ID == Obj::HERO && objAtTile->tempOwner == LOCPLINT->playerID)
CCS->curh->changeGraphic(0, 2);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 2);
else
CCS->curh->changeGraphic(0, 0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
}
else
CCS->curh->changeGraphic(0, 0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
}
else if(const CGHeroInstance *h = curHero())
{
@ -1291,18 +1291,18 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
if(!LOCPLINT->cb->getPlayerRelations( LOCPLINT->playerID, objAtTile->tempOwner)) //enemy hero
{
if(accessible)
CCS->curh->changeGraphic(0, 5 + turns*6);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 5 + turns*6);
else
CCS->curh->changeGraphic(0, 0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
}
else //our or ally hero
{
if(selection == objAtTile)
CCS->curh->changeGraphic(0, 2);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 2);
else if(accessible)
CCS->curh->changeGraphic(0, 8 + turns*6);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 8 + turns*6);
else
CCS->curh->changeGraphic(0, 2);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 2);
}
}
else if(objAtTile->ID == Obj::TOWN)
@ -1315,30 +1315,30 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
// Show movement cursor for unguarded enemy towns, otherwise attack cursor.
if (townObj && !townObj->armedGarrison())
CCS->curh->changeGraphic(0, 9 + turns*6);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 9 + turns*6);
else
CCS->curh->changeGraphic(0, 5 + turns*6);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 5 + turns*6);
}
else
{
CCS->curh->changeGraphic(0, 0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
}
}
else //our or ally town
{
if(accessible)
CCS->curh->changeGraphic(0, 9 + turns*6);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 9 + turns*6);
else
CCS->curh->changeGraphic(0, 3);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 3);
}
}
else if(objAtTile->ID == Obj::BOAT)
{
if(accessible)
CCS->curh->changeGraphic(0, 6 + turns*6);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 6 + turns*6);
else
CCS->curh->changeGraphic(0, 0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
}
else if (objAtTile->ID == Obj::GARRISON || objAtTile->ID == Obj::GARRISON2)
{
@ -1349,28 +1349,28 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
// Show battle cursor for guarded enemy garrisons, otherwise movement cursor.
if (garrObj && garrObj->stacksCount()
&& !LOCPLINT->cb->getPlayerRelations( LOCPLINT->playerID, garrObj->tempOwner) )
CCS->curh->changeGraphic(0, 5 + turns*6);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 5 + turns*6);
else
CCS->curh->changeGraphic(0, 9 + turns*6);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 9 + turns*6);
}
else
CCS->curh->changeGraphic(0, 0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
}
else if (guardingCreature && accessible) //(objAtTile->ID == 54) //monster
{
CCS->curh->changeGraphic(0, 5 + turns*6);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 5 + turns*6);
}
else
{
if(accessible)
{
if(pnode->land)
CCS->curh->changeGraphic(0, 9 + turns*6);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 9 + turns*6);
else
CCS->curh->changeGraphic(0, 28 + turns);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 28 + turns);
}
else
CCS->curh->changeGraphic(0, 0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
}
}
else //no objs
@ -1379,29 +1379,29 @@ void CAdvMapInt::tileHovered(const int3 &mapPos)
{
if (guardingCreature)
{
CCS->curh->changeGraphic(0, 5 + turns*6);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 5 + turns*6);
}
else
{
if(pnode->land)
{
if(LOCPLINT->cb->getTile(h->getPosition(false))->terType != ETerrainType::WATER)
CCS->curh->changeGraphic(0, 4 + turns*6);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 4 + turns*6);
else
CCS->curh->changeGraphic(0, 7 + turns*6); //anchor
CCS->curh->changeGraphic(ECursor::ADVENTURE, 7 + turns*6); //anchor
}
else
CCS->curh->changeGraphic(0, 6 + turns*6);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 6 + turns*6);
}
}
else
CCS->curh->changeGraphic(0, 0);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 0);
}
}
if(ourInaccessibleShipyard(objAtTile))
{
CCS->curh->changeGraphic(0, 6);
CCS->curh->changeGraphic(ECursor::ADVENTURE, 6);
}
}
@ -1480,7 +1480,7 @@ const IShipyard * CAdvMapInt::ourInaccessibleShipyard(const CGObjectInstance *ob
{
const IShipyard *ret = IShipyard::castFrom(obj);
if(!ret || obj->tempOwner != player || CCS->curh->mode || (CCS->curh->number != 6 && CCS->curh->number != 0))
if(!ret || obj->tempOwner != player || CCS->curh->type || (CCS->curh->frame != 6 && CCS->curh->frame != 0))
return NULL;
return ret;

View File

@ -624,9 +624,9 @@ void CCreatureWindow::setArt(const CArtifactInstance *art)
if (creatureArtifact)
{
if (artifactImage == NULL)
artifactImage = new CAnimImage("ARTIFACT", creatureArtifact->artType->id, 0, 466, 100);
artifactImage = new CAnimImage("ARTIFACT", creatureArtifact->artType->iconIndex, 0, 466, 100);
else
artifactImage->setFrame(creatureArtifact->artType->id);
artifactImage->setFrame(creatureArtifact->artType->iconIndex);
}
else
artifactImage = NULL;

View File

@ -1569,9 +1569,9 @@ void CPlayerInterface::update()
GH.drawFPSCounter();
// draw the mouse cursor and update the screen
CCS->curh->draw1();
CCS->curh->drawWithScreenRestore();
CSDL_Ext::update(screen);
CCS->curh->draw2();
CCS->curh->drawRestored();
}
int CPlayerInterface::getLastIndex( std::string namePrefix)

View File

@ -511,9 +511,9 @@ void CGPreGame::update()
GH.drawFPSCounter();
// draw the mouse cursor and update the screen
CCS->curh->draw1();
CCS->curh->drawWithScreenRestore();
CSDL_Ext::update(screen);
CCS->curh->draw2();
CCS->curh->drawRestored();
}
void CGPreGame::openCampaignScreen(std::string name)
@ -808,7 +808,7 @@ void CSelectionScreen::changeSelection(const CMapInfo * to)
}
else
{
sInfo.mapGenOptions = nullptr;
sInfo.mapGenOptions.reset();
}
}
}
@ -2812,7 +2812,7 @@ OptionsTab::CPregameTooltipBox::CPregameTooltipBox(CPlayerSettingsHelper & helpe
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
int value;
int value = PlayerSettings::NONE;
switch(CPlayerSettingsHelper::type)
{

View File

@ -203,9 +203,9 @@ CTownTooltip::CTownTooltip(Point pos, const CGTownInstance * town):
void CGarrisonSlot::setHighlight(bool on)
{
if (on)
selectionImage->recActions |= UPDATE | SHOWALL; //show
selectionImage->enable(); //show
else
selectionImage->recActions &= ~(UPDATE | SHOWALL); //hide
selectionImage->disable(); //hide
}
void CGarrisonSlot::hover (bool on)
@ -459,16 +459,16 @@ void CGarrisonSlot::update()
if (creature)
{
creatureImage->recActions |= (UPDATE | SHOWALL);
creatureImage->enable();
creatureImage->setFrame(creature->iconIndex);
stackCount->recActions |= (UPDATE | SHOWALL);
stackCount->enable();
stackCount->setTxt(boost::lexical_cast<std::string>(myStack->count));
}
else
{
creatureImage->recActions &= ~(UPDATE | SHOWALL);
stackCount->recActions &= ~(UPDATE | SHOWALL);
creatureImage->disable();
stackCount->disable();
}
}
@ -489,10 +489,10 @@ CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg
creatureImage = new CAnimImage(imgName, creature ? creature->iconIndex : 0);
if (!creature)
creatureImage->recActions &= ~(UPDATE | SHOWALL);
creatureImage->disable();
selectionImage = new CAnimImage(imgName, 1);
selectionImage->recActions &= ~(UPDATE | SHOWALL); //hide it
selectionImage->disable();
if(Owner->smallIcons)
{
@ -507,7 +507,7 @@ CGarrisonSlot::CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg
stackCount = new CLabel(pos.w, pos.h, owner->smallIcons ? FONT_TINY : FONT_MEDIUM, BOTTOMRIGHT, Colors::WHITE);
if (!creature)
stackCount->recActions &= ~(UPDATE | SHOWALL);
stackCount->disable();
else
stackCount->setTxt(boost::lexical_cast<std::string>(myStack->count));
}
@ -937,7 +937,7 @@ size_t CComponent::getIndex()
case secskill: return subtype*3 + 3 + val - 1;
case resource: return subtype;
case creature: return CGI->creh->creatures[subtype]->iconIndex;
case artifact: return subtype;
case artifact: return CGI->arth->artifacts[subtype]->iconIndex;
case experience: return 4;
case spell: return subtype;
case morale: return val+3;
@ -2005,7 +2005,7 @@ void CTradeWindow::CTradeableItem::clickLeft(tribool down, bool previousState)
aw->arts->markPossibleSlots(art);
//aw->arts->commonInfo->dst.AOH = aw->arts;
CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[art->artType->id].bitmap);
CCS->curh->dragAndDropCursor(new CAnimImage("artifact", art->artType->iconIndex));
aw->arts->artifactsOnAltar.erase(art);
id = -1;
@ -3964,16 +3964,67 @@ void CWindowWithGarrison::updateGarrisons()
garr->recreateSlots();
}
CArtPlace::CArtPlace(const CArtifactInstance* Art)
:picked(false), marked(false), locked(false), ourArt(Art)
{
}
CArtPlace::CArtPlace(Point position, const CArtifactInstance * Art):
picked(false), marked(false), locked(false), ourArt(Art)
locked(false), picked(false), marked(false), ourArt(Art)
{
pos += position;
pos.w = pos.h = 44;
createImage();
}
void CArtPlace::createImage()
{
OBJ_CONSTRUCTION_CAPTURING_ALL;
int graphic = 0;
if (ourArt)
graphic = ourArt->artType->iconIndex;
if (locked)
graphic = GameConstants::ID_LOCK;
image = new CAnimImage("artifact", graphic);
if (!ourArt)
image->disable();
selection = new CAnimImage("artifact", GameConstants::ID_SELECTION);
selection->disable();
}
void CArtPlace::lockSlot(bool on)
{
if (locked == on)
return;
locked = on;
if (on)
image->setFrame(GameConstants::ID_LOCK);
else
image->setFrame(ourArt->artType->iconIndex);
}
void CArtPlace::pickSlot(bool on)
{
if (picked == on)
return;
picked = on;
if (on)
image->disable();
else
image->enable();
}
void CArtPlace::selectSlot(bool on)
{
if (marked == on)
return;
marked = on;
if (on)
selection->enable();
else
selection->disable();
}
void CArtPlace::clickLeft(tribool down, bool previousState)
@ -3994,7 +4045,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
else
{
ourOwner->unmarkSlots(false);
marked = true;
selectSlot(true);
ourOwner->highlightModeCallback(this);
}
}
@ -4150,19 +4201,20 @@ void CArtPlace::select ()
if (locked)
return;
picked = true;
selectSlot(true);
pickSlot(true);
if(ourArt->canBeDisassembled() && slotID < GameConstants::BACKPACK_START) //worn combined artifact -> locks have to disappear
{
for(int i = 0; i < GameConstants::BACKPACK_START; i++)
{
CArtPlace *ap = ourOwner->getArtPlace(i);
ap->picked = ourArt->isPart(ap->ourArt);
ap->pickSlot(ourArt->isPart(ap->ourArt));
}
}
//int backpackCorrection = -(slotID - Arts::BACKPACK_START < ourOwner->backpackPos);
CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[ourArt->artType->id].bitmap);
CCS->curh->dragAndDropCursor(new CAnimImage("artifact", ourArt->artType->iconIndex));
ourOwner->commonInfo->src.setTo(this, false);
ourOwner->markPossibleSlots(ourArt);
@ -4178,11 +4230,11 @@ void CArtPlace::select ()
*/
void CArtPlace::deselect ()
{
picked = false;
pickSlot(false);
if(ourArt && ourArt->canBeDisassembled()) //combined art returned to its slot -> restore locks
{
for(int i = 0; i < GameConstants::BACKPACK_START; i++)
ourOwner->getArtPlace(i)->picked = false;
ourOwner->getArtPlace(i)->pickSlot(false);
}
CCS->curh->dragAndDropCursor(NULL);
@ -4200,8 +4252,7 @@ void CArtPlace::showAll(SDL_Surface * to)
{
if (ourArt && !picked && ourArt == ourOwner->curHero->getArt(slotID, false)) //last condition is needed for disassembling -> artifact may be gone, but we don't know yet TODO: real, nice solution
{
int graphic = locked ? GameConstants::ID_LOCK : ourArt->artType->id;
blitAt(graphics->artDefs->ourImages[graphic].bitmap, pos.x, pos.y, to);
CIntObject::showAll(to);
}
if(marked && active)
@ -4246,11 +4297,14 @@ void CArtPlace::setArtifact(const CArtifactInstance *art)
ourArt = art;
if(!art)
{
image->disable();
text = std::string();
hoverText = CGI->generaltexth->allTexts[507];
}
else
{
image->enable();
image->setFrame(locked ? GameConstants::ID_LOCK : art->artType->iconIndex);
text = ourArt->artType->Description();
if(art->artType->id == 1) //spell scroll
{
@ -4529,7 +4583,7 @@ void CArtifactsOfHero::markPossibleSlots(const CArtifactInstance* art)
{
BOOST_FOREACH(CArtifactsOfHero *aoh, commonInfo->participants)
BOOST_FOREACH(CArtPlace *place, aoh->artWorn)
place->marked = art->canBePutAt(ArtifactLocation(aoh->curHero, place->slotID), true);
place->selectSlot(art->canBePutAt(ArtifactLocation(aoh->curHero, place->slotID), true));
safeRedraw();
}
@ -4552,9 +4606,9 @@ void CArtifactsOfHero::unmarkSlots(bool withRedraw /*= true*/)
void CArtifactsOfHero::unmarkLocalSlots(bool withRedraw /*= true*/)
{
BOOST_FOREACH(CArtPlace *place, artWorn)
place->marked = false;
place->selectSlot(false);
BOOST_FOREACH(CArtPlace *place, backpack)
place->marked = false;
place->selectSlot(false);
if(withRedraw)
safeRedraw();
@ -4570,13 +4624,13 @@ void CArtifactsOfHero::setSlotData(CArtPlace* artPlace, int slotID)
return;
}
artPlace->picked = false;
artPlace->pickSlot(false);
artPlace->slotID = slotID;
if(const ArtSlotInfo *asi = curHero->getSlot(slotID))
{
artPlace->setArtifact(asi->artifact);
artPlace->locked = asi->locked;
artPlace->lockSlot(asi->locked);
}
else
artPlace->setArtifact(NULL);
@ -4587,7 +4641,7 @@ void CArtifactsOfHero::setSlotData(CArtPlace* artPlace, int slotID)
*/
void CArtifactsOfHero::eraseSlotData (CArtPlace* artPlace, int slotID)
{
artPlace->picked = false;
artPlace->pickSlot(false);
artPlace->slotID = slotID;
artPlace->setArtifact(NULL);
}
@ -4638,20 +4692,19 @@ CArtifactsOfHero::CArtifactsOfHero(const Point& position, bool createCommonPart
pos += position;
artWorn.resize(19);
std::vector<Rect> slotPos;
slotPos += genRect(44,44,509,30), genRect(44,44,567,240), genRect(44,44,509,80),
genRect(44,44,383,68), genRect(44,44,564,183), genRect(44,44,509,130),
genRect(44,44,431,68), genRect(44,44,610,183), genRect(44,44,515,295),
genRect(44,44,383,143), genRect(44,44,399,194), genRect(44,44,415,245),
genRect(44,44,431,296), genRect(44,44,564,30), genRect(44,44,610,30),
genRect(44,44,610,76), genRect(44,44,610,122), genRect(44,44,610,310),
genRect(44,44,381,296);
std::vector<Point> slotPos;
slotPos += Point(509,30), Point(567,240), Point(509,80),
Point(383,68), Point(564,183), Point(509,130),
Point(431,68), Point(610,183), Point(515,295),
Point(383,143), Point(399,194), Point(415,245),
Point(431,296), Point(564,30), Point(610,30),
Point(610,76), Point(610,122), Point(610,310),
Point(381,296);
// Create slots for worn artifacts.
for (size_t g = 0; g < 19 ; g++)
{
artWorn[g] = new CArtPlace(NULL);
artWorn[g]->pos = slotPos[g] + pos;
artWorn[g] = new CArtPlace(slotPos[g]);
artWorn[g]->ourOwner = this;
eraseSlotData(artWorn[g], g);
}
@ -4659,12 +4712,9 @@ CArtifactsOfHero::CArtifactsOfHero(const Point& position, bool createCommonPart
// Create slots for the backpack.
for(size_t s=0; s<5; ++s)
{
CArtPlace * add = new CArtPlace(NULL);
CArtPlace * add = new CArtPlace(Point(403 + 46 * s, 365));
add->ourOwner = this;
add->pos.x = pos.x + 403 + 46*s;
add->pos.y = pos.y + 365;
add->pos.h = add->pos.w = 44;
eraseSlotData(add, 19 + s);
backpack.push_back(add);
@ -4782,7 +4832,7 @@ void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const Artifact
commonInfo->src.art = dst.getArt();
commonInfo->src.slotID = dst.slot;
assert(commonInfo->src.AOH);
CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[dst.getArt()->artType->id].bitmap);
CCS->curh->dragAndDropCursor(new CAnimImage("artifact", dst.getArt()->artType->iconIndex));
markPossibleSlots(dst.getArt());
}
}
@ -5272,7 +5322,7 @@ int CUniversityWindow::CItem::state()
return 1;
if (parent->hero->secSkills.size() >= GameConstants::SKILL_PER_HERO)//can't learn more skills
return 0;
if (parent->hero->type->heroClass->proSec[ID]==0)//can't learn this skill (like necromancy for most of non-necros)
if (parent->hero->type->heroClass->secSkillProbability[ID]==0)//can't learn this skill (like necromancy for most of non-necros)
return 0;
return 2;
}

View File

@ -881,16 +881,26 @@ public:
/// Artifacts can be placed there. Gets shown at the hero window
class CArtPlace: public LRClickableAreaWTextComp
{
public:
int slotID; //Arts::EPOS enum + backpack starting from Arts::BACKPACK_START
CAnimImage *image;
CAnimImage *selection;
void createImage();
public:
// consider these members as const - change them only with appropriate methods e.g. lockSlot()
bool locked;
bool picked;
bool marked;
bool locked;
CArtifactsOfHero * ourOwner;
const CArtifactInstance * ourArt;
CArtPlace(const CArtifactInstance * Art); //c-tor
int slotID; //Arts::EPOS enum + backpack starting from Arts::BACKPACK_START
void lockSlot(bool on);
void pickSlot(bool on);
void selectSlot(bool on);
CArtifactsOfHero * ourOwner;
const CArtifactInstance * ourArt; // should be changed only with setArtifact()
CArtPlace(Point position, const CArtifactInstance * Art = NULL); //c-tor
void clickLeft(tribool down, bool previousState);
void clickRight(tribool down, bool previousState);

View File

@ -142,7 +142,6 @@ Graphics::Graphics()
tasks += GET_DEF_ESS(resources32,"RESOURCE.DEF");
tasks += GET_DEF(smi2,"TWCRPORT.DEF");
tasks += GET_DEF_ESS(flags,"CREST58.DEF");
tasks += GET_DEF_ESS(abils82,"SECSK82.DEF");
tasks += GET_DEF_ESS(spellscr,"SPELLSCR.DEF");
tasks += GET_DEF_ESS(heroMoveArrows,"ADAG.DEF");

View File

@ -66,8 +66,6 @@ public:
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
//abilities
CDefEssential * abils82;
//spells
CDefEssential *spellscr; //spell on the scroll 83x61
//functions

View File

@ -3,8 +3,8 @@
#include <SDL.h>
#include "SDL_Extensions.h"
#include "../CGameInfo.h"
#include "../CDefHandler.h"
#include "CAnimation.h"
#include "UIFramework/CGuiHandler.h"
/*
* CCursorHandler.cpp, part of VCMI engine
@ -20,31 +20,44 @@ extern SDL_Surface * screen;
void CCursorHandler::initCursor()
{
mode = number = xpos = ypos = 0;
dndImage = NULL;
xpos = ypos = 0;
type = ECursor::DEFAULT;
dndObject = nullptr;
help = CSDL_Ext::newSurface(40,40);
cursors.push_back(CDefHandler::giveDef("CRADVNTR.DEF"));
cursors.push_back(CDefHandler::giveDef("CRCOMBAT.DEF"));
cursors.push_back(CDefHandler::giveDef("CRDEFLT.DEF"));
cursors.push_back(CDefHandler::giveDef("CRSPELL.DEF"));
SDL_ShowCursor(SDL_DISABLE);
changeGraphic(ECursor::ADVENTURE, 0);
}
void CCursorHandler::changeGraphic(const int & type, const int & no)
void CCursorHandler::changeGraphic(ECursor::ECursorTypes type, int index)
{
mode = type;
number = no;
std::string cursorDefs[4] = { "CRADVNTR.DEF", "CRCOMBAT.DEF", "CRDEFLT.DEF", "CRSPELL.DEF" };
if (type != this->type)
{
BLOCK_CAPTURING; // not used here
this->type = type;
this->frame = index;
delete currentCursor;
currentCursor = new CAnimImage(cursorDefs[int(type)], index);
}
if (frame != index)
{
frame = index;
currentCursor->setFrame(index);
}
}
/**
* Replaces the cursor with a custom image.
*
* @param image Image to replace cursor with or NULL to use the normal
* cursor.
*/
void CCursorHandler::dragAndDropCursor(SDL_Surface* image)
void CCursorHandler::dragAndDropCursor(CAnimImage * object)
{
dndImage = image;
if (dndObject)
delete dndObject;
dndObject = object;
}
void CCursorHandler::cursorMove(const int & x, const int & y)
@ -52,31 +65,34 @@ void CCursorHandler::cursorMove(const int & x, const int & y)
xpos = x;
ypos = y;
}
void CCursorHandler::draw1()
void CCursorHandler::drawWithScreenRestore()
{
if(!Show) return;
if(!showing) return;
int x = xpos, y = ypos;
shiftPos(x, y);
SDL_Rect temp_rect1 = genRect(40,40,x,y);
SDL_Rect temp_rect2 = genRect(40,40,0,0);
SDL_BlitSurface(screen, &temp_rect1, help, &temp_rect2);
// if (dndImage)
// blitAt(dndImage, x - dndImage->w/2, y - dndImage->h/2);
// else
// blitAt(cursors[mode]->ourImages[number].bitmap,x,y);
if (dndImage) {
SDL_Rect temp_rect =genRect(40, 40, x - dndImage->w/2, y - dndImage->h/2);
SDL_BlitSurface(dndImage, NULL, screen, &temp_rect);
} else {
SDL_Rect temp_rect = genRect(40,40,x,y);
SDL_BlitSurface(cursors[mode]->ourImages[number].bitmap, NULL, screen, &temp_rect);
if (dndObject)
{
dndObject->moveTo(Point(x - dndObject->pos.w/2, y - dndObject->pos.h/2));
dndObject->showAll(screen);
}
else
{
currentCursor->moveTo(Point(x,y));
currentCursor->showAll(screen);
}
}
void CCursorHandler::draw2()
void CCursorHandler::drawRestored()
{
if(!Show) return;
if(!showing)
return;
int x = xpos, y = ypos;
shiftPos(x, y);
@ -87,21 +103,21 @@ void CCursorHandler::draw2()
void CCursorHandler::draw(SDL_Surface *to)
{
SDL_Rect temp_rect = genRect(40, 40, xpos, ypos);
CSDL_Ext::blitSurface(cursors[mode]->ourImages[number].bitmap, 0, to, &temp_rect);
currentCursor->moveTo(Point(xpos, ypos));
currentCursor->showAll(screen);
}
void CCursorHandler::shiftPos( int &x, int &y )
{
if((mode==1 && number!=6) || mode ==3)
if(( type == ECursor::COMBAT && frame != ECursor::COMBAT_POINTER) || type == ECursor::SPELLBOOK)
{
x-=16;
y-=16;
// Properly align the melee attack cursors.
if (mode == 1)
if (type == ECursor::COMBAT == 1)
{
switch (number)
switch (frame)
{
case 7: // Bottom left
x -= 6;
@ -138,22 +154,22 @@ void CCursorHandler::shiftPos( int &x, int &y )
}
}
}
else if(mode==0)
else if(ECursor::ADVENTURE == 0)
{
if(number == 0); //to exclude
else if(number == 2)
if (frame == 0); //to exclude
else if(frame == 2)
{
x -= 12;
y -= 10;
}
else if(number == 3)
else if(frame == 3)
{
x -= 12;
y -= 12;
}
else if(number < 27)
else if(frame < 27)
{
int hlpNum = (number - 4)%6;
int hlpNum = (frame - 4)%6;
if(hlpNum == 0)
{
x -= 15;
@ -185,12 +201,12 @@ void CCursorHandler::shiftPos( int &x, int &y )
y -= 16;
}
}
else if(number == 41)
else if(frame == 41)
{
x -= 14;
y -= 16;
}
else if(number < 31 || number == 42)
else if(frame < 31 || frame == 42)
{
x -= 20;
y -= 20;
@ -200,10 +216,9 @@ void CCursorHandler::shiftPos( int &x, int &y )
void CCursorHandler::centerCursor()
{
SDL_Surface *cursor = this->cursors[mode]->ourImages[number].bitmap;
this->xpos = (screen->w / 2.) - (cursor->w / 2.);
this->ypos = (screen->h / 2.) - (cursor->h / 2.);
SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
this->xpos = (screen->w / 2.) - (currentCursor->pos.w / 2.);
this->ypos = (screen->h / 2.) - (currentCursor->pos.h / 2.);
SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
SDL_WarpMouse(this->xpos, this->ypos);
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
}
@ -213,6 +228,6 @@ CCursorHandler::~CCursorHandler()
if(help)
SDL_FreeSurface(help);
for(int g=0; g<cursors.size(); ++g)
delete cursors[g];
delete currentCursor;
delete dndObject;
}

View File

@ -1,9 +1,6 @@
#pragma once
struct SDL_Thread;
class CDefHandler;
class CAnimImage;
struct SDL_Surface;
/*
@ -30,25 +27,48 @@ namespace ECursor
/// handles mouse cursor
class CCursorHandler
{
public:
int mode, number;
SDL_Surface * help;
SDL_Surface * dndImage;
bool Show;
CAnimImage * currentCursor;
CAnimImage * dndObject; //if set, overrides currentCursor
bool showing;
std::vector<CDefHandler*> cursors;
int xpos, ypos; //position of cursor
void initCursor(); //inits cursorHandler - run only once, it's not memleak-proof (rev 1333)
void cursorMove(const int & x, const int & y); //change cursor's positions to (x, y)
void changeGraphic(const int & type, const int & no); //changes cursor graphic for type type (0 - adventure, 1 - combat, 2 - default, 3 - spellbook) and frame no (not used for type 3)
void dragAndDropCursor (SDL_Surface* image); // Replace cursor with a custom image.
void draw1();
public:
/// position of cursor
int xpos, ypos;
/// Current cursor
ECursor::ECursorTypes type;
size_t frame;
/// inits cursorHandler - run only once, it's not memleak-proof (rev 1333)
void initCursor();
/// changes cursor graphic for type type (0 - adventure, 1 - combat, 2 - default, 3 - spellbook) and frame index (not used for type 3)
void changeGraphic(ECursor::ECursorTypes type, int index);
/**
* Replaces the cursor with a custom image.
*
* @param image Image to replace cursor with or NULL to use the normal
* cursor. CursorHandler takes ownership of object
*/
void dragAndDropCursor (CAnimImage * image);
/// Draw cursor preserving original image below cursor
void drawWithScreenRestore();
/// Restore original image below cursor
void drawRestored();
/// Simple draw cursor
void draw(SDL_Surface *to);
void shiftPos( int &x, int &y );
void draw2();
void hide() { Show=0; };
void show() { Show=1; };
void hide() { showing=0; };
void show() { showing=1; };
/// change cursor's positions to (x, y)
void cursorMove(const int & x, const int & y);
/// Move cursor to screen center
void centerCursor();
~CCursorHandler();
};

View File

@ -568,7 +568,7 @@ void CMapHandler::terrainRect( int3 top_tile, ui8 anim, const std::vector< std::
//pick graphics of hero (or boat if hero is sailing)
iv = (themp->boat)
? &graphics->boatAnims[themp->boat->subID]->ourImages
: &graphics->heroAnims[themp->type->heroType]->ourImages;
: &graphics->heroAnims[themp->type->heroClass->id]->ourImages;
//pick appropriate flag set
if(themp->boat)

File diff suppressed because it is too large Load Diff

View File

@ -310,6 +310,7 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
}
CArtifact &nart = *art;
nart.id=i;
nart.iconIndex=i;
nart.setName (parser.readString());
nart.setEventText (events.readString());
events.endLine();

View File

@ -403,7 +403,7 @@ CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, TPlayerColor p
for(auto i=available.begin(); i!=available.end(); i++)
{
if(pavailable.find(i->first)->second & 1<<player
&& i->second->type->heroType/2 == town->typeID)
&& i->second->type->heroClass->faction == town->typeID)
{
pool.push_back(i->second); //get all available heroes
}
@ -680,7 +680,7 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
cur->ID = ran.first;
h->portrait = cur->subID = ran.second;
h->type = VLC->heroh->heroes[ran.second];
h->randomizeArmy(h->type->heroType/2);
h->randomizeArmy(h->type->heroClass->faction);
map->heroes.push_back(h);
return; //TODO: maybe we should do something with definfo?
}

View File

@ -35,6 +35,16 @@ public:
std::string readString();
float readNumber();
template <typename numeric>
std::vector<numeric> readNumArray(size_t size)
{
std::vector<numeric> ret;
ret.reserve(size);
while (size--)
ret.push_back(readNumber());
return ret;
}
/// returns true if next entry is empty
bool isNextEntryEmpty();

View File

@ -5,7 +5,7 @@
#include "Filesystem/CResourceLoader.h"
#include "VCMI_Lib.h"
#include "JsonNode.h"
#include "GameConstants.h"
#include "StringConstants.h"
#include "BattleHex.h"
#include "CModHandler.h"
@ -21,7 +21,6 @@
CHeroClass::CHeroClass()
{
skillLimit = 8;
}
CHeroClass::~CHeroClass()
{
@ -33,12 +32,12 @@ int CHeroClass::chooseSecSkill(const std::set<int> & possibles) const //picks se
int totalProb = 0;
for(std::set<int>::const_iterator i=possibles.begin(); i!=possibles.end(); i++)
{
totalProb += proSec[*i];
totalProb += secSkillProbability[*i];
}
int ran = rand()%totalProb;
for(std::set<int>::const_iterator i=possibles.begin(); i!=possibles.end(); i++)
{
ran -= proSec[*i];
ran -= secSkillProbability[*i];
if(ran<0)
return *i;
}
@ -47,7 +46,7 @@ int CHeroClass::chooseSecSkill(const std::set<int> & possibles) const //picks se
EAlignment::EAlignment CHeroClass::getAlignment() const
{
return (EAlignment::EAlignment)alignment;
return EAlignment::EAlignment(VLC->townh->factions[faction].alignment);
}
std::vector<BattleHex> CObstacleInfo::getBlocked(BattleHex hex) const
@ -83,18 +82,78 @@ bool CObstacleInfo::isAppropriate(int terrainType, int specialBattlefield /*= -1
return vstd::contains(allowedTerrains, terrainType);
}
void CHeroClassHandler::load()
{
CLegacyConfigParser parser("DATA/HCTRAITS.TXT");
parser.endLine(); // header
parser.endLine();
do
{
CHeroClass * hc = new CHeroClass;
hc->name = parser.readString();
hc->aggression = parser.readNumber();
hc->id = heroClasses.size();
hc->primarySkillInitial = parser.readNumArray<int>(GameConstants::PRIMARY_SKILLS);
hc->primarySkillLowLevel = parser.readNumArray<int>(GameConstants::PRIMARY_SKILLS);
hc->primarySkillHighLevel = parser.readNumArray<int>(GameConstants::PRIMARY_SKILLS);
hc->secSkillProbability = parser.readNumArray<int>(GameConstants::SKILL_QUANTITY);
for(int dd=0; dd<GameConstants::F_NUMBER; ++dd)
{
hc->selectionProbability[dd] = parser.readNumber();
}
VLC->modh->identifiers.requestIdentifier("faction." + ETownType::names[heroClasses.size()/2],
[=](si32 faction)
{
hc->faction = faction;
});
heroClasses.push_back(hc);
VLC->modh->identifiers.registerObject("heroClass." + GameConstants::HERO_CLASSES_NAMES[hc->id], hc->id);
}
while (parser.endLine() && !parser.isNextEntryEmpty());
}
void CHeroClassHandler::load(const JsonNode & classes)
{
//TODO
}
void CHeroClassHandler::loadClass(const JsonNode & heroClass)
{
//TODO
}
CHeroClassHandler::~CHeroClassHandler()
{
BOOST_FOREACH(auto heroClass, heroClasses)
{
delete heroClass.get();
}
}
CHeroHandler::~CHeroHandler()
{
for (int i = 0; i < heroes.size(); i++)
heroes[i].dellNull();
for (int i = 0; i < heroClasses.size(); i++)
delete heroClasses[i];
BOOST_FOREACH(auto hero, heroes)
delete hero.get();
}
CHeroHandler::CHeroHandler()
{}
void CHeroHandler::load()
{
classes.load();
loadHeroes();
loadObstacles();
}
void CHeroHandler::loadObstacles()
{
auto loadObstacles = [](const JsonNode &node, bool absolute, std::map<int, CObstacleInfo> &out)
@ -154,20 +213,20 @@ void CHeroHandler::loadHeroes()
// Load heroes information
const JsonNode config(ResourceID("config/heroes.json"));
BOOST_FOREACH(const JsonNode &hero, config["heroes"].Vector()) {
int hid = hero["id"].Float();
CHero * currentHero = heroes[hero["id"].Float()];
const JsonNode *value;
// sex: 0=male, 1=female
heroes[hid]->sex = !!hero["female"].Bool();
heroes[hid]->heroType = CHero::EHeroClasses((int)hero["class"].Float());
currentHero->sex = !!hero["female"].Bool();
BOOST_FOREACH(const JsonNode &set, hero["skill_set"].Vector()) {
heroes[hid]->secSkillsInit.push_back(std::make_pair(set["skill"].Float(), set["level"].Float()));
currentHero->secSkillsInit.push_back(std::make_pair(set["skill"].Float(), set["level"].Float()));
}
value = &hero["spell"];
if (!value->isNull()) {
heroes[hid]->startingSpell = value->Float();
currentHero->startingSpell = value->Float();
}
BOOST_FOREACH(const JsonNode &specialty, hero["specialties"].Vector())
@ -179,12 +238,17 @@ void CHeroHandler::loadHeroes()
dummy.subtype = specialty["subtype"].Float();
dummy.additionalinfo = specialty["info"].Float();
heroes[hid]->spec.push_back(dummy); //put a copy of dummy
currentHero->spec.push_back(dummy); //put a copy of dummy
}
VLC->modh->identifiers.requestIdentifier("heroClass." + hero["class"].String(),
[=](si32 classID)
{
currentHero->heroClass = classes.heroClasses[classID];
});
}
loadHeroClasses();
initHeroClasses();
loadTerrains();
expPerLevel.push_back(0);
expPerLevel.push_back(1000);
expPerLevel.push_back(2000);
@ -232,61 +296,6 @@ void CHeroHandler::loadHeroes()
while (ballParser.endLine());
}
void CHeroHandler::loadHeroClasses()
{
CLegacyConfigParser parser("DATA/HCTRAITS.TXT");
parser.endLine(); // header
parser.endLine();
do
{
CHeroClass * hc = new CHeroClass;
hc->alignment = heroClasses.size() / 6;
hc->name = parser.readString();
hc->aggression = parser.readNumber();
for(int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
{
hc->initialPrimSkills[g] = parser.readNumber();
}
hc->primChance.resize(GameConstants::PRIMARY_SKILLS);
for(int x=0; x<GameConstants::PRIMARY_SKILLS; ++x)
{
hc->primChance[x].first = parser.readNumber();
}
for(int x=0; x<GameConstants::PRIMARY_SKILLS; ++x)
{
hc->primChance[x].second = parser.readNumber();
}
hc->proSec.resize(GameConstants::SKILL_QUANTITY);
for(int dd=0; dd<GameConstants::SKILL_QUANTITY; ++dd)
{
hc->proSec[dd] = parser.readNumber();
}
for(int dd=0; dd<GameConstants::F_NUMBER; ++dd)
{
hc->selectionProbability[dd] = parser.readNumber();
}
heroClasses.push_back(hc);
}
while (parser.endLine() && !parser.isNextEntryEmpty());
}
void CHeroHandler::initHeroClasses()
{
for(int gg=0; gg<heroes.size(); ++gg)
{
heroes[gg]->heroClass = heroClasses[heroes[gg]->heroType];
}
loadTerrains();
}
ui32 CHeroHandler::level (ui64 experience) const
{
int i;

View File

@ -18,6 +18,7 @@ class CDefHandler;
class CGameInfo;
class CGHeroInstance;
struct BattleHex;
class JsonNode;
struct SSpecialtyInfo
{ si32 type;
@ -45,17 +46,12 @@ public:
}
};
enum EHeroClasses {KNIGHT, CLERIC, RANGER, DRUID, ALCHEMIST, WIZARD,
DEMONIAC, HERETIC, DEATHKNIGHT, NECROMANCER, WARLOCK, OVERLORD,
BARBARIAN, BATTLEMAGE, BEASTMASTER, WITCH, PLANESWALKER, ELEMENTALIST};
std::string name; //name of hero
si32 ID;
InitialArmyStack initialArmy[3];
CHeroClass * heroClass;
EHeroClasses heroType; //hero class
std::vector<std::pair<ui8,ui8> > secSkillsInit; //initial secondary skills; first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert)
std::vector<SSpecialtyInfo> spec;
si32 startingSpell; //-1 if none
@ -67,20 +63,25 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & name & ID & initialArmy & heroClass & heroType & secSkillsInit & spec & startingSpell & sex;
h & name & ID & initialArmy & heroClass & secSkillsInit & spec & startingSpell & sex;
}
};
class DLL_LINKAGE CHeroClass
{
public:
ui8 alignment;
ui32 skillLimit; //how many secondary skills can hero learn
std::string name;
std::string identifier;
std::string name; // translatable
double aggression;
int initialPrimSkills[GameConstants::PRIMARY_SKILLS]; //initial values of primary skills, uses PrimarySkill enum
std::vector<std::pair<int,int> > primChance;//primChance[PRIMARY_SKILL_ID] - first is for levels 2 - 9, second for 10+;;; probability (%) of getting point of primary skill when getting new level
std::vector<int> proSec; //probabilities of gaining secondary skills (out of 112), in id order
TFaction faction;
ui8 id;
std::vector<int> primarySkillInitial; // initial primary skills
std::vector<int> primarySkillLowLevel; // probability (%) of getting point of primary skill when getting level
std::vector<int> primarySkillHighLevel;// same for high levels (> 10)
std::vector<int> secSkillProbability; //probabilities of gaining secondary skills (out of 112), in id order
std::map<TFaction, int> selectionProbability; //probability of selection in towns
int chooseSecSkill(const std::set<int> & possibles) const; //picks secondary skill out from given possibilities
@ -89,8 +90,10 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & skillLimit & name & aggression & initialPrimSkills & primChance
& proSec & selectionProbability & alignment;
h & identifier & name & faction & aggression;
h & primarySkillInitial & primarySkillLowLevel;
h & primarySkillHighLevel & secSkillProbability;
h & selectionProbability;
}
EAlignment::EAlignment getAlignment() const;
};
@ -116,14 +119,38 @@ struct DLL_LINKAGE CObstacleInfo
}
};
class DLL_LINKAGE CHeroHandler
class DLL_LINKAGE CHeroClassHandler
{
public:
std::vector< ConstTransitivePtr<CHero> > heroes; //changed from nodrze
std::vector<CHeroClass *> heroClasses;
std::vector< ConstTransitivePtr<CHeroClass> > heroClasses;
/// load from H3 config
void load();
/// load any number of classes from json
void load(const JsonNode & classes);
/// load one class from json
void loadClass(const JsonNode & heroClass);
~CHeroClassHandler();
template <typename Handler> void serialize(Handler &h, const int version)
{
h & heroClasses;
}
};
class DLL_LINKAGE CHeroHandler
{
std::vector<ui64> expPerLevel; //expPerLEvel[i] is amount of exp needed to reach level i; if it is not in this vector, multiplicate last value by 1,2 to get next value
//default costs of going through terrains: dirt, sand, grass, snow, swamp, rough, subterranean, lava, water, rock; -1 means terrain is imapassable
public:
CHeroClassHandler classes;
std::vector< ConstTransitivePtr<CHero> > heroes; //changed from nodrze
//default costs of going through terrains: dirt, sand, grass, snow, swamp, rough, subterranean, lava, water, rock; -1 means terrain is imapassable
std::vector<int> terrCosts;
struct SBallisticsLevelInfo
@ -147,9 +174,8 @@ public:
ui32 level(ui64 experience) const; //calculates level corresponding to given experience amount
ui64 reqExp(ui32 level) const; //calculates experience required for given level
void load();
void loadHeroes();
void loadHeroClasses();
void initHeroClasses();
void loadTerrains();
CHeroHandler(); //c-tor
~CHeroHandler(); //d-tor
@ -167,15 +193,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & heroClasses & heroes & expPerLevel & ballistics & terrCosts;
h & classes & heroes & expPerLevel & ballistics & terrCosts;
h & obstacles & absoluteObstacles;
if(!h.saving)
{
//restore class pointers
for (int i=0; i<heroes.size(); i++)
{
heroes[i]->heroClass = heroClasses[heroes[i]->heroType];
}
}
}
};

View File

@ -58,6 +58,7 @@ set(lib_HEADERS
CScriptingModule.h
CStopWatch.h
GameConstants.h
StringConstants.h
IGameEventsReceiver.h
int3.h
Interprocess.h

View File

@ -725,7 +725,7 @@ void CGHeroInstance::initHero()
{
for(int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
{
pushPrimSkill(static_cast<PrimarySkill::PrimarySkill>(g), type->heroClass->initialPrimSkills[g]);
pushPrimSkill(static_cast<PrimarySkill::PrimarySkill>(g), type->heroClass->primarySkillInitial[g]);
}
}
if(secSkills.size() == 1 && secSkills[0] == std::pair<ui8,ui8>(-1, -1)) //set secondary skills to default
@ -753,7 +753,7 @@ void CGHeroInstance::initHero()
if (VLC->modh->modules.COMMANDERS)
{
commander = new CCommanderInstance (VLC->creh->factionCommanders[type->heroType / 2]); //hopefully it returns town type
commander = new CCommanderInstance (VLC->creh->factionCommanders[type->heroClass->faction]);
commander->setArmyObj (castToArmyObj()); //TODO: separate function for setting commanders
}

View File

@ -4,7 +4,7 @@
#include "VCMI_Lib.h"
#include "CGeneralTextHandler.h"
#include "JsonNode.h"
#include "GameConstants.h"
#include "StringConstants.h"
#include "CModHandler.h"
#include "Filesystem/CResourceLoader.h"
@ -508,20 +508,12 @@ void CTownHandler::load()
JsonNode legacyConfig;
loadLegacyData(legacyConfig);
//hardcoded list of H3 factions. Should be only used to convert H3 configs
static const std::string factionName [GameConstants::F_NUMBER] =
{
"castle", "rampart", "tower",
"inferno", "necropolis", "dungeon",
"stronghold", "fortress", "conflux"
};
// semi-manually merge legacy config with towns json
for (size_t i=0; i< legacyConfig.Vector().size(); i++)
{
JsonNode & legacyFaction = legacyConfig.Vector()[i];
JsonNode & outputFaction = buildingsConf[factionName[i]];
JsonNode & outputFaction = buildingsConf[ETownType::names[i]];
if (outputFaction["name"].isNull())
outputFaction["name"] = legacyFaction["name"];

View File

@ -148,8 +148,6 @@ public:
h & names & typeID & creatures & buildings & hordeLvl & mageLevel
& primaryRes & warMachine & clientInfo;
}
friend class CTownHandler;
};
struct DLL_LINKAGE SPuzzleInfo

View File

@ -84,17 +84,11 @@ namespace GameConstants
const int BATTLE_PENALTY_DISTANCE = 10; //if the distance is > than this, then shooting stack has distance penalty
const ui16 BACKPACK_START = 19;
const int ID_CATAPULT = 3, ID_LOCK = 145;
const int ID_CATAPULT = 3, ID_SELECTION=144, ID_LOCK = 145;
const int TERRAIN_TYPES=10;
const std::string TERRAIN_NAMES [TERRAIN_TYPES] = {
"dirt", "sand", "grass", "snow", "swamp", "rough", "subterra", "lava", "water", "rock"
};
const int RESOURCE_QUANTITY=8;
const std::string RESOURCE_NAMES [RESOURCE_QUANTITY] = {
"wood", "mercury", "ore", "sulfur", "crystal", "gems", "gold", "mithril"
};
}
// Enum declarations
@ -117,8 +111,6 @@ namespace ELossConditionType
namespace EAlignment
{
enum EAlignment { GOOD, EVIL, NEUTRAL };
const std::string names [3] = {"good", "evil", "neutral"}; //for parsing from config file
}
namespace ETownType

View File

@ -38,6 +38,9 @@ public:
virtual int limit(const BonusLimitationContext &context) const; //0 - accept bonus; 1 - drop bonus; 2 - delay (drops eventually)
virtual int callNext(const BonusLimitationContext &context) const;
virtual ~LimiterDecorator()
{}
};
#define BONUS_TREE_DESERIALIZATION_FIX if(!h.saving && h.smartPointerSerialization) deserializationFix();

View File

@ -341,7 +341,7 @@ void CCampaignScenario::prepareCrossoverHeroes( std::vector<CGHeroInstance *> he
{
cgh->getBonusLocalFirst(Selector::type(Bonus::PRIMARY_SKILL) &&
Selector::subtype(g) && Selector::sourceType(Bonus::HERO_BASE_SKILL) )->val
= cgh->type->heroClass->initialPrimSkills[g];
= cgh->type->heroClass->primarySkillInitial[g];
}
}
}

View File

@ -1,6 +1,6 @@
#include "StdInc.h"
#include "ResourceSet.h"
#include "GameConstants.h"
#include "StringConstants.h"
#include "JsonNode.h"
Res::ResourceSet::ResourceSet()

67
lib/StringConstants.h Normal file
View File

@ -0,0 +1,67 @@
#pragma once
#include "GameConstants.h"
/*
* GameConstants.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
///
/// String ID which are pointless to move to config file - these types are mostly hardcoded
///
namespace GameConstants
{
const std::string TERRAIN_NAMES [TERRAIN_TYPES] = {
"dirt", "sand", "grass", "snow", "swamp", "rough", "subterra", "lava", "water", "rock"
};
const std::string RESOURCE_NAMES [RESOURCE_QUANTITY] = {
"wood", "mercury", "ore", "sulfur", "crystal", "gems", "gold", "mithril"
};
const std::string HERO_CLASSES_NAMES [F_NUMBER * 2] = {
"knight", "cleric", "ranger", "druid", "alchemist", "wizard",
"demoniac", "heretic", "deathknight", "necromancer", "warlock", "overlord",
"barbarian", "battlemage", "beastmaster", "witch", "planeswalker", "elementalist"
};
}
namespace EAlignment
{
const std::string names [3] = {"good", "evil", "neutral"};
}
namespace PrimarySkill
{
const std::string names [GameConstants::PRIMARY_SKILLS] = { "attack", "defence", "spellpower", "knowledge" };
}
namespace SecondarySkill
{
const std::string names [GameConstants::SKILL_QUANTITY] =
{
"pathfinding", "archery", "logistics", "scouting", "diplomacy", // 5
"navigation", "leadership", "wisdom", "mysticism", "luck", // 10
"ballistics", "eagleEye", "necromancy", "estates", "fireMagic", // 15
"airMagic", "waterMagic", "earthMagic", "scholar", "tactics", // 20
"artillery", "learning", "offence", "armorer", "intelligence", // 25
"sorcery", "resistance", "firstAid"
};
}
namespace ETownType
{
const std::string names [GameConstants::F_NUMBER] =
{
"castle", "rampart", "tower",
"inferno", "necropolis", "dungeon",
"stronghold", "fortress", "conflux"
};
}

View File

@ -82,8 +82,7 @@ void LibClasses::init()
tlog0<<"\tGeneral text handler: "<<pomtime.getDiff()<<std::endl;
heroh = new CHeroHandler;
heroh->loadHeroes();
heroh->loadObstacles();
heroh->load();
tlog0 <<"\tHero handler: "<<pomtime.getDiff()<<std::endl;
arth = new CArtHandler;

View File

@ -215,10 +215,12 @@ void CGameHandler::levelUpHero(int ID)
//give prim skill
tlog5 << hero->name <<" got level "<<hero->level<<std::endl;
int r = rand()%100, pom=0, x=0;
int std::pair<int,int>::*g = (hero->level>9) ? (&std::pair<int,int>::second) : (&std::pair<int,int>::first);
auto & skillChances = (hero->level>9) ? hero->type->heroClass->primarySkillLowLevel : hero->type->heroClass->primarySkillHighLevel;
for(;x<GameConstants::PRIMARY_SKILLS;x++)
{
pom += hero->type->heroClass->primChance[x].*g;
pom += skillChances[x];
if(r<pom)
break;
}
@ -257,14 +259,14 @@ void CGameHandler::levelUpHero(int ID)
hlu.skills.push_back(s);
basicAndAdv.erase(s);
}
else if(none.size() && hero->secSkills.size() < hero->type->heroClass->skillLimit)
else if(none.size() && hero->secSkills.size() < GameConstants::SKILL_PER_HERO)
{
hlu.skills.push_back(hero->type->heroClass->chooseSecSkill(none)); //give new skill
none.erase(hlu.skills.back());
}
//second offered skill
if(none.size() && hero->secSkills.size() < hero->type->heroClass->skillLimit) //hero have free skill slot
if(none.size() && hero->secSkills.size() < GameConstants::SKILL_PER_HERO) //hero have free skill slot
{
hlu.skills.push_back(hero->type->heroClass->chooseSecSkill(none)); //new skill
}
@ -1695,7 +1697,7 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
{
obj->onHeroLeave(h);
}
getTilesInRange(tmh.fowRevealed, h->getSightCenter()+(tmh.end-tmh.start), h->getSightRadious(), h->tempOwner, 1);
this->getTilesInRange(tmh.fowRevealed, h->getSightCenter()+(tmh.end-tmh.start), h->getSightRadious(), h->tempOwner, 1);
};
auto applyWithResult = [&](TryMoveHero::EResult result) -> bool
@ -3006,7 +3008,7 @@ bool CGameHandler::buySecSkill( const IMarket *m, const CGHeroInstance *h, int s
if (h->secSkills.size() >= GameConstants::SKILL_PER_HERO)//can't learn more skills
COMPLAIN_RET("Hero can't learn any more skills");
if (h->type->heroClass->proSec[skill]==0)//can't learn this skill (like necromancy for most of non-necros)
if (h->type->heroClass->secSkillProbability[skill]==0)//can't learn this skill (like necromancy for most of non-necros)
COMPLAIN_RET("The hero can't learn this skill!");
if(!vstd::contains(m->availableItemsIds(EMarketMode::RESOURCE_SKILL), skill))