mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Merge branch 'develop' into creature-numeric-quantities
This commit is contained in:
commit
685d63603d
@ -49,7 +49,8 @@ int64_t AttackPossibility::calculateDamageReduce(
|
||||
|
||||
vstd::amin(damageDealt, defender->getAvailableHealth());
|
||||
|
||||
auto enemyDamageBeforeAttack = cb.battleEstimateDamage(BattleAttackInfo(defender, attacker, defender->canShoot()));
|
||||
// FIXME: provide distance info for Jousting bonus
|
||||
auto enemyDamageBeforeAttack = cb.battleEstimateDamage(defender, attacker, 0);
|
||||
auto enemiesKilled = damageDealt / defender->MaxHealth() + (damageDealt % defender->MaxHealth() >= defender->getFirstHPleft() ? 1 : 0);
|
||||
auto enemyDamage = averageDmg(enemyDamageBeforeAttack);
|
||||
auto damagePerEnemy = enemyDamage / (double)defender->getCount();
|
||||
@ -74,10 +75,11 @@ int64_t AttackPossibility::evaluateBlockedShootersDmg(const BattleAttackInfo & a
|
||||
if(!state.battleCanShoot(st))
|
||||
continue;
|
||||
|
||||
BattleAttackInfo rangeAttackInfo(st, attacker, true);
|
||||
// FIXME: provide distance info for Jousting bonus
|
||||
BattleAttackInfo rangeAttackInfo(st, attacker, 0, true);
|
||||
rangeAttackInfo.defenderPos = hex;
|
||||
|
||||
BattleAttackInfo meleeAttackInfo(st, attacker, false);
|
||||
BattleAttackInfo meleeAttackInfo(st, attacker, 0, false);
|
||||
meleeAttackInfo.defenderPos = hex;
|
||||
|
||||
auto rangeDmg = state.battleEstimateDamage(rangeAttackInfo);
|
||||
@ -211,8 +213,8 @@ AttackPossibility AttackPossibility::evaluate(const BattleAttackInfo & attackInf
|
||||
bestAp.shootersBlockedDmg = evaluateBlockedShootersDmg(attackInfo, hex, state);
|
||||
|
||||
logAi->debug("BattleAI best AP: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld",
|
||||
attackInfo.attacker->unitType()->identifier,
|
||||
attackInfo.defender->unitType()->identifier,
|
||||
attackInfo.attacker->unitType()->getJsonKey(),
|
||||
attackInfo.defender->unitType()->getJsonKey(),
|
||||
(int)bestAp.dest, (int)bestAp.from, (int)bestAp.affectedUnits.size(),
|
||||
bestAp.defenderDamageReduce, bestAp.attackerDamageReduce, bestAp.collateralDamageReduce, bestAp.shootersBlockedDmg);
|
||||
|
||||
|
@ -46,14 +46,14 @@ std::vector<BattleHex> CBattleAI::getBrokenWallMoatHexes() const
|
||||
{
|
||||
std::vector<BattleHex> result;
|
||||
|
||||
for(int wallPart = EWallPart::BOTTOM_WALL; wallPart < EWallPart::UPPER_WALL; wallPart++)
|
||||
for(EWallPart wallPart : { EWallPart::BOTTOM_WALL, EWallPart::BELOW_GATE, EWallPart::OVER_GATE, EWallPart::UPPER_WALL })
|
||||
{
|
||||
auto state = cb->battleGetWallState(wallPart);
|
||||
|
||||
if(state != EWallState::DESTROYED)
|
||||
continue;
|
||||
|
||||
auto wallHex = cb->wallPartToBattleHex((EWallPart::EWallPart)wallPart);
|
||||
auto wallHex = cb->wallPartToBattleHex((EWallPart)wallPart);
|
||||
auto moatHex = wallHex.cloneInDirection(BattleHex::LEFT);
|
||||
|
||||
result.push_back(moatHex);
|
||||
@ -207,10 +207,10 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
||||
}
|
||||
|
||||
logAi->debug("BattleAI: %s -> %s x %d, %s, from %d curpos %d dist %d speed %d: +%lld -%lld = %lld",
|
||||
bestAttack.attackerState->unitType()->identifier,
|
||||
bestAttack.affectedUnits[0]->unitType()->identifier,
|
||||
bestAttack.attackerState->unitType()->getJsonKey(),
|
||||
bestAttack.affectedUnits[0]->unitType()->getJsonKey(),
|
||||
(int)bestAttack.affectedUnits[0]->getCount(), action, (int)bestAttack.from, (int)bestAttack.attack.attacker->getPosition().hex,
|
||||
bestAttack.attack.chargedFields, bestAttack.attack.attacker->Speed(0, true),
|
||||
bestAttack.attack.chargeDistance, bestAttack.attack.attacker->Speed(0, true),
|
||||
bestAttack.defenderDamageReduce, bestAttack.attackerDamageReduce, bestAttack.attackValue()
|
||||
);
|
||||
}
|
||||
@ -364,7 +364,7 @@ BattleAction CBattleAI::useCatapult(const CStack * stack)
|
||||
}
|
||||
else
|
||||
{
|
||||
EWallPart::EWallPart wallParts[] = {
|
||||
EWallPart wallParts[] = {
|
||||
EWallPart::KEEP,
|
||||
EWallPart::BOTTOM_TOWER,
|
||||
EWallPart::UPPER_TOWER,
|
||||
@ -378,10 +378,9 @@ BattleAction CBattleAI::useCatapult(const CStack * stack)
|
||||
{
|
||||
auto wallState = cb->battleGetWallState(wallPart);
|
||||
|
||||
if(wallState == EWallState::INTACT || wallState == EWallState::DAMAGED)
|
||||
if(wallState == EWallState::REINFORCED || wallState == EWallState::INTACT || wallState == EWallState::DAMAGED)
|
||||
{
|
||||
targetHex = cb->wallPartToBattleHex(wallPart);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -688,7 +687,7 @@ void CBattleAI::attemptCastingSpell()
|
||||
|
||||
if(castToPerform.value > 0)
|
||||
{
|
||||
LOGFL("Best spell is %s (value %d). Will cast.", castToPerform.spell->name % castToPerform.value);
|
||||
LOGFL("Best spell is %s (value %d). Will cast.", castToPerform.spell->getNameTranslated() % castToPerform.value);
|
||||
BattleAction spellcast;
|
||||
spellcast.actionType = EActionType::HERO_SPELL;
|
||||
spellcast.actionSubtype = castToPerform.spell->id;
|
||||
@ -699,7 +698,7 @@ void CBattleAI::attemptCastingSpell()
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGFL("Best spell is %s. But it is actually useless (value %d).", castToPerform.spell->name % castToPerform.value);
|
||||
LOGFL("Best spell is %s. But it is actually useless (value %d).", castToPerform.spell->getNameTranslated() % castToPerform.value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,8 @@ int64_t BattleExchangeVariant::trackAttack(
|
||||
const bool counterAttacksBlocked = attacker->hasBonus(selectorBlocksRetaliation, cachingStringBlocksRetaliation);
|
||||
|
||||
TDmgRange retaliation;
|
||||
BattleAttackInfo bai(attacker.get(), defender.get(), shooting);
|
||||
// FIXME: provide distance info for Jousting bonus
|
||||
BattleAttackInfo bai(attacker.get(), defender.get(), 0, shooting);
|
||||
|
||||
if(shooting)
|
||||
{
|
||||
@ -234,7 +235,8 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(const battle::Uni
|
||||
|
||||
for(auto hex : hexes)
|
||||
{
|
||||
auto bai = BattleAttackInfo(activeStack, closestStack, cb->battleCanShoot(activeStack));
|
||||
// FIXME: provide distance info for Jousting bonus
|
||||
auto bai = BattleAttackInfo(activeStack, closestStack, 0, cb->battleCanShoot(activeStack));
|
||||
auto attack = AttackPossibility::evaluate(bai, hex, hb);
|
||||
|
||||
attack.shootersBlockedDmg = 0; // we do not want to count on it, it is not for sure
|
||||
|
@ -46,10 +46,8 @@ PotentialTargets::PotentialTargets(const battle::Unit * attacker, const Hypothet
|
||||
|
||||
auto GenerateAttackInfo = [&](bool shooting, BattleHex hex) -> AttackPossibility
|
||||
{
|
||||
auto bai = BattleAttackInfo(attackerInfo, defender, shooting);
|
||||
|
||||
if(hex.isValid() && !shooting)
|
||||
bai.chargedFields = reachability.distances[hex];
|
||||
int distance = hex.isValid() ? reachability.distances[hex] : 0;
|
||||
auto bai = BattleAttackInfo(attackerInfo, defender, distance, shooting);
|
||||
|
||||
return AttackPossibility::evaluate(bai, hex, state);
|
||||
};
|
||||
@ -92,8 +90,8 @@ PotentialTargets::PotentialTargets(const battle::Unit * attacker, const Hypothet
|
||||
auto & bestAp = possibleAttacks[0];
|
||||
|
||||
logGlobal->info("Battle AI best: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld",
|
||||
bestAp.attack.attacker->unitType()->identifier,
|
||||
state.battleGetUnitByPos(bestAp.dest)->unitType()->identifier,
|
||||
bestAp.attack.attacker->unitType()->getJsonKey(),
|
||||
state.battleGetUnitByPos(bestAp.dest)->unitType()->getJsonKey(),
|
||||
(int)bestAp.dest, (int)bestAp.from, (int)bestAp.affectedUnits.size(),
|
||||
bestAp.defenderDamageReduce, bestAp.attackerDamageReduce, bestAp.collateralDamageReduce, bestAp.shootersBlockedDmg);
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ std::string StackWithBonuses::getDescription() const
|
||||
oss << unitOwner().getStr();
|
||||
oss << " battle stack [" << unitId() << "]: " << getCount() << " of ";
|
||||
if(type)
|
||||
oss << type->namePl;
|
||||
oss << type->getJsonKey();
|
||||
else
|
||||
oss << "[UNDEFINED TYPE]";
|
||||
|
||||
@ -403,7 +403,7 @@ void HypotheticBattle::removeUnitBonus(uint32_t id, const std::vector<Bonus> & b
|
||||
bonusTreeVersion++;
|
||||
}
|
||||
|
||||
void HypotheticBattle::setWallState(int partOfWall, si8 state)
|
||||
void HypotheticBattle::setWallState(EWallPart partOfWall, EWallState state)
|
||||
{
|
||||
//TODO:HypotheticBattle::setWallState
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ public:
|
||||
void updateUnitBonus(uint32_t id, const std::vector<Bonus> & bonus) override;
|
||||
void removeUnitBonus(uint32_t id, const std::vector<Bonus> & bonus) override;
|
||||
|
||||
void setWallState(int partOfWall, si8 state) override;
|
||||
void setWallState(EWallPart partOfWall, EWallState state) override;
|
||||
|
||||
void addObstacle(const ObstacleChanges & changes) override;
|
||||
void updateObstacle(const ObstacleChanges& changes) override;
|
||||
|
@ -283,7 +283,7 @@ void AIGateway::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID her
|
||||
auto firstHero = cb->getHero(hero1);
|
||||
auto secondHero = cb->getHero(hero2);
|
||||
|
||||
status.addQuery(query, boost::str(boost::format("Exchange between heroes %s (%d) and %s (%d)") % firstHero->name % firstHero->tempOwner % secondHero->name % secondHero->tempOwner));
|
||||
status.addQuery(query, boost::str(boost::format("Exchange between heroes %s (%d) and %s (%d)") % firstHero->getNameTranslated() % firstHero->tempOwner % secondHero->getNameTranslated() % secondHero->tempOwner));
|
||||
|
||||
requestActionASAP([=]()
|
||||
{
|
||||
@ -544,7 +544,7 @@ void AIGateway::heroGotLevel(const CGHeroInstance * hero, PrimarySkill::PrimaryS
|
||||
LOG_TRACE_PARAMS(logAi, "queryID '%i'", queryID);
|
||||
NET_EVENT_HANDLER;
|
||||
|
||||
status.addQuery(queryID, boost::str(boost::format("Hero %s got level %d") % hero->name % hero->level));
|
||||
status.addQuery(queryID, boost::str(boost::format("Hero %s got level %d") % hero->getNameTranslated() % hero->level));
|
||||
HeroPtr hPtr = hero;
|
||||
|
||||
requestActionASAP([=]()
|
||||
@ -737,7 +737,7 @@ bool AIGateway::makePossibleUpgrades(const CArmedInstance * obj)
|
||||
{
|
||||
myCb->upgradeCreature(obj, SlotID(i), ui.newID[0]);
|
||||
upgraded = true;
|
||||
logAi->debug("Upgraded %d %s to %s", s->count, ui.oldID.toCreature()->namePl, ui.newID[0].toCreature()->namePl);
|
||||
logAi->debug("Upgraded %d %s to %s", s->count, ui.oldID.toCreature()->getNamePluralTranslated(), ui.newID[0].toCreature()->getNamePluralTranslated());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -787,7 +787,7 @@ void AIGateway::makeTurn()
|
||||
for (auto h : cb->getHeroesInfo())
|
||||
{
|
||||
if (h->movement)
|
||||
logAi->warn("Hero %s has %d MP left", h->name, h->movement);
|
||||
logAi->warn("Hero %s has %d MP left", h->getNameTranslated(), h->movement);
|
||||
}
|
||||
#if NKAI_TRACE_LEVEL == 0
|
||||
}
|
||||
@ -808,7 +808,7 @@ void AIGateway::makeTurn()
|
||||
|
||||
void AIGateway::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
|
||||
{
|
||||
LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->name % obj->getObjectName() % obj->pos.toString());
|
||||
LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->getNameTranslated() % obj->getObjectName() % obj->pos.toString());
|
||||
switch(obj->ID)
|
||||
{
|
||||
case Obj::CREATURE_GENERATOR1:
|
||||
@ -1070,7 +1070,7 @@ void AIGateway::battleStart(const CCreatureSet * army1, const CCreatureSet * arm
|
||||
assert(playerID > PlayerColor::PLAYER_LIMIT || status.getBattle() == UPCOMING_BATTLE);
|
||||
status.setBattle(ONGOING_BATTLE);
|
||||
const CGObjectInstance * presumedEnemy = vstd::backOrNull(cb->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
|
||||
battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->name : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString());
|
||||
battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->getNameTranslated() : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString());
|
||||
CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side);
|
||||
}
|
||||
|
||||
@ -1172,7 +1172,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
}
|
||||
};
|
||||
|
||||
logAi->debug("Moving hero %s to tile %s", h->name, dst.toString());
|
||||
logAi->debug("Moving hero %s to tile %s", h->getNameTranslated(), dst.toString());
|
||||
int3 startHpos = h->visitablePos();
|
||||
bool ret = false;
|
||||
if(startHpos == dst)
|
||||
@ -1192,7 +1192,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
cb->getPathsInfo(h.get())->getPath(path, dst);
|
||||
if(path.nodes.empty())
|
||||
{
|
||||
logAi->error("Hero %s cannot reach %s.", h->name, dst.toString());
|
||||
logAi->error("Hero %s cannot reach %s.", h->getNameTranslated(), dst.toString());
|
||||
return true;
|
||||
}
|
||||
int i = (int)path.nodes.size() - 1;
|
||||
@ -1344,15 +1344,15 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
throw cannotFulfillGoalException("Invalid path found!");
|
||||
}
|
||||
|
||||
logAi->debug("Hero %s moved from %s to %s. Returning %d.", h->name, startHpos.toString(), h->visitablePos().toString(), ret);
|
||||
logAi->debug("Hero %s moved from %s to %s. Returning %d.", h->getNameTranslated(), startHpos.toString(), h->visitablePos().toString(), ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AIGateway::buildStructure(const CGTownInstance * t, BuildingID building)
|
||||
{
|
||||
auto name = t->town->buildings.at(building)->Name();
|
||||
logAi->debug("Player %d will build %s in town of %s at %s", ai->playerID, name, t->name, t->pos.toString());
|
||||
auto name = t->town->buildings.at(building)->getNameTranslated();
|
||||
logAi->debug("Player %d will build %s in town of %s at %s", ai->playerID, name, t->getNameTranslated(), t->pos.toString());
|
||||
cb->buildBuilding(t, building); //just do this;
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ HeroPtr::HeroPtr(const CGHeroInstance * H)
|
||||
}
|
||||
|
||||
h = H;
|
||||
name = h->name;
|
||||
name = h->getNameTranslated();
|
||||
hid = H->id;
|
||||
// infosCount[ai->playerID][hid]++;
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ void BuildAnalyzer::update()
|
||||
|
||||
for(const CGTownInstance* town : towns)
|
||||
{
|
||||
logAi->trace("Checking town %s", town->name);
|
||||
logAi->trace("Checking town %s", town->getNameTranslated());
|
||||
|
||||
developmentInfos.push_back(TownDevelopmentInfo(town));
|
||||
TownDevelopmentInfo & developmentInfo = developmentInfos.back();
|
||||
@ -351,7 +351,7 @@ BuildingInfo::BuildingInfo(
|
||||
dailyIncome = building->produce;
|
||||
exists = town->hasBuilt(id);
|
||||
prerequisitesCount = 1;
|
||||
name = building->Name();
|
||||
name = building->getNameTranslated();
|
||||
|
||||
if(creature)
|
||||
{
|
||||
|
@ -70,7 +70,7 @@ float HeroManager::evaluateSecSkill(SecondarySkill skill, const CGHeroInstance *
|
||||
|
||||
float HeroManager::evaluateSpeciality(const CGHeroInstance * hero) const
|
||||
{
|
||||
auto heroSpecial = Selector::source(Bonus::HERO_SPECIAL, hero->type->ID.getNum());
|
||||
auto heroSpecial = Selector::source(Bonus::HERO_SPECIAL, hero->type->getIndex());
|
||||
auto secondarySkillBonus = Selector::type()(Bonus::SECONDARY_SKILL_PREMY);
|
||||
auto specialSecondarySkillBonuses = hero->getBonuses(heroSpecial.And(secondarySkillBonus));
|
||||
float specialityScore = 0.0f;
|
||||
@ -172,7 +172,7 @@ void HeroManager::update()
|
||||
|
||||
for(auto hero : myHeroes)
|
||||
{
|
||||
logAi->trace("Hero %s has role %s", hero->name, heroRoles[hero] == HeroRole::MAIN ? "main" : "scout");
|
||||
logAi->trace("Hero %s has role %s", hero->getNameTranslated(), heroRoles[hero] == HeroRole::MAIN ? "main" : "scout");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,6 @@ void ObjectClusterizer::clusterize()
|
||||
Obj::WHIRLPOOL,
|
||||
Obj::BUOY,
|
||||
Obj::SIGN,
|
||||
Obj::SIGN,
|
||||
Obj::GARRISON,
|
||||
Obj::MONSTER,
|
||||
Obj::GARRISON2,
|
||||
|
@ -50,14 +50,14 @@ Goals::TGoalVec DefenceBehavior::decompose() const
|
||||
|
||||
void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInstance * town) const
|
||||
{
|
||||
logAi->trace("Evaluating defence for %s", town->name);
|
||||
logAi->trace("Evaluating defence for %s", town->getNameTranslated());
|
||||
|
||||
auto treatNode = ai->nullkiller->dangerHitMap->getObjectTreat(town);
|
||||
auto treats = { treatNode.fastestDanger, treatNode.maximumDanger };
|
||||
|
||||
if(!treatNode.fastestDanger.hero)
|
||||
{
|
||||
logAi->trace("No treat found for town %s", town->name);
|
||||
logAi->trace("No treat found for town %s", town->getNameTranslated());
|
||||
|
||||
return;
|
||||
}
|
||||
@ -78,8 +78,8 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
||||
|
||||
logAi->trace(
|
||||
"Hero %s in garrison of town %s is suposed to defend the town",
|
||||
town->garrisonHero->name,
|
||||
town->name);
|
||||
town->garrisonHero->getNameTranslated(),
|
||||
town->getNameTranslated());
|
||||
|
||||
return;
|
||||
}
|
||||
@ -88,7 +88,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
||||
|
||||
if(reinforcement)
|
||||
{
|
||||
logAi->trace("Town %s can buy defence army %lld", town->name, reinforcement);
|
||||
logAi->trace("Town %s can buy defence army %lld", town->getNameTranslated(), reinforcement);
|
||||
tasks.push_back(Goals::sptr(Goals::BuyArmy(town, reinforcement).setpriority(0.5f)));
|
||||
}
|
||||
|
||||
@ -98,10 +98,10 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
||||
{
|
||||
logAi->trace(
|
||||
"Town %s has treat %lld in %s turns, hero: %s",
|
||||
town->name,
|
||||
town->getNameTranslated(),
|
||||
treat.danger,
|
||||
std::to_string(treat.turn),
|
||||
treat.hero->name);
|
||||
treat.hero->getNameTranslated());
|
||||
|
||||
bool treatIsUnderControl = false;
|
||||
|
||||
@ -187,7 +187,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
|
||||
|
||||
if(paths.empty())
|
||||
{
|
||||
logAi->trace("No ways to defend town %s", town->name);
|
||||
logAi->trace("No ways to defend town %s", town->getNameTranslated());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ int getDwellingArmyCost(const CGObjectInstance * target)
|
||||
|
||||
uint64_t evaluateArtifactArmyValue(CArtifactInstance * art)
|
||||
{
|
||||
if(art->artType->id == ArtifactID::SPELL_SCROLL)
|
||||
if(art->artType->getId() == ArtifactID::SPELL_SCROLL)
|
||||
return 1500;
|
||||
|
||||
auto statsValue =
|
||||
|
@ -60,7 +60,7 @@ std::string AbstractGoal::toString() const //TODO: virtualize
|
||||
desc = "GATHER TROOPS";
|
||||
break;
|
||||
case GET_ART_TYPE:
|
||||
desc = "GET ARTIFACT OF TYPE " + VLC->arth->objects[aid]->getName();
|
||||
desc = "GET ARTIFACT OF TYPE " + VLC->arth->objects[aid]->getNameTranslated();
|
||||
break;
|
||||
case DIG_AT_TILE:
|
||||
desc = "DIG AT TILE " + tile.toString();
|
||||
@ -69,7 +69,7 @@ std::string AbstractGoal::toString() const //TODO: virtualize
|
||||
return boost::lexical_cast<std::string>(goalType);
|
||||
}
|
||||
if(hero.get(true)) //FIXME: used to crash when we lost hero and failed goal
|
||||
desc += " (" + hero->name + ")";
|
||||
desc += " (" + hero->getNameTranslated() + ")";
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
@ -33,19 +33,19 @@ void AdventureSpellCast::accept(AIGateway * ai)
|
||||
|
||||
auto spell = getSpell();
|
||||
|
||||
logAi->trace("Decomposing adventure spell cast of %s for hero %s", spell->name, hero->name);
|
||||
logAi->trace("Decomposing adventure spell cast of %s for hero %s", spell->getNameTranslated(), hero->getNameTranslated());
|
||||
|
||||
if(!spell->isAdventure())
|
||||
throw cannotFulfillGoalException(spell->name + " is not an adventure spell.");
|
||||
throw cannotFulfillGoalException(spell->getNameTranslated() + " is not an adventure spell.");
|
||||
|
||||
if(!hero->canCastThisSpell(spell))
|
||||
throw cannotFulfillGoalException("Hero can not cast " + spell->name);
|
||||
throw cannotFulfillGoalException("Hero can not cast " + spell->getNameTranslated());
|
||||
|
||||
if(hero->mana < hero->getSpellCost(spell))
|
||||
throw cannotFulfillGoalException("Hero has not enough mana to cast " + spell->name);
|
||||
throw cannotFulfillGoalException("Hero has not enough mana to cast " + spell->getNameTranslated());
|
||||
|
||||
if(spellID == SpellID::TOWN_PORTAL && town && town->visitingHero)
|
||||
throw cannotFulfillGoalException("The town is already occupied by " + town->visitingHero->name);
|
||||
throw cannotFulfillGoalException("The town is already occupied by " + town->visitingHero->getNameTranslated());
|
||||
|
||||
if(town && spellID == SpellID::TOWN_PORTAL)
|
||||
{
|
||||
@ -70,7 +70,7 @@ void AdventureSpellCast::accept(AIGateway * ai)
|
||||
|
||||
std::string AdventureSpellCast::toString() const
|
||||
{
|
||||
return "AdventureSpellCast " + spellID.toSpell()->name;
|
||||
return "AdventureSpellCast " + spellID.toSpell()->getNameTranslated();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ bool BuildThis::operator==(const BuildThis & other) const
|
||||
|
||||
std::string BuildThis::toString() const
|
||||
{
|
||||
return "Build " + buildingInfo.name + " in " + town->name;
|
||||
return "Build " + buildingInfo.name + " in " + town->getNameTranslated();
|
||||
}
|
||||
|
||||
void BuildThis::accept(AIGateway * ai)
|
||||
@ -58,7 +58,7 @@ void BuildThis::accept(AIGateway * ai)
|
||||
if(cb->canBuildStructure(town, b) == EBuildingState::ALLOWED)
|
||||
{
|
||||
logAi->debug("Player %d will build %s in town of %s at %s",
|
||||
ai->playerID, town->town->buildings.at(b)->Name(), town->name, town->pos.toString());
|
||||
ai->playerID, town->town->buildings.at(b)->getNameTranslated(), town->getNameTranslated(), town->pos.toString());
|
||||
cb->buildBuilding(town, b);
|
||||
|
||||
return;
|
||||
|
@ -29,7 +29,7 @@ bool BuyArmy::operator==(const BuyArmy & other) const
|
||||
|
||||
std::string BuyArmy::toString() const
|
||||
{
|
||||
return "Buy army at " + town->name;
|
||||
return "Buy army at " + town->getNameTranslated();
|
||||
}
|
||||
|
||||
void BuyArmy::accept(AIGateway * ai)
|
||||
|
@ -33,7 +33,7 @@ ExchangeSwapTownHeroes::ExchangeSwapTownHeroes(
|
||||
|
||||
std::string ExchangeSwapTownHeroes::toString() const
|
||||
{
|
||||
return "Exchange and swap heroes of " + town->name;
|
||||
return "Exchange and swap heroes of " + town->getNameTranslated();
|
||||
}
|
||||
|
||||
bool ExchangeSwapTownHeroes::operator==(const ExchangeSwapTownHeroes & other) const
|
||||
@ -54,13 +54,13 @@ void ExchangeSwapTownHeroes::accept(AIGateway * ai)
|
||||
|
||||
if(currentGarrisonHero.get() != town->visitingHero.get())
|
||||
{
|
||||
logAi->error("VisitingHero is empty, expected %s", currentGarrisonHero->name);
|
||||
logAi->error("VisitingHero is empty, expected %s", currentGarrisonHero->getNameTranslated());
|
||||
return;
|
||||
}
|
||||
|
||||
ai->buildArmyIn(town);
|
||||
ai->nullkiller->unlockHero(currentGarrisonHero.get());
|
||||
logAi->debug("Extracted hero %s from garrison of %s", currentGarrisonHero->name, town->name);
|
||||
logAi->debug("Extracted hero %s from garrison of %s", currentGarrisonHero->getNameTranslated(), town->getNameTranslated());
|
||||
|
||||
return;
|
||||
}
|
||||
@ -91,7 +91,7 @@ void ExchangeSwapTownHeroes::accept(AIGateway * ai)
|
||||
ai->makePossibleUpgrades(town->visitingHero);
|
||||
}
|
||||
|
||||
logAi->debug("Put hero %s to garrison of %s", garrisonHero->name, town->name);
|
||||
logAi->debug("Put hero %s to garrison of %s", garrisonHero->getNameTranslated(), town->getNameTranslated());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ void ExecuteHeroChain::accept(AIGateway * ai)
|
||||
continue;
|
||||
}
|
||||
|
||||
logAi->debug("Executing chain node %d. Moving hero %s to %s", i, hero->name, node.coord.toString());
|
||||
logAi->debug("Executing chain node %d. Moving hero %s to %s", i, hero->getNameTranslated(), node.coord.toString());
|
||||
|
||||
try
|
||||
{
|
||||
@ -111,7 +111,7 @@ void ExecuteHeroChain::accept(AIGateway * ai)
|
||||
{
|
||||
logAi->error(
|
||||
"Unable to complete chain. Expected hero %s to arrive to %s in 0 turns but he cannot do this",
|
||||
hero->name,
|
||||
hero->getNameTranslated(),
|
||||
node.coord.toString());
|
||||
|
||||
return;
|
||||
@ -143,7 +143,7 @@ void ExecuteHeroChain::accept(AIGateway * ai)
|
||||
|
||||
if(isOk && path.nodes.back().turns > 0)
|
||||
{
|
||||
logAi->warn("Hero %s has %d mp which is not enough to continue his way towards %s.", hero->name, hero->movement, node.coord.toString());
|
||||
logAi->warn("Hero %s has %d mp which is not enough to continue his way towards %s.", hero->getNameTranslated(), hero->movement, node.coord.toString());
|
||||
|
||||
ai->nullkiller->lockHero(hero, HeroLockedReason::HERO_CHAIN);
|
||||
return;
|
||||
@ -162,7 +162,7 @@ void ExecuteHeroChain::accept(AIGateway * ai)
|
||||
{
|
||||
logAi->error(
|
||||
"Enable to complete chain. Expected hero %s to arive to %s but he is at %s",
|
||||
hero->name,
|
||||
hero->getNameTranslated(),
|
||||
node.coord.toString(),
|
||||
hero->visitablePos().toString());
|
||||
|
||||
@ -187,14 +187,14 @@ void ExecuteHeroChain::accept(AIGateway * ai)
|
||||
|
||||
std::string ExecuteHeroChain::toString() const
|
||||
{
|
||||
return "ExecuteHeroChain " + targetName + " by " + chainPath.targetHero->name;
|
||||
return "ExecuteHeroChain " + targetName + " by " + chainPath.targetHero->getNameTranslated();
|
||||
}
|
||||
|
||||
bool ExecuteHeroChain::moveHeroToTile(const CGHeroInstance * hero, const int3 & tile)
|
||||
{
|
||||
if(tile == hero->visitablePos() && cb->getVisitableObjs(hero->visitablePos()).size() < 2)
|
||||
{
|
||||
logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", hero->name, tile.toString());
|
||||
logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", hero->getNameTranslated(), tile.toString());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ using namespace Goals;
|
||||
|
||||
std::string RecruitHero::toString() const
|
||||
{
|
||||
return "Recruit hero at " + town->name;
|
||||
return "Recruit hero at " + town->getNameTranslated();
|
||||
}
|
||||
|
||||
void RecruitHero::accept(AIGateway * ai)
|
||||
@ -40,7 +40,7 @@ void RecruitHero::accept(AIGateway * ai)
|
||||
throw cannotFulfillGoalException("No town to recruit hero!");
|
||||
}
|
||||
|
||||
logAi->debug("Trying to recruit a hero in %s at %s", t->name, t->visitablePos().toString());
|
||||
logAi->debug("Trying to recruit a hero in %s at %s", t->getNameTranslated(), t->visitablePos().toString());
|
||||
|
||||
auto heroes = cb->getAvailableHeroes(t);
|
||||
|
||||
@ -78,4 +78,4 @@ void RecruitHero::accept(AIGateway * ai)
|
||||
ai->moveHeroToTile(t->visitablePos(), t->visitingHero.get());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1437,10 +1437,10 @@ std::string AIPath::toString() const
|
||||
{
|
||||
std::stringstream str;
|
||||
|
||||
str << targetHero->name << "[" << std::hex << chainMask << std::dec << "]" << ", turn " << (int)(turn()) << ": ";
|
||||
str << targetHero->getNameTranslated() << "[" << std::hex << chainMask << std::dec << "]" << ", turn " << (int)(turn()) << ": ";
|
||||
|
||||
for(auto node : nodes)
|
||||
str << node.targetHero->name << "[" << std::hex << node.chainMask << std::dec << "]" << "->" << node.coord.toString() << "; ";
|
||||
str << node.targetHero->getNameTranslated() << "[" << std::hex << node.chainMask << std::dec << "]" << "->" << node.coord.toString() << "; ";
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ namespace AIPathfinding
|
||||
if(!hero->visitedTown)
|
||||
{
|
||||
throw cannotFulfillGoalException(
|
||||
hero->name + " being at " + hero->visitablePos().toString() + " has no town to recruit creatures.");
|
||||
hero->getNameTranslated() + " being at " + hero->visitablePos().toString() + " has no town to recruit creatures.");
|
||||
}
|
||||
|
||||
ai->recruitCreatures(hero->visitedTown, hero);
|
||||
|
@ -34,7 +34,7 @@ void TownPortalAction::execute(const CGHeroInstance * hero) const
|
||||
|
||||
std::string TownPortalAction::toString() const
|
||||
{
|
||||
return "Town Portal to " + target->name;
|
||||
return "Town Portal to " + target->getNameTranslated();
|
||||
}
|
||||
/*
|
||||
bool TownPortalAction::canAct(const CGHeroInstance * hero, const AIPathNode * source) const
|
||||
|
@ -80,7 +80,7 @@ int ChainActor::maxMovePoints(CGPathNode::ELayer layer)
|
||||
|
||||
std::string ChainActor::toString() const
|
||||
{
|
||||
return hero->name;
|
||||
return hero->getNameTranslated();
|
||||
}
|
||||
|
||||
ObjectActor::ObjectActor(const CGObjectInstance * obj, const CCreatureSet * army, uint64_t chainMask, int initialTurn)
|
||||
@ -463,5 +463,5 @@ TownGarrisonActor::TownGarrisonActor(const CGTownInstance * town, uint64_t chain
|
||||
|
||||
std::string TownGarrisonActor::toString() const
|
||||
{
|
||||
return town->name;
|
||||
return town->getNameTranslated();
|
||||
}
|
||||
|
@ -55,7 +55,8 @@ public:
|
||||
{}
|
||||
void calcDmg(const CStack * ourStack)
|
||||
{
|
||||
TDmgRange retal, dmg = cbc->battleEstimateDamage(ourStack, s, &retal);
|
||||
// FIXME: provide distance info for Jousting bonus
|
||||
TDmgRange retal, dmg = cbc->battleEstimateDamage(ourStack, s, 0, &retal);
|
||||
adi = static_cast<int>((dmg.first + dmg.second) / 2);
|
||||
adr = static_cast<int>((retal.first + retal.second) / 2);
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ HeroPtr::HeroPtr(const CGHeroInstance * H)
|
||||
}
|
||||
|
||||
h = H;
|
||||
name = h->name;
|
||||
name = h->getNameTranslated();
|
||||
hid = H->id;
|
||||
// infosCount[ai->playerID][hid]++;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ std::string AbstractGoal::name() const //TODO: virtualize
|
||||
}
|
||||
break;
|
||||
case GET_ART_TYPE:
|
||||
desc = "GET ARTIFACT OF TYPE " + VLC->artifacts()->getByIndex(aid)->getName();
|
||||
desc = "GET ARTIFACT OF TYPE " + VLC->artifacts()->getByIndex(aid)->getNameTranslated();
|
||||
break;
|
||||
case VISIT_TILE:
|
||||
desc = "VISIT TILE " + tile.toString();
|
||||
@ -106,7 +106,7 @@ std::string AbstractGoal::name() const //TODO: virtualize
|
||||
return boost::lexical_cast<std::string>(goalType);
|
||||
}
|
||||
if(hero.get(true)) //FIXME: used to crash when we lost hero and failed goal
|
||||
desc += " (" + hero->name + ")";
|
||||
desc += " (" + hero->getNameTranslated() + ")";
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
@ -33,19 +33,19 @@ TSubgoal AdventureSpellCast::whatToDoToAchieve()
|
||||
|
||||
auto spell = getSpell();
|
||||
|
||||
logAi->trace("Decomposing adventure spell cast of %s for hero %s", spell->getName(), hero->name);
|
||||
logAi->trace("Decomposing adventure spell cast of %s for hero %s", spell->getNameTranslated(), hero->getNameTranslated());
|
||||
|
||||
if(!spell->isAdventure())
|
||||
throw cannotFulfillGoalException(spell->getName() + " is not an adventure spell.");
|
||||
throw cannotFulfillGoalException(spell->getNameTranslated() + " is not an adventure spell.");
|
||||
|
||||
if(!hero->canCastThisSpell(spell))
|
||||
throw cannotFulfillGoalException("Hero can not cast " + spell->getName());
|
||||
throw cannotFulfillGoalException("Hero can not cast " + spell->getNameTranslated());
|
||||
|
||||
if(hero->mana < hero->getSpellCost(spell))
|
||||
throw cannotFulfillGoalException("Hero has not enough mana to cast " + spell->getName());
|
||||
throw cannotFulfillGoalException("Hero has not enough mana to cast " + spell->getNameTranslated());
|
||||
|
||||
if(spellID == SpellID::TOWN_PORTAL && town && town->visitingHero)
|
||||
throw cannotFulfillGoalException("The town is already occupied by " + town->visitingHero->name);
|
||||
throw cannotFulfillGoalException("The town is already occupied by " + town->visitingHero->getNameTranslated());
|
||||
|
||||
return iAmElementar();
|
||||
}
|
||||
@ -75,10 +75,10 @@ void AdventureSpellCast::accept(VCAI * ai)
|
||||
|
||||
std::string AdventureSpellCast::name() const
|
||||
{
|
||||
return "AdventureSpellCast " + getSpell()->getName();
|
||||
return "AdventureSpellCast " + getSpell()->getNameTranslated();
|
||||
}
|
||||
|
||||
std::string AdventureSpellCast::completeMessage() const
|
||||
{
|
||||
return "Spell cast successfully " + getSpell()->getName();
|
||||
return "Spell cast successfully " + getSpell()->getNameTranslated();
|
||||
}
|
||||
|
@ -41,5 +41,5 @@ TSubgoal BuyArmy::whatToDoToAchieve()
|
||||
|
||||
std::string BuyArmy::completeMessage() const
|
||||
{
|
||||
return boost::format("Bought army of value %d in town of %s") % value, town->name;
|
||||
return boost::format("Bought army of value %d in town of %s") % value, town->getNameTranslated();
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ TSubgoal CompleteQuest::whatToDoToAchieve()
|
||||
result->name(),
|
||||
result->tile.toString(),
|
||||
result->objid,
|
||||
result->hero.validAndSet() ? result->hero->name : "not specified");
|
||||
result->hero.validAndSet() ? result->hero->getNameTranslated() : "not specified");
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -273,4 +273,4 @@ TGoalVec CompleteQuest::missionDestroyObj() const
|
||||
}
|
||||
|
||||
return solutions;
|
||||
}
|
||||
}
|
||||
|
@ -240,7 +240,7 @@ bool Explore::operator==(const Explore & other) const
|
||||
|
||||
std::string Explore::completeMessage() const
|
||||
{
|
||||
return "Hero " + hero.get()->name + " completed exploration";
|
||||
return "Hero " + hero.get()->getNameTranslated() + " completed exploration";
|
||||
}
|
||||
|
||||
TSubgoal Explore::whatToDoToAchieve()
|
||||
@ -339,7 +339,7 @@ TGoalVec Explore::getAllPossibleSubgoals()
|
||||
{
|
||||
for(auto h : heroes)
|
||||
{
|
||||
logAi->trace("Exploration searching for a new point for hero %s", h->name);
|
||||
logAi->trace("Exploration searching for a new point for hero %s", h->getNameTranslated());
|
||||
|
||||
TSubgoal goal = explorationNewPoint(h);
|
||||
|
||||
|
@ -33,7 +33,7 @@ bool GatherArmy::operator==(const GatherArmy & other) const
|
||||
|
||||
std::string GatherArmy::completeMessage() const
|
||||
{
|
||||
return "Hero " + hero.get()->name + " gathered army of value " + boost::lexical_cast<std::string>(value);
|
||||
return "Hero " + hero.get()->getNameTranslated() + " gathered army of value " + boost::lexical_cast<std::string>(value);
|
||||
}
|
||||
|
||||
TSubgoal GatherArmy::whatToDoToAchieve()
|
||||
|
@ -56,7 +56,7 @@ TSubgoal GatherTroops::whatToDoToAchieve()
|
||||
{
|
||||
if(getCreaturesCount(hero) >= this->value)
|
||||
{
|
||||
logAi->trace("Completing GATHER_TROOPS by hero %s", hero->name);
|
||||
logAi->trace("Completing GATHER_TROOPS by hero %s", hero->getNameTranslated());
|
||||
|
||||
throw goalFulfilledException(sptr(*this));
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ bool VisitHero::operator==(const VisitHero & other) const
|
||||
|
||||
std::string VisitHero::completeMessage() const
|
||||
{
|
||||
return "hero " + hero.get()->name + " visited hero " + boost::lexical_cast<std::string>(objid);
|
||||
return "hero " + hero.get()->getNameTranslated() + " visited hero " + boost::lexical_cast<std::string>(objid);
|
||||
}
|
||||
|
||||
TSubgoal VisitHero::whatToDoToAchieve()
|
||||
|
@ -33,7 +33,7 @@ bool VisitObj::operator==(const VisitObj & other) const
|
||||
|
||||
std::string VisitObj::completeMessage() const
|
||||
{
|
||||
return "hero " + hero.get()->name + " captured Object ID = " + boost::lexical_cast<std::string>(objid);
|
||||
return "hero " + hero.get()->getNameTranslated() + " captured Object ID = " + boost::lexical_cast<std::string>(objid);
|
||||
}
|
||||
|
||||
TGoalVec VisitObj::getAllPossibleSubgoals()
|
||||
|
@ -33,7 +33,7 @@ bool VisitTile::operator==(const VisitTile & other) const
|
||||
|
||||
std::string VisitTile::completeMessage() const
|
||||
{
|
||||
return "Hero " + hero.get()->name + " visited tile " + tile.toString();
|
||||
return "Hero " + hero.get()->getNameTranslated() + " visited tile " + tile.toString();
|
||||
}
|
||||
|
||||
TSubgoal VisitTile::whatToDoToAchieve()
|
||||
|
@ -55,7 +55,7 @@ void AIPathfinder::updatePaths(std::vector<HeroPtr> heroes)
|
||||
|
||||
auto calculatePaths = [&](const CGHeroInstance * hero, std::shared_ptr<AIPathfinding::AIPathfinderConfig> config)
|
||||
{
|
||||
logAi->debug("Recalculate paths for %s", hero->name);
|
||||
logAi->debug("Recalculate paths for %s", hero->getNameTranslated());
|
||||
|
||||
cb->calculatePaths(config);
|
||||
};
|
||||
|
@ -303,7 +303,7 @@ void VCAI::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, Q
|
||||
auto firstHero = cb->getHero(hero1);
|
||||
auto secondHero = cb->getHero(hero2);
|
||||
|
||||
status.addQuery(query, boost::str(boost::format("Exchange between heroes %s (%d) and %s (%d)") % firstHero->name % firstHero->tempOwner % secondHero->name % secondHero->tempOwner));
|
||||
status.addQuery(query, boost::str(boost::format("Exchange between heroes %s (%d) and %s (%d)") % firstHero->getNameTranslated() % firstHero->tempOwner % secondHero->getNameTranslated() % secondHero->tempOwner));
|
||||
|
||||
requestActionASAP([=]()
|
||||
{
|
||||
@ -617,7 +617,7 @@ void VCAI::heroGotLevel(const CGHeroInstance * hero, PrimarySkill::PrimarySkill
|
||||
{
|
||||
LOG_TRACE_PARAMS(logAi, "queryID '%i'", queryID);
|
||||
NET_EVENT_HANDLER;
|
||||
status.addQuery(queryID, boost::str(boost::format("Hero %s got level %d") % hero->name % hero->level));
|
||||
status.addQuery(queryID, boost::str(boost::format("Hero %s got level %d") % hero->getNameTranslated() % hero->level));
|
||||
requestActionASAP([=](){ answerQuery(queryID, 0); });
|
||||
}
|
||||
|
||||
@ -814,7 +814,7 @@ void VCAI::makeTurn()
|
||||
for (auto h : cb->getHeroesInfo())
|
||||
{
|
||||
if (h->movement)
|
||||
logAi->warn("Hero %s has %d MP left", h->name, h->movement);
|
||||
logAi->warn("Hero %s has %d MP left", h->getNameTranslated(), h->movement);
|
||||
}
|
||||
}
|
||||
catch (boost::thread_interrupted & e)
|
||||
@ -1034,7 +1034,7 @@ void VCAI::mainLoop()
|
||||
|
||||
void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
|
||||
{
|
||||
LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->name % obj->getObjectName() % obj->pos.toString());
|
||||
LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->getNameTranslated() % obj->getObjectName() % obj->pos.toString());
|
||||
switch(obj->ID)
|
||||
{
|
||||
case Obj::CREATURE_GENERATOR1:
|
||||
@ -1427,7 +1427,7 @@ void VCAI::wander(HeroPtr h)
|
||||
{
|
||||
//TODO pick the truly best
|
||||
const CGTownInstance * t = *boost::max_element(townsNotReachable, compareReinforcements);
|
||||
logAi->debug("%s can't reach any town, we'll try to make our way to %s at %s", h->name, t->name, t->visitablePos().toString());
|
||||
logAi->debug("%s can't reach any town, we'll try to make our way to %s at %s", h->getNameTranslated(), t->getNameTranslated(), t->visitablePos().toString());
|
||||
int3 pos1 = h->pos;
|
||||
striveToGoal(sptr(Goals::ClearWayTo(t->visitablePos()).sethero(h))); //TODO: drop "strive", add to mainLoop
|
||||
//if out hero is stuck, we may need to request another hero to clear the way we see
|
||||
@ -1581,7 +1581,7 @@ void VCAI::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, i
|
||||
assert(playerID > PlayerColor::PLAYER_LIMIT || status.getBattle() == UPCOMING_BATTLE);
|
||||
status.setBattle(ONGOING_BATTLE);
|
||||
const CGObjectInstance * presumedEnemy = vstd::backOrNull(cb->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
|
||||
battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->name : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString());
|
||||
battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->getNameTranslated() : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString());
|
||||
CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side);
|
||||
}
|
||||
|
||||
@ -1667,7 +1667,7 @@ void VCAI::validateVisitableObjs()
|
||||
});
|
||||
for(auto & p : reservedHeroesMap)
|
||||
{
|
||||
errorMsg = " shouldn't be on list for hero " + p.first->name + "!";
|
||||
errorMsg = " shouldn't be on list for hero " + p.first->getNameTranslated() + "!";
|
||||
vstd::erase_if(p.second, shouldBeErased);
|
||||
}
|
||||
|
||||
@ -1808,7 +1808,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
}
|
||||
};
|
||||
|
||||
logAi->debug("Moving hero %s to tile %s", h->name, dst.toString());
|
||||
logAi->debug("Moving hero %s to tile %s", h->getNameTranslated(), dst.toString());
|
||||
int3 startHpos = h->visitablePos();
|
||||
bool ret = false;
|
||||
if(startHpos == dst)
|
||||
@ -1828,7 +1828,7 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
cb->getPathsInfo(h.get())->getPath(path, dst);
|
||||
if(path.nodes.empty())
|
||||
{
|
||||
logAi->error("Hero %s cannot reach %s.", h->name, dst.toString());
|
||||
logAi->error("Hero %s cannot reach %s.", h->getNameTranslated(), dst.toString());
|
||||
throw goalFulfilledException(sptr(Goals::VisitTile(dst).sethero(h)));
|
||||
}
|
||||
int i = (int)path.nodes.size() - 1;
|
||||
@ -1990,15 +1990,15 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
throw cannotFulfillGoalException("Invalid path found!");
|
||||
}
|
||||
evaluateGoal(h); //new hero position means new game situation
|
||||
logAi->debug("Hero %s moved from %s to %s. Returning %d.", h->name, startHpos.toString(), h->visitablePos().toString(), ret);
|
||||
logAi->debug("Hero %s moved from %s to %s. Returning %d.", h->getNameTranslated(), startHpos.toString(), h->visitablePos().toString(), ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void VCAI::buildStructure(const CGTownInstance * t, BuildingID building)
|
||||
{
|
||||
auto name = t->town->buildings.at(building)->Name();
|
||||
logAi->debug("Player %d will build %s in town of %s at %s", ai->playerID, name, t->name, t->pos.toString());
|
||||
auto name = t->town->buildings.at(building)->getNameTranslated();
|
||||
logAi->debug("Player %d will build %s in town of %s at %s", ai->playerID, name, t->getNameTranslated(), t->pos.toString());
|
||||
cb->buildBuilding(t, building); //just do this;
|
||||
}
|
||||
|
||||
@ -2027,7 +2027,7 @@ void VCAI::tryRealize(Goals::VisitTile & g)
|
||||
throw cannotFulfillGoalException("Cannot visit tile: hero is out of MPs!");
|
||||
if(g.tile == g.hero->visitablePos() && cb->getVisitableObjs(g.hero->visitablePos()).size() < 2)
|
||||
{
|
||||
logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", g.hero->name, g.tile.toString());
|
||||
logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", g.hero->getNameTranslated(), g.tile.toString());
|
||||
throw goalFulfilledException(sptr(g));
|
||||
}
|
||||
if(ai->moveHeroToTile(g.tile, g.hero.get()))
|
||||
@ -2043,7 +2043,7 @@ void VCAI::tryRealize(Goals::VisitObj & g)
|
||||
throw cannotFulfillGoalException("Cannot visit object: hero is out of MPs!");
|
||||
if(position == g.hero->visitablePos() && cb->getVisitableObjs(g.hero->visitablePos()).size() < 2)
|
||||
{
|
||||
logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", g.hero->name, g.tile.toString());
|
||||
logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", g.hero->getNameTranslated(), g.tile.toString());
|
||||
throw goalFulfilledException(sptr(g));
|
||||
}
|
||||
if(ai->moveHeroToTile(position, g.hero.get()))
|
||||
@ -2081,7 +2081,7 @@ void VCAI::tryRealize(Goals::BuildThis & g)
|
||||
if (cb->canBuildStructure(t, b) == EBuildingState::ALLOWED)
|
||||
{
|
||||
logAi->debug("Player %d will build %s in town of %s at %s",
|
||||
playerID, t->town->buildings.at(b)->Name(), t->name, t->pos.toString());
|
||||
playerID, t->town->buildings.at(b)->getNameTranslated(), t->getNameTranslated(), t->pos.toString());
|
||||
cb->buildBuilding(t, b);
|
||||
throw goalFulfilledException(sptr(g));
|
||||
}
|
||||
@ -2404,7 +2404,7 @@ void VCAI::performTypicalActions()
|
||||
if(!h) //hero might be lost. getUnblockedHeroes() called once on start of turn
|
||||
continue;
|
||||
|
||||
logAi->debug("Hero %s started wandering, MP=%d", h->name.c_str(), h->movement);
|
||||
logAi->debug("Hero %s started wandering, MP=%d", h->getNameTranslated(), h->movement);
|
||||
makePossibleUpgrades(*h);
|
||||
pickBestArtifacts(*h);
|
||||
try
|
||||
@ -2439,7 +2439,7 @@ void VCAI::checkHeroArmy(HeroPtr h)
|
||||
|
||||
void VCAI::recruitHero(const CGTownInstance * t, bool throwing)
|
||||
{
|
||||
logAi->debug("Trying to recruit a hero in %s at %s", t->name, t->visitablePos().toString());
|
||||
logAi->debug("Trying to recruit a hero in %s at %s", t->getNameTranslated(), t->visitablePos().toString());
|
||||
|
||||
auto heroes = cb->getAvailableHeroes(t);
|
||||
if(heroes.size())
|
||||
|
12
CI/conan/base/apple
Normal file
12
CI/conan/base/apple
Normal file
@ -0,0 +1,12 @@
|
||||
[settings]
|
||||
compiler=apple-clang
|
||||
compiler.version=14
|
||||
compiler.libcxx=libc++
|
||||
build_type=Release
|
||||
|
||||
# required for Boost.Locale in versions >= 1.81
|
||||
compiler.cppstd=11
|
||||
|
||||
[conf]
|
||||
tools.apple:enable_bitcode = False
|
||||
tools.cmake.cmaketoolchain:generator = Ninja
|
5
CI/conan/base/ios
Normal file
5
CI/conan/base/ios
Normal file
@ -0,0 +1,5 @@
|
||||
include(apple)
|
||||
|
||||
[settings]
|
||||
os=iOS
|
||||
os.sdk=iphoneos
|
4
CI/conan/base/macos
Normal file
4
CI/conan/base/macos
Normal file
@ -0,0 +1,4 @@
|
||||
include(apple)
|
||||
|
||||
[settings]
|
||||
os=Macos
|
@ -1,14 +1,5 @@
|
||||
include(base/ios)
|
||||
|
||||
[settings]
|
||||
os=iOS
|
||||
os.version=12.0
|
||||
os.sdk=iphoneos
|
||||
arch=armv8
|
||||
compiler=apple-clang
|
||||
compiler.version=13
|
||||
compiler.libcxx=libc++
|
||||
build_type=Release
|
||||
[options]
|
||||
[build_requires]
|
||||
[env]
|
||||
[conf]
|
||||
tools.cmake.cmaketoolchain:generator = Ninja
|
||||
|
@ -1,14 +1,8 @@
|
||||
include(base/ios)
|
||||
|
||||
[settings]
|
||||
os=iOS
|
||||
os.version=10.0
|
||||
os.sdk=iphoneos
|
||||
arch=armv7
|
||||
compiler=apple-clang
|
||||
|
||||
# Xcode 13.x is the last version that can build for armv7
|
||||
compiler.version=13
|
||||
compiler.libcxx=libc++
|
||||
build_type=Release
|
||||
[options]
|
||||
[build_requires]
|
||||
[env]
|
||||
[conf]
|
||||
tools.cmake.cmaketoolchain:generator = Ninja
|
||||
|
@ -1,13 +1,5 @@
|
||||
include(base/macos)
|
||||
|
||||
[settings]
|
||||
os=Macos
|
||||
os.version=11.0
|
||||
arch=armv8
|
||||
compiler=apple-clang
|
||||
compiler.version=13
|
||||
compiler.libcxx=libc++
|
||||
build_type=Release
|
||||
[options]
|
||||
[build_requires]
|
||||
[env]
|
||||
[conf]
|
||||
tools.cmake.cmaketoolchain:generator = Ninja
|
||||
|
@ -1,13 +1,5 @@
|
||||
include(base/macos)
|
||||
|
||||
[settings]
|
||||
os=Macos
|
||||
os.version=10.13
|
||||
arch=x86_64
|
||||
compiler=apple-clang
|
||||
compiler.version=13
|
||||
compiler.libcxx=libc++
|
||||
build_type=Release
|
||||
[options]
|
||||
[build_requires]
|
||||
[env]
|
||||
[conf]
|
||||
tools.cmake.cmaketoolchain:generator = Ninja
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo DEVELOPER_DIR=/Applications/Xcode_13.4.1.app >> $GITHUB_ENV
|
||||
echo DEVELOPER_DIR=/Applications/Xcode_14.2.app >> $GITHUB_ENV
|
||||
|
||||
mkdir ~/.conan ; cd ~/.conan
|
||||
curl -L 'https://github.com/vcmi/vcmi-ios-deps/releases/download/1.1/ios-arm64.xz' \
|
||||
curl -L 'https://github.com/vcmi/vcmi-ios-deps/releases/download/1.2/ios-arm64.txz' \
|
||||
| tar -xf -
|
||||
|
@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo DEVELOPER_DIR=/Applications/Xcode_13.4.1.app >> $GITHUB_ENV
|
||||
echo DEVELOPER_DIR=/Applications/Xcode_14.2.app >> $GITHUB_ENV
|
||||
|
||||
brew install ninja
|
||||
|
||||
mkdir ~/.conan ; cd ~/.conan
|
||||
curl -L "https://github.com/vcmi/vcmi-deps-macos/releases/download/1.1/$DEPS_FILENAME.txz" \
|
||||
curl -L "https://github.com/vcmi/vcmi-deps-macos/releases/download/1.2/$DEPS_FILENAME.txz" \
|
||||
| tar -xf -
|
||||
|
@ -1,10 +1,10 @@
|
||||
curl -LfsS -o "vcpkg-export-${VCMI_BUILD_PLATFORM}-windows-v140.7z" \
|
||||
"https://github.com/vcmi/vcmi-deps-windows/releases/download/v1.5/vcpkg-export-${VCMI_BUILD_PLATFORM}-windows-v140.7z"
|
||||
7z x "vcpkg-export-${VCMI_BUILD_PLATFORM}-windows-v140.7z"
|
||||
curl -LfsS -o "vcpkg-export-${VCMI_BUILD_PLATFORM}-windows-v143.7z" \
|
||||
"https://github.com/vcmi/vcmi-deps-windows/releases/download/v1.6/vcpkg-export-${VCMI_BUILD_PLATFORM}-windows-v143.7z"
|
||||
7z x "vcpkg-export-${VCMI_BUILD_PLATFORM}-windows-v143.7z"
|
||||
|
||||
rm -r -f vcpkg/installed/${VCMI_BUILD_PLATFORM}-windows/debug
|
||||
mkdir -p vcpkg/installed/${VCMI_BUILD_PLATFORM}-windows/debug/bin
|
||||
cp vcpkg/installed/${VCMI_BUILD_PLATFORM}-windows/bin/* vcpkg/installed/${VCMI_BUILD_PLATFORM}-windows/debug/bin
|
||||
#rm -r -f vcpkg/installed/${VCMI_BUILD_PLATFORM}-windows/debug
|
||||
#mkdir -p vcpkg/installed/${VCMI_BUILD_PLATFORM}-windows/debug/bin
|
||||
#cp vcpkg/installed/${VCMI_BUILD_PLATFORM}-windows/bin/* vcpkg/installed/${VCMI_BUILD_PLATFORM}-windows/debug/bin
|
||||
|
||||
DUMPBIN_DIR=$(vswhere -latest -find **/dumpbin.exe | head -n 1)
|
||||
dirname "$DUMPBIN_DIR" > $GITHUB_PATH
|
||||
dirname "$DUMPBIN_DIR" > $GITHUB_PATH
|
||||
|
@ -90,6 +90,11 @@ if(APPLE_IOS AND COPY_CONFIG_ON_BUILD)
|
||||
set(COPY_CONFIG_ON_BUILD OFF)
|
||||
endif()
|
||||
|
||||
# No QT Linguist on MXE
|
||||
if((MINGW) AND (${CMAKE_CROSSCOMPILING}))
|
||||
set(ENABLE_TRANSLATIONS OFF)
|
||||
endif()
|
||||
|
||||
############################################
|
||||
# Miscellaneous options #
|
||||
############################################
|
||||
@ -181,6 +186,14 @@ set(CMAKE_XCODE_ATTRIBUTE_MARKETING_VERSION ${APP_SHORT_VERSION})
|
||||
set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH NO)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH[variant=Debug] YES)
|
||||
|
||||
if(ENABLE_LAUNCHER)
|
||||
add_definitions(-DENABLE_LAUNCHER)
|
||||
endif()
|
||||
|
||||
if(ENABLE_EDITOR)
|
||||
add_definitions(-DENABLE_EDITOR)
|
||||
endif()
|
||||
|
||||
if(ENABLE_SINGLE_APP_BUILD)
|
||||
add_definitions(-DSINGLE_PROCESS_APP=1)
|
||||
endif()
|
||||
@ -232,7 +245,7 @@ if(MINGW OR MSVC)
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4800") # 4800: implicit conversion from 'xxx' to bool. Possible information loss
|
||||
|
||||
if(ENABLE_STRICT_COMPILATION)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wx") # Treats all compiler warnings as errors
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX") # Treats all compiler warnings as errors
|
||||
endif()
|
||||
|
||||
if(ENABLE_MULTI_PROCESS_BUILDS)
|
||||
@ -360,12 +373,8 @@ if(ENABLE_LAUNCHER OR ENABLE_EDITOR)
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network)
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS LinguistTools)
|
||||
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS LinguistTools)
|
||||
if(NOT Qt${QT_VERSION_MAJOR}LinguistTools_DIR)
|
||||
set(ENABLE_TRANSLATIONS OFF)
|
||||
endif()
|
||||
if(ENABLE_TRANSLATIONS)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS LinguistTools)
|
||||
add_definitions(-DENABLE_QT_TRANSLATIONS)
|
||||
endif()
|
||||
endif()
|
||||
@ -563,6 +572,9 @@ if(WIN32)
|
||||
FILES ${integration_loc}
|
||||
DESTINATION ${BIN_DIR}/platforms
|
||||
)
|
||||
install(
|
||||
FILES "$<TARGET_FILE:Qt${QT_VERSION_MAJOR}::QWindowsVistaStylePlugin>"
|
||||
DESTINATION ${BIN_DIR}/styles)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -1,6 +1,20 @@
|
||||
{
|
||||
"name" : "VCMI essential files",
|
||||
"description" : "Essential files required for VCMI to run correctly",
|
||||
|
||||
"german" : {
|
||||
"name" : "VCMI - grundlegende Dateien",
|
||||
"description" : "Grundlegende Dateien, die für die korrekte Ausführung von VCMI erforderlich sind",
|
||||
"author" : "VCMI-Team",
|
||||
"modType" : "Grafik",
|
||||
},
|
||||
|
||||
"ukrainian" : {
|
||||
"name" : "VCMI - ключові файли",
|
||||
"description" : "Ключові файли необхідні для повноцінної роботи VCMI",
|
||||
"author" : "Команда VCMI",
|
||||
"modType" : "Графіка",
|
||||
},
|
||||
|
||||
"version" : "1.1",
|
||||
"author" : "VCMI Team",
|
||||
|
@ -10,8 +10,7 @@
|
||||
#include "StdInc.h"
|
||||
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "SDL.h"
|
||||
#include "SDL_image.h"
|
||||
#include <SDL_image.h>
|
||||
#include "CBitmapHandler.h"
|
||||
#include "gui/SDL_Extensions.h"
|
||||
#include "../lib/vcmi_endian.h"
|
||||
|
@ -38,7 +38,7 @@ VCMI_LIB_NAMESPACE_END
|
||||
class CMapHandler;
|
||||
class CSoundHandler;
|
||||
class CMusicHandler;
|
||||
class CCursorHandler;
|
||||
class CursorHandler;
|
||||
class IMainVideoPlayer;
|
||||
class CServerHandler;
|
||||
|
||||
@ -49,7 +49,7 @@ public:
|
||||
CSoundHandler * soundh;
|
||||
CMusicHandler * musich;
|
||||
CConsoleHandler * consoleh;
|
||||
CCursorHandler * curh;
|
||||
CursorHandler * curh;
|
||||
IMainVideoPlayer * videoh;
|
||||
};
|
||||
extern CClientState * CCS;
|
||||
|
521
client/CMT.cpp
521
client/CMT.cpp
@ -13,8 +13,6 @@
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <vcmi/scripting/Service.h>
|
||||
|
||||
#include "gui/SDL_Extensions.h"
|
||||
#include "CGameInfo.h"
|
||||
#include "mapHandler.h"
|
||||
@ -25,7 +23,7 @@
|
||||
#include "lobby/CSelectionBase.h"
|
||||
#include "windows/CCastleInterface.h"
|
||||
#include "../lib/CConsoleHandler.h"
|
||||
#include "gui/CCursorHandler.h"
|
||||
#include "gui/CursorHandler.h"
|
||||
#include "../lib/CGameState.h"
|
||||
#include "../CCallback.h"
|
||||
#include "CPlayerInterface.h"
|
||||
@ -33,37 +31,32 @@
|
||||
#include "../lib/CBuildingHandler.h"
|
||||
#include "CVideoHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
#include "../lib/CCreatureHandler.h"
|
||||
#include "../lib/spells/CSpellHandler.h"
|
||||
#include "CMusicHandler.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "Graphics.h"
|
||||
#include "Client.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "../lib/serializer/BinaryDeserializer.h"
|
||||
#include "../lib/serializer/BinarySerializer.h"
|
||||
#include "../lib/VCMI_Lib.h"
|
||||
#include "../lib/VCMIDirs.h"
|
||||
#include "../lib/NetPacks.h"
|
||||
#include "CMessage.h"
|
||||
#include "../lib/CModHandler.h"
|
||||
#include "../lib/ScriptHandler.h"
|
||||
#include "../lib/CTownHandler.h"
|
||||
#include "../lib/CArtHandler.h"
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "../lib/logging/CBasicLogConfigurator.h"
|
||||
#include "../lib/StringConstants.h"
|
||||
#include "../lib/CPlayerState.h"
|
||||
#include "gui/CAnimation.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
#include "CServerHandler.h"
|
||||
#include "gui/NotificationHandler.h"
|
||||
#include "ClientCommandManager.h"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include "mainmenu/CPrologEpilogVideo.h"
|
||||
#include <vstd/StringUtils.h>
|
||||
#include <SDL.h>
|
||||
|
||||
#ifdef VCMI_WINDOWS
|
||||
#include "SDL_syswm.h"
|
||||
@ -71,7 +64,7 @@
|
||||
#ifdef VCMI_ANDROID
|
||||
#include "lib/CAndroidVMHelper.h"
|
||||
#endif
|
||||
#include "../lib/UnlockGuard.h"
|
||||
|
||||
#include "CMT.h"
|
||||
|
||||
#if __MINGW32__
|
||||
@ -208,6 +201,8 @@ int main(int argc, char * argv[])
|
||||
("lobby-host", "if this client hosts session")
|
||||
("lobby-uuid", po::value<std::string>(), "uuid to the server")
|
||||
("lobby-connections", po::value<ui16>(), "connections of server")
|
||||
("lobby-username", po::value<std::string>(), "player name")
|
||||
("lobby-gamemode", po::value<ui16>(), "use 0 for new game and 1 for load game")
|
||||
("uuid", po::value<std::string>(), "uuid for the client");
|
||||
|
||||
if(argc > 1)
|
||||
@ -247,7 +242,14 @@ int main(int argc, char * argv[])
|
||||
std::cout.flags(std::ios::unitbuf);
|
||||
#ifndef VCMI_IOS
|
||||
console = new CConsoleHandler();
|
||||
*console->cb = processCommand;
|
||||
|
||||
auto callbackFunction = [](std::string buffer, bool calledFromIngameConsole)
|
||||
{
|
||||
ClientCommandManager commandController;
|
||||
commandController.processCommand(buffer, calledFromIngameConsole);
|
||||
};
|
||||
|
||||
*console->cb = callbackFunction;
|
||||
console->start();
|
||||
#endif
|
||||
|
||||
@ -470,7 +472,7 @@ int main(int argc, char * argv[])
|
||||
pomtime.getDiff();
|
||||
graphics = new Graphics(); // should be before curh
|
||||
|
||||
CCS->curh = new CCursorHandler();
|
||||
CCS->curh = new CursorHandler();
|
||||
logGlobal->info("Screen handler: %d ms", pomtime.getDiff());
|
||||
pomtime.getDiff();
|
||||
|
||||
@ -489,29 +491,8 @@ int main(int argc, char * argv[])
|
||||
session["autoSkip"].Bool() = vm.count("autoSkip");
|
||||
session["oneGoodAI"].Bool() = vm.count("oneGoodAI");
|
||||
session["aiSolo"].Bool() = false;
|
||||
std::shared_ptr<CMainMenu> mmenu;
|
||||
|
||||
session["lobby"].Bool() = false;
|
||||
if(vm.count("lobby"))
|
||||
{
|
||||
session["lobby"].Bool() = true;
|
||||
session["host"].Bool() = false;
|
||||
session["address"].String() = vm["lobby-address"].as<std::string>();
|
||||
CSH->uuid = vm["uuid"].as<std::string>();
|
||||
session["port"].Integer() = vm["lobby-port"].as<ui16>();
|
||||
logGlobal->info("Remote lobby mode at %s:%d, uuid is %s", session["address"].String(), session["port"].Integer(), CSH->uuid);
|
||||
if(vm.count("lobby-host"))
|
||||
{
|
||||
session["host"].Bool() = true;
|
||||
session["hostConnections"].String() = std::to_string(vm["lobby-connections"].as<ui16>());
|
||||
session["hostUuid"].String() = vm["lobby-uuid"].as<std::string>();
|
||||
logGlobal->info("This client will host session, server uuid is %s", session["hostUuid"].String());
|
||||
}
|
||||
|
||||
//we should not reconnect to previous game in online mode
|
||||
Settings saveSession = settings.write["server"]["reconnect"];
|
||||
saveSession->Bool() = false;
|
||||
}
|
||||
|
||||
if(vm.count("testmap"))
|
||||
{
|
||||
session["testmap"].String() = vm["testmap"].as<std::string>();
|
||||
@ -526,7 +507,44 @@ int main(int argc, char * argv[])
|
||||
}
|
||||
else
|
||||
{
|
||||
GH.curInt = CMainMenu::create().get();
|
||||
mmenu = CMainMenu::create();
|
||||
GH.curInt = mmenu.get();
|
||||
}
|
||||
|
||||
std::vector<std::string> names;
|
||||
session["lobby"].Bool() = false;
|
||||
if(vm.count("lobby"))
|
||||
{
|
||||
session["lobby"].Bool() = true;
|
||||
session["host"].Bool() = false;
|
||||
session["address"].String() = vm["lobby-address"].as<std::string>();
|
||||
if(vm.count("lobby-username"))
|
||||
session["username"].String() = vm["lobby-username"].as<std::string>();
|
||||
else
|
||||
session["username"].String() = settings["launcher"]["lobbyUsername"].String();
|
||||
if(vm.count("lobby-gamemode"))
|
||||
session["gamemode"].Integer() = vm["lobby-gamemode"].as<ui16>();
|
||||
else
|
||||
session["gamemode"].Integer() = 0;
|
||||
CSH->uuid = vm["uuid"].as<std::string>();
|
||||
session["port"].Integer() = vm["lobby-port"].as<ui16>();
|
||||
logGlobal->info("Remote lobby mode at %s:%d, uuid is %s", session["address"].String(), session["port"].Integer(), CSH->uuid);
|
||||
if(vm.count("lobby-host"))
|
||||
{
|
||||
session["host"].Bool() = true;
|
||||
session["hostConnections"].String() = std::to_string(vm["lobby-connections"].as<ui16>());
|
||||
session["hostUuid"].String() = vm["lobby-uuid"].as<std::string>();
|
||||
logGlobal->info("This client will host session, server uuid is %s", session["hostUuid"].String());
|
||||
}
|
||||
|
||||
//we should not reconnect to previous game in online mode
|
||||
Settings saveSession = settings.write["server"]["reconnect"];
|
||||
saveSession->Bool() = false;
|
||||
|
||||
//start lobby immediately
|
||||
names.push_back(session["username"].String());
|
||||
ESelectionScreen sscreen = session["gamemode"].Integer() == 0 ? ESelectionScreen::newGame : ESelectionScreen::loadGame;
|
||||
mmenu->openLobby(sscreen, session["host"].Bool(), &names, ELoadMode::MULTI);
|
||||
}
|
||||
|
||||
// Restore remote session - start game immediately
|
||||
@ -548,437 +566,6 @@ int main(int argc, char * argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
void printInfoAboutIntObject(const CIntObject *obj, int level)
|
||||
{
|
||||
std::stringstream sbuffer;
|
||||
sbuffer << std::string(level, '\t');
|
||||
|
||||
sbuffer << typeid(*obj).name() << " *** ";
|
||||
if (obj->active)
|
||||
{
|
||||
#define PRINT(check, text) if (obj->active & CIntObject::check) sbuffer << text
|
||||
PRINT(LCLICK, 'L');
|
||||
PRINT(RCLICK, 'R');
|
||||
PRINT(HOVER, 'H');
|
||||
PRINT(MOVE, 'M');
|
||||
PRINT(KEYBOARD, 'K');
|
||||
PRINT(TIME, 'T');
|
||||
PRINT(GENERAL, 'A');
|
||||
PRINT(WHEEL, 'W');
|
||||
PRINT(DOUBLECLICK, 'D');
|
||||
#undef PRINT
|
||||
}
|
||||
else
|
||||
sbuffer << "inactive";
|
||||
sbuffer << " at " << obj->pos.x <<"x"<< obj->pos.y;
|
||||
sbuffer << " (" << obj->pos.w <<"x"<< obj->pos.h << ")";
|
||||
logGlobal->info(sbuffer.str());
|
||||
|
||||
for(const CIntObject *child : obj->children)
|
||||
printInfoAboutIntObject(child, level+1);
|
||||
}
|
||||
|
||||
void removeGUI()
|
||||
{
|
||||
// CClient::endGame
|
||||
GH.curInt = nullptr;
|
||||
if(GH.topInt())
|
||||
GH.topInt()->deactivate();
|
||||
adventureInt = nullptr;
|
||||
GH.listInt.clear();
|
||||
GH.objsToBlit.clear();
|
||||
GH.statusbar = nullptr;
|
||||
logGlobal->info("Removed GUI.");
|
||||
|
||||
LOCPLINT = nullptr;
|
||||
}
|
||||
|
||||
#ifndef VCMI_IOS
|
||||
void processCommand(const std::string &message)
|
||||
{
|
||||
std::istringstream readed;
|
||||
readed.str(message);
|
||||
std::string cn; //command name
|
||||
readed >> cn;
|
||||
|
||||
// Check mantis issue 2292 for details
|
||||
// if(LOCPLINT && LOCPLINT->cingconsole)
|
||||
// LOCPLINT->cingconsole->print(message);
|
||||
|
||||
if(message==std::string("die, fool"))
|
||||
{
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else if(cn==std::string("activate"))
|
||||
{
|
||||
int what;
|
||||
readed >> what;
|
||||
switch (what)
|
||||
{
|
||||
case 0:
|
||||
GH.topInt()->activate();
|
||||
break;
|
||||
case 1:
|
||||
adventureInt->activate();
|
||||
break;
|
||||
case 2:
|
||||
LOCPLINT->castleInt->activate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(cn=="redraw")
|
||||
{
|
||||
GH.totalRedraw();
|
||||
}
|
||||
else if(cn=="screen")
|
||||
{
|
||||
std::cout << "Screenbuf points to ";
|
||||
|
||||
if(screenBuf == screen)
|
||||
logGlobal->error("screen");
|
||||
else if(screenBuf == screen2)
|
||||
logGlobal->error("screen2");
|
||||
else
|
||||
logGlobal->error("?!?");
|
||||
|
||||
SDL_SaveBMP(screen, "Screen_c.bmp");
|
||||
SDL_SaveBMP(screen2, "Screen2_c.bmp");
|
||||
}
|
||||
else if(cn=="save")
|
||||
{
|
||||
if(!CSH->client)
|
||||
{
|
||||
std::cout << "Game in not active";
|
||||
return;
|
||||
}
|
||||
std::string fname;
|
||||
readed >> fname;
|
||||
CSH->client->save(fname);
|
||||
}
|
||||
// else if(cn=="load")
|
||||
// {
|
||||
// // TODO: this code should end the running game and manage to call startGame instead
|
||||
// std::string fname;
|
||||
// readed >> fname;
|
||||
// CSH->client->loadGame(fname);
|
||||
// }
|
||||
else if(message=="convert txt")
|
||||
{
|
||||
VLC->generaltexth->dumpAllTexts();
|
||||
}
|
||||
else if(message=="get config")
|
||||
{
|
||||
std::cout << "Command accepted.\t";
|
||||
|
||||
const bfs::path outPath =
|
||||
VCMIDirs::get().userExtractedPath() / "configuration";
|
||||
|
||||
bfs::create_directories(outPath);
|
||||
|
||||
const std::vector<std::string> contentNames = {"heroClasses", "artifacts", "creatures", "factions", "objects", "heroes", "spells", "skills"};
|
||||
|
||||
for(auto contentName : contentNames)
|
||||
{
|
||||
auto & content = (*VLC->modh->content)[contentName];
|
||||
|
||||
auto contentOutPath = outPath / contentName;
|
||||
bfs::create_directories(contentOutPath);
|
||||
|
||||
for(auto & iter : content.modData)
|
||||
{
|
||||
const JsonNode & modData = iter.second.modData;
|
||||
|
||||
for(auto & nameAndObject : modData.Struct())
|
||||
{
|
||||
const JsonNode & object = nameAndObject.second;
|
||||
|
||||
std::string name = CModHandler::normalizeIdentifier(object.meta, CModHandler::scopeBuiltin(), nameAndObject.first);
|
||||
|
||||
boost::algorithm::replace_all(name,":","_");
|
||||
|
||||
const bfs::path filePath = contentOutPath / (name + ".json");
|
||||
bfs::ofstream file(filePath);
|
||||
file << object.toJson();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "\rExtracting done :)\n";
|
||||
std::cout << " Extracted files can be found in " << outPath << " directory\n";
|
||||
}
|
||||
#if SCRIPTING_ENABLED
|
||||
else if(message=="get scripts")
|
||||
{
|
||||
std::cout << "Command accepted.\t";
|
||||
|
||||
const bfs::path outPath =
|
||||
VCMIDirs::get().userExtractedPath() / "scripts";
|
||||
|
||||
bfs::create_directories(outPath);
|
||||
|
||||
for(auto & kv : VLC->scriptHandler->objects)
|
||||
{
|
||||
std::string name = kv.first;
|
||||
boost::algorithm::replace_all(name,":","_");
|
||||
|
||||
const scripting::ScriptImpl * script = kv.second.get();
|
||||
bfs::path filePath = outPath / (name + ".lua");
|
||||
bfs::ofstream file(filePath);
|
||||
file << script->getSource();
|
||||
}
|
||||
std::cout << "\rExtracting done :)\n";
|
||||
std::cout << " Extracted files can be found in " << outPath << " directory\n";
|
||||
}
|
||||
#endif
|
||||
else if(message=="get txt")
|
||||
{
|
||||
std::cout << "Command accepted.\t";
|
||||
|
||||
const bfs::path outPath =
|
||||
VCMIDirs::get().userExtractedPath();
|
||||
|
||||
auto list = CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident)
|
||||
{
|
||||
return ident.getType() == EResType::TEXT && boost::algorithm::starts_with(ident.getName(), "DATA/");
|
||||
});
|
||||
|
||||
for (auto & filename : list)
|
||||
{
|
||||
const bfs::path filePath = outPath / (filename.getName() + ".TXT");
|
||||
|
||||
bfs::create_directories(filePath.parent_path());
|
||||
|
||||
bfs::ofstream file(filePath);
|
||||
auto text = CResourceHandler::get()->load(filename)->readAll();
|
||||
|
||||
file.write((char*)text.first.get(), text.second);
|
||||
}
|
||||
|
||||
std::cout << "\rExtracting done :)\n";
|
||||
std::cout << " Extracted files can be found in " << outPath << " directory\n";
|
||||
}
|
||||
else if(cn=="crash")
|
||||
{
|
||||
int *ptr = nullptr;
|
||||
*ptr = 666;
|
||||
//disaster!
|
||||
}
|
||||
else if(cn == "mp" && adventureInt)
|
||||
{
|
||||
if(const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(adventureInt->selection))
|
||||
std::cout << h->movement << "; max: " << h->maxMovePoints(true) << "/" << h->maxMovePoints(false) << std::endl;
|
||||
}
|
||||
else if(cn == "bonuses")
|
||||
{
|
||||
bool jsonFormat = (message == "bonuses json");
|
||||
auto format = [jsonFormat](const BonusList & b) -> std::string
|
||||
{
|
||||
if(jsonFormat)
|
||||
return b.toJsonNode().toJson(true);
|
||||
std::ostringstream ss;
|
||||
ss << b;
|
||||
return ss.str();
|
||||
};
|
||||
std::cout << "Bonuses of " << adventureInt->selection->getObjectName() << std::endl
|
||||
<< format(adventureInt->selection->getBonusList()) << std::endl;
|
||||
|
||||
std::cout << "\nInherited bonuses:\n";
|
||||
TCNodes parents;
|
||||
adventureInt->selection->getParents(parents);
|
||||
for(const CBonusSystemNode *parent : parents)
|
||||
{
|
||||
std::cout << "\nBonuses from " << typeid(*parent).name() << std::endl << format(*parent->getAllBonuses(Selector::all, Selector::all)) << std::endl;
|
||||
}
|
||||
}
|
||||
else if(cn == "not dialog")
|
||||
{
|
||||
LOCPLINT->showingDialog->setn(false);
|
||||
}
|
||||
else if(cn == "gui")
|
||||
{
|
||||
for(auto & child : GH.listInt)
|
||||
{
|
||||
const auto childPtr = child.get();
|
||||
if(const CIntObject * obj = dynamic_cast<const CIntObject *>(childPtr))
|
||||
printInfoAboutIntObject(obj, 0);
|
||||
else
|
||||
std::cout << typeid(childPtr).name() << std::endl;
|
||||
}
|
||||
}
|
||||
else if(cn=="tell")
|
||||
{
|
||||
std::string what;
|
||||
int id1, id2;
|
||||
readed >> what >> id1 >> id2;
|
||||
if(what == "hs")
|
||||
{
|
||||
for(const CGHeroInstance *h : LOCPLINT->cb->getHeroesInfo())
|
||||
if(h->type->ID.getNum() == id1)
|
||||
if(const CArtifactInstance *a = h->getArt(ArtifactPosition(id2)))
|
||||
std::cout << a->nodeName();
|
||||
}
|
||||
}
|
||||
else if (cn == "set")
|
||||
{
|
||||
std::string what, value;
|
||||
readed >> what;
|
||||
|
||||
Settings conf = settings.write["session"][what];
|
||||
|
||||
readed >> value;
|
||||
|
||||
if (value == "on")
|
||||
{
|
||||
conf->Bool() = true;
|
||||
logGlobal->info("Option %s enabled!", what);
|
||||
}
|
||||
else if (value == "off")
|
||||
{
|
||||
conf->Bool() = false;
|
||||
logGlobal->info("Option %s disabled!", what);
|
||||
}
|
||||
}
|
||||
else if(cn == "unlock")
|
||||
{
|
||||
std::string mxname;
|
||||
readed >> mxname;
|
||||
if(mxname == "pim" && LOCPLINT)
|
||||
LOCPLINT->pim->unlock();
|
||||
}
|
||||
else if(cn == "def2bmp")
|
||||
{
|
||||
std::string URI;
|
||||
readed >> URI;
|
||||
std::unique_ptr<CAnimation> anim = std::make_unique<CAnimation>(URI);
|
||||
anim->preload();
|
||||
anim->exportBitmaps(VCMIDirs::get().userExtractedPath());
|
||||
}
|
||||
else if(cn == "extract")
|
||||
{
|
||||
std::string URI;
|
||||
readed >> URI;
|
||||
|
||||
if (CResourceHandler::get()->existsResource(ResourceID(URI)))
|
||||
{
|
||||
const bfs::path outPath = VCMIDirs::get().userExtractedPath() / URI;
|
||||
|
||||
auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
|
||||
|
||||
bfs::create_directories(outPath.parent_path());
|
||||
bfs::ofstream outFile(outPath, bfs::ofstream::binary);
|
||||
outFile.write((char*)data.first.get(), data.second);
|
||||
}
|
||||
else
|
||||
logGlobal->error("File not found!");
|
||||
}
|
||||
else if(cn == "setBattleAI")
|
||||
{
|
||||
std::string fname;
|
||||
readed >> fname;
|
||||
std::cout << "Will try loading that AI to see if it is correct name...\n";
|
||||
try
|
||||
{
|
||||
if(auto ai = CDynLibHandler::getNewBattleAI(fname)) //test that given AI is indeed available... heavy but it is easy to make a typo and break the game
|
||||
{
|
||||
Settings neutralAI = settings.write["server"]["neutralAI"];
|
||||
neutralAI->String() = fname;
|
||||
std::cout << "Setting changed, from now the battle ai will be " << fname << "!\n";
|
||||
}
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
logGlobal->warn("Failed opening %s: %s", fname, e.what());
|
||||
logGlobal->warn("Setting not changes, AI not found or invalid!");
|
||||
}
|
||||
}
|
||||
|
||||
auto giveTurn = [&](PlayerColor player)
|
||||
{
|
||||
YourTurn yt;
|
||||
yt.player = player;
|
||||
yt.daysWithoutCastle = CSH->client->getPlayerState(player)->daysWithoutCastle;
|
||||
yt.applyCl(CSH->client);
|
||||
};
|
||||
|
||||
Settings session = settings.write["session"];
|
||||
if(cn == "autoskip")
|
||||
{
|
||||
session["autoSkip"].Bool() = !session["autoSkip"].Bool();
|
||||
}
|
||||
else if(cn == "gosolo")
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
|
||||
if(!CSH->client)
|
||||
{
|
||||
std::cout << "Game in not active";
|
||||
return;
|
||||
}
|
||||
PlayerColor color;
|
||||
if(session["aiSolo"].Bool())
|
||||
{
|
||||
for(auto & elem : CSH->client->gameState()->players)
|
||||
{
|
||||
if(elem.second.human)
|
||||
CSH->client->installNewPlayerInterface(std::make_shared<CPlayerInterface>(elem.first), elem.first);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
color = LOCPLINT->playerID;
|
||||
removeGUI();
|
||||
for(auto & elem : CSH->client->gameState()->players)
|
||||
{
|
||||
if(elem.second.human)
|
||||
{
|
||||
auto AiToGive = CSH->client->aiNameForPlayer(*CSH->client->getPlayerSettings(elem.first), false);
|
||||
logNetwork->info("Player %s will be lead by %s", elem.first, AiToGive);
|
||||
CSH->client->installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), elem.first);
|
||||
}
|
||||
}
|
||||
GH.totalRedraw();
|
||||
giveTurn(color);
|
||||
}
|
||||
session["aiSolo"].Bool() = !session["aiSolo"].Bool();
|
||||
}
|
||||
else if(cn == "controlai")
|
||||
{
|
||||
std::string colorName;
|
||||
readed >> colorName;
|
||||
boost::to_lower(colorName);
|
||||
|
||||
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
|
||||
if(!CSH->client)
|
||||
{
|
||||
std::cout << "Game in not active";
|
||||
return;
|
||||
}
|
||||
PlayerColor color;
|
||||
if(LOCPLINT)
|
||||
color = LOCPLINT->playerID;
|
||||
for(auto & elem : CSH->client->gameState()->players)
|
||||
{
|
||||
if(elem.second.human || (colorName.length() &&
|
||||
elem.first.getNum() != vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, colorName)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
removeGUI();
|
||||
CSH->client->installNewPlayerInterface(std::make_shared<CPlayerInterface>(elem.first), elem.first);
|
||||
}
|
||||
GH.totalRedraw();
|
||||
if(color != PlayerColor::NEUTRAL)
|
||||
giveTurn(color);
|
||||
}
|
||||
// Check mantis issue 2292 for details
|
||||
/* else if(client && client->serv && client->serv->connected && LOCPLINT) //send to server
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
|
||||
LOCPLINT->cb->sendMessage(message);
|
||||
}*/
|
||||
}
|
||||
#endif
|
||||
|
||||
//plays intro, ends when intro is over or button has been pressed (handles events)
|
||||
void playIntro()
|
||||
{
|
||||
|
@ -8,7 +8,11 @@
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
#include <SDL_render.h>
|
||||
|
||||
struct SDL_Texture;
|
||||
struct SDL_Window;
|
||||
struct SDL_Renderer;
|
||||
struct SDL_Surface;
|
||||
|
||||
extern SDL_Texture * screenTexture;
|
||||
|
||||
@ -19,5 +23,4 @@ extern SDL_Surface *screen; // main screen surface
|
||||
extern SDL_Surface *screen2; // and hlp surface (used to store not-active interfaces layer)
|
||||
extern SDL_Surface *screenBuf; // points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed
|
||||
|
||||
void removeGUI();
|
||||
void handleQuit(bool ask = true);
|
||||
|
@ -18,12 +18,11 @@ set(client_SRCS
|
||||
|
||||
gui/CAnimation.cpp
|
||||
gui/Canvas.cpp
|
||||
gui/CCursorHandler.cpp
|
||||
gui/CursorHandler.cpp
|
||||
gui/CGuiHandler.cpp
|
||||
gui/CIntObject.cpp
|
||||
gui/ColorFilter.cpp
|
||||
gui/Fonts.cpp
|
||||
gui/Geometries.cpp
|
||||
gui/SDL_Extensions.cpp
|
||||
gui/NotificationHandler.cpp
|
||||
gui/InterfaceObjectConfigurable.cpp
|
||||
@ -82,6 +81,7 @@ set(client_SRCS
|
||||
NetPacksClient.cpp
|
||||
NetPacksLobbyClient.cpp
|
||||
SDLRWwrapper.cpp
|
||||
ClientCommandManager.cpp
|
||||
)
|
||||
|
||||
set(client_HEADERS
|
||||
@ -104,12 +104,12 @@ set(client_HEADERS
|
||||
|
||||
gui/CAnimation.h
|
||||
gui/Canvas.h
|
||||
gui/CCursorHandler.h
|
||||
gui/CursorHandler.h
|
||||
gui/CGuiHandler.h
|
||||
gui/ColorFilter.h
|
||||
gui/CIntObject.h
|
||||
gui/Fonts.h
|
||||
gui/Geometries.h
|
||||
gui/TextAlignment.h
|
||||
gui/SDL_Compat.h
|
||||
gui/SDL_Extensions.h
|
||||
gui/SDL_Pixels.h
|
||||
@ -168,6 +168,7 @@ set(client_HEADERS
|
||||
mapHandler.h
|
||||
resource.h
|
||||
SDLRWwrapper.h
|
||||
ClientCommandManager.h
|
||||
)
|
||||
|
||||
if(APPLE_IOS)
|
||||
@ -232,7 +233,7 @@ if(WIN32)
|
||||
add_custom_command(TARGET vcmiclient POST_BUILD
|
||||
WORKING_DIRECTORY "$<TARGET_FILE_DIR:vcmiclient>"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy AI/fuzzylite.dll fuzzylite.dll
|
||||
COMMAND ${CMAKE_COMMAND} -E copy AI/tbb.dll tbb.dll
|
||||
COMMAND ${CMAKE_COMMAND} -E copy AI/tbb12.dll tbb12.dll
|
||||
)
|
||||
endif()
|
||||
elseif(APPLE_IOS)
|
||||
|
@ -102,9 +102,7 @@ SDL_Surface * CMessage::drawDialogBox(int w, int h, PlayerColor playerColor)
|
||||
{
|
||||
for (int j=0; j<h; j+=background->h)
|
||||
{
|
||||
Rect srcR(0,0,background->w, background->h);
|
||||
Rect dstR(i,j,w,h);
|
||||
CSDL_Ext::blitSurface(background, &srcR, ret, &dstR);
|
||||
CSDL_Ext::blitSurface(background, ret, Point(i,j));
|
||||
}
|
||||
}
|
||||
drawBorder(playerColor, ret, w, h);
|
||||
|
@ -10,7 +10,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Graphics.h"
|
||||
#include "gui/Geometries.h"
|
||||
|
||||
struct SDL_Surface;
|
||||
class CInfoWindow;
|
||||
|
@ -9,7 +9,7 @@
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include <SDL_mixer.h>
|
||||
#include <SDL.h>
|
||||
#include <SDL_timer.h>
|
||||
|
||||
#include "CMusicHandler.h"
|
||||
#include "CGameInfo.h"
|
||||
@ -20,7 +20,7 @@
|
||||
#include "../lib/StringConstants.h"
|
||||
#include "../lib/CRandomGenerator.h"
|
||||
#include "../lib/VCMIDirs.h"
|
||||
#include "../lib/Terrain.h"
|
||||
#include "../lib/TerrainHandler.h"
|
||||
|
||||
#define VCMI_SOUND_NAME(x)
|
||||
#define VCMI_SOUND_FILE(y) #y,
|
||||
@ -89,36 +89,6 @@ CSoundHandler::CSoundHandler():
|
||||
soundBase::battle02, soundBase::battle03, soundBase::battle04,
|
||||
soundBase::battle05, soundBase::battle06, soundBase::battle07
|
||||
};
|
||||
|
||||
//predefine terrain set
|
||||
//TODO: support custom sounds for new terrains and load from json
|
||||
horseSounds =
|
||||
{
|
||||
{Terrain::DIRT, soundBase::horseDirt},
|
||||
{Terrain::SAND, soundBase::horseSand},
|
||||
{Terrain::GRASS, soundBase::horseGrass},
|
||||
{Terrain::SNOW, soundBase::horseSnow},
|
||||
{Terrain::SWAMP, soundBase::horseSwamp},
|
||||
{Terrain::ROUGH, soundBase::horseRough},
|
||||
{Terrain::SUBTERRANEAN, soundBase::horseSubterranean},
|
||||
{Terrain::LAVA, soundBase::horseLava},
|
||||
{Terrain::WATER, soundBase::horseWater},
|
||||
{Terrain::ROCK, soundBase::horseRock}
|
||||
};
|
||||
}
|
||||
|
||||
void CSoundHandler::loadHorseSounds()
|
||||
{
|
||||
const auto & terrains = CGI->terrainTypeHandler->terrains();
|
||||
for(const auto & terrain : terrains)
|
||||
{
|
||||
//since all sounds are hardcoded, let's keep it
|
||||
if(vstd::contains(horseSounds, terrain.id))
|
||||
continue;
|
||||
|
||||
//Use already existing horse sound
|
||||
horseSounds[terrain.id] = horseSounds.at(terrains[terrain.id].horseSoundId);
|
||||
}
|
||||
}
|
||||
|
||||
void CSoundHandler::init()
|
||||
@ -368,9 +338,9 @@ CMusicHandler::CMusicHandler():
|
||||
|
||||
void CMusicHandler::loadTerrainMusicThemes()
|
||||
{
|
||||
for (const auto & terrain : CGI->terrainTypeHandler->terrains())
|
||||
for (const auto & terrain : CGI->terrainTypeHandler->objects)
|
||||
{
|
||||
addEntryToSet("terrain_" + terrain.name, "Music/" + terrain.musicFilename);
|
||||
addEntryToSet("terrain_" + terrain->getJsonKey(), "Music/" + terrain->musicFilename);
|
||||
}
|
||||
}
|
||||
|
||||
@ -399,6 +369,7 @@ void CMusicHandler::release()
|
||||
boost::mutex::scoped_lock guard(mutex);
|
||||
|
||||
Mix_HookMusicFinished(nullptr);
|
||||
current->stop();
|
||||
|
||||
current.reset();
|
||||
next.reset();
|
||||
@ -542,6 +513,20 @@ MusicEntry::MusicEntry(CMusicHandler *owner, std::string setName, std::string mu
|
||||
}
|
||||
MusicEntry::~MusicEntry()
|
||||
{
|
||||
if (playing)
|
||||
{
|
||||
assert(0);
|
||||
logGlobal->error("Attempt to delete music while playing!");
|
||||
Mix_HaltMusic();
|
||||
}
|
||||
|
||||
if (loop == 0 && Mix_FadingMusic() != MIX_NO_FADING)
|
||||
{
|
||||
assert(0);
|
||||
logGlobal->error("Attempt to delete music while fading out!");
|
||||
Mix_HaltMusic();
|
||||
}
|
||||
|
||||
logGlobal->trace("Del-ing music file %s", currentName);
|
||||
if (music)
|
||||
Mix_FreeMusic(music);
|
||||
@ -619,7 +604,7 @@ bool MusicEntry::play()
|
||||
|
||||
bool MusicEntry::stop(int fade_ms)
|
||||
{
|
||||
if (playing)
|
||||
if (Mix_PlayingMusic())
|
||||
{
|
||||
playing = false;
|
||||
loop = 0;
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "../lib/CSoundBase.h"
|
||||
#include "../lib/Terrain.h"
|
||||
|
||||
struct _Mix_Music;
|
||||
struct SDL_RWops;
|
||||
@ -61,7 +60,6 @@ public:
|
||||
CSoundHandler();
|
||||
|
||||
void init() override;
|
||||
void loadHorseSounds();
|
||||
void release() override;
|
||||
|
||||
void setVolume(ui32 percent) override;
|
||||
@ -84,7 +82,6 @@ public:
|
||||
// Sets
|
||||
std::vector<soundBase::soundID> pickupSounds;
|
||||
std::vector<soundBase::soundID> battleIntroSounds;
|
||||
std::map<TerrainId, soundBase::soundID> horseSounds;
|
||||
};
|
||||
|
||||
// Helper //now it looks somewhat useless
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "battle/BattleWindow.h"
|
||||
#include "../CCallback.h"
|
||||
#include "windows/CCastleInterface.h"
|
||||
#include "gui/CCursorHandler.h"
|
||||
#include "gui/CursorHandler.h"
|
||||
#include "windows/CKingdomInterface.h"
|
||||
#include "CGameInfo.h"
|
||||
#include "windows/CHeroWindow.h"
|
||||
@ -61,7 +61,9 @@
|
||||
#include "windows/InfoWindows.h"
|
||||
#include "../lib/UnlockGuard.h"
|
||||
#include "../lib/CPathfinder.h"
|
||||
#include <SDL.h>
|
||||
#include "../lib/RoadHandler.h"
|
||||
#include "../lib/TerrainHandler.h"
|
||||
#include <SDL_timer.h>
|
||||
#include "CServerHandler.h"
|
||||
// FIXME: only needed for CGameState::mutex
|
||||
#include "../lib/CGameState.h"
|
||||
@ -156,7 +158,6 @@ void CPlayerInterface::initGameInterface(std::shared_ptr<Environment> ENV, std::
|
||||
cb = CB;
|
||||
env = ENV;
|
||||
|
||||
CCS->soundh->loadHorseSounds();
|
||||
CCS->musich->loadTerrainMusicThemes();
|
||||
|
||||
initializeHeroTownList();
|
||||
@ -260,7 +261,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
|
||||
{
|
||||
updateAmbientSounds();
|
||||
//We may need to change music - select new track, music handler will change it if needed
|
||||
CCS->musich->playMusicFromSet("terrain", LOCPLINT->cb->getTile(hero->visitablePos())->terType->name, true, false);
|
||||
CCS->musich->playMusicFromSet("terrain", LOCPLINT->cb->getTile(hero->visitablePos())->terType->getJsonKey(), true, false);
|
||||
|
||||
if(details.result == TryMoveHero::TELEPORTATION)
|
||||
{
|
||||
@ -409,7 +410,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
|
||||
void CPlayerInterface::heroKilled(const CGHeroInstance* hero)
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
LOG_TRACE_PARAMS(logGlobal, "Hero %s killed handler for player %s", hero->name % playerID);
|
||||
LOG_TRACE_PARAMS(logGlobal, "Hero %s killed handler for player %s", hero->getNameTranslated() % playerID);
|
||||
|
||||
const CArmedInstance *newSelection = nullptr;
|
||||
if (makingTurn)
|
||||
@ -436,7 +437,7 @@ void CPlayerInterface::heroKilled(const CGHeroInstance* hero)
|
||||
adventureInt->select(newSelection, true);
|
||||
else if (adventureInt->selection == hero)
|
||||
adventureInt->selection = nullptr;
|
||||
|
||||
|
||||
if (vstd::contains(paths, hero))
|
||||
paths.erase(hero);
|
||||
}
|
||||
@ -1267,7 +1268,7 @@ template <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, c
|
||||
if (p.second.nodes.size())
|
||||
pathsMap[p.first] = p.second.endPos();
|
||||
else
|
||||
logGlobal->debug("%s has assigned an empty path! Ignoring it...", p.first->name);
|
||||
logGlobal->debug("%s has assigned an empty path! Ignoring it...", p.first->getNameTranslated());
|
||||
}
|
||||
h & pathsMap;
|
||||
}
|
||||
@ -1362,14 +1363,14 @@ void CPlayerInterface::showGarrisonDialog( const CArmedInstance *up, const CGHer
|
||||
*/
|
||||
void CPlayerInterface::showArtifactAssemblyDialog(const Artifact * artifact, const Artifact * assembledArtifact, CFunctionList<bool()> onYes)
|
||||
{
|
||||
std::string text = artifact->getDescription();
|
||||
std::string text = artifact->getDescriptionTranslated();
|
||||
text += "\n\n";
|
||||
std::vector<std::shared_ptr<CComponent>> scs;
|
||||
|
||||
if(assembledArtifact)
|
||||
{
|
||||
// You possess all of the components to...
|
||||
text += boost::str(boost::format(CGI->generaltexth->allTexts[732]) % assembledArtifact->getName());
|
||||
text += boost::str(boost::format(CGI->generaltexth->allTexts[732]) % assembledArtifact->getNameTranslated());
|
||||
|
||||
// Picture of assembled artifact at bottom.
|
||||
auto sc = std::make_shared<CComponent>(CComponent::artifact, assembledArtifact->getIndex(), 0);
|
||||
@ -1623,7 +1624,7 @@ int CPlayerInterface::getLastIndex( std::string namePrefix)
|
||||
else
|
||||
for (directory_iterator dir(gamesDir); dir != enddir; ++dir)
|
||||
{
|
||||
if (is_regular(dir->status()))
|
||||
if (is_regular_file(dir->status()))
|
||||
{
|
||||
std::string name = dir->path().filename().string();
|
||||
if (starts_with(name, namePrefix) && ends_with(name, ".vcgm1"))
|
||||
@ -2372,8 +2373,9 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
|
||||
for (auto & elem : path.nodes)
|
||||
elem.coord = h->convertFromVisitablePos(elem.coord);
|
||||
|
||||
TerrainId currentTerrain = Terrain::BORDER; // not init yet
|
||||
TerrainId currentTerrain = ETerrainId::NONE;
|
||||
TerrainId newTerrain;
|
||||
bool wasOnRoad = true;
|
||||
int sh = -1;
|
||||
|
||||
auto canStop = [&](CGPathNode * node) -> bool
|
||||
@ -2389,13 +2391,18 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
|
||||
|
||||
for (i=(int)path.nodes.size()-1; i>0 && (stillMoveHero.data == CONTINUE_MOVE || !canStop(&path.nodes[i])); i--)
|
||||
{
|
||||
int3 currentCoord = path.nodes[i].coord;
|
||||
int3 prevCoord = path.nodes[i].coord;
|
||||
int3 nextCoord = path.nodes[i-1].coord;
|
||||
|
||||
auto currentObject = getObj(currentCoord, currentCoord == h->pos);
|
||||
auto prevRoad = cb->getTile(h->convertToVisitablePos(prevCoord))->roadType;
|
||||
auto nextRoad = cb->getTile(h->convertToVisitablePos(nextCoord))->roadType;
|
||||
|
||||
bool movingOnRoad = prevRoad->getId() != Road::NO_ROAD && nextRoad->getId() != Road::NO_ROAD;
|
||||
|
||||
auto prevObject = getObj(prevCoord, prevCoord == h->pos);
|
||||
auto nextObjectTop = getObj(nextCoord, false);
|
||||
auto nextObject = getObj(nextCoord, true);
|
||||
auto destTeleportObj = getDestTeleportObj(currentObject, nextObjectTop, nextObject);
|
||||
auto destTeleportObj = getDestTeleportObj(prevObject, nextObjectTop, nextObject);
|
||||
if (isTeleportAction(path.nodes[i-1].action) && destTeleportObj != nullptr)
|
||||
{
|
||||
CCS->soundh->stopSound(sh);
|
||||
@ -2410,7 +2417,10 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
|
||||
}
|
||||
if(i != path.nodes.size() - 1)
|
||||
{
|
||||
sh = CCS->soundh->playSound(CCS->soundh->horseSounds[currentTerrain], -1);
|
||||
if (movingOnRoad)
|
||||
sh = CCS->soundh->playSound(VLC->terrainTypeHandler->getById(currentTerrain)->horseSound, -1);
|
||||
else
|
||||
sh = CCS->soundh->playSound(VLC->terrainTypeHandler->getById(currentTerrain)->horseSoundPenalty, -1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@ -2428,12 +2438,16 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
|
||||
sh = CCS->soundh->playSound(soundBase::horseFlying, -1);
|
||||
#endif
|
||||
{
|
||||
newTerrain = cb->getTile(h->convertToVisitablePos(currentCoord))->terType->id;
|
||||
if(newTerrain != currentTerrain)
|
||||
newTerrain = cb->getTile(h->convertToVisitablePos(prevCoord))->terType->getId();
|
||||
if(newTerrain != currentTerrain || wasOnRoad != movingOnRoad)
|
||||
{
|
||||
CCS->soundh->stopSound(sh);
|
||||
sh = CCS->soundh->playSound(CCS->soundh->horseSounds[newTerrain], -1);
|
||||
if (movingOnRoad)
|
||||
sh = CCS->soundh->playSound(VLC->terrainTypeHandler->getById(newTerrain)->horseSound, -1);
|
||||
else
|
||||
sh = CCS->soundh->playSound(VLC->terrainTypeHandler->getById(newTerrain)->horseSoundPenalty, -1);
|
||||
currentTerrain = newTerrain;
|
||||
wasOnRoad = movingOnRoad;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2473,6 +2487,9 @@ void CPlayerInterface::doMoveHero(const CGHeroInstance * h, CGPath path)
|
||||
// (i == 0) means hero went through all the path
|
||||
adventureInt->updateMoveHero(h, (i != 0));
|
||||
adventureInt->updateNextHero(h);
|
||||
|
||||
// ugly workaround to force instant update of adventure map
|
||||
adventureInt->animValHitCount = 8;
|
||||
}
|
||||
|
||||
setMovementStatus(false);
|
||||
|
@ -8,7 +8,6 @@
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include <SDL.h>
|
||||
#include "CVideoHandler.h"
|
||||
|
||||
#include "gui/CGuiHandler.h"
|
||||
@ -67,8 +66,8 @@ CVideoPlayer::CVideoPlayer()
|
||||
context = nullptr;
|
||||
texture = nullptr;
|
||||
dest = nullptr;
|
||||
destRect = genRect(0,0,0,0);
|
||||
pos = genRect(0,0,0,0);
|
||||
destRect = CSDL_Ext::genRect(0,0,0,0);
|
||||
pos = CSDL_Ext::genRect(0,0,0,0);
|
||||
refreshWait = 0;
|
||||
refreshCount = 0;
|
||||
doLoop = false;
|
||||
@ -339,10 +338,10 @@ void CVideoPlayer::show( int x, int y, SDL_Surface *dst, bool update )
|
||||
|
||||
pos.x = x;
|
||||
pos.y = y;
|
||||
CSDL_Ext::blitSurface(dest, &destRect, dst, &pos);
|
||||
CSDL_Ext::blitSurface(dest, destRect, dst, pos.topLeft());
|
||||
|
||||
if (update)
|
||||
SDL_UpdateRect(dst, pos.x, pos.y, pos.w, pos.h);
|
||||
CSDL_Ext::updateRect(dst, pos);
|
||||
}
|
||||
|
||||
void CVideoPlayer::redraw( int x, int y, SDL_Surface *dst, bool update )
|
||||
@ -442,7 +441,9 @@ bool CVideoPlayer::playVideo(int x, int y, bool stopOnKey)
|
||||
if(stopOnKey && keyDown())
|
||||
return false;
|
||||
|
||||
SDL_RenderCopy(mainRenderer, texture, nullptr, &pos);
|
||||
SDL_Rect rect = CSDL_Ext::toSDL(pos);
|
||||
|
||||
SDL_RenderCopy(mainRenderer, texture, nullptr, &rect);
|
||||
SDL_RenderPresent(mainRenderer);
|
||||
|
||||
// Wait 3 frames
|
||||
|
@ -9,8 +9,10 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
struct SDL_Surface;
|
||||
#include "../lib/Rect.h"
|
||||
|
||||
struct SDL_Surface;
|
||||
struct SDL_Texture;
|
||||
|
||||
class IVideoPlayer
|
||||
{
|
||||
@ -54,9 +56,6 @@ public:
|
||||
|
||||
#include "../lib/filesystem/CInputStream.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_video.h>
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
@ -106,8 +105,8 @@ class CVideoPlayer : public IMainVideoPlayer
|
||||
|
||||
SDL_Texture *texture;
|
||||
SDL_Surface *dest;
|
||||
SDL_Rect destRect; // valid when dest is used
|
||||
SDL_Rect pos; // destination on screen
|
||||
Rect destRect; // valid when dest is used
|
||||
Rect pos; // destination on screen
|
||||
|
||||
int refreshWait; // Wait several refresh before updating the image
|
||||
int refreshCount;
|
||||
|
@ -10,8 +10,6 @@
|
||||
#include "StdInc.h"
|
||||
#include "Client.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "CMusicHandler.h"
|
||||
#include "../lib/mapping/CCampaignHandler.h"
|
||||
#include "../CCallback.h"
|
||||
@ -46,9 +44,9 @@
|
||||
#include "../lib/CThreadHelper.h"
|
||||
#include "../lib/registerTypes/RegisterTypes.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "CMT.h"
|
||||
#include "CServerHandler.h"
|
||||
#include "../lib/ScriptHandler.h"
|
||||
#include "windows/CAdvmapInterface.h"
|
||||
#include <vcmi/events/EventBus.h>
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
@ -761,8 +759,29 @@ void CClient::reinitScripting()
|
||||
#endif
|
||||
}
|
||||
|
||||
void CClient::removeGUI()
|
||||
{
|
||||
// CClient::endGame
|
||||
GH.curInt = nullptr;
|
||||
if(GH.topInt())
|
||||
GH.topInt()->deactivate();
|
||||
adventureInt.reset();
|
||||
GH.listInt.clear();
|
||||
GH.objsToBlit.clear();
|
||||
GH.statusbar.reset();
|
||||
logGlobal->info("Removed GUI.");
|
||||
|
||||
LOCPLINT = nullptr;
|
||||
}
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_clientSetupJNI(JNIEnv * env, jobject cls)
|
||||
{
|
||||
logNetwork->info("Received clientSetupJNI");
|
||||
|
||||
CAndroidVMHelper::cacheVM(env);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerClosed(JNIEnv * env, jobject cls)
|
||||
{
|
||||
logNetwork->info("Received server closed signal");
|
||||
|
@ -240,6 +240,7 @@ public:
|
||||
|
||||
void showInfoDialog(InfoWindow * iw) override {};
|
||||
void showInfoDialog(const std::string & msg, PlayerColor player) override {};
|
||||
void removeGUI();
|
||||
|
||||
#if SCRIPTING_ENABLED
|
||||
scripting::Pool * getGlobalContextPool() const override;
|
||||
|
494
client/ClientCommandManager.cpp
Normal file
494
client/ClientCommandManager.cpp
Normal file
@ -0,0 +1,494 @@
|
||||
/*
|
||||
* ClientCommandManager.cpp, 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
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
|
||||
#include "ClientCommandManager.h"
|
||||
|
||||
#include "Client.h"
|
||||
#include "CPlayerInterface.h"
|
||||
#include "CServerHandler.h"
|
||||
#include "gui/CGuiHandler.h"
|
||||
#include "../lib/NetPacks.h"
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "../lib/CGameState.h"
|
||||
#include "../lib/CPlayerState.h"
|
||||
#include "../lib/StringConstants.h"
|
||||
#include "gui/CAnimation.h"
|
||||
#include "windows/CAdvmapInterface.h"
|
||||
#include "windows/CCastleInterface.h"
|
||||
#include "../CCallback.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
#include "../lib/CModHandler.h"
|
||||
#include "../lib/VCMIDirs.h"
|
||||
|
||||
#ifdef SCRIPTING_ENABLED
|
||||
#include "../lib/ScriptHandler.h"
|
||||
#endif
|
||||
|
||||
void ClientCommandManager::handleGoSolo()
|
||||
{
|
||||
Settings session = settings.write["session"];
|
||||
|
||||
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
|
||||
if(!CSH->client)
|
||||
{
|
||||
printCommandMessage("Game is not in playing state");
|
||||
return;
|
||||
}
|
||||
PlayerColor color;
|
||||
if(session["aiSolo"].Bool())
|
||||
{
|
||||
for(auto & elem : CSH->client->gameState()->players)
|
||||
{
|
||||
if(elem.second.human)
|
||||
CSH->client->installNewPlayerInterface(std::make_shared<CPlayerInterface>(elem.first), elem.first);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
color = LOCPLINT->playerID;
|
||||
CSH->client->removeGUI();
|
||||
for(auto & elem : CSH->client->gameState()->players)
|
||||
{
|
||||
if(elem.second.human)
|
||||
{
|
||||
auto AiToGive = CSH->client->aiNameForPlayer(*CSH->client->getPlayerSettings(elem.first), false);
|
||||
printCommandMessage("Player " + elem.first.getStr() + " will be lead by " + AiToGive, ELogLevel::INFO);
|
||||
CSH->client->installNewPlayerInterface(CDynLibHandler::getNewAI(AiToGive), elem.first);
|
||||
}
|
||||
}
|
||||
GH.totalRedraw();
|
||||
giveTurn(color);
|
||||
}
|
||||
session["aiSolo"].Bool() = !session["aiSolo"].Bool();
|
||||
}
|
||||
|
||||
void ClientCommandManager::handleControlAi(const std::string &colorName)
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
|
||||
if(!CSH->client)
|
||||
{
|
||||
printCommandMessage("Game is not in playing state");
|
||||
return;
|
||||
}
|
||||
PlayerColor color;
|
||||
if(LOCPLINT)
|
||||
color = LOCPLINT->playerID;
|
||||
for(auto & elem : CSH->client->gameState()->players)
|
||||
{
|
||||
if(elem.second.human || (colorName.length() &&
|
||||
elem.first.getNum() != vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, colorName)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CSH->client->removeGUI();
|
||||
CSH->client->installNewPlayerInterface(std::make_shared<CPlayerInterface>(elem.first), elem.first);
|
||||
}
|
||||
GH.totalRedraw();
|
||||
if(color != PlayerColor::NEUTRAL)
|
||||
giveTurn(color);
|
||||
}
|
||||
|
||||
void ClientCommandManager::processCommand(const std::string &message, bool calledFromIngameConsole)
|
||||
{
|
||||
std::istringstream singleWordBuffer;
|
||||
singleWordBuffer.str(message);
|
||||
std::string commandName;
|
||||
singleWordBuffer >> commandName;
|
||||
currentCallFromIngameConsole = calledFromIngameConsole;
|
||||
|
||||
if(message==std::string("die, fool"))
|
||||
{
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
else if(commandName == std::string("activate"))
|
||||
{
|
||||
int what;
|
||||
singleWordBuffer >> what;
|
||||
switch (what)
|
||||
{
|
||||
case 0:
|
||||
GH.topInt()->activate();
|
||||
break;
|
||||
case 1:
|
||||
adventureInt->activate();
|
||||
break;
|
||||
case 2:
|
||||
LOCPLINT->castleInt->activate();
|
||||
break;
|
||||
default:
|
||||
printCommandMessage("Wrong argument specified!", ELogLevel::ERROR);
|
||||
}
|
||||
}
|
||||
else if(commandName == "redraw")
|
||||
{
|
||||
GH.totalRedraw();
|
||||
}
|
||||
else if(commandName == "screen")
|
||||
{
|
||||
printCommandMessage("Screenbuf points to ");
|
||||
|
||||
if(screenBuf == screen)
|
||||
printCommandMessage("screen", ELogLevel::ERROR);
|
||||
else if(screenBuf == screen2)
|
||||
printCommandMessage("screen2", ELogLevel::ERROR);
|
||||
else
|
||||
printCommandMessage("?!?", ELogLevel::ERROR);
|
||||
|
||||
SDL_SaveBMP(screen, "Screen_c.bmp");
|
||||
SDL_SaveBMP(screen2, "Screen2_c.bmp");
|
||||
}
|
||||
else if(commandName == "save")
|
||||
{
|
||||
if(!CSH->client)
|
||||
{
|
||||
printCommandMessage("Game is not in playing state");
|
||||
return;
|
||||
}
|
||||
std::string fname;
|
||||
singleWordBuffer >> fname;
|
||||
CSH->client->save(fname);
|
||||
}
|
||||
// else if(commandName=="load")
|
||||
// {
|
||||
// // TODO: this code should end the running game and manage to call startGame instead
|
||||
// std::string fname;
|
||||
// singleWordBuffer >> fname;
|
||||
// CSH->client->loadGame(fname);
|
||||
// }
|
||||
else if(message=="convert txt")
|
||||
{
|
||||
VLC->generaltexth->dumpAllTexts();
|
||||
}
|
||||
else if(message=="get config")
|
||||
{
|
||||
printCommandMessage("Command accepted.\t");
|
||||
|
||||
const boost::filesystem::path outPath =
|
||||
VCMIDirs::get().userExtractedPath() / "configuration";
|
||||
|
||||
boost::filesystem::create_directories(outPath);
|
||||
|
||||
const std::vector<std::string> contentNames = {"heroClasses", "artifacts", "creatures", "factions", "objects", "heroes", "spells", "skills"};
|
||||
|
||||
for(auto contentName : contentNames)
|
||||
{
|
||||
auto & content = (*VLC->modh->content)[contentName];
|
||||
|
||||
auto contentOutPath = outPath / contentName;
|
||||
boost::filesystem::create_directories(contentOutPath);
|
||||
|
||||
for(auto & iter : content.modData)
|
||||
{
|
||||
const JsonNode & modData = iter.second.modData;
|
||||
|
||||
for(auto & nameAndObject : modData.Struct())
|
||||
{
|
||||
const JsonNode & object = nameAndObject.second;
|
||||
|
||||
std::string name = CModHandler::makeFullIdentifier(object.meta, contentName, nameAndObject.first);
|
||||
|
||||
boost::algorithm::replace_all(name,":","_");
|
||||
|
||||
const boost::filesystem::path filePath = contentOutPath / (name + ".json");
|
||||
boost::filesystem::ofstream file(filePath);
|
||||
file << object.toJson();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printCommandMessage("\rExtracting done :)\n");
|
||||
printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
|
||||
}
|
||||
#if SCRIPTING_ENABLED
|
||||
else if(message=="get scripts")
|
||||
{
|
||||
printCommandMessage("Command accepted.\t");
|
||||
|
||||
const boost::filesystem::path outPath =
|
||||
VCMIDirs::get().userExtractedPath() / "scripts";
|
||||
|
||||
boost::filesystem::create_directories(outPath);
|
||||
|
||||
for(auto & kv : VLC->scriptHandler->objects)
|
||||
{
|
||||
std::string name = kv.first;
|
||||
boost::algorithm::replace_all(name,":","_");
|
||||
|
||||
const scripting::ScriptImpl * script = kv.second.get();
|
||||
boost::filesystem::path filePath = outPath / (name + ".lua");
|
||||
boost::filesystem::ofstream file(filePath);
|
||||
file << script->getSource();
|
||||
}
|
||||
printCommandMessage("\rExtracting done :)\n");
|
||||
printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
|
||||
}
|
||||
#endif
|
||||
else if(message=="get txt")
|
||||
{
|
||||
printCommandMessage("Command accepted.\t");
|
||||
|
||||
const boost::filesystem::path outPath =
|
||||
VCMIDirs::get().userExtractedPath();
|
||||
|
||||
auto list =
|
||||
CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident)
|
||||
{
|
||||
return ident.getType() == EResType::TEXT && boost::algorithm::starts_with(ident.getName(), "DATA/");
|
||||
});
|
||||
|
||||
for (auto & filename : list)
|
||||
{
|
||||
const boost::filesystem::path filePath = outPath / (filename.getName() + ".TXT");
|
||||
|
||||
boost::filesystem::create_directories(filePath.parent_path());
|
||||
|
||||
boost::filesystem::ofstream file(filePath);
|
||||
auto text = CResourceHandler::get()->load(filename)->readAll();
|
||||
|
||||
file.write((char*)text.first.get(), text.second);
|
||||
}
|
||||
|
||||
printCommandMessage("\rExtracting done :)\n");
|
||||
printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
|
||||
}
|
||||
else if(commandName == "crash")
|
||||
{
|
||||
int *ptr = nullptr;
|
||||
*ptr = 666;
|
||||
//disaster!
|
||||
}
|
||||
else if(commandName == "mp" && adventureInt)
|
||||
{
|
||||
if(const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(adventureInt->selection))
|
||||
printCommandMessage(std::to_string(h->movement) + "; max: " + std::to_string(h->maxMovePoints(true)) + "/" + std::to_string(h->maxMovePoints(false)) + "\n");
|
||||
}
|
||||
else if(commandName == "bonuses")
|
||||
{
|
||||
bool jsonFormat = (message == "bonuses json");
|
||||
auto format = [jsonFormat](const BonusList & b) -> std::string
|
||||
{
|
||||
if(jsonFormat)
|
||||
return b.toJsonNode().toJson(true);
|
||||
std::ostringstream ss;
|
||||
ss << b;
|
||||
return ss.str();
|
||||
};
|
||||
printCommandMessage("Bonuses of " + adventureInt->selection->getObjectName() + "\n");
|
||||
printCommandMessage(format(adventureInt->selection->getBonusList()) + "\n");
|
||||
|
||||
printCommandMessage("\nInherited bonuses:\n");
|
||||
TCNodes parents;
|
||||
adventureInt->selection->getParents(parents);
|
||||
for(const CBonusSystemNode *parent : parents)
|
||||
{
|
||||
printCommandMessage(std::string("\nBonuses from ") + typeid(*parent).name() + "\n" + format(*parent->getAllBonuses(Selector::all, Selector::all)) + "\n");
|
||||
}
|
||||
}
|
||||
else if(commandName == "not dialog")
|
||||
{
|
||||
LOCPLINT->showingDialog->setn(false);
|
||||
}
|
||||
else if(commandName == "gui")
|
||||
{
|
||||
for(auto & child : GH.listInt)
|
||||
{
|
||||
const auto childPtr = child.get();
|
||||
if(const CIntObject * obj = dynamic_cast<const CIntObject *>(childPtr))
|
||||
printInfoAboutInterfaceObject(obj, 0);
|
||||
else
|
||||
printCommandMessage(std::string(typeid(childPtr).name()) + "\n");
|
||||
}
|
||||
}
|
||||
else if(commandName == "tell")
|
||||
{
|
||||
std::string what;
|
||||
int id1, id2;
|
||||
singleWordBuffer >> what >> id1 >> id2;
|
||||
if(what == "hs")
|
||||
{
|
||||
for(const CGHeroInstance *h : LOCPLINT->cb->getHeroesInfo())
|
||||
if(h->type->getIndex() == id1)
|
||||
if(const CArtifactInstance *a = h->getArt(ArtifactPosition(id2)))
|
||||
printCommandMessage(a->nodeName());
|
||||
}
|
||||
}
|
||||
else if (commandName == "set")
|
||||
{
|
||||
std::string what, value;
|
||||
singleWordBuffer >> what;
|
||||
|
||||
Settings config = settings.write["session"][what];
|
||||
|
||||
singleWordBuffer >> value;
|
||||
|
||||
if (value == "on")
|
||||
{
|
||||
config->Bool() = true;
|
||||
printCommandMessage("Option " + what + " enabled!", ELogLevel::INFO);
|
||||
}
|
||||
else if (value == "off")
|
||||
{
|
||||
config->Bool() = false;
|
||||
printCommandMessage("Option " + what + " disabled!", ELogLevel::INFO);
|
||||
}
|
||||
}
|
||||
else if(commandName == "unlock")
|
||||
{
|
||||
std::string mxname;
|
||||
singleWordBuffer >> mxname;
|
||||
if(mxname == "pim" && LOCPLINT)
|
||||
LOCPLINT->pim->unlock();
|
||||
}
|
||||
else if(commandName == "def2bmp")
|
||||
{
|
||||
std::string URI;
|
||||
singleWordBuffer >> URI;
|
||||
std::unique_ptr<CAnimation> anim = std::make_unique<CAnimation>(URI);
|
||||
anim->preload();
|
||||
anim->exportBitmaps(VCMIDirs::get().userExtractedPath());
|
||||
}
|
||||
else if(commandName == "extract")
|
||||
{
|
||||
std::string URI;
|
||||
singleWordBuffer >> URI;
|
||||
|
||||
if (CResourceHandler::get()->existsResource(ResourceID(URI)))
|
||||
{
|
||||
const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / URI;
|
||||
|
||||
auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
|
||||
|
||||
boost::filesystem::create_directories(outPath.parent_path());
|
||||
boost::filesystem::ofstream outFile(outPath, boost::filesystem::ofstream::binary);
|
||||
outFile.write((char*)data.first.get(), data.second);
|
||||
}
|
||||
else
|
||||
printCommandMessage("File not found!", ELogLevel::ERROR);
|
||||
}
|
||||
else if(commandName == "setBattleAI")
|
||||
{
|
||||
std::string fname;
|
||||
singleWordBuffer >> fname;
|
||||
printCommandMessage("Will try loading that AI to see if it is correct name...\n");
|
||||
try
|
||||
{
|
||||
if(auto ai = CDynLibHandler::getNewBattleAI(fname)) //test that given AI is indeed available... heavy but it is easy to make a typo and break the game
|
||||
{
|
||||
Settings neutralAI = settings.write["server"]["neutralAI"];
|
||||
neutralAI->String() = fname;
|
||||
printCommandMessage("Setting changed, from now the battle ai will be " + fname + "!\n");
|
||||
}
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
printCommandMessage("Failed opening " + fname + ": " + e.what(), ELogLevel::WARN);
|
||||
printCommandMessage("Setting not changed, AI not found or invalid!", ELogLevel::WARN);
|
||||
}
|
||||
}
|
||||
else if(commandName == "autoskip")
|
||||
{
|
||||
Settings session = settings.write["session"];
|
||||
session["autoSkip"].Bool() = !session["autoSkip"].Bool();
|
||||
}
|
||||
else if(commandName == "gosolo")
|
||||
{
|
||||
ClientCommandManager::handleGoSolo();
|
||||
}
|
||||
else if(commandName == "controlai")
|
||||
{
|
||||
std::string colorName;
|
||||
singleWordBuffer >> colorName;
|
||||
boost::to_lower(colorName);
|
||||
|
||||
ClientCommandManager::handleControlAi(colorName);
|
||||
}
|
||||
else
|
||||
{
|
||||
printCommandMessage("Command not found :(", ELogLevel::ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientCommandManager::giveTurn(const PlayerColor &colorIdentifier)
|
||||
{
|
||||
YourTurn yt;
|
||||
yt.player = colorIdentifier;
|
||||
yt.daysWithoutCastle = CSH->client->getPlayerState(colorIdentifier)->daysWithoutCastle;
|
||||
yt.applyCl(CSH->client);
|
||||
}
|
||||
|
||||
void ClientCommandManager::printInfoAboutInterfaceObject(const CIntObject *obj, int level)
|
||||
{
|
||||
std::stringstream sbuffer;
|
||||
sbuffer << std::string(level, '\t');
|
||||
|
||||
sbuffer << typeid(*obj).name() << " *** ";
|
||||
if (obj->active)
|
||||
{
|
||||
#define PRINT(check, text) if (obj->active & CIntObject::check) sbuffer << text
|
||||
PRINT(LCLICK, 'L');
|
||||
PRINT(RCLICK, 'R');
|
||||
PRINT(HOVER, 'H');
|
||||
PRINT(MOVE, 'M');
|
||||
PRINT(KEYBOARD, 'K');
|
||||
PRINT(TIME, 'T');
|
||||
PRINT(GENERAL, 'A');
|
||||
PRINT(WHEEL, 'W');
|
||||
PRINT(DOUBLECLICK, 'D');
|
||||
#undef PRINT
|
||||
}
|
||||
else
|
||||
sbuffer << "inactive";
|
||||
sbuffer << " at " << obj->pos.x <<"x"<< obj->pos.y;
|
||||
sbuffer << " (" << obj->pos.w <<"x"<< obj->pos.h << ")";
|
||||
printCommandMessage(sbuffer.str(), ELogLevel::INFO);
|
||||
|
||||
for(const CIntObject *child : obj->children)
|
||||
printInfoAboutInterfaceObject(child, level+1);
|
||||
}
|
||||
|
||||
void ClientCommandManager::printCommandMessage(const std::string &commandMessage, ELogLevel::ELogLevel messageType)
|
||||
{
|
||||
switch(messageType)
|
||||
{
|
||||
case ELogLevel::NOT_SET:
|
||||
std::cout << commandMessage;
|
||||
break;
|
||||
case ELogLevel::TRACE:
|
||||
logGlobal->trace(commandMessage);
|
||||
break;
|
||||
case ELogLevel::DEBUG:
|
||||
logGlobal->debug(commandMessage);
|
||||
break;
|
||||
case ELogLevel::INFO:
|
||||
logGlobal->info(commandMessage);
|
||||
break;
|
||||
case ELogLevel::WARN:
|
||||
logGlobal->warn(commandMessage);
|
||||
break;
|
||||
case ELogLevel::ERROR:
|
||||
logGlobal->error(commandMessage);
|
||||
break;
|
||||
default:
|
||||
std::cout << commandMessage;
|
||||
break;
|
||||
}
|
||||
|
||||
if(currentCallFromIngameConsole)
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
|
||||
if(LOCPLINT && LOCPLINT->cingconsole)
|
||||
{
|
||||
LOCPLINT->cingconsole->print(commandMessage);
|
||||
}
|
||||
}
|
||||
}
|
31
client/ClientCommandManager.h
Normal file
31
client/ClientCommandManager.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* ClientCommandManager.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
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class PlayerColor;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
class CIntObject;
|
||||
|
||||
class ClientCommandManager //take mantis #2292 issue about account if thinking about handling cheats from command-line
|
||||
{
|
||||
bool currentCallFromIngameConsole;
|
||||
|
||||
void giveTurn(const PlayerColor &color);
|
||||
void printInfoAboutInterfaceObject(const CIntObject *obj, int level);
|
||||
void printCommandMessage(const std::string &commandMessage, ELogLevel::ELogLevel messageType = ELogLevel::NOT_SET);
|
||||
void handleGoSolo();
|
||||
void handleControlAi(const std::string &colorName);
|
||||
|
||||
public:
|
||||
ClientCommandManager() = default;
|
||||
void processCommand(const std::string &message, bool calledFromIngameConsole);
|
||||
};
|
@ -286,7 +286,7 @@ void Graphics::blueToPlayersAdv(SDL_Surface * sur, PlayerColor player)
|
||||
//FIXME: not all player colored images have player palette at last 32 indexes
|
||||
//NOTE: following code is much more correct but still not perfect (bugged with status bar)
|
||||
|
||||
SDL_SetColors(sur, palette, 224, 32);
|
||||
CSDL_Ext::setColors(sur, palette, 224, 32);
|
||||
|
||||
|
||||
#if 0
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#include "gui/Fonts.h"
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "gui/Geometries.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -63,7 +63,7 @@ void LobbyClientDisconnected::applyOnLobbyScreen(CLobbyScreen * lobby, CServerHa
|
||||
|
||||
void LobbyChatMessage::applyOnLobbyScreen(CLobbyScreen * lobby, CServerHandler * handler)
|
||||
{
|
||||
if(lobby)
|
||||
if(lobby && lobby->card)
|
||||
{
|
||||
lobby->card->chat->addNewMessage(playerName + ": " + message);
|
||||
lobby->card->setChat(true);
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../gui/CCursorHandler.h"
|
||||
#include "../gui/CursorHandler.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/CIntObject.h"
|
||||
#include "../windows/CCreatureWindow.h"
|
||||
@ -460,28 +460,31 @@ void BattleActionsController::handleHex(BattleHex myNumber, int eventType)
|
||||
}
|
||||
};
|
||||
|
||||
TDmgRange damage = owner.curInt->cb->battleEstimateDamage(owner.stacksController->getActiveStack(), shere);
|
||||
BattleHex attackFromHex = owner.fieldController->fromWhichHexAttack(myNumber);
|
||||
TDmgRange damage = owner.curInt->cb->battleEstimateDamage(owner.stacksController->getActiveStack(), shere, attackFromHex);
|
||||
std::string estDmgText = formatDmgRange(std::make_pair((ui32)damage.first, (ui32)damage.second)); //calculating estimated dmg
|
||||
newConsoleMsg = (boost::format(CGI->generaltexth->allTexts[36]) % shere->getName() % estDmgText).str(); //Attack %s (%s damage)
|
||||
}
|
||||
break;
|
||||
case PossiblePlayerBattleAction::SHOOT:
|
||||
{
|
||||
if (owner.curInt->cb->battleHasShootingPenalty(owner.stacksController->getActiveStack(), myNumber))
|
||||
auto const * shooter = owner.stacksController->getActiveStack();
|
||||
|
||||
if (owner.curInt->cb->battleHasShootingPenalty(shooter, myNumber))
|
||||
cursorFrame = Cursor::Combat::SHOOT_PENALTY;
|
||||
else
|
||||
cursorFrame = Cursor::Combat::SHOOT;
|
||||
|
||||
realizeAction = [=](){owner.giveCommand(EActionType::SHOOT, myNumber);};
|
||||
TDmgRange damage = owner.curInt->cb->battleEstimateDamage(owner.stacksController->getActiveStack(), shere);
|
||||
TDmgRange damage = owner.curInt->cb->battleEstimateDamage(shooter, shere, shooter->getPosition());
|
||||
std::string estDmgText = formatDmgRange(std::make_pair((ui32)damage.first, (ui32)damage.second)); //calculating estimated dmg
|
||||
//printing - Shoot %s (%d shots left, %s damage)
|
||||
newConsoleMsg = (boost::format(CGI->generaltexth->allTexts[296]) % shere->getName() % owner.stacksController->getActiveStack()->shots.available() % estDmgText).str();
|
||||
newConsoleMsg = (boost::format(CGI->generaltexth->allTexts[296]) % shere->getName() % shooter->shots.available() % estDmgText).str();
|
||||
}
|
||||
break;
|
||||
case PossiblePlayerBattleAction::AIMED_SPELL_CREATURE:
|
||||
currentSpell = CGI->spellh->objects[creatureCasting ? owner.stacksController->activeStackSpellToCast() : spellToCast->actionSubtype]; //necessary if creature has random Genie spell at same time
|
||||
newConsoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[27]) % currentSpell->name % shere->getName()); //Cast %s on %s
|
||||
newConsoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[27]) % currentSpell->getNameTranslated() % shere->getName()); //Cast %s on %s
|
||||
switch (currentSpell->id)
|
||||
{
|
||||
case SpellID::SACRIFICE:
|
||||
@ -494,7 +497,7 @@ void BattleActionsController::handleHex(BattleHex myNumber, int eventType)
|
||||
break;
|
||||
case PossiblePlayerBattleAction::ANY_LOCATION:
|
||||
currentSpell = CGI->spellh->objects[creatureCasting ? owner.stacksController->activeStackSpellToCast() : spellToCast->actionSubtype]; //necessary if creature has random Genie spell at same time
|
||||
newConsoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[26]) % currentSpell->name); //Cast %s
|
||||
newConsoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[26]) % currentSpell->getNameTranslated()); //Cast %s
|
||||
isCastingPossible = true;
|
||||
break;
|
||||
case PossiblePlayerBattleAction::RANDOM_GENIE_SPELL: //we assume that teleport / sacrifice will never be available as random spell
|
||||
@ -519,7 +522,7 @@ void BattleActionsController::handleHex(BattleHex myNumber, int eventType)
|
||||
isCastingPossible = true;
|
||||
break;
|
||||
case PossiblePlayerBattleAction::FREE_LOCATION:
|
||||
newConsoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[26]) % currentSpell->name); //Cast %s
|
||||
newConsoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[26]) % currentSpell->getNameTranslated()); //Cast %s
|
||||
isCastingPossible = true;
|
||||
break;
|
||||
case PossiblePlayerBattleAction::HEAL:
|
||||
@ -558,7 +561,7 @@ void BattleActionsController::handleHex(BattleHex myNumber, int eventType)
|
||||
break;
|
||||
case PossiblePlayerBattleAction::FREE_LOCATION:
|
||||
cursorFrame = Cursor::Combat::BLOCKED;
|
||||
newConsoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[181]) % currentSpell->name); //No room to place %s here
|
||||
newConsoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[181]) % currentSpell->getNameTranslated()); //No room to place %s here
|
||||
break;
|
||||
default:
|
||||
if (myNumber == -1)
|
||||
@ -579,7 +582,7 @@ void BattleActionsController::handleHex(BattleHex myNumber, int eventType)
|
||||
default:
|
||||
spellcastingCursor = true;
|
||||
if (newConsoleMsg.empty() && currentSpell)
|
||||
newConsoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[26]) % currentSpell->name); //Cast %s
|
||||
newConsoleMsg = boost::str(boost::format(CGI->generaltexth->allTexts[26]) % currentSpell->getNameTranslated()); //Cast %s
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
#include "../CGameInfo.h"
|
||||
#include "../CMusicHandler.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../gui/CCursorHandler.h"
|
||||
#include "../gui/CursorHandler.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
|
||||
#include "../../CCallback.h"
|
||||
|
@ -10,7 +10,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../lib/battle/BattleHex.h"
|
||||
#include "../gui/Geometries.h"
|
||||
#include "BattleConstants.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
@ -18,6 +17,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
class CStack;
|
||||
class CCreature;
|
||||
class CSpell;
|
||||
class Point;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
@ -28,7 +28,6 @@ class CAnimation;
|
||||
class BattleInterface;
|
||||
class CreatureAnimation;
|
||||
struct StackAttackedInfo;
|
||||
struct Point;
|
||||
|
||||
/// Base class of battle animations
|
||||
class BattleAnimation
|
||||
|
@ -10,7 +10,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../lib/battle/BattleHex.h"
|
||||
#include "../gui/Geometries.h"
|
||||
#include "../../lib/Point.h"
|
||||
#include "BattleConstants.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "../gui/CAnimation.h"
|
||||
#include "../gui/Canvas.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/CCursorHandler.h"
|
||||
#include "../gui/CursorHandler.h"
|
||||
|
||||
#include "../../CCallback.h"
|
||||
#include "../../lib/BattleFieldHandler.h"
|
||||
@ -211,11 +211,11 @@ std::set<BattleHex> BattleFieldController::getHighlightedHexesStackRange()
|
||||
for(BattleHex hex : set)
|
||||
result.insert(hex);
|
||||
|
||||
// display the movement shadow of the stack at b (i.e. stack under mouse)
|
||||
const CStack * const shere = owner.curInt->cb->battleGetStackByPos(hoveredHex, false);
|
||||
if(shere && shere != owner.stacksController->getActiveStack() && shere->alive())
|
||||
// display the movement shadow of stack under mouse
|
||||
const CStack * const hoveredStack = owner.curInt->cb->battleGetStackByPos(hoveredHex, true);
|
||||
if(hoveredStack && hoveredStack != owner.stacksController->getActiveStack())
|
||||
{
|
||||
std::vector<BattleHex> v = owner.curInt->cb->battleGetAvailableHexes(shere, true, nullptr);
|
||||
std::vector<BattleHex> v = owner.curInt->cb->battleGetAvailableHexes(hoveredStack, true, nullptr);
|
||||
for(BattleHex hex : v)
|
||||
result.insert(hex);
|
||||
}
|
||||
|
@ -15,12 +15,11 @@
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CStack;
|
||||
class Rect;
|
||||
class Point;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
struct Rect;
|
||||
struct Point;
|
||||
|
||||
class ClickableHex;
|
||||
class BattleHero;
|
||||
class Canvas;
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "../CMusicHandler.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../gui/Canvas.h"
|
||||
#include "../gui/CCursorHandler.h"
|
||||
#include "../gui/CursorHandler.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../windows/CAdvmapInterface.h"
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
#include "../../lib/NetPacks.h"
|
||||
#include "../../lib/UnlockGuard.h"
|
||||
#include "../../lib/TerrainHandler.h"
|
||||
|
||||
CondSh<BattleAction *> BattleInterface::givenCommand(nullptr);
|
||||
|
||||
@ -136,8 +137,8 @@ BattleInterface::~BattleInterface()
|
||||
if (adventureInt && adventureInt->selection)
|
||||
{
|
||||
//FIXME: this should be moved to adventureInt which should restore correct track based on selection/active player
|
||||
const auto & terrain = *(LOCPLINT->cb->getTile(adventureInt->selection->visitablePos())->terType);
|
||||
CCS->musich->playMusicFromSet("terrain", terrain.name, true, false);
|
||||
const auto * terrain = LOCPLINT->cb->getTile(adventureInt->selection->visitablePos())->terType;
|
||||
CCS->musich->playMusicFromSet("terrain", terrain->getJsonKey(), true, false);
|
||||
}
|
||||
|
||||
// may happen if user decided to close game while in battle
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "../Graphics.h"
|
||||
#include "../gui/CAnimation.h"
|
||||
#include "../gui/Canvas.h"
|
||||
#include "../gui/CCursorHandler.h"
|
||||
#include "../gui/CursorHandler.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../widgets/AdventureMapClasses.h"
|
||||
#include "../widgets/Buttons.h"
|
||||
@ -160,7 +160,7 @@ void BattleConsole::setEnteringMode(bool on)
|
||||
if (on)
|
||||
{
|
||||
assert(enteringText == false);
|
||||
CSDL_Ext::startTextInput(&pos);
|
||||
CSDL_Ext::startTextInput(pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -308,7 +308,7 @@ void BattleHero::clickRight(tribool down, bool previousState)
|
||||
return;
|
||||
|
||||
Point windowPosition;
|
||||
windowPosition.x = (!defender) ? owner.fieldController->pos.topLeft().x + 1 : owner.fieldController->pos.topRight().x - 79;
|
||||
windowPosition.x = (!defender) ? owner.fieldController->pos.left() + 1 : owner.fieldController->pos.right() - 79;
|
||||
windowPosition.y = owner.fieldController->pos.y + 135;
|
||||
|
||||
InfoAboutHero targetHero;
|
||||
@ -494,7 +494,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
|
||||
{
|
||||
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
|
||||
|
||||
pos = genRect(561, 470, (screen->w - 800)/2 + 165, (screen->h - 600)/2 + 19);
|
||||
pos = CSDL_Ext::genRect(561, 470, (screen->w - 800)/2 + 165, (screen->h - 600)/2 + 19);
|
||||
background = std::make_shared<CPicture>("CPRESULT");
|
||||
background->colorize(owner.playerID);
|
||||
|
||||
@ -551,7 +551,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
|
||||
if(best != stacks.end()) //should be always but to be safe...
|
||||
{
|
||||
icons.push_back(std::make_shared<CAnimImage>("TWCRPORT", (*best)->type->getIconIndex(), 0, xs[i], 38));
|
||||
sideNames[i] = (*best)->type->getPluralName();
|
||||
sideNames[i] = (*best)->type->getNamePluralTranslated();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -613,7 +613,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
|
||||
if (ourHero)
|
||||
{
|
||||
str += CGI->generaltexth->allTexts[305];
|
||||
boost::algorithm::replace_first(str, "%s", ourHero->name);
|
||||
boost::algorithm::replace_first(str, "%s", ourHero->getNameTranslated());
|
||||
boost::algorithm::replace_first(str, "%d", boost::lexical_cast<std::string>(br.exp[weAreAttacker ? 0 : 1]));
|
||||
}
|
||||
|
||||
@ -804,7 +804,7 @@ void StackQueue::update()
|
||||
|
||||
int32_t StackQueue::getSiegeShooterIconID()
|
||||
{
|
||||
return owner.siegeController->getSiegedTown()->town->faction->index;
|
||||
return owner.siegeController->getSiegedTown()->town->faction->getIndex();
|
||||
}
|
||||
|
||||
StackQueue::StackBox::StackBox(StackQueue * owner):
|
||||
@ -850,7 +850,7 @@ void StackQueue::StackBox::setUnit(const battle::Unit * unit, size_t turn)
|
||||
if (unit->unitType()->idNumber == CreatureID::ARROW_TOWERS)
|
||||
icon->setFrame(owner->getSiegeShooterIconID(), 1);
|
||||
|
||||
amount->setText(makeNumberShort(unit->getCount()));
|
||||
amount->setText(CSDL_Ext::makeNumberShort(unit->getCount()));
|
||||
|
||||
if(stateIcon)
|
||||
{
|
||||
|
@ -13,6 +13,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct BattleHex;
|
||||
struct CObstacleInstance;
|
||||
class Point;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
@ -21,7 +22,6 @@ class Canvas;
|
||||
class CAnimation;
|
||||
class BattleInterface;
|
||||
class BattleRenderer;
|
||||
struct Point;
|
||||
|
||||
/// Controls all currently active projectiles on the battlefield
|
||||
/// (with exception of moat, which is apparently handled by siege controller)
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "BattleStacksController.h"
|
||||
#include "CreatureAnimation.h"
|
||||
|
||||
#include "../gui/Geometries.h"
|
||||
#include "../gui/CAnimation.h"
|
||||
#include "../gui/Canvas.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
@ -158,7 +157,7 @@ const CCreature & BattleProjectileController::getShooter(const CStack * stack) c
|
||||
|
||||
if(creature->animation.missleFrameAngles.empty())
|
||||
{
|
||||
logAnim->error("Mod error: Creature '%s' on the Archer's tower is not a shooter. Mod should be fixed. Trying to use archer's data instead...", creature->nameSing);
|
||||
logAnim->error("Mod error: Creature '%s' on the Archer's tower is not a shooter. Mod should be fixed. Trying to use archer's data instead...", creature->getNameSingularTranslated());
|
||||
creature = CGI->creh->objects[CreatureID::ARCHER];
|
||||
}
|
||||
|
||||
@ -313,7 +312,7 @@ void BattleProjectileController::createProjectile(const CStack * shooter, Point
|
||||
std::shared_ptr<ProjectileBase> projectile;
|
||||
if (stackUsesRayProjectile(shooter) && stackUsesMissileProjectile(shooter))
|
||||
{
|
||||
logAnim->error("Mod error: Creature '%s' has both missile and ray projectiles configured. Mod should be fixed. Using ray projectile configuration...", shooterInfo.nameSing);
|
||||
logAnim->error("Mod error: Creature '%s' has both missile and ray projectiles configured. Mod should be fixed. Using ray projectile configuration...", shooterInfo.getNameSingularTranslated());
|
||||
}
|
||||
|
||||
if (stackUsesRayProjectile(shooter))
|
||||
|
@ -10,7 +10,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../lib/CCreatureHandler.h"
|
||||
#include "../gui/Geometries.h"
|
||||
#include "../../lib/Point.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -19,7 +19,6 @@ class CSpell;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
struct Point;
|
||||
class CAnimation;
|
||||
class Canvas;
|
||||
class BattleInterface;
|
||||
|
@ -28,22 +28,29 @@
|
||||
#include "../../lib/CStack.h"
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
|
||||
std::string BattleSiegeController::getWallPieceImageName(EWallVisual::EWallVisual what, EWallState::EWallState state) const
|
||||
std::string BattleSiegeController::getWallPieceImageName(EWallVisual::EWallVisual what, EWallState state) const
|
||||
{
|
||||
auto getImageIndex = [&]() -> int
|
||||
{
|
||||
bool isTower = (what == EWallVisual::KEEP || what == EWallVisual::BOTTOM_TOWER || what == EWallVisual::UPPER_TOWER);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case EWallState::INTACT :
|
||||
case EWallState::REINFORCED :
|
||||
return 1;
|
||||
case EWallState::INTACT :
|
||||
if (town->hasBuilt(BuildingID::CASTLE))
|
||||
return 2; // reinforced walls were damaged
|
||||
else
|
||||
return 1;
|
||||
case EWallState::DAMAGED :
|
||||
// towers don't have separate image here - INTACT and DAMAGED is 1, DESTROYED is 2
|
||||
if(what == EWallVisual::KEEP || what == EWallVisual::BOTTOM_TOWER || what == EWallVisual::UPPER_TOWER)
|
||||
if (isTower)
|
||||
return 1;
|
||||
else
|
||||
return 2;
|
||||
case EWallState::DESTROYED :
|
||||
if (what == EWallVisual::KEEP || what == EWallVisual::BOTTOM_TOWER || what == EWallVisual::UPPER_TOWER)
|
||||
if (isTower)
|
||||
return 2;
|
||||
else
|
||||
return 3;
|
||||
@ -58,7 +65,7 @@ std::string BattleSiegeController::getWallPieceImageName(EWallVisual::EWallVisua
|
||||
{
|
||||
case EWallVisual::BACKGROUND_WALL:
|
||||
{
|
||||
switch(town->town->faction->index)
|
||||
switch(town->town->faction->getIndex())
|
||||
{
|
||||
case ETownType::RAMPART:
|
||||
case ETownType::NECROPOLIS:
|
||||
@ -128,11 +135,11 @@ bool BattleSiegeController::getWallPieceExistance(EWallVisual::EWallVisual what)
|
||||
|
||||
switch (what)
|
||||
{
|
||||
case EWallVisual::MOAT: return town->hasBuilt(BuildingID::CITADEL) && town->town->faction->index != ETownType::TOWER;
|
||||
case EWallVisual::MOAT_BANK: return town->hasBuilt(BuildingID::CITADEL) && town->town->faction->index != ETownType::TOWER && town->town->faction->index != ETownType::NECROPOLIS;
|
||||
case EWallVisual::KEEP_BATTLEMENT: return town->hasBuilt(BuildingID::CITADEL) && EWallState::EWallState(owner.curInt->cb->battleGetWallState(EWallPart::KEEP)) != EWallState::DESTROYED;
|
||||
case EWallVisual::UPPER_BATTLEMENT: return town->hasBuilt(BuildingID::CASTLE) && EWallState::EWallState(owner.curInt->cb->battleGetWallState(EWallPart::UPPER_TOWER)) != EWallState::DESTROYED;
|
||||
case EWallVisual::BOTTOM_BATTLEMENT: return town->hasBuilt(BuildingID::CASTLE) && EWallState::EWallState(owner.curInt->cb->battleGetWallState(EWallPart::BOTTOM_TOWER)) != EWallState::DESTROYED;
|
||||
case EWallVisual::MOAT: return town->hasBuilt(BuildingID::CITADEL) && town->town->faction->getIndex() != ETownType::TOWER;
|
||||
case EWallVisual::MOAT_BANK: return town->hasBuilt(BuildingID::CITADEL) && town->town->faction->getIndex() != ETownType::TOWER && town->town->faction->getIndex() != ETownType::NECROPOLIS;
|
||||
case EWallVisual::KEEP_BATTLEMENT: return town->hasBuilt(BuildingID::CITADEL) && owner.curInt->cb->battleGetWallState(EWallPart::KEEP) != EWallState::DESTROYED;
|
||||
case EWallVisual::UPPER_BATTLEMENT: return town->hasBuilt(BuildingID::CASTLE) && owner.curInt->cb->battleGetWallState(EWallPart::UPPER_TOWER) != EWallState::DESTROYED;
|
||||
case EWallVisual::BOTTOM_BATTLEMENT: return town->hasBuilt(BuildingID::CASTLE) && owner.curInt->cb->battleGetWallState(EWallPart::BOTTOM_TOWER) != EWallState::DESTROYED;
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
@ -177,7 +184,7 @@ BattleSiegeController::BattleSiegeController(BattleInterface & owner, const CGTo
|
||||
if ( !getWallPieceExistance(EWallVisual::EWallVisual(g)) )
|
||||
continue;
|
||||
|
||||
wallPieceImages[g] = IImage::createFromFile(getWallPieceImageName(EWallVisual::EWallVisual(g), EWallState::INTACT));
|
||||
wallPieceImages[g] = IImage::createFromFile(getWallPieceImageName(EWallVisual::EWallVisual(g), EWallState::REINFORCED));
|
||||
}
|
||||
}
|
||||
|
||||
@ -321,7 +328,7 @@ bool BattleSiegeController::isAttackableByCatapult(BattleHex hex) const
|
||||
if (!owner.curInt->cb->isWallPartPotentiallyAttackable(wallPart))
|
||||
return false;
|
||||
|
||||
auto state = owner.curInt->cb->battleGetWallState(static_cast<int>(wallPart));
|
||||
auto state = owner.curInt->cb->battleGetWallState(wallPart);
|
||||
return state != EWallState::DESTROYED && state != EWallState::NONE;
|
||||
}
|
||||
|
||||
@ -354,12 +361,12 @@ void BattleSiegeController::stackIsCatapulting(const CatapultAttack & ca)
|
||||
|
||||
for (auto attackInfo : ca.attackedParts)
|
||||
{
|
||||
int wallId = attackInfo.attackedPart + EWallVisual::DESTRUCTIBLE_FIRST;
|
||||
int wallId = static_cast<int>(attackInfo.attackedPart) + EWallVisual::DESTRUCTIBLE_FIRST;
|
||||
//gate state changing handled separately
|
||||
if (wallId == EWallVisual::GATE)
|
||||
continue;
|
||||
|
||||
auto wallState = EWallState::EWallState(owner.curInt->cb->battleGetWallState(attackInfo.attackedPart));
|
||||
auto wallState = EWallState(owner.curInt->cb->battleGetWallState(attackInfo.attackedPart));
|
||||
|
||||
wallPieceImages[wallId] = IImage::createFromFile(getWallPieceImageName(EWallVisual::EWallVisual(wallId), wallState));
|
||||
}
|
||||
|
@ -18,10 +18,10 @@ struct CatapultAttack;
|
||||
class CCreature;
|
||||
class CStack;
|
||||
class CGTownInstance;
|
||||
class Point;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
struct Point;
|
||||
class Canvas;
|
||||
class BattleInterface;
|
||||
class BattleRenderer;
|
||||
@ -76,7 +76,7 @@ class BattleSiegeController
|
||||
std::array<std::shared_ptr<IImage>, EWallVisual::WALL_LAST + 1> wallPieceImages;
|
||||
|
||||
/// return URI for image for a wall piece
|
||||
std::string getWallPieceImageName(EWallVisual::EWallVisual what, EWallState::EWallState state) const;
|
||||
std::string getWallPieceImageName(EWallVisual::EWallVisual what, EWallState state) const;
|
||||
|
||||
/// returns BattleHex to which chosen wall piece is bound
|
||||
BattleHex getWallPiecePosition(EWallVisual::EWallVisual what) const;
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "../gui/CAnimation.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/Canvas.h"
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
#include "../../lib/spells/ISpellMechanics.h"
|
||||
|
||||
#include "../../CCallback.h"
|
||||
@ -83,10 +84,10 @@ BattleStacksController::BattleStacksController(BattleInterface & owner):
|
||||
amountNegative = IImage::createFromFile("CMNUMWIN.BMP");
|
||||
amountEffNeutral = IImage::createFromFile("CMNUMWIN.BMP");
|
||||
|
||||
static const auto shifterNormal = ColorFilter::genRangeShifter( 0,0,0, 0.6, 0.2, 1.0 );
|
||||
static const auto shifterPositive = ColorFilter::genRangeShifter( 0,0,0, 0.2, 1.0, 0.2 );
|
||||
static const auto shifterNegative = ColorFilter::genRangeShifter( 0,0,0, 1.0, 0.2, 0.2 );
|
||||
static const auto shifterNeutral = ColorFilter::genRangeShifter( 0,0,0, 1.0, 1.0, 0.2 );
|
||||
static const auto shifterNormal = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 0.6f, 0.2f, 1.0f );
|
||||
static const auto shifterPositive = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 0.2f, 1.0f, 0.2f );
|
||||
static const auto shifterNegative = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 1.0f, 0.2f, 0.2f );
|
||||
static const auto shifterNeutral = ColorFilter::genRangeShifter( 0.f, 0.f, 0.f, 1.0f, 1.0f, 0.2f );
|
||||
|
||||
amountNormal->adjustPalette(shifterNormal);
|
||||
amountPositive->adjustPalette(shifterPositive);
|
||||
@ -317,7 +318,7 @@ void BattleStacksController::showStackAmountBox(Canvas & canvas, const CStack *
|
||||
//blitting amount
|
||||
Point textPos = stackAnimation[stack->ID]->pos.topLeft() + amountBG->dimensions()/2 + Point(xAdd, yAdd);
|
||||
|
||||
canvas.drawText(textPos, EFonts::FONT_TINY, Colors::WHITE, ETextAlignment::CENTER, makeNumberShort(stack->getCount()));
|
||||
canvas.drawText(textPos, EFonts::FONT_TINY, Colors::WHITE, ETextAlignment::CENTER, CSDL_Ext::makeNumberShort(stack->getCount()));
|
||||
}
|
||||
|
||||
void BattleStacksController::showStack(Canvas & canvas, const CStack * stack)
|
||||
@ -543,7 +544,6 @@ void BattleStacksController::stackMoved(const CStack *stack, std::vector<BattleH
|
||||
bool BattleStacksController::shouldAttackFacingRight(const CStack * attacker, const CStack * defender)
|
||||
{
|
||||
bool mustReverse = owner.curInt->cb->isToReverse(
|
||||
attacker->getPosition(),
|
||||
attacker,
|
||||
defender);
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../gui/Geometries.h"
|
||||
#include "../gui/ColorFilter.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
@ -19,6 +18,7 @@ class BattleAction;
|
||||
class CStack;
|
||||
class CSpell;
|
||||
class SpellID;
|
||||
class Point;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../CMusicHandler.h"
|
||||
#include "../gui/Canvas.h"
|
||||
#include "../gui/CCursorHandler.h"
|
||||
#include "../gui/CursorHandler.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/CAnimation.h"
|
||||
#include "../windows/CSpellWindow.h"
|
||||
@ -274,10 +274,10 @@ void BattleWindow::bFleef()
|
||||
//calculating fleeing hero's name
|
||||
if (owner.attackingHeroInstance)
|
||||
if (owner.attackingHeroInstance->tempOwner == owner.curInt->cb->getMyColor())
|
||||
heroName = owner.attackingHeroInstance->name;
|
||||
heroName = owner.attackingHeroInstance->getNameTranslated();
|
||||
if (owner.defendingHeroInstance)
|
||||
if (owner.defendingHeroInstance->tempOwner == owner.curInt->cb->getMyColor())
|
||||
heroName = owner.defendingHeroInstance->name;
|
||||
heroName = owner.defendingHeroInstance->getNameTranslated();
|
||||
//calculating text
|
||||
auto txt = boost::format(CGI->generaltexth->allTexts[340]) % heroName; //The Shackles of War are present. %s can not retreat!
|
||||
|
||||
@ -416,11 +416,11 @@ void BattleWindow::bSpellf()
|
||||
const auto artID = ArtifactID(blockingBonus->sid);
|
||||
//If we have artifact, put name of our hero. Otherwise assume it's the enemy.
|
||||
//TODO check who *really* is source of bonus
|
||||
std::string heroName = myHero->hasArt(artID) ? myHero->name : owner.enemyHero().name;
|
||||
std::string heroName = myHero->hasArt(artID) ? myHero->getNameTranslated() : owner.enemyHero().name;
|
||||
|
||||
//%s wields the %s, an ancient artifact which creates a p dead to all magic.
|
||||
LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[683])
|
||||
% heroName % CGI->artifacts()->getByIndex(artID)->getName()));
|
||||
% heroName % CGI->artifacts()->getByIndex(artID)->getNameTranslated()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "../gui/Canvas.h"
|
||||
#include "../gui/ColorFilter.h"
|
||||
#include "../gui/SDL_Extensions.h"
|
||||
|
||||
static const SDL_Color creatureBlueBorder = { 0, 255, 255, 255 };
|
||||
static const SDL_Color creatureGoldBorder = { 255, 255, 0, 255 };
|
||||
|
@ -94,8 +94,8 @@ public:
|
||||
// Keep the original palette, in order to do color switching operation
|
||||
void savePalette();
|
||||
|
||||
void draw(SDL_Surface * where, int posX=0, int posY=0, const Rect *src=nullptr, ui8 alpha=255) const override;
|
||||
void draw(SDL_Surface * where, const SDL_Rect * dest, const SDL_Rect * src, ui8 alpha=255) const override;
|
||||
void draw(SDL_Surface * where, int posX=0, int posY=0, const Rect *src=nullptr) const override;
|
||||
void draw(SDL_Surface * where, const Rect * dest, const Rect * src) const override;
|
||||
std::shared_ptr<IImage> scaleFast(float scale) const override;
|
||||
void exportBitmap(const boost::filesystem::path & path) const override;
|
||||
void playerColored(PlayerColor player) override;
|
||||
@ -642,17 +642,16 @@ SDLImage::SDLImage(std::string filename)
|
||||
}
|
||||
}
|
||||
|
||||
void SDLImage::draw(SDL_Surface *where, int posX, int posY, const Rect *src, ui8 alpha) const
|
||||
void SDLImage::draw(SDL_Surface *where, int posX, int posY, const Rect *src) const
|
||||
{
|
||||
if(!surf)
|
||||
return;
|
||||
|
||||
Rect destRect(posX, posY, surf->w, surf->h);
|
||||
|
||||
draw(where, &destRect, src);
|
||||
}
|
||||
|
||||
void SDLImage::draw(SDL_Surface* where, const SDL_Rect* dest, const SDL_Rect* src, ui8 alpha) const
|
||||
void SDLImage::draw(SDL_Surface* where, const Rect * dest, const Rect* src) const
|
||||
{
|
||||
if (!surf)
|
||||
return;
|
||||
@ -669,28 +668,23 @@ void SDLImage::draw(SDL_Surface* where, const SDL_Rect* dest, const SDL_Rect* sr
|
||||
if(src->y < margins.y)
|
||||
destShift.y += margins.y - src->y;
|
||||
|
||||
sourceRect = Rect(*src) & Rect(margins.x, margins.y, surf->w, surf->h);
|
||||
sourceRect = Rect(*src).intersect(Rect(margins.x, margins.y, surf->w, surf->h));
|
||||
|
||||
sourceRect -= margins;
|
||||
}
|
||||
else
|
||||
destShift = margins;
|
||||
|
||||
Rect destRect(destShift.x, destShift.y, surf->w, surf->h);
|
||||
|
||||
if(dest)
|
||||
{
|
||||
destRect.x += dest->x;
|
||||
destRect.y += dest->y;
|
||||
}
|
||||
destShift += dest->topLeft();
|
||||
|
||||
if(surf->format->BitsPerPixel == 8)
|
||||
{
|
||||
CSDL_Ext::blit8bppAlphaTo24bpp(surf, &sourceRect, where, &destRect);
|
||||
CSDL_Ext::blit8bppAlphaTo24bpp(surf, sourceRect, where, destShift);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDL_UpperBlit(surf, &sourceRect, where, &destRect);
|
||||
CSDL_Ext::blitSurface(surf, sourceRect, where, destShift);
|
||||
}
|
||||
}
|
||||
|
||||
@ -788,7 +782,7 @@ void SDLImage::shiftPalette(int from, int howMany)
|
||||
{
|
||||
palette[(i+1)%howMany] = surf->format->palette->colors[from + i];
|
||||
}
|
||||
SDL_SetColors(surf, palette, from, howMany);
|
||||
CSDL_Ext::setColors(surf, palette, from, howMany);
|
||||
}
|
||||
}
|
||||
|
||||
@ -828,7 +822,7 @@ void SDLImage::setSpecialPallete(const IImage::SpecialPalette & SpecialPalette)
|
||||
{
|
||||
if(surf->format->palette)
|
||||
{
|
||||
SDL_SetColors(surf, const_cast<SDL_Color *>(SpecialPalette.data()), 1, 7);
|
||||
CSDL_Ext::setColors(surf, const_cast<SDL_Color *>(SpecialPalette.data()), 1, 7);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1274,7 +1268,7 @@ void CFadeAnimation::init(EMode mode, SDL_Surface * sourceSurface, bool freeSurf
|
||||
shouldFreeSurface = freeSurfaceAtEnd;
|
||||
}
|
||||
|
||||
void CFadeAnimation::draw(SDL_Surface * targetSurface, const SDL_Rect * sourceRect, SDL_Rect * destRect)
|
||||
void CFadeAnimation::draw(SDL_Surface * targetSurface, const Point &targetPoint)
|
||||
{
|
||||
if (!fading || !fadingSurface || fadingMode == EMode::NONE)
|
||||
{
|
||||
@ -1283,6 +1277,6 @@ void CFadeAnimation::draw(SDL_Surface * targetSurface, const SDL_Rect * sourceRe
|
||||
}
|
||||
|
||||
CSDL_Ext::setAlpha(fadingSurface, (int)(fadingCounter * 255));
|
||||
SDL_BlitSurface(fadingSurface, const_cast<SDL_Rect *>(sourceRect), targetSurface, destRect); //FIXME
|
||||
CSDL_Ext::blitSurface(fadingSurface, targetSurface, targetPoint); //FIXME
|
||||
CSDL_Ext::setAlpha(fadingSurface, 255);
|
||||
}
|
||||
|
@ -10,7 +10,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../lib/vcmi_endian.h"
|
||||
#include "Geometries.h"
|
||||
#include "../../lib/GameConstants.h"
|
||||
|
||||
#ifdef IN
|
||||
@ -24,10 +23,13 @@
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class JsonNode;
|
||||
class Rect;
|
||||
class Point;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
struct SDL_Surface;
|
||||
struct SDL_Color;
|
||||
class CDefFile;
|
||||
class ColorFilter;
|
||||
|
||||
@ -40,8 +42,8 @@ public:
|
||||
using SpecialPalette = std::array<SDL_Color, 7>;
|
||||
|
||||
//draws image on surface "where" at position
|
||||
virtual void draw(SDL_Surface * where, int posX = 0, int posY = 0, const Rect * src = nullptr, ui8 alpha = 255) const=0;
|
||||
virtual void draw(SDL_Surface * where, const SDL_Rect * dest, const SDL_Rect * src, ui8 alpha = 255) const = 0;
|
||||
virtual void draw(SDL_Surface * where, int posX = 0, int posY = 0, const Rect * src = nullptr) const = 0;
|
||||
virtual void draw(SDL_Surface * where, const Rect * dest, const Rect * src) const = 0;
|
||||
|
||||
virtual std::shared_ptr<IImage> scaleFast(float scale) const = 0;
|
||||
|
||||
@ -177,6 +179,6 @@ public:
|
||||
~CFadeAnimation();
|
||||
void init(EMode mode, SDL_Surface * sourceSurface, bool freeSurfaceAtEnd = false, float animDelta = DEFAULT_DELTA);
|
||||
void update();
|
||||
void draw(SDL_Surface * targetSurface, const SDL_Rect * sourceRect, SDL_Rect * destRect);
|
||||
void draw(SDL_Surface * targetSurface, const Point & targetPoint);
|
||||
bool isFading() const { return fading; }
|
||||
};
|
||||
|
@ -1,317 +0,0 @@
|
||||
/*
|
||||
* CCursorHandler.cpp, 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
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "CCursorHandler.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "SDL_Extensions.h"
|
||||
#include "CGuiHandler.h"
|
||||
#include "../widgets/Images.h"
|
||||
|
||||
#include "../CMT.h"
|
||||
|
||||
void CCursorHandler::clearBuffer()
|
||||
{
|
||||
Uint32 fillColor = SDL_MapRGBA(buffer->format, 0, 0, 0, 0);
|
||||
CSDL_Ext::fillRect(buffer, nullptr, fillColor);
|
||||
}
|
||||
|
||||
void CCursorHandler::updateBuffer(CIntObject * payload)
|
||||
{
|
||||
payload->moveTo(Point(0,0));
|
||||
payload->showAll(buffer);
|
||||
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
void CCursorHandler::replaceBuffer(CIntObject * payload)
|
||||
{
|
||||
clearBuffer();
|
||||
updateBuffer(payload);
|
||||
}
|
||||
|
||||
CCursorHandler::CCursorHandler()
|
||||
: needUpdate(true)
|
||||
, buffer(nullptr)
|
||||
, cursorLayer(nullptr)
|
||||
, frameTime(0.f)
|
||||
, showing(false)
|
||||
{
|
||||
cursorLayer = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 40, 40);
|
||||
SDL_SetTextureBlendMode(cursorLayer, SDL_BLENDMODE_BLEND);
|
||||
|
||||
xpos = ypos = 0;
|
||||
type = Cursor::Type::DEFAULT;
|
||||
dndObject = nullptr;
|
||||
|
||||
cursors =
|
||||
{
|
||||
std::make_unique<CAnimImage>("CRADVNTR", 0),
|
||||
std::make_unique<CAnimImage>("CRCOMBAT", 0),
|
||||
std::make_unique<CAnimImage>("CRDEFLT", 0),
|
||||
std::make_unique<CAnimImage>("CRSPELL", 0)
|
||||
};
|
||||
|
||||
currentCursor = cursors.at(static_cast<size_t>(Cursor::Type::DEFAULT)).get();
|
||||
|
||||
buffer = CSDL_Ext::newSurface(40,40);
|
||||
|
||||
SDL_SetSurfaceBlendMode(buffer, SDL_BLENDMODE_NONE);
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
|
||||
set(Cursor::Map::POINTER);
|
||||
}
|
||||
|
||||
Point CCursorHandler::position() const
|
||||
{
|
||||
return Point(xpos, ypos);
|
||||
}
|
||||
|
||||
void CCursorHandler::changeGraphic(Cursor::Type type, size_t index)
|
||||
{
|
||||
assert(dndObject == nullptr);
|
||||
|
||||
if(type != this->type)
|
||||
{
|
||||
this->type = type;
|
||||
this->frame = index;
|
||||
currentCursor = cursors.at(static_cast<size_t>(type)).get();
|
||||
currentCursor->setFrame(index);
|
||||
}
|
||||
else if(index != this->frame)
|
||||
{
|
||||
this->frame = index;
|
||||
currentCursor->setFrame(index);
|
||||
}
|
||||
|
||||
replaceBuffer(currentCursor);
|
||||
}
|
||||
|
||||
void CCursorHandler::set(Cursor::Default index)
|
||||
{
|
||||
changeGraphic(Cursor::Type::DEFAULT, static_cast<size_t>(index));
|
||||
}
|
||||
|
||||
void CCursorHandler::set(Cursor::Map index)
|
||||
{
|
||||
changeGraphic(Cursor::Type::ADVENTURE, static_cast<size_t>(index));
|
||||
}
|
||||
|
||||
void CCursorHandler::set(Cursor::Combat index)
|
||||
{
|
||||
changeGraphic(Cursor::Type::COMBAT, static_cast<size_t>(index));
|
||||
}
|
||||
|
||||
void CCursorHandler::set(Cursor::Spellcast index)
|
||||
{
|
||||
//Note: this is animated cursor, ignore specified frame and only change type
|
||||
changeGraphic(Cursor::Type::SPELLBOOK, frame);
|
||||
}
|
||||
|
||||
void CCursorHandler::dragAndDropCursor(std::unique_ptr<CAnimImage> object)
|
||||
{
|
||||
dndObject = std::move(object);
|
||||
if(dndObject)
|
||||
replaceBuffer(dndObject.get());
|
||||
else
|
||||
replaceBuffer(currentCursor);
|
||||
}
|
||||
|
||||
void CCursorHandler::cursorMove(const int & x, const int & y)
|
||||
{
|
||||
xpos = x;
|
||||
ypos = y;
|
||||
}
|
||||
|
||||
void CCursorHandler::shiftPos( int &x, int &y )
|
||||
{
|
||||
if(( type == Cursor::Type::COMBAT && frame != static_cast<size_t>(Cursor::Combat::POINTER)) || type == Cursor::Type::SPELLBOOK)
|
||||
{
|
||||
x-=16;
|
||||
y-=16;
|
||||
|
||||
// Properly align the melee attack cursors.
|
||||
if (type == Cursor::Type::COMBAT)
|
||||
{
|
||||
switch (static_cast<Cursor::Combat>(frame))
|
||||
{
|
||||
case Cursor::Combat::HIT_NORTHEAST:
|
||||
x -= 6;
|
||||
y += 16;
|
||||
break;
|
||||
case Cursor::Combat::HIT_EAST:
|
||||
x -= 16;
|
||||
y += 10;
|
||||
break;
|
||||
case Cursor::Combat::HIT_SOUTHEAST:
|
||||
x -= 6;
|
||||
y -= 6;
|
||||
break;
|
||||
case Cursor::Combat::HIT_SOUTHWEST:
|
||||
x += 16;
|
||||
y -= 6;
|
||||
break;
|
||||
case Cursor::Combat::HIT_WEST:
|
||||
x += 16;
|
||||
y += 11;
|
||||
break;
|
||||
case Cursor::Combat::HIT_NORTHWEST:
|
||||
x += 16;
|
||||
y += 16;
|
||||
break;
|
||||
case Cursor::Combat::HIT_NORTH:
|
||||
x += 9;
|
||||
y += 16;
|
||||
break;
|
||||
case Cursor::Combat::HIT_SOUTH:
|
||||
x += 9;
|
||||
y -= 15;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(type == Cursor::Type::ADVENTURE)
|
||||
{
|
||||
if (frame == 0)
|
||||
{
|
||||
//no-op
|
||||
}
|
||||
else if(frame == 2)
|
||||
{
|
||||
x -= 12;
|
||||
y -= 10;
|
||||
}
|
||||
else if(frame == 3)
|
||||
{
|
||||
x -= 12;
|
||||
y -= 12;
|
||||
}
|
||||
else if(frame < 27)
|
||||
{
|
||||
int hlpNum = (frame - 4)%6;
|
||||
if(hlpNum == 0)
|
||||
{
|
||||
x -= 15;
|
||||
y -= 13;
|
||||
}
|
||||
else if(hlpNum == 1)
|
||||
{
|
||||
x -= 13;
|
||||
y -= 13;
|
||||
}
|
||||
else if(hlpNum == 2)
|
||||
{
|
||||
x -= 20;
|
||||
y -= 20;
|
||||
}
|
||||
else if(hlpNum == 3)
|
||||
{
|
||||
x -= 13;
|
||||
y -= 16;
|
||||
}
|
||||
else if(hlpNum == 4)
|
||||
{
|
||||
x -= 8;
|
||||
y -= 9;
|
||||
}
|
||||
else if(hlpNum == 5)
|
||||
{
|
||||
x -= 14;
|
||||
y -= 16;
|
||||
}
|
||||
}
|
||||
else if(frame == 41)
|
||||
{
|
||||
x -= 14;
|
||||
y -= 16;
|
||||
}
|
||||
else if(frame < 31 || frame == 42)
|
||||
{
|
||||
x -= 20;
|
||||
y -= 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCursorHandler::centerCursor()
|
||||
{
|
||||
this->xpos = static_cast<int>((screen->w / 2.) - (currentCursor->pos.w / 2.));
|
||||
this->ypos = static_cast<int>((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);
|
||||
}
|
||||
|
||||
void CCursorHandler::render()
|
||||
{
|
||||
if(!showing)
|
||||
return;
|
||||
|
||||
if (type == Cursor::Type::SPELLBOOK)
|
||||
{
|
||||
static const float frameDisplayDuration = 0.1f;
|
||||
|
||||
frameTime += GH.mainFPSmng->getElapsedMilliseconds() / 1000.f;
|
||||
size_t newFrame = frame;
|
||||
|
||||
while (frameTime > frameDisplayDuration)
|
||||
{
|
||||
frameTime -= frameDisplayDuration;
|
||||
newFrame++;
|
||||
}
|
||||
|
||||
auto & animation = cursors.at(static_cast<size_t>(type));
|
||||
|
||||
while (newFrame > animation->size())
|
||||
newFrame -= animation->size();
|
||||
|
||||
changeGraphic(Cursor::Type::SPELLBOOK, newFrame);
|
||||
}
|
||||
|
||||
//the must update texture in the main (renderer) thread, but changes to cursor type may come from other threads
|
||||
updateTexture();
|
||||
|
||||
int x = xpos;
|
||||
int y = ypos;
|
||||
shiftPos(x, y);
|
||||
|
||||
if(dndObject)
|
||||
{
|
||||
x -= dndObject->pos.w/2;
|
||||
y -= dndObject->pos.h/2;
|
||||
}
|
||||
|
||||
SDL_Rect destRect;
|
||||
destRect.x = x;
|
||||
destRect.y = y;
|
||||
destRect.w = 40;
|
||||
destRect.h = 40;
|
||||
|
||||
SDL_RenderCopy(mainRenderer, cursorLayer, nullptr, &destRect);
|
||||
}
|
||||
|
||||
void CCursorHandler::updateTexture()
|
||||
{
|
||||
if(needUpdate)
|
||||
{
|
||||
SDL_UpdateTexture(cursorLayer, nullptr, buffer->pixels, buffer->pitch);
|
||||
needUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
CCursorHandler::~CCursorHandler()
|
||||
{
|
||||
if(buffer)
|
||||
SDL_FreeSurface(buffer);
|
||||
|
||||
if(cursorLayer)
|
||||
SDL_DestroyTexture(cursorLayer);
|
||||
}
|
@ -11,10 +11,11 @@
|
||||
#include "CGuiHandler.h"
|
||||
#include "../lib/CondSh.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_timer.h>
|
||||
|
||||
#include "CIntObject.h"
|
||||
#include "CCursorHandler.h"
|
||||
#include "CursorHandler.h"
|
||||
#include "SDL_Extensions.h"
|
||||
|
||||
#include "../CGameInfo.h"
|
||||
#include "../../lib/CThreadHelper.h"
|
||||
@ -167,7 +168,7 @@ void CGuiHandler::totalRedraw()
|
||||
#endif
|
||||
for(auto & elem : objsToBlit)
|
||||
elem->showAll(screen2);
|
||||
blitAt(screen2,0,0,screen);
|
||||
CSDL_Ext::blitAt(screen2,0,0,screen);
|
||||
}
|
||||
|
||||
void CGuiHandler::updateTime()
|
||||
@ -289,7 +290,7 @@ void CGuiHandler::handleCurrentEvent()
|
||||
for(auto i = hlp.begin(); i != hlp.end() && continueEventHandling; i++)
|
||||
{
|
||||
if(!vstd::contains(doubleClickInterested, *i)) continue;
|
||||
if(isItIn(&(*i)->pos, current->motion.x, current->motion.y))
|
||||
if((*i)->pos.isInside(current->motion.x, current->motion.y))
|
||||
{
|
||||
(*i)->onDoubleClick();
|
||||
}
|
||||
@ -321,7 +322,7 @@ void CGuiHandler::handleCurrentEvent()
|
||||
// SDL doesn't have the proper values for mouse positions on SDL_MOUSEWHEEL, refetch them
|
||||
int x = 0, y = 0;
|
||||
SDL_GetMouseState(&x, &y);
|
||||
(*i)->wheelScrolled(current->wheel.y < 0, isItIn(&(*i)->pos, x, y));
|
||||
(*i)->wheelScrolled(current->wheel.y < 0, (*i)->pos.isInside(x, y));
|
||||
}
|
||||
}
|
||||
else if(current->type == SDL_TEXTINPUT)
|
||||
@ -367,7 +368,7 @@ void CGuiHandler::handleMouseButtonClick(CIntObjectList & interestedObjs, EIntOb
|
||||
auto prev = (*i)->mouseState(btn);
|
||||
if(!isPressed)
|
||||
(*i)->updateMouseState(btn, isPressed);
|
||||
if(isItIn(&(*i)->pos, current->motion.x, current->motion.y))
|
||||
if((*i)->pos.isInside(current->motion.x, current->motion.y))
|
||||
{
|
||||
if(isPressed)
|
||||
(*i)->updateMouseState(btn, isPressed);
|
||||
@ -384,7 +385,7 @@ void CGuiHandler::handleMouseMotion()
|
||||
std::vector<CIntObject*> hlp;
|
||||
for(auto & elem : hoverable)
|
||||
{
|
||||
if(isItIn(&(elem)->pos, current->motion.x, current->motion.y))
|
||||
if(elem->pos.isInside(current->motion.x, current->motion.y))
|
||||
{
|
||||
if (!(elem)->hovered)
|
||||
hlp.push_back((elem));
|
||||
@ -408,7 +409,7 @@ void CGuiHandler::simpleRedraw()
|
||||
{
|
||||
//update only top interface and draw background
|
||||
if(objsToBlit.size() > 1)
|
||||
blitAt(screen2,0,0,screen); //blit background
|
||||
CSDL_Ext::blitAt(screen2,0,0,screen); //blit background
|
||||
if(!objsToBlit.empty())
|
||||
objsToBlit.back()->show(screen); //blit active interface/window
|
||||
}
|
||||
@ -419,7 +420,7 @@ void CGuiHandler::handleMoveInterested(const SDL_MouseMotionEvent & motion)
|
||||
std::list<CIntObject*> miCopy = motioninterested;
|
||||
for(auto & elem : miCopy)
|
||||
{
|
||||
if(elem->strongInterest || isItInOrLowerBounds(&elem->pos, motion.x, motion.y)) //checking lower bounds fixes bug #2476
|
||||
if(elem->strongInterest || Rect::createAround(elem->pos, 1).isInside( motion.x, motion.y)) //checking bounds including border fixes bug #2476
|
||||
{
|
||||
(elem)->mouseMoved(motion);
|
||||
}
|
||||
|
@ -9,9 +9,9 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
//#include "../../lib/CStopWatch.h"
|
||||
#include "Geometries.h"
|
||||
#include "SDL_Extensions.h"
|
||||
#include "../../lib/Point.h"
|
||||
|
||||
#include <SDL_events.h>
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -19,6 +19,8 @@ template <typename T> struct CondSh;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
union SDL_Event;
|
||||
|
||||
class CFramerateManager;
|
||||
class IStatusBar;
|
||||
class CIntObject;
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "SDL_Extensions.h"
|
||||
#include "../CMessage.h"
|
||||
|
||||
#include <SDL_pixels.h>
|
||||
|
||||
IShowActivatable::IShowActivatable()
|
||||
{
|
||||
type = 0;
|
||||
@ -176,7 +178,7 @@ void CIntObject::printAtMiddleLoc(const std::string & text, const Point &p, EFon
|
||||
|
||||
void CIntObject::blitAtLoc( SDL_Surface * src, int x, int y, SDL_Surface * dst )
|
||||
{
|
||||
blitAt(src, pos.x + x, pos.y + y, dst);
|
||||
CSDL_Ext::blitAt(src, pos.x + x, pos.y + y, dst);
|
||||
}
|
||||
|
||||
void CIntObject::blitAtLoc(SDL_Surface * src, const Point &p, SDL_Surface * dst)
|
||||
@ -219,16 +221,6 @@ void CIntObject::enable()
|
||||
recActions = 255;
|
||||
}
|
||||
|
||||
bool CIntObject::isItInLoc( const SDL_Rect &rect, int x, int y )
|
||||
{
|
||||
return isItIn(&rect, x - pos.x, y - pos.y);
|
||||
}
|
||||
|
||||
bool CIntObject::isItInLoc( const SDL_Rect &rect, const Point &p )
|
||||
{
|
||||
return isItIn(&rect, p.x - pos.x, p.y - pos.y);
|
||||
}
|
||||
|
||||
void CIntObject::fitToScreen(int borderWidth, bool propagate)
|
||||
{
|
||||
Point newPos = pos.topLeft();
|
||||
|
@ -9,8 +9,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <SDL_events.h>
|
||||
#include "Geometries.h"
|
||||
#include "../../lib/Rect.h"
|
||||
#include "../Graphics.h"
|
||||
|
||||
struct SDL_Surface;
|
||||
@ -18,6 +17,9 @@ class CGuiHandler;
|
||||
class CPicture;
|
||||
|
||||
struct SDL_KeyboardEvent;
|
||||
struct SDL_TextInputEvent;
|
||||
struct SDL_TextEditingEvent;
|
||||
struct SDL_MouseMotionEvent;
|
||||
|
||||
using boost::logic::tribool;
|
||||
|
||||
@ -165,8 +167,6 @@ public:
|
||||
//request complete redraw of this object
|
||||
void redraw() override;
|
||||
|
||||
bool isItInLoc(const SDL_Rect &rect, int x, int y);
|
||||
bool isItInLoc(const SDL_Rect &rect, const Point &p);
|
||||
const Rect & center(const Rect &r, bool propagate = true); //sets pos so that r will be in the center of screen, assigns sizes of r to pos, returns new position
|
||||
const Rect & center(const Point &p, bool propagate = true); //moves object so that point p will be in its center
|
||||
const Rect & center(bool propagate = true); //centers when pos.w and pos.h are set, returns new position
|
||||
|
@ -11,11 +11,12 @@
|
||||
#include "Canvas.h"
|
||||
|
||||
#include "SDL_Extensions.h"
|
||||
#include "Geometries.h"
|
||||
#include "CAnimation.h"
|
||||
|
||||
#include "../Graphics.h"
|
||||
|
||||
#include <SDL_surface.h>
|
||||
|
||||
Canvas::Canvas(SDL_Surface * surface):
|
||||
surface(surface),
|
||||
renderOffset(0,0)
|
||||
@ -34,10 +35,10 @@ Canvas::Canvas(Canvas & other, const Rect & newClipRect):
|
||||
Canvas(other)
|
||||
{
|
||||
clipRect.emplace();
|
||||
SDL_GetClipRect(surface, clipRect.get_ptr());
|
||||
CSDL_Ext::getClipRect(surface, clipRect.get());
|
||||
|
||||
Rect currClipRect = newClipRect + renderOffset;
|
||||
SDL_SetClipRect(surface, &currClipRect);
|
||||
CSDL_Ext::setClipRect(surface, currClipRect);
|
||||
|
||||
renderOffset += newClipRect.topLeft();
|
||||
}
|
||||
@ -51,7 +52,7 @@ Canvas::Canvas(const Point & size):
|
||||
Canvas::~Canvas()
|
||||
{
|
||||
if (clipRect)
|
||||
SDL_SetClipRect(surface, clipRect.get_ptr());
|
||||
CSDL_Ext::setClipRect(surface, clipRect.get());
|
||||
|
||||
SDL_FreeSurface(surface);
|
||||
}
|
||||
@ -70,16 +71,9 @@ void Canvas::draw(std::shared_ptr<IImage> image, const Point & pos, const Rect &
|
||||
image->draw(surface, renderOffset.x + pos.x, renderOffset.y + pos.y, &sourceRect);
|
||||
}
|
||||
|
||||
void Canvas::draw(std::shared_ptr<IImage> image, const Point & pos, const Rect & sourceRect, uint8_t alpha)
|
||||
{
|
||||
assert(image);
|
||||
if (image)
|
||||
image->draw(surface, renderOffset.x + pos.x, renderOffset.y + pos.y, &sourceRect, alpha);
|
||||
}
|
||||
|
||||
void Canvas::draw(Canvas & image, const Point & pos)
|
||||
{
|
||||
blitAt(image.surface, renderOffset.x + pos.x, renderOffset.y + pos.y, surface);
|
||||
CSDL_Ext::blitAt(image.surface, renderOffset.x + pos.x, renderOffset.y + pos.y, surface);
|
||||
}
|
||||
|
||||
void Canvas::drawLine(const Point & from, const Point & dest, const SDL_Color & colorFrom, const SDL_Color & colorDest)
|
||||
|
@ -9,7 +9,8 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "Geometries.h"
|
||||
#include "TextAlignment.h"
|
||||
#include "../../lib/Rect.h"
|
||||
|
||||
struct SDL_Color;
|
||||
struct SDL_Surface;
|
||||
@ -51,10 +52,6 @@ public:
|
||||
/// renders section of image bounded by sourceRect at specified position
|
||||
void draw(std::shared_ptr<IImage> image, const Point & pos, const Rect & sourceRect);
|
||||
|
||||
/// renders section of image bounded by sourceRect at specified position at specific transparency value
|
||||
void draw(std::shared_ptr<IImage> image, const Point & pos, const Rect & sourceRect, uint8_t alpha);
|
||||
|
||||
|
||||
/// renders another canvas onto this canvas
|
||||
void draw(Canvas & image, const Point & pos);
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "StdInc.h"
|
||||
#include "ColorFilter.h"
|
||||
|
||||
#include <SDL2/SDL_pixels.h>
|
||||
#include <SDL_pixels.h>
|
||||
|
||||
#include "../../lib/JsonNode.h"
|
||||
|
||||
|
439
client/gui/CursorHandler.cpp
Normal file
439
client/gui/CursorHandler.cpp
Normal file
@ -0,0 +1,439 @@
|
||||
/*
|
||||
* CCursorHandler.cpp, 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
|
||||
*
|
||||
*/
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "CursorHandler.h"
|
||||
|
||||
#include "SDL_Extensions.h"
|
||||
#include "CGuiHandler.h"
|
||||
#include "CAnimation.h"
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
|
||||
std::unique_ptr<ICursor> CursorHandler::createCursor()
|
||||
{
|
||||
if (settings["video"]["cursor"].String() == "auto")
|
||||
{
|
||||
#if defined(VCMI_ANDROID) || defined(VCMI_IOS)
|
||||
return std::make_unique<CursorSoftware>();
|
||||
#else
|
||||
return std::make_unique<CursorHardware>();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (settings["video"]["cursor"].String() == "hardware")
|
||||
return std::make_unique<CursorHardware>();
|
||||
|
||||
assert(settings["video"]["cursor"].String() == "software");
|
||||
return std::make_unique<CursorSoftware>();
|
||||
}
|
||||
|
||||
CursorHandler::CursorHandler()
|
||||
: cursor(createCursor())
|
||||
, frameTime(0.f)
|
||||
, showing(false)
|
||||
, pos(0,0)
|
||||
{
|
||||
|
||||
type = Cursor::Type::DEFAULT;
|
||||
dndObject = nullptr;
|
||||
|
||||
cursors =
|
||||
{
|
||||
std::make_unique<CAnimation>("CRADVNTR"),
|
||||
std::make_unique<CAnimation>("CRCOMBAT"),
|
||||
std::make_unique<CAnimation>("CRDEFLT"),
|
||||
std::make_unique<CAnimation>("CRSPELL")
|
||||
};
|
||||
|
||||
for (auto & cursor : cursors)
|
||||
cursor->preload();
|
||||
|
||||
set(Cursor::Map::POINTER);
|
||||
}
|
||||
|
||||
Point CursorHandler::position() const
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
void CursorHandler::changeGraphic(Cursor::Type type, size_t index)
|
||||
{
|
||||
assert(dndObject == nullptr);
|
||||
|
||||
if (type == this->type && index == this->frame)
|
||||
return;
|
||||
|
||||
this->type = type;
|
||||
this->frame = index;
|
||||
|
||||
cursor->setImage(getCurrentImage(), getPivotOffset());
|
||||
}
|
||||
|
||||
void CursorHandler::set(Cursor::Default index)
|
||||
{
|
||||
changeGraphic(Cursor::Type::DEFAULT, static_cast<size_t>(index));
|
||||
}
|
||||
|
||||
void CursorHandler::set(Cursor::Map index)
|
||||
{
|
||||
changeGraphic(Cursor::Type::ADVENTURE, static_cast<size_t>(index));
|
||||
}
|
||||
|
||||
void CursorHandler::set(Cursor::Combat index)
|
||||
{
|
||||
changeGraphic(Cursor::Type::COMBAT, static_cast<size_t>(index));
|
||||
}
|
||||
|
||||
void CursorHandler::set(Cursor::Spellcast index)
|
||||
{
|
||||
//Note: this is animated cursor, ignore specified frame and only change type
|
||||
changeGraphic(Cursor::Type::SPELLBOOK, frame);
|
||||
}
|
||||
|
||||
void CursorHandler::dragAndDropCursor(std::shared_ptr<IImage> image)
|
||||
{
|
||||
dndObject = image;
|
||||
cursor->setImage(getCurrentImage(), getPivotOffset());
|
||||
}
|
||||
|
||||
void CursorHandler::dragAndDropCursor (std::string path, size_t index)
|
||||
{
|
||||
CAnimation anim(path);
|
||||
anim.load(index);
|
||||
dragAndDropCursor(anim.getImage(index));
|
||||
}
|
||||
|
||||
void CursorHandler::cursorMove(const int & x, const int & y)
|
||||
{
|
||||
pos.x = x;
|
||||
pos.y = y;
|
||||
|
||||
cursor->setCursorPosition(pos);
|
||||
}
|
||||
|
||||
Point CursorHandler::getPivotOffsetDefault(size_t index)
|
||||
{
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
Point CursorHandler::getPivotOffsetMap(size_t index)
|
||||
{
|
||||
static const std::array<Point, 43> offsets = {{
|
||||
{ 0, 0}, // POINTER = 0,
|
||||
{ 0, 0}, // HOURGLASS = 1,
|
||||
{ 12, 10}, // HERO = 2,
|
||||
{ 12, 12}, // TOWN = 3,
|
||||
|
||||
{ 15, 13}, // T1_MOVE = 4,
|
||||
{ 13, 13}, // T1_ATTACK = 5,
|
||||
{ 16, 32}, // T1_SAIL = 6,
|
||||
{ 13, 20}, // T1_DISEMBARK = 7,
|
||||
{ 8, 9}, // T1_EXCHANGE = 8,
|
||||
{ 14, 16}, // T1_VISIT = 9,
|
||||
|
||||
{ 15, 13}, // T2_MOVE = 10,
|
||||
{ 13, 13}, // T2_ATTACK = 11,
|
||||
{ 16, 32}, // T2_SAIL = 12,
|
||||
{ 13, 20}, // T2_DISEMBARK = 13,
|
||||
{ 8, 9}, // T2_EXCHANGE = 14,
|
||||
{ 14, 16}, // T2_VISIT = 15,
|
||||
|
||||
{ 15, 13}, // T3_MOVE = 16,
|
||||
{ 13, 13}, // T3_ATTACK = 17,
|
||||
{ 16, 32}, // T3_SAIL = 18,
|
||||
{ 13, 20}, // T3_DISEMBARK = 19,
|
||||
{ 8, 9}, // T3_EXCHANGE = 20,
|
||||
{ 14, 16}, // T3_VISIT = 21,
|
||||
|
||||
{ 15, 13}, // T4_MOVE = 22,
|
||||
{ 13, 13}, // T4_ATTACK = 23,
|
||||
{ 16, 32}, // T4_SAIL = 24,
|
||||
{ 13, 20}, // T4_DISEMBARK = 25,
|
||||
{ 8, 9}, // T4_EXCHANGE = 26,
|
||||
{ 14, 16}, // T4_VISIT = 27,
|
||||
|
||||
{ 16, 32}, // T1_SAIL_VISIT = 28,
|
||||
{ 16, 32}, // T2_SAIL_VISIT = 29,
|
||||
{ 16, 32}, // T3_SAIL_VISIT = 30,
|
||||
{ 16, 32}, // T4_SAIL_VISIT = 31,
|
||||
|
||||
{ 6, 1}, // SCROLL_NORTH = 32,
|
||||
{ 16, 2}, // SCROLL_NORTHEAST = 33,
|
||||
{ 21, 6}, // SCROLL_EAST = 34,
|
||||
{ 16, 16}, // SCROLL_SOUTHEAST = 35,
|
||||
{ 6, 21}, // SCROLL_SOUTH = 36,
|
||||
{ 1, 16}, // SCROLL_SOUTHWEST = 37,
|
||||
{ 1, 5}, // SCROLL_WEST = 38,
|
||||
{ 2, 1}, // SCROLL_NORTHWEST = 39,
|
||||
|
||||
{ 0, 0}, // POINTER_COPY = 40,
|
||||
{ 14, 16}, // TELEPORT = 41,
|
||||
{ 20, 20}, // SCUTTLE_BOAT = 42
|
||||
}};
|
||||
|
||||
assert(offsets.size() == size_t(Cursor::Map::COUNT)); //Invalid number of pivot offsets for cursor
|
||||
assert(index < offsets.size());
|
||||
return offsets[index];
|
||||
}
|
||||
|
||||
Point CursorHandler::getPivotOffsetCombat(size_t index)
|
||||
{
|
||||
static const std::array<Point, 20> offsets = {{
|
||||
{ 12, 12 }, // BLOCKED = 0,
|
||||
{ 10, 14 }, // MOVE = 1,
|
||||
{ 14, 14 }, // FLY = 2,
|
||||
{ 12, 12 }, // SHOOT = 3,
|
||||
{ 12, 12 }, // HERO = 4,
|
||||
{ 8, 12 }, // QUERY = 5,
|
||||
{ 0, 0 }, // POINTER = 6,
|
||||
{ 21, 0 }, // HIT_NORTHEAST = 7,
|
||||
{ 31, 5 }, // HIT_EAST = 8,
|
||||
{ 21, 21 }, // HIT_SOUTHEAST = 9,
|
||||
{ 0, 21 }, // HIT_SOUTHWEST = 10,
|
||||
{ 0, 5 }, // HIT_WEST = 11,
|
||||
{ 0, 0 }, // HIT_NORTHWEST = 12,
|
||||
{ 6, 0 }, // HIT_NORTH = 13,
|
||||
{ 6, 31 }, // HIT_SOUTH = 14,
|
||||
{ 14, 0 }, // SHOOT_PENALTY = 15,
|
||||
{ 12, 12 }, // SHOOT_CATAPULT = 16,
|
||||
{ 12, 12 }, // HEAL = 17,
|
||||
{ 12, 12 }, // SACRIFICE = 18,
|
||||
{ 14, 20 }, // TELEPORT = 19
|
||||
}};
|
||||
|
||||
assert(offsets.size() == size_t(Cursor::Combat::COUNT)); //Invalid number of pivot offsets for cursor
|
||||
assert(index < offsets.size());
|
||||
return offsets[index];
|
||||
}
|
||||
|
||||
Point CursorHandler::getPivotOffsetSpellcast()
|
||||
{
|
||||
return { 18, 28};
|
||||
}
|
||||
|
||||
Point CursorHandler::getPivotOffset()
|
||||
{
|
||||
if (dndObject)
|
||||
return dndObject->dimensions() / 2;
|
||||
|
||||
switch (type) {
|
||||
case Cursor::Type::ADVENTURE: return getPivotOffsetMap(frame);
|
||||
case Cursor::Type::COMBAT: return getPivotOffsetCombat(frame);
|
||||
case Cursor::Type::DEFAULT: return getPivotOffsetDefault(frame);
|
||||
case Cursor::Type::SPELLBOOK: return getPivotOffsetSpellcast();
|
||||
};
|
||||
|
||||
assert(0);
|
||||
return {0, 0};
|
||||
}
|
||||
|
||||
std::shared_ptr<IImage> CursorHandler::getCurrentImage()
|
||||
{
|
||||
if (dndObject)
|
||||
return dndObject;
|
||||
|
||||
return cursors[static_cast<size_t>(type)]->getImage(frame);
|
||||
}
|
||||
|
||||
void CursorHandler::centerCursor()
|
||||
{
|
||||
Point screenSize {screen->w, screen->h};
|
||||
pos = screenSize / 2 - getPivotOffset();
|
||||
|
||||
SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
|
||||
CSDL_Ext::warpMouse(pos.x, pos.y);
|
||||
SDL_EventState(SDL_MOUSEMOTION, SDL_ENABLE);
|
||||
|
||||
cursor->setCursorPosition(pos);
|
||||
}
|
||||
|
||||
void CursorHandler::updateSpellcastCursor()
|
||||
{
|
||||
static const float frameDisplayDuration = 0.1f;
|
||||
|
||||
frameTime += GH.mainFPSmng->getElapsedMilliseconds() / 1000.f;
|
||||
size_t newFrame = frame;
|
||||
|
||||
while (frameTime >= frameDisplayDuration)
|
||||
{
|
||||
frameTime -= frameDisplayDuration;
|
||||
newFrame++;
|
||||
}
|
||||
|
||||
auto & animation = cursors.at(static_cast<size_t>(type));
|
||||
|
||||
while (newFrame >= animation->size())
|
||||
newFrame -= animation->size();
|
||||
|
||||
changeGraphic(Cursor::Type::SPELLBOOK, newFrame);
|
||||
}
|
||||
|
||||
void CursorHandler::render()
|
||||
{
|
||||
if(!showing)
|
||||
return;
|
||||
|
||||
if (type == Cursor::Type::SPELLBOOK)
|
||||
updateSpellcastCursor();
|
||||
|
||||
cursor->render();
|
||||
}
|
||||
|
||||
void CursorHandler::hide()
|
||||
{
|
||||
if (!showing)
|
||||
return;
|
||||
|
||||
showing = false;
|
||||
cursor->setVisible(false);
|
||||
}
|
||||
|
||||
void CursorHandler::show()
|
||||
{
|
||||
if (showing)
|
||||
return;
|
||||
|
||||
showing = true;
|
||||
cursor->setVisible(true);
|
||||
}
|
||||
|
||||
void CursorSoftware::render()
|
||||
{
|
||||
//texture must be updated in the main (renderer) thread, but changes to cursor type may come from other threads
|
||||
if (needUpdate)
|
||||
updateTexture();
|
||||
|
||||
Point renderPos = pos - pivot;
|
||||
|
||||
SDL_Rect destRect;
|
||||
destRect.x = renderPos.x;
|
||||
destRect.y = renderPos.y;
|
||||
destRect.w = 40;
|
||||
destRect.h = 40;
|
||||
|
||||
SDL_RenderCopy(mainRenderer, cursorTexture, nullptr, &destRect);
|
||||
}
|
||||
|
||||
void CursorSoftware::createTexture(const Point & dimensions)
|
||||
{
|
||||
if(cursorTexture)
|
||||
SDL_DestroyTexture(cursorTexture);
|
||||
|
||||
if (cursorSurface)
|
||||
SDL_FreeSurface(cursorSurface);
|
||||
|
||||
cursorSurface = CSDL_Ext::newSurface(dimensions.x, dimensions.y);
|
||||
cursorTexture = SDL_CreateTexture(mainRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, dimensions.x, dimensions.y);
|
||||
|
||||
SDL_SetSurfaceBlendMode(cursorSurface, SDL_BLENDMODE_NONE);
|
||||
SDL_SetTextureBlendMode(cursorTexture, SDL_BLENDMODE_BLEND);
|
||||
}
|
||||
|
||||
void CursorSoftware::updateTexture()
|
||||
{
|
||||
Point dimensions(-1, -1);
|
||||
|
||||
if (!cursorSurface || Point(cursorSurface->w, cursorSurface->h) != cursorImage->dimensions())
|
||||
createTexture(cursorImage->dimensions());
|
||||
|
||||
CSDL_Ext::fillSurface(cursorSurface, Colors::TRANSPARENCY);
|
||||
|
||||
cursorImage->draw(cursorSurface);
|
||||
SDL_UpdateTexture(cursorTexture, NULL, cursorSurface->pixels, cursorSurface->pitch);
|
||||
needUpdate = false;
|
||||
}
|
||||
|
||||
void CursorSoftware::setImage(std::shared_ptr<IImage> image, const Point & pivotOffset)
|
||||
{
|
||||
assert(image != nullptr);
|
||||
cursorImage = image;
|
||||
pivot = pivotOffset;
|
||||
needUpdate = true;
|
||||
}
|
||||
|
||||
void CursorSoftware::setCursorPosition( const Point & newPos )
|
||||
{
|
||||
pos = newPos;
|
||||
}
|
||||
|
||||
void CursorSoftware::setVisible(bool on)
|
||||
{
|
||||
visible = on;
|
||||
}
|
||||
|
||||
CursorSoftware::CursorSoftware():
|
||||
cursorTexture(nullptr),
|
||||
cursorSurface(nullptr),
|
||||
needUpdate(false),
|
||||
visible(false),
|
||||
pivot(0,0)
|
||||
{
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
}
|
||||
|
||||
CursorSoftware::~CursorSoftware()
|
||||
{
|
||||
if(cursorTexture)
|
||||
SDL_DestroyTexture(cursorTexture);
|
||||
|
||||
if (cursorSurface)
|
||||
SDL_FreeSurface(cursorSurface);
|
||||
}
|
||||
|
||||
CursorHardware::CursorHardware():
|
||||
cursor(nullptr)
|
||||
{
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
}
|
||||
|
||||
CursorHardware::~CursorHardware()
|
||||
{
|
||||
if(cursor)
|
||||
SDL_FreeCursor(cursor);
|
||||
}
|
||||
|
||||
void CursorHardware::setVisible(bool on)
|
||||
{
|
||||
if (on)
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
else
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
}
|
||||
|
||||
void CursorHardware::setImage(std::shared_ptr<IImage> image, const Point & pivotOffset)
|
||||
{
|
||||
auto cursorSurface = CSDL_Ext::newSurface(image->dimensions().x, image->dimensions().y);
|
||||
|
||||
CSDL_Ext::fillSurface(cursorSurface, Colors::TRANSPARENCY);
|
||||
|
||||
image->draw(cursorSurface);
|
||||
|
||||
auto oldCursor = cursor;
|
||||
cursor = SDL_CreateColorCursor(cursorSurface, pivotOffset.x, pivotOffset.y);
|
||||
|
||||
if (!cursor)
|
||||
logGlobal->error("Failed to set cursor! SDL says %s", SDL_GetError());
|
||||
|
||||
SDL_FreeSurface(cursorSurface);
|
||||
SDL_SetCursor(cursor);
|
||||
|
||||
if (oldCursor)
|
||||
SDL_FreeCursor(oldCursor);
|
||||
}
|
||||
|
||||
void CursorHardware::setCursorPosition( const Point & newPos )
|
||||
{
|
||||
//no-op
|
||||
}
|
||||
|
||||
void CursorHardware::render()
|
||||
{
|
||||
//no-op
|
||||
}
|
@ -8,11 +8,14 @@
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
class CIntObject;
|
||||
class CAnimImage;
|
||||
|
||||
class CAnimation;
|
||||
class IImage;
|
||||
struct SDL_Surface;
|
||||
struct SDL_Texture;
|
||||
struct Point;
|
||||
struct SDL_Cursor;
|
||||
|
||||
#include "../../lib/Point.h"
|
||||
|
||||
namespace Cursor
|
||||
{
|
||||
@ -51,7 +54,9 @@ namespace Cursor
|
||||
SHOOT_CATAPULT = 16,
|
||||
HEAL = 17,
|
||||
SACRIFICE = 18,
|
||||
TELEPORT = 19
|
||||
TELEPORT = 19,
|
||||
|
||||
COUNT
|
||||
};
|
||||
|
||||
enum class Map {
|
||||
@ -97,7 +102,9 @@ namespace Cursor
|
||||
SCROLL_NORTHWEST = 39,
|
||||
//POINTER_COPY = 40, // probably unused
|
||||
TELEPORT = 41,
|
||||
SCUTTLE_BOAT = 42
|
||||
SCUTTLE_BOAT = 42,
|
||||
|
||||
COUNT
|
||||
};
|
||||
|
||||
enum class Spellcast {
|
||||
@ -105,49 +112,96 @@ namespace Cursor
|
||||
};
|
||||
}
|
||||
|
||||
/// handles mouse cursor
|
||||
class CCursorHandler final
|
||||
class ICursor
|
||||
{
|
||||
public:
|
||||
virtual ~ICursor() = default;
|
||||
|
||||
virtual void setImage(std::shared_ptr<IImage> image, const Point & pivotOffset) = 0;
|
||||
virtual void setCursorPosition( const Point & newPos ) = 0;
|
||||
virtual void render() = 0;
|
||||
virtual void setVisible( bool on) = 0;
|
||||
};
|
||||
|
||||
class CursorHardware : public ICursor
|
||||
{
|
||||
std::shared_ptr<IImage> cursorImage;
|
||||
|
||||
SDL_Cursor * cursor;
|
||||
|
||||
public:
|
||||
CursorHardware();
|
||||
~CursorHardware();
|
||||
|
||||
void setImage(std::shared_ptr<IImage> image, const Point & pivotOffset) override;
|
||||
void setCursorPosition( const Point & newPos ) override;
|
||||
void render() override;
|
||||
void setVisible( bool on) override;
|
||||
};
|
||||
|
||||
class CursorSoftware : public ICursor
|
||||
{
|
||||
std::shared_ptr<IImage> cursorImage;
|
||||
|
||||
SDL_Texture * cursorTexture;
|
||||
SDL_Surface * cursorSurface;
|
||||
|
||||
Point pos;
|
||||
Point pivot;
|
||||
bool needUpdate;
|
||||
SDL_Texture * cursorLayer;
|
||||
bool visible;
|
||||
|
||||
SDL_Surface * buffer;
|
||||
CAnimImage * currentCursor;
|
||||
void createTexture(const Point & dimensions);
|
||||
void updateTexture();
|
||||
public:
|
||||
CursorSoftware();
|
||||
~CursorSoftware();
|
||||
|
||||
std::unique_ptr<CAnimImage> dndObject; //if set, overrides currentCursor
|
||||
void setImage(std::shared_ptr<IImage> image, const Point & pivotOffset) override;
|
||||
void setCursorPosition( const Point & newPos ) override;
|
||||
void render() override;
|
||||
void setVisible( bool on) override;
|
||||
};
|
||||
|
||||
std::array<std::unique_ptr<CAnimImage>, 4> cursors;
|
||||
/// handles mouse cursor
|
||||
class CursorHandler final
|
||||
{
|
||||
std::shared_ptr<IImage> dndObject; //if set, overrides currentCursor
|
||||
|
||||
std::array<std::unique_ptr<CAnimation>, 4> cursors;
|
||||
|
||||
bool showing;
|
||||
|
||||
void clearBuffer();
|
||||
void updateBuffer(CIntObject * payload);
|
||||
void replaceBuffer(CIntObject * payload);
|
||||
void shiftPos( int &x, int &y );
|
||||
|
||||
void updateTexture();
|
||||
|
||||
/// Current cursor
|
||||
Cursor::Type type;
|
||||
size_t frame;
|
||||
float frameTime;
|
||||
Point pos;
|
||||
|
||||
void changeGraphic(Cursor::Type type, size_t index);
|
||||
|
||||
/// position of cursor
|
||||
int xpos, ypos;
|
||||
Point getPivotOffsetDefault(size_t index);
|
||||
Point getPivotOffsetMap(size_t index);
|
||||
Point getPivotOffsetCombat(size_t index);
|
||||
Point getPivotOffsetSpellcast();
|
||||
Point getPivotOffset();
|
||||
|
||||
void updateSpellcastCursor();
|
||||
|
||||
std::shared_ptr<IImage> getCurrentImage();
|
||||
|
||||
std::unique_ptr<ICursor> cursor;
|
||||
|
||||
static std::unique_ptr<ICursor> createCursor();
|
||||
public:
|
||||
CCursorHandler();
|
||||
~CCursorHandler();
|
||||
CursorHandler();
|
||||
~CursorHandler();
|
||||
|
||||
/**
|
||||
* Replaces the cursor with a custom image.
|
||||
*
|
||||
* @param image Image to replace cursor with or nullptr to use the normal
|
||||
* cursor. CursorHandler takes ownership of object
|
||||
*/
|
||||
void dragAndDropCursor (std::unique_ptr<CAnimImage> image);
|
||||
/// Replaces the cursor with a custom image.
|
||||
/// @param image Image to replace cursor with or nullptr to use the normal cursor.
|
||||
void dragAndDropCursor(std::shared_ptr<IImage> image);
|
||||
|
||||
void dragAndDropCursor(std::string path, size_t index);
|
||||
|
||||
/// Returns current position of the cursor
|
||||
Point position() const;
|
||||
@ -172,8 +226,8 @@ public:
|
||||
|
||||
void render();
|
||||
|
||||
void hide() { showing=false; };
|
||||
void show() { showing=true; };
|
||||
void hide();
|
||||
void show();
|
||||
|
||||
/// change cursor's positions to (x, y)
|
||||
void cursorMove(const int & x, const int & y);
|
@ -130,11 +130,11 @@ size_t CBitmapFont::getGlyphWidth(const char * data) const
|
||||
void CBitmapFont::renderCharacter(SDL_Surface * surface, const BitmapChar & character, const SDL_Color & color, int &posX, int &posY) const
|
||||
{
|
||||
Rect clipRect;
|
||||
SDL_GetClipRect(surface, &clipRect);
|
||||
CSDL_Ext::getClipRect(surface, clipRect);
|
||||
|
||||
posX += character.leftOffset;
|
||||
|
||||
TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface, 0);
|
||||
CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface, 0);
|
||||
|
||||
Uint8 bpp = surface->format->BytesPerPixel;
|
||||
|
||||
@ -270,7 +270,7 @@ void CTrueTypeFont::renderText(SDL_Surface * surface, const std::string & data,
|
||||
if (color.r != 0 && color.g != 0 && color.b != 0) // not black - add shadow
|
||||
{
|
||||
SDL_Color black = { 0, 0, 0, SDL_ALPHA_OPAQUE};
|
||||
renderText(surface, data, black, Point(pos.x + 1, pos.y + 1));
|
||||
renderText(surface, data, black, pos + Point(1,1));
|
||||
}
|
||||
|
||||
if (!data.empty())
|
||||
@ -283,8 +283,7 @@ void CTrueTypeFont::renderText(SDL_Surface * surface, const std::string & data,
|
||||
|
||||
assert(rendered);
|
||||
|
||||
Rect rect(pos.x, pos.y, rendered->w, rendered->h);
|
||||
SDL_BlitSurface(rendered, nullptr, surface, &rect);
|
||||
CSDL_Ext::blitSurface(rendered, surface, pos);
|
||||
SDL_FreeSurface(rendered);
|
||||
}
|
||||
}
|
||||
@ -308,9 +307,9 @@ void CBitmapHanFont::renderCharacter(SDL_Surface * surface, int characterIndex,
|
||||
{
|
||||
//TODO: somewhat duplicated with CBitmapFont::renderCharacter();
|
||||
Rect clipRect;
|
||||
SDL_GetClipRect(surface, &clipRect);
|
||||
CSDL_Ext::getClipRect(surface, clipRect);
|
||||
|
||||
TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface, 0);
|
||||
CSDL_Ext::TColorPutter colorPutter = CSDL_Ext::getPutterFor(surface, 0);
|
||||
Uint8 bpp = surface->format->BytesPerPixel;
|
||||
|
||||
// start of line, may differ from 0 due to end of surface or clipped surface
|
||||
|
@ -12,10 +12,10 @@
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class JsonNode;
|
||||
class Point;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
struct Point;
|
||||
struct SDL_Surface;
|
||||
struct SDL_Color;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user