mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-24 08:32:34 +02:00
Merge remote-tracking branch 'remotes/origin/develop' into feature/VCMIMapFormat1
Conflicts: lib/CArtHandler.h lib/mapObjects/MiscObjects.cpp
This commit is contained in:
commit
89d986fc6a
@ -435,10 +435,18 @@ TSubgoal VisitHero::whatToDoToAchieve()
|
||||
|
||||
bool VisitHero::fulfillsMe (TSubgoal goal)
|
||||
{
|
||||
if (goal->goalType == Goals::VISIT_TILE && cb->getObj(ObjectInstanceID(objid))->visitablePos() == goal->tile)
|
||||
return true;
|
||||
else
|
||||
if (goal->goalType != Goals::VISIT_TILE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto obj = cb->getObj(ObjectInstanceID(objid));
|
||||
if (!obj)
|
||||
{
|
||||
logAi->errorStream() << boost::format("Hero %s: VisitHero::fulfillsMe at %s: object %d not found")
|
||||
% hero.name % goal->tile % objid;
|
||||
return false;
|
||||
}
|
||||
return obj->visitablePos() == goal->tile;
|
||||
}
|
||||
|
||||
TSubgoal GetArtOfType::whatToDoToAchieve()
|
||||
|
@ -1987,7 +1987,6 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
if(teleportChannelProbingList.size())
|
||||
doChannelProbing();
|
||||
}
|
||||
ret = !i;
|
||||
}
|
||||
if (h)
|
||||
{
|
||||
@ -2002,6 +2001,8 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
completeGoal (sptr(Goals::VisitTile(dst).sethero(h))); //we stepped on some tile, anyway
|
||||
completeGoal (sptr(Goals::ClearWayTo(dst).sethero(h)));
|
||||
|
||||
ret = (dst == h->visitablePos());
|
||||
|
||||
if(!ret) //reserve object we are heading towards
|
||||
{
|
||||
auto obj = vstd::frontOrNull(cb->getVisitableObjs(dst));
|
||||
@ -2020,7 +2021,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
}
|
||||
void VCAI::tryRealize(Goals::Explore & g)
|
||||
{
|
||||
throw cannotFulfillGoalException("EXPLORE is not a elementar goal!");
|
||||
throw cannotFulfillGoalException("EXPLORE is not an elementar goal!");
|
||||
}
|
||||
|
||||
void VCAI::tryRealize(Goals::RecruitHero & g)
|
||||
|
@ -8,6 +8,8 @@ GENERAL:
|
||||
- Angel Wings
|
||||
- Boots of Levitation
|
||||
* Implemented rumors in tavern window
|
||||
* New cheat code:
|
||||
- vcmiglaurung - gives 5000 crystal dragons into each slot
|
||||
|
||||
ADVETURE AI:
|
||||
* Fixed AI trying to go through underground rock
|
||||
@ -19,6 +21,8 @@ RANDOM MAP GENERATOR:
|
||||
* Changed fractalization algorithm so it can create cycles
|
||||
* Zones will not have straight paths anymore, they are totally random
|
||||
* Added Thieves Guild random object (1 per zone)
|
||||
* Added Seer Huts with quests that match OH3
|
||||
* RMG will guarantee at least 100 pairs of Monoliths are available even if there are not enough different defs
|
||||
|
||||
0.97 -> 0.98
|
||||
GENERAL:
|
||||
|
@ -440,6 +440,11 @@ int main(int argc, char** argv)
|
||||
CCS->musich->setVolume(settings["general"]["music"].Float());
|
||||
logGlobal->infoStream()<<"Initializing screen and sound handling: "<<pomtime.getDiff();
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Ctrl+click should be treated as a right click on Mac OS X
|
||||
SDL_SetHint(SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, "1");
|
||||
#endif
|
||||
|
||||
#ifndef VCMI_NO_THREADED_LOAD
|
||||
//we can properly play intro only in the main thread, so we have to move loading to the separate thread
|
||||
boost::thread loading(init);
|
||||
|
@ -647,6 +647,8 @@ void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet
|
||||
autofightingAI->battleStart(army1, army2, int3(0,0,0), hero1, hero2, side);
|
||||
isAutoFightOn = true;
|
||||
cb->registerBattleInterface(autofightingAI);
|
||||
// Player shouldn't be able to move on adventure map if quick combat is going
|
||||
adventureInt->quickCombatLock();
|
||||
}
|
||||
|
||||
//Don't wait for dialogs when we are non-active hot-seat player
|
||||
@ -843,6 +845,7 @@ void CPlayerInterface::battleEnd(const BattleResult *br)
|
||||
isAutoFightOn = false;
|
||||
cb->unregisterBattleInterface(autofightingAI);
|
||||
autofightingAI.reset();
|
||||
adventureInt->quickCombatUnlock();
|
||||
|
||||
if(!battleInt)
|
||||
{
|
||||
@ -1332,7 +1335,7 @@ void CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
|
||||
if(showingDialog->get() || !dialogs.empty())
|
||||
return;
|
||||
|
||||
duringMovement = true;
|
||||
setMovementStatus(true);
|
||||
|
||||
if (adventureInt && adventureInt->isHeroSleeping(h))
|
||||
{
|
||||
@ -1344,8 +1347,6 @@ void CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path )
|
||||
}
|
||||
|
||||
boost::thread moveHeroTask(std::bind(&CPlayerInterface::doMoveHero,this,h,path));
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool CPlayerInterface::shiftPressed() const
|
||||
@ -1556,6 +1557,7 @@ void CPlayerInterface::centerView (int3 pos, int focusTime)
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
waitWhileDialog();
|
||||
CCS->curh->hide();
|
||||
adventureInt->centerOn (pos);
|
||||
if(focusTime)
|
||||
{
|
||||
@ -1566,6 +1568,7 @@ void CPlayerInterface::centerView (int3 pos, int focusTime)
|
||||
SDL_Delay(focusTime);
|
||||
}
|
||||
}
|
||||
CCS->curh->show();
|
||||
}
|
||||
|
||||
void CPlayerInterface::objectRemoved( const CGObjectInstance *obj )
|
||||
@ -2507,9 +2510,20 @@ void CPlayerInterface::stacksRebalanced(const StackLocation &src, const StackLoc
|
||||
garrisonsChanged(objects);
|
||||
}
|
||||
|
||||
void CPlayerInterface::askToAssembleArtifact(const ArtifactLocation &al)
|
||||
{
|
||||
auto hero = dynamic_cast<const CGHeroInstance*>(al.relatedObj());
|
||||
if(hero)
|
||||
{
|
||||
CArtPlace::askToAssemble(hero->getArt(al.slot), al.slot, hero);
|
||||
}
|
||||
}
|
||||
|
||||
void CPlayerInterface::artifactPut(const ArtifactLocation &al)
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
adventureInt->infoBar.showSelection();
|
||||
askToAssembleArtifact(al);
|
||||
}
|
||||
|
||||
void CPlayerInterface::artifactRemoved(const ArtifactLocation &al)
|
||||
@ -2534,6 +2548,7 @@ void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const Artifact
|
||||
if(artWin)
|
||||
artWin->artifactMoved(src, dst);
|
||||
}
|
||||
askToAssembleArtifact(dst);
|
||||
}
|
||||
|
||||
void CPlayerInterface::artifactAssembled(const ArtifactLocation &al)
|
||||
@ -2629,6 +2644,19 @@ bool CPlayerInterface::capturedAllEvents()
|
||||
return false;
|
||||
}
|
||||
|
||||
void CPlayerInterface::setMovementStatus(bool value)
|
||||
{
|
||||
duringMovement = value;
|
||||
if(value)
|
||||
{
|
||||
CCS->curh->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
CCS->curh->show();
|
||||
}
|
||||
}
|
||||
|
||||
void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
|
||||
{
|
||||
int i = 1;
|
||||
@ -2773,7 +2801,7 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
|
||||
adventureInt->updateNextHero(h);
|
||||
}
|
||||
|
||||
duringMovement = false;
|
||||
setMovementStatus(false);
|
||||
}
|
||||
|
||||
void CPlayerInterface::showWorldViewEx(const std::vector<ObjectPosInfo>& objectPositions)
|
||||
|
@ -295,6 +295,8 @@ private:
|
||||
bool ignoreEvents;
|
||||
|
||||
void doMoveHero(const CGHeroInstance *h, CGPath path);
|
||||
void setMovementStatus(bool value);
|
||||
void askToAssembleArtifact(const ArtifactLocation &al);
|
||||
};
|
||||
|
||||
extern CPlayerInterface * LOCPLINT;
|
||||
|
@ -214,6 +214,32 @@ void CArtPlace::clickLeft(tribool down, bool previousState)
|
||||
}
|
||||
}
|
||||
|
||||
bool CArtPlace::askToAssemble(const CArtifactInstance *art, ArtifactPosition slot,
|
||||
const CGHeroInstance *hero)
|
||||
{
|
||||
std::vector<const CArtifact *> assemblyPossibilities = art->assemblyPossibilities(hero);
|
||||
|
||||
// If the artifact can be assembled, display dialog.
|
||||
for(const CArtifact *combination : assemblyPossibilities)
|
||||
{
|
||||
LOCPLINT->showArtifactAssemblyDialog(
|
||||
art->artType->id,
|
||||
combination->id,
|
||||
true,
|
||||
std::bind(&CCallback::assembleArtifacts, LOCPLINT->cb.get(), hero, slot, true, combination->id),
|
||||
0);
|
||||
|
||||
if(assemblyPossibilities.size() > 2)
|
||||
{
|
||||
logGlobal->warnStream() << boost::format(
|
||||
"More than one possibility of assembling on %s... taking only first")
|
||||
% art->artType->Name();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CArtPlace::clickRight(tribool down, bool previousState)
|
||||
{
|
||||
if(down && ourArt && !locked && text.size() && !picked) //if there is no description or it's a lock, do nothing ;]
|
||||
@ -225,20 +251,8 @@ void CArtPlace::clickRight(tribool down, bool previousState)
|
||||
std::vector<const CArtifact *> assemblyPossibilities = ourArt->assemblyPossibilities(ourOwner->curHero);
|
||||
|
||||
// If the artifact can be assembled, display dialog.
|
||||
for(const CArtifact *combination : assemblyPossibilities)
|
||||
if (askToAssemble(ourArt, slotID, ourOwner->curHero))
|
||||
{
|
||||
LOCPLINT->showArtifactAssemblyDialog(
|
||||
ourArt->artType->id,
|
||||
combination->id,
|
||||
true,
|
||||
std::bind(&CCallback::assembleArtifacts, LOCPLINT->cb.get(), ourOwner->curHero, slotID, true, combination->id),
|
||||
0);
|
||||
|
||||
if(assemblyPossibilities.size() > 2)
|
||||
{
|
||||
logGlobal->warnStream() << "More than one possibility of assembling... taking only first";
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -587,8 +601,8 @@ void CArtifactsOfHero::setSlotData(CArtPlace* artPlace, ArtifactPosition slotID)
|
||||
|
||||
if(const ArtSlotInfo *asi = curHero->getSlot(slotID))
|
||||
{
|
||||
artPlace->setArtifact(asi->artifact);
|
||||
artPlace->lockSlot(asi->locked);
|
||||
artPlace->setArtifact(asi->artifact);
|
||||
}
|
||||
else
|
||||
artPlace->setArtifact(nullptr);
|
||||
|
@ -74,6 +74,8 @@ public:
|
||||
|
||||
void setMeAsDest(bool backpackAsVoid = true);
|
||||
void setArtifact(const CArtifactInstance *art);
|
||||
static bool askToAssemble(const CArtifactInstance *art, ArtifactPosition slot,
|
||||
const CGHeroInstance *hero);
|
||||
};
|
||||
|
||||
/// Contains artifacts of hero. Distincts which artifacts are worn or backpacked
|
||||
|
@ -186,19 +186,31 @@ std::string CComponent::getSubtitleInternal()
|
||||
case artifact: return CGI->arth->artifacts[subtype]->Name();
|
||||
case experience:
|
||||
{
|
||||
if (subtype == 1) //+1 level - tree of knowledge
|
||||
if(subtype == 1) //+1 level - tree of knowledge
|
||||
{
|
||||
std::string level = CGI->generaltexth->allTexts[442];
|
||||
boost::replace_first(level, "1", boost::lexical_cast<std::string>(val));
|
||||
return level;
|
||||
}
|
||||
else
|
||||
{
|
||||
return boost::lexical_cast<std::string>(val); //amount of experience OR level required for seer hut;
|
||||
}
|
||||
}
|
||||
case spell: return CGI->spellh->objects[subtype]->name;
|
||||
case morale: return "";
|
||||
case luck: return "";
|
||||
case building: return CGI->townh->factions[subtype]->town->buildings[BuildingID(val)]->Name();
|
||||
case building:
|
||||
{
|
||||
auto building = CGI->townh->factions[subtype]->town->buildings[BuildingID(val)];
|
||||
if(!building)
|
||||
{
|
||||
logGlobal->errorStream() << boost::format("Town of faction %s has no building #%d")
|
||||
% CGI->townh->factions[subtype]->town->faction->name % val;
|
||||
return (boost::format("Missing building #%d") % val).str();
|
||||
}
|
||||
return building->Name();
|
||||
}
|
||||
case hero: return "";
|
||||
case flag: return CGI->generaltexth->capColors[subtype];
|
||||
}
|
||||
|
@ -73,11 +73,11 @@ void CGarrisonSlot::hover (bool on)
|
||||
{
|
||||
if(upg == EGarrisonType::UP)
|
||||
{
|
||||
temp = CGI->generaltexth->tcommands[32]; //Select %s (visiting)
|
||||
temp = CGI->generaltexth->tcommands[12]; //Select %s (in garrison)
|
||||
}
|
||||
else if(owner->armedObjs[0] && (owner->armedObjs[0]->ID == Obj::TOWN || owner->armedObjs[0]->ID == Obj::HERO))
|
||||
{
|
||||
temp = CGI->generaltexth->tcommands[12]; //Select %s (in garrison)
|
||||
temp = CGI->generaltexth->tcommands[32]; //Select %s (visiting)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -322,18 +322,21 @@ void CTerrainRect::showAnim(SDL_Surface * to)
|
||||
show(to); // currently the same; maybe we should pass some flag to map handler so it redraws ONLY tiles that need redraw instead of full
|
||||
}
|
||||
|
||||
int3 CTerrainRect::whichTileIsIt(const int & x, const int & y)
|
||||
int3 CTerrainRect::whichTileIsIt(const int x, const int y)
|
||||
{
|
||||
int3 ret;
|
||||
ret.x = adventureInt->position.x + ((GH.current->motion.x-CGI->mh->offsetX-pos.x)/32);
|
||||
ret.y = adventureInt->position.y + ((GH.current->motion.y-CGI->mh->offsetY-pos.y)/32);
|
||||
ret.x = adventureInt->position.x + ((x-CGI->mh->offsetX-pos.x)/32);
|
||||
ret.y = adventureInt->position.y + ((y-CGI->mh->offsetY-pos.y)/32);
|
||||
ret.z = adventureInt->position.z;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int3 CTerrainRect::whichTileIsIt()
|
||||
{
|
||||
if(GH.current)
|
||||
return whichTileIsIt(GH.current->motion.x,GH.current->motion.y);
|
||||
else
|
||||
return int3(-1);
|
||||
}
|
||||
|
||||
int3 CTerrainRect::tileCountOnScreen()
|
||||
@ -755,14 +758,15 @@ void CAdvMapInt::updateSleepWake(const CGHeroInstance *h)
|
||||
|
||||
void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath)
|
||||
{
|
||||
//default value is for everywhere but CPlayerInterface::moveHero, because paths are not updated from there immediately
|
||||
if (hasPath == boost::indeterminate)
|
||||
hasPath = LOCPLINT->paths[h].nodes.size() ? true : false;
|
||||
if (!h)
|
||||
if(!h)
|
||||
{
|
||||
moveHero->block(true);
|
||||
return;
|
||||
}
|
||||
//default value is for everywhere but CPlayerInterface::moveHero, because paths are not updated from there immediately
|
||||
if(boost::logic::indeterminate(hasPath))
|
||||
hasPath = LOCPLINT->paths[h].nodes.size() ? true : false;
|
||||
|
||||
moveHero->block(!hasPath || (h->movement == 0));
|
||||
}
|
||||
|
||||
@ -1417,12 +1421,12 @@ void CAdvMapInt::tileLClicked(const int3 &mapPos)
|
||||
bool canSelect = topBlocking && topBlocking->ID == Obj::HERO && topBlocking->tempOwner == LOCPLINT->playerID;
|
||||
canSelect |= topBlocking && topBlocking->ID == Obj::TOWN && LOCPLINT->cb->getPlayerRelations(LOCPLINT->playerID, topBlocking->tempOwner);
|
||||
|
||||
if (selection->ID != Obj::HERO) //hero is not selected (presumably town)
|
||||
if(selection->ID != Obj::HERO) //hero is not selected (presumably town)
|
||||
{
|
||||
assert(!terrain.currentPath); //path can be active only when hero is selected
|
||||
if(selection == topBlocking) //selected town clicked
|
||||
LOCPLINT->openTownWindow(static_cast<const CGTownInstance*>(topBlocking));
|
||||
else if ( canSelect )
|
||||
else if(canSelect)
|
||||
select(static_cast<const CArmedInstance*>(topBlocking), false);
|
||||
return;
|
||||
}
|
||||
@ -1441,22 +1445,26 @@ void CAdvMapInt::tileLClicked(const int3 &mapPos)
|
||||
}
|
||||
else //still here? we need to move hero if we clicked end of already selected path or calculate a new path otherwise
|
||||
{
|
||||
if (terrain.currentPath && terrain.currentPath->endPos() == mapPos)//we'll be moving
|
||||
if(terrain.currentPath && terrain.currentPath->endPos() == mapPos)//we'll be moving
|
||||
{
|
||||
if (CGI->mh->canStartHeroMovement())
|
||||
LOCPLINT->moveHero(currentHero,*terrain.currentPath);
|
||||
if(CGI->mh->canStartHeroMovement())
|
||||
LOCPLINT->moveHero(currentHero, *terrain.currentPath);
|
||||
return;
|
||||
}
|
||||
else/* if(mp.z == currentHero->pos.z)*/ //remove old path and find a new one if we clicked on the map level on which hero is present
|
||||
else //remove old path and find a new one if we clicked on accessible tile
|
||||
{
|
||||
CGPath &path = LOCPLINT->paths[currentHero];
|
||||
CGPath newpath;
|
||||
bool gotPath = LOCPLINT->cb->getPathsInfo(currentHero)->getPath(newpath, mapPos); //try getting path, erase if failed
|
||||
if(gotPath && newpath.nodes.size())
|
||||
path = newpath;
|
||||
|
||||
if(path.nodes.size())
|
||||
terrain.currentPath = &path;
|
||||
bool gotPath = LOCPLINT->cb->getPathsInfo(currentHero)->getPath(path, mapPos); //try getting path, erase if failed
|
||||
updateMoveHero(currentHero);
|
||||
if (!gotPath)
|
||||
LOCPLINT->eraseCurrentPathOf(currentHero);
|
||||
else
|
||||
return;
|
||||
LOCPLINT->eraseCurrentPathOf(currentHero);
|
||||
|
||||
updateMoveHero(currentHero);
|
||||
}
|
||||
}
|
||||
} //end of hero is selected "case"
|
||||
@ -1704,6 +1712,18 @@ void CAdvMapInt::adjustActiveness(bool aiTurnStart)
|
||||
activate();
|
||||
}
|
||||
|
||||
void CAdvMapInt::quickCombatLock()
|
||||
{
|
||||
if(!duringAITurn)
|
||||
deactivate();
|
||||
}
|
||||
|
||||
void CAdvMapInt::quickCombatUnlock()
|
||||
{
|
||||
if(!duringAITurn)
|
||||
activate();
|
||||
}
|
||||
|
||||
void CAdvMapInt::changeMode(EAdvMapMode newMode, float newScale /* = 0.4f */)
|
||||
{
|
||||
if (mode != newMode)
|
||||
|
@ -74,7 +74,7 @@ public:
|
||||
void showAll(SDL_Surface * to) override;
|
||||
void showAnim(SDL_Surface * to);
|
||||
void showPath(const SDL_Rect * extRect, SDL_Surface * to);
|
||||
int3 whichTileIsIt(const int & x, const int & y); //x,y are cursor position
|
||||
int3 whichTileIsIt(const int x, const int y); //x,y are cursor position
|
||||
int3 whichTileIsIt(); //uses current cursor pos
|
||||
/// @returns number of visible tiles on screen respecting current map scaling
|
||||
int3 tileCountOnScreen();
|
||||
@ -224,6 +224,8 @@ public:
|
||||
void aiTurnStarted();
|
||||
|
||||
void adjustActiveness(bool aiTurnStart); //should be called every time at AI/human turn transition; blocks GUI during AI turn
|
||||
void quickCombatLock(); //should be called when quick battle started
|
||||
void quickCombatUnlock();
|
||||
void tileLClicked(const int3 &mapPos);
|
||||
void tileHovered(const int3 &mapPos);
|
||||
void tileRClicked(const int3 &mapPos);
|
||||
|
@ -1178,9 +1178,42 @@ const CArtifactInstance * CArtifactSet::getArtByInstanceId( ArtifactInstanceID a
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CArtifactSet::hasArt(ui32 aid, bool onlyWorn /*= false*/) const
|
||||
bool CArtifactSet::hasArt(ui32 aid, bool onlyWorn /*= false*/,
|
||||
bool searchBackpackAssemblies /*= false*/) const
|
||||
{
|
||||
return getArtPos(aid, onlyWorn) != ArtifactPosition::PRE_FIRST;
|
||||
return getArtPos(aid, onlyWorn) != ArtifactPosition::PRE_FIRST ||
|
||||
(searchBackpackAssemblies && getHiddenArt(aid));
|
||||
}
|
||||
|
||||
std::pair<const CCombinedArtifactInstance *, const CArtifactInstance *>
|
||||
CArtifactSet::searchForConstituent(int aid) const
|
||||
{
|
||||
for(auto & slot : artifactsInBackpack)
|
||||
{
|
||||
auto art = slot.artifact;
|
||||
if(art->canBeDisassembled())
|
||||
{
|
||||
auto ass = static_cast<CCombinedArtifactInstance *>(art.get());
|
||||
for(auto& ci : ass->constituentsInfo)
|
||||
{
|
||||
if(ci.art->artType->id == aid)
|
||||
{
|
||||
return {ass, ci.art};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {nullptr, nullptr};
|
||||
}
|
||||
|
||||
const CArtifactInstance *CArtifactSet::getHiddenArt(int aid) const
|
||||
{
|
||||
return searchForConstituent(aid).second;
|
||||
}
|
||||
|
||||
const CCombinedArtifactInstance *CArtifactSet::getAssemblyByConstituent(int aid) const
|
||||
{
|
||||
return searchForConstituent(aid).first;
|
||||
}
|
||||
|
||||
const ArtSlotInfo * CArtifactSet::getSlot(ArtifactPosition pos) const
|
||||
|
@ -133,7 +133,9 @@ public:
|
||||
virtual bool canBeDisassembled() const;
|
||||
virtual void putAt(ArtifactLocation al);
|
||||
virtual void removeFrom(ArtifactLocation al);
|
||||
virtual bool isPart(const CArtifactInstance *supposedPart) const; //checks if this a part of this artifact: artifact instance is a part of itself, additionally truth is returned for consituents of combined arts
|
||||
/// Checks if this a part of this artifact: artifact instance is a part
|
||||
/// of itself, additionally truth is returned for constituents of combined arts
|
||||
virtual bool isPart(const CArtifactInstance *supposedPart) const;
|
||||
|
||||
std::vector<const CArtifact *> assemblyPossibilities(const CArtifactSet *h) const;
|
||||
void move(ArtifactLocation src, ArtifactLocation dst);
|
||||
@ -177,7 +179,7 @@ public:
|
||||
|
||||
void createConstituents();
|
||||
void addAsConstituent(CArtifactInstance *art, ArtifactPosition slot);
|
||||
CArtifactInstance *figureMainConstituent(const ArtifactLocation al); //main constituent is replcaed with us (combined art), not lock
|
||||
CArtifactInstance *figureMainConstituent(const ArtifactLocation al); //main constituent is replaced with us (combined art), not lock
|
||||
|
||||
CCombinedArtifactInstance();
|
||||
|
||||
@ -270,10 +272,8 @@ struct DLL_LINKAGE ArtSlotInfo
|
||||
ConstTransitivePtr<CArtifactInstance> artifact;
|
||||
ui8 locked; //if locked, then artifact points to the combined artifact
|
||||
|
||||
ArtSlotInfo()
|
||||
{
|
||||
locked = false;
|
||||
}
|
||||
ArtSlotInfo() : locked(false) {}
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & artifact & locked;
|
||||
@ -293,10 +293,16 @@ public:
|
||||
const ArtSlotInfo *getSlot(ArtifactPosition pos) const;
|
||||
const CArtifactInstance* getArt(ArtifactPosition pos, bool excludeLocked = true) const; //nullptr - no artifact
|
||||
CArtifactInstance* getArt(ArtifactPosition pos, bool excludeLocked = true); //nullptr - no artifact
|
||||
ArtifactPosition getArtPos(int aid, bool onlyWorn = true) const; //looks for equipped artifact with given ID and returns its slot ID or -1 if none(if more than one such artifact lower ID is returned)
|
||||
/// Looks for equipped artifact with given ID and returns its slot ID or -1 if none
|
||||
/// (if more than one such artifact lower ID is returned)
|
||||
ArtifactPosition getArtPos(int aid, bool onlyWorn = true) const;
|
||||
ArtifactPosition getArtPos(const CArtifactInstance *art) const;
|
||||
const CArtifactInstance *getArtByInstanceId(ArtifactInstanceID artInstId) const;
|
||||
bool hasArt(ui32 aid, bool onlyWorn = false) const; //checks if hero possess artifact of given id (either in backack or worn)
|
||||
/// Search for constituents of assemblies in backpack which do not have an ArtifactPosition
|
||||
const CArtifactInstance *getHiddenArt(int aid) const;
|
||||
const CCombinedArtifactInstance *getAssemblyByConstituent(int aid) const;
|
||||
/// Checks if hero possess artifact of given id (either in backack or worn)
|
||||
bool hasArt(ui32 aid, bool onlyWorn = false, bool searchBackpackAssemblies = false) const;
|
||||
bool isPositionFree(ArtifactPosition pos, bool onlyLockCheck = false) const;
|
||||
si32 getArtTypeId(ArtifactPosition pos) const;
|
||||
|
||||
@ -313,4 +319,7 @@ public:
|
||||
protected:
|
||||
void writeJson(JsonNode & json) const;
|
||||
void readJson(const JsonNode & json);
|
||||
|
||||
protected:
|
||||
std::pair<const CCombinedArtifactInstance *, const CArtifactInstance *> searchForConstituent(int aid) const;
|
||||
};
|
||||
|
@ -1658,15 +1658,16 @@ void CGameState::initStartingBonus()
|
||||
switch(scenarioOps->playerInfos[elem.first].bonus)
|
||||
{
|
||||
case PlayerSettings::GOLD:
|
||||
elem.second.resources[Res::GOLD] += rand.nextInt(500, 1000);
|
||||
elem.second.resources[Res::GOLD] += rand.nextInt(5, 10) * 100;
|
||||
break;
|
||||
case PlayerSettings::RESOURCE:
|
||||
{
|
||||
int res = VLC->townh->factions[scenarioOps->playerInfos[elem.first].castle]->town->primaryRes;
|
||||
if(res == Res::WOOD_AND_ORE)
|
||||
{
|
||||
elem.second.resources[Res::WOOD] += rand.nextInt(5, 10);
|
||||
elem.second.resources[Res::ORE] += rand.nextInt(5, 10);
|
||||
int amount = rand.nextInt(5, 10);
|
||||
elem.second.resources[Res::WOOD] += amount;
|
||||
elem.second.resources[Res::ORE] += amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
namespace GameConstants
|
||||
{
|
||||
const std::string VCMI_VERSION = "VCMI 0.98f";
|
||||
const std::string VCMI_VERSION = "VCMI 0.98g";
|
||||
|
||||
const int BFIELD_WIDTH = 17;
|
||||
const int BFIELD_HEIGHT = 11;
|
||||
|
@ -754,7 +754,7 @@ DLL_LINKAGE const CArtifactInstance *ArtifactLocation::getArt() const
|
||||
return s->artifact;
|
||||
else
|
||||
{
|
||||
logNetwork->warnStream() << "ArtifactLocation::getArt: That location is locked!";
|
||||
logNetwork->warnStream() << "ArtifactLocation::getArt: This location is locked!";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@ -914,6 +914,32 @@ DLL_LINKAGE void PutArtifact::applyGs( CGameState *gs )
|
||||
|
||||
DLL_LINKAGE void EraseArtifact::applyGs( CGameState *gs )
|
||||
{
|
||||
auto slot = al.getSlot();
|
||||
if(slot->locked)
|
||||
{
|
||||
logGlobal->debugStream() << "Erasing locked artifact: " << slot->artifact->artType->Name();
|
||||
DisassembledArtifact dis;
|
||||
dis.al.artHolder = al.artHolder;
|
||||
auto aset = al.getHolderArtSet();
|
||||
bool found = false;
|
||||
for(auto& p : aset->artifactsWorn)
|
||||
{
|
||||
auto art = p.second.artifact;
|
||||
if(art->canBeDisassembled() && art->isPart(slot->artifact))
|
||||
{
|
||||
dis.al.slot = aset->getArtPos(art);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(found && "Failed to determine the assembly this locked artifact belongs to");
|
||||
logGlobal->debugStream() << "Found the corresponding assembly: " << dis.al.getSlot()->artifact->artType->Name();
|
||||
dis.applyGs(gs);
|
||||
}
|
||||
else
|
||||
{
|
||||
logGlobal->debugStream() << "Erasing artifact " << slot->artifact->artType->Name();
|
||||
}
|
||||
al.removeArtifact();
|
||||
}
|
||||
|
||||
|
@ -315,6 +315,16 @@ void CObjectClassesHandler::afterLoadFinalization()
|
||||
logGlobal->warnStream() << "No templates found for " << entry.first << ":" << obj.first;
|
||||
}
|
||||
}
|
||||
|
||||
//duplicate existing two-way portals to make reserve for RMG
|
||||
auto& portalVec = objects[Obj::MONOLITH_TWO_WAY]->objects;
|
||||
size_t portalCount = portalVec.size();
|
||||
size_t currentIndex = portalCount;
|
||||
while (portalVec.size() < 100)
|
||||
{
|
||||
portalVec[currentIndex] = portalVec[currentIndex % portalCount];
|
||||
currentIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
std::string CObjectClassesHandler::getObjectName(si32 type) const
|
||||
|
@ -183,7 +183,7 @@ std::set<int3> CGObjectInstance::getBlockedPos() const
|
||||
{
|
||||
for(int h=0; h<getHeight(); ++h)
|
||||
{
|
||||
if (appearance.isBlockedAt(w, h))
|
||||
if(appearance.isBlockedAt(w, h))
|
||||
ret.insert(int3(pos.x - w, pos.y - h, pos.z));
|
||||
}
|
||||
}
|
||||
@ -205,7 +205,13 @@ void CGObjectInstance::setType(si32 ID, si32 subID)
|
||||
//recalculate blockvis tiles - new appearance might have different blockmap than before
|
||||
cb->gameState()->map->removeBlockVisTiles(this, true);
|
||||
auto handler = VLC->objtypeh->getHandlerFor(ID, subID);
|
||||
if (!handler->getTemplates(tile.terType).empty())
|
||||
if(!handler)
|
||||
{
|
||||
logGlobal->errorStream() << boost::format(
|
||||
"Unknown object type %d:%d at %s") % ID % subID % visitablePos();
|
||||
return;
|
||||
}
|
||||
if(!handler->getTemplates(tile.terType).empty())
|
||||
appearance = handler->getTemplates(tile.terType)[0];
|
||||
else
|
||||
appearance = handler->getTemplates()[0]; // get at least some appearance since alternative is crash
|
||||
@ -410,9 +416,9 @@ int3 IBoatGenerator::bestLocation() const
|
||||
|
||||
for (auto & offset : offsets)
|
||||
{
|
||||
if (const TerrainTile *tile = IObjectInterface::cb->getTile(o->pos + offset, false)) //tile is in the map
|
||||
if(const TerrainTile *tile = IObjectInterface::cb->getTile(o->pos + offset, false)) //tile is in the map
|
||||
{
|
||||
if (tile->terType == ETerrainType::WATER && (!tile->blocked || tile->blockingObjects.front()->ID == Obj::BOAT)) //and is water and is not blocked or is blocked by boat
|
||||
if(tile->terType == ETerrainType::WATER && (!tile->blocked || tile->blockingObjects.front()->ID == Obj::BOAT)) //and is water and is not blocked or is blocked by boat
|
||||
return o->pos + offset;
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ bool CQuest::checkQuest (const CGHeroInstance * h) const
|
||||
case MISSION_ART:
|
||||
for (auto & elem : m5arts)
|
||||
{
|
||||
if (h->hasArt(elem))
|
||||
if (h->hasArt(elem, false, true))
|
||||
continue;
|
||||
return false; //if the artifact was not found
|
||||
}
|
||||
@ -630,6 +630,18 @@ void CGSeerHut::finishQuest(const CGHeroInstance * h, ui32 accept) const
|
||||
case CQuest::MISSION_ART:
|
||||
for (auto & elem : quest->m5arts)
|
||||
{
|
||||
if(!h->hasArt(elem))
|
||||
{
|
||||
// first we need to disassemble this backpack artifact
|
||||
auto assembly = h->getAssemblyByConstituent(elem);
|
||||
assert(assembly);
|
||||
for(auto & ci : assembly->constituentsInfo)
|
||||
{
|
||||
cb->giveHeroNewArtifact(h, ci.art->artType, ArtifactPosition::PRE_FIRST);
|
||||
}
|
||||
// remove the assembly
|
||||
cb->removeArtifact(ArtifactLocation(h, h->getArtPos(assembly)));
|
||||
}
|
||||
cb->removeArtifact(ArtifactLocation(h, h->getArtPos(elem, false)));
|
||||
}
|
||||
break;
|
||||
|
@ -496,6 +496,7 @@ void CGPickable::initObj()
|
||||
info.resize(1);
|
||||
info[0].message.addTxt(MetaString::ADVOB_TXT, 51);
|
||||
info[0].reward.removeObject = true;
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
info.resize(1);
|
||||
@ -682,7 +683,6 @@ void CGBonusingObject::initObj()
|
||||
info[i].message.addTxt(MetaString::ADVOB_TXT, 62);
|
||||
soundID = soundBase::experience;
|
||||
}
|
||||
onVisited.addTxt(MetaString::ADVOB_TXT, 63);
|
||||
info.back().limiter.dayOfWeek = 7;
|
||||
configureBonus(info.back(), Bonus::MORALE, 1, 68); // on last day of week
|
||||
configureBonus(info.back(), Bonus::LUCK, 1, 68);
|
||||
|
@ -393,6 +393,7 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co
|
||||
if(cost)
|
||||
cb->giveResource(h->tempOwner,Res::GOLD,-cost);
|
||||
|
||||
giveReward(h);
|
||||
cb->tryJoiningArmy(this, h, true, true);
|
||||
}
|
||||
}
|
||||
@ -456,6 +457,7 @@ void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult &
|
||||
|
||||
if(result.winner==0)
|
||||
{
|
||||
giveReward(hero);
|
||||
cb->removeObject(this);
|
||||
}
|
||||
else
|
||||
@ -558,6 +560,35 @@ int CGCreature::getNumberOfStacks(const CGHeroInstance *hero) const
|
||||
return split;
|
||||
}
|
||||
|
||||
void CGCreature::giveReward(const CGHeroInstance * h) const
|
||||
{
|
||||
InfoWindow iw;
|
||||
iw.player = h->tempOwner;
|
||||
|
||||
if(resources.size())
|
||||
{
|
||||
cb->giveResources(h->tempOwner, resources);
|
||||
for(int i = 0; i < resources.size(); i++)
|
||||
{
|
||||
if(resources[i] > 0)
|
||||
iw.components.push_back(Component(Component::RESOURCE, i, resources[i], 0));
|
||||
}
|
||||
}
|
||||
|
||||
if(gainedArtifact != ArtifactID::NONE)
|
||||
{
|
||||
cb->giveHeroNewArtifact(h, VLC->arth->artifacts[gainedArtifact], ArtifactPosition::FIRST_AVAILABLE);
|
||||
iw.components.push_back(Component(Component::ARTIFACT, gainedArtifact, 0, 0));
|
||||
}
|
||||
|
||||
if(iw.components.size())
|
||||
{
|
||||
iw.text.addTxt(MetaString::ADVOB_TXT, 183); // % has found treasure
|
||||
iw.text.addReplacement(h->name);
|
||||
cb->showInfoDialog(&iw);
|
||||
}
|
||||
}
|
||||
|
||||
void CGCreature::writeJsonOptions(JsonNode& json) const
|
||||
{
|
||||
|
||||
@ -1791,6 +1822,7 @@ void CGMagi::onHeroVisit(const CGHeroInstance * h) const
|
||||
cb->sendAndApply(&cv);
|
||||
}
|
||||
cv.pos = h->getPosition(false);
|
||||
cv.focusTime = 0;
|
||||
cb->sendAndApply(&cv);
|
||||
}
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ private:
|
||||
void joinDecision(const CGHeroInstance *h, int cost, ui32 accept) const;
|
||||
|
||||
int takenAction(const CGHeroInstance *h, bool allowJoin=true) const; //action on confrontation: -2 - fight, -1 - flee, >=0 - will join for given value of gold (may be 0)
|
||||
void giveReward(const CGHeroInstance * h) const;
|
||||
|
||||
};
|
||||
|
||||
|
@ -20,6 +20,8 @@ void CMapGenerator::foreach_neighbour(const int3 &pos, std::function<void(int3&
|
||||
for(const int3 &dir : int3::getDirs())
|
||||
{
|
||||
int3 n = pos + dir;
|
||||
/*important notice: perform any translation before this function is called,
|
||||
so the actual map position is checked*/
|
||||
if(map->isInTheMap(n))
|
||||
foo(n);
|
||||
}
|
||||
|
@ -1176,17 +1176,16 @@ bool CRmgTemplateZone::createTreasurePile(CMapGenerator* gen, int3 &pos, float m
|
||||
|
||||
int3 closestTile = int3(-1,-1,-1);
|
||||
float minDistance = 1e10;
|
||||
|
||||
for (auto visitablePos : info.visitableFromBottomPositions) //objects that are not visitable from top must be accessible from bottom or side
|
||||
{
|
||||
int3 closestFreeTile = findClosestTile(freePaths, visitablePos);
|
||||
if (closestFreeTile.dist2d(visitablePos) < minDistance)
|
||||
{
|
||||
closestTile = visitablePos + int3 (0, 1, 0); //start below object (y+1), possibly even outside the map (?)
|
||||
closestTile = visitablePos + int3 (0, 1, 0); //start below object (y+1), possibly even outside the map, to not make path up through it
|
||||
minDistance = closestFreeTile.dist2d(visitablePos);
|
||||
}
|
||||
}
|
||||
if (!closestTile.valid())
|
||||
{
|
||||
for (auto visitablePos : info.visitableFromTopPositions) //all objects are accessible from any direction
|
||||
{
|
||||
int3 closestFreeTile = findClosestTile(freePaths, visitablePos);
|
||||
@ -1196,7 +1195,6 @@ bool CRmgTemplateZone::createTreasurePile(CMapGenerator* gen, int3 &pos, float m
|
||||
minDistance = closestFreeTile.dist2d(visitablePos);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert (closestTile.valid());
|
||||
|
||||
for (auto tile : info.occupiedPositions)
|
||||
@ -1245,6 +1243,8 @@ bool CRmgTemplateZone::createTreasurePile(CMapGenerator* gen, int3 &pos, float m
|
||||
for (auto treasure : treasures)
|
||||
{
|
||||
int3 visitableOffset = treasure.second->getVisitableOffset();
|
||||
if (treasure.second->ID == Obj::SEER_HUT) //FIXME: find generic solution or figure out why Seer Hut doesn't behave correctly
|
||||
visitableOffset.x += 1;
|
||||
placeObject(gen, treasure.second, treasure.first + visitableOffset);
|
||||
}
|
||||
if (addMonster(gen, guardPos, currentValue, false))
|
||||
@ -2661,8 +2661,7 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
|
||||
//seer huts with creatures or generic rewards
|
||||
|
||||
//if (questArtZone) //we won't be placing seer huts if there is no zone left to place arties
|
||||
if (false) //FIXME: Seer Huts are bugged
|
||||
if (questArtZone) //we won't be placing seer huts if there is no zone left to place arties
|
||||
{
|
||||
static const int genericSeerHuts = 8;
|
||||
int seerHutsPerType = 0;
|
||||
@ -2718,6 +2717,9 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
obj->quest->missionType = CQuest::MISSION_ART;
|
||||
ArtifactID artid = *RandomGeneratorUtil::nextItem(gen->getQuestArtsRemaning(), gen->rand);
|
||||
obj->quest->m5arts.push_back(artid);
|
||||
obj->quest->lastDay = -1;
|
||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
||||
|
||||
gen->banQuestArt(artid);
|
||||
gen->map->addQuest(obj);
|
||||
|
||||
@ -2754,6 +2756,9 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
obj->quest->missionType = CQuest::MISSION_ART;
|
||||
ArtifactID artid = *RandomGeneratorUtil::nextItem(gen->getQuestArtsRemaning(), gen->rand);
|
||||
obj->quest->m5arts.push_back(artid);
|
||||
obj->quest->lastDay = -1;
|
||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
||||
|
||||
gen->banQuestArt(artid);
|
||||
gen->map->addQuest(obj);
|
||||
|
||||
@ -2775,6 +2780,9 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen)
|
||||
obj->quest->missionType = CQuest::MISSION_ART;
|
||||
ArtifactID artid = *RandomGeneratorUtil::nextItem(gen->getQuestArtsRemaning(), gen->rand);
|
||||
obj->quest->m5arts.push_back(artid);
|
||||
obj->quest->lastDay = -1;
|
||||
obj->quest->isCustomFirst = obj->quest->isCustomNext = obj->quest->isCustomComplete = false;
|
||||
|
||||
gen->banQuestArt(artid);
|
||||
gen->map->addQuest(obj);
|
||||
|
||||
|
@ -926,7 +926,10 @@ void CGameHandler::handleConnection(std::set<PlayerColor> players, CConnection &
|
||||
{
|
||||
const bool result = apply->applyOnGH(this,&c,pack, player);
|
||||
if(!result)
|
||||
complain("Got false in applying... that request must have been fishy!");
|
||||
{
|
||||
complain((boost::format("Got false in applying %s... that request must have been fishy!")
|
||||
% typeid(*pack).name()).str());
|
||||
}
|
||||
logGlobal->traceStream() << "Message successfully applied (result=" << result << ")!";
|
||||
sendPackageResponse(true);
|
||||
}
|
||||
@ -2113,7 +2116,6 @@ void CGameHandler::stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroI
|
||||
|
||||
void CGameHandler::removeArtifact(const ArtifactLocation &al)
|
||||
{
|
||||
assert(al.getArt());
|
||||
EraseArtifact ea;
|
||||
ea.al = al;
|
||||
sendAndApply(&ea);
|
||||
@ -3038,7 +3040,7 @@ bool CGameHandler::assembleArtifacts (ObjectInstanceID heroID, ArtifactPosition
|
||||
sendAndApply(&da);
|
||||
}
|
||||
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CGameHandler::buyArtifact( ObjectInstanceID hid, ArtifactID aid )
|
||||
@ -4026,6 +4028,16 @@ void CGameHandler::playerMessage( PlayerColor player, const std::string &message
|
||||
if(!hero->hasStackAtSlot(SlotID(i)))
|
||||
insertNewStack(StackLocation(hero, SlotID(i)), blackKnight, 10);
|
||||
}
|
||||
else if(message == "vcmiglaurung") //gives 5000 crystal dragons into each slot
|
||||
{
|
||||
CGHeroInstance *hero = gs->getHero(currObj);
|
||||
const CCreature *crystalDragon = VLC->creh->creatures.at(133);
|
||||
if(!hero) return;
|
||||
|
||||
for(int i = 0; i < GameConstants::ARMY_SIZE; i++)
|
||||
if(!hero->hasStackAtSlot(SlotID(i)))
|
||||
insertNewStack(StackLocation(hero, SlotID(i)), crystalDragon, 5000);
|
||||
}
|
||||
else if(message == "vcminoldor") //all war machines
|
||||
{
|
||||
CGHeroInstance *hero = gs->getHero(currObj);
|
||||
|
@ -321,7 +321,8 @@ CBlockingDialogQuery::CBlockingDialogQuery(const BlockingDialog &bd)
|
||||
|
||||
void CTeleportDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const
|
||||
{
|
||||
auto obj = dynamic_ptr_cast<const CGTeleport>(objectVisit.visitedObject);
|
||||
// do not change to dynamic_ptr_cast - SIGSEGV!
|
||||
auto obj = dynamic_cast<const CGTeleport*>(objectVisit.visitedObject);
|
||||
obj->teleportDialogAnswered(objectVisit.visitingHero, *answer, td.exits);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user