mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-24 08:32:34 +02:00
Merge branch 'develop' into regions
This commit is contained in:
commit
d2e24e01b4
@ -93,6 +93,8 @@ int64_t DamageCache::getOriginalDamage(const battle::Unit * attacker, const batt
|
||||
AttackPossibility::AttackPossibility(BattleHex from, BattleHex dest, const BattleAttackInfo & attack)
|
||||
: from(from), dest(dest), attack(attack)
|
||||
{
|
||||
this->attack.attackerPos = from;
|
||||
this->attack.defenderPos = dest;
|
||||
}
|
||||
|
||||
float AttackPossibility::damageDiff() const
|
||||
@ -261,63 +263,105 @@ AttackPossibility AttackPossibility::evaluate(
|
||||
if (!attackInfo.shooting)
|
||||
ap.attackerState->setPosition(hex);
|
||||
|
||||
std::vector<const battle::Unit*> units;
|
||||
std::vector<const battle::Unit *> defenderUnits;
|
||||
std::vector<const battle::Unit *> retaliatedUnits = {attacker};
|
||||
std::vector<const battle::Unit *> affectedUnits;
|
||||
|
||||
if (attackInfo.shooting)
|
||||
units = state->getAttackedBattleUnits(attacker, defHex, true, BattleHex::INVALID);
|
||||
defenderUnits = state->getAttackedBattleUnits(attacker, defender, defHex, true, hex, defender->getPosition());
|
||||
else
|
||||
units = state->getAttackedBattleUnits(attacker, defHex, false, hex);
|
||||
|
||||
// ensure the defender is also affected
|
||||
bool addDefender = true;
|
||||
for(auto unit : units)
|
||||
{
|
||||
if (unit->unitId() == defender->unitId())
|
||||
defenderUnits = state->getAttackedBattleUnits(attacker, defender, defHex, false, hex, defender->getPosition());
|
||||
retaliatedUnits = state->getAttackedBattleUnits(defender, attacker, hex, false, defender->getPosition(), hex);
|
||||
|
||||
// attacker can not melle-attack itself but still can hit that place where it was before moving
|
||||
vstd::erase_if(defenderUnits, [attacker](const battle::Unit * u) -> bool { return u->unitId() == attacker->unitId(); });
|
||||
|
||||
if(!vstd::contains_if(retaliatedUnits, [attacker](const battle::Unit * u) -> bool { return u->unitId() == attacker->unitId(); }))
|
||||
{
|
||||
addDefender = false;
|
||||
break;
|
||||
retaliatedUnits.push_back(attacker);
|
||||
}
|
||||
}
|
||||
|
||||
if(addDefender)
|
||||
units.push_back(defender);
|
||||
|
||||
for(auto u : units)
|
||||
// ensure the defender is also affected
|
||||
if(!vstd::contains_if(defenderUnits, [defender](const battle::Unit * u) -> bool { return u->unitId() == defender->unitId(); }))
|
||||
{
|
||||
if(!ap.attackerState->alive())
|
||||
break;
|
||||
defenderUnits.push_back(defender);
|
||||
}
|
||||
|
||||
affectedUnits = defenderUnits;
|
||||
vstd::concatenate(affectedUnits, retaliatedUnits);
|
||||
|
||||
logAi->trace("Attacked battle units count %d, %d->%d", affectedUnits.size(), hex.hex, defHex.hex);
|
||||
|
||||
std::map<uint32_t, std::shared_ptr<battle::CUnitState>> defenderStates;
|
||||
|
||||
for(auto u : affectedUnits)
|
||||
{
|
||||
if(u->unitId() == attacker->unitId())
|
||||
continue;
|
||||
|
||||
auto defenderState = u->acquireState();
|
||||
ap.affectedUnits.push_back(defenderState);
|
||||
|
||||
for(int i = 0; i < totalAttacks; i++)
|
||||
ap.affectedUnits.push_back(defenderState);
|
||||
defenderStates[u->unitId()] = defenderState;
|
||||
}
|
||||
|
||||
for(int i = 0; i < totalAttacks; i++)
|
||||
{
|
||||
if(!ap.attackerState->alive() || !defenderStates[defender->unitId()]->alive())
|
||||
break;
|
||||
|
||||
for(auto u : defenderUnits)
|
||||
{
|
||||
auto defenderState = defenderStates.at(u->unitId());
|
||||
|
||||
int64_t damageDealt;
|
||||
int64_t damageReceived;
|
||||
float defenderDamageReduce;
|
||||
float attackerDamageReduce;
|
||||
|
||||
DamageEstimation retaliation;
|
||||
auto attackDmg = state->battleEstimateDamage(ap.attack, &retaliation);
|
||||
|
||||
vstd::amin(attackDmg.damage.min, defenderState->getAvailableHealth());
|
||||
vstd::amin(attackDmg.damage.max, defenderState->getAvailableHealth());
|
||||
|
||||
vstd::amin(retaliation.damage.min, ap.attackerState->getAvailableHealth());
|
||||
vstd::amin(retaliation.damage.max, ap.attackerState->getAvailableHealth());
|
||||
|
||||
damageDealt = averageDmg(attackDmg.damage);
|
||||
defenderDamageReduce = calculateDamageReduce(attacker, defender, damageDealt, damageCache, state);
|
||||
vstd::amin(damageDealt, defenderState->getAvailableHealth());
|
||||
|
||||
defenderDamageReduce = calculateDamageReduce(attacker, u, damageDealt, damageCache, state);
|
||||
ap.attackerState->afterAttack(attackInfo.shooting, false);
|
||||
|
||||
//FIXME: use ranged retaliation
|
||||
damageReceived = 0;
|
||||
attackerDamageReduce = 0;
|
||||
|
||||
if (!attackInfo.shooting && defenderState->ableToRetaliate() && !counterAttacksBlocked)
|
||||
if (!attackInfo.shooting && u->unitId() == defender->unitId() && defenderState->ableToRetaliate() && !counterAttacksBlocked)
|
||||
{
|
||||
damageReceived = averageDmg(retaliation.damage);
|
||||
attackerDamageReduce = calculateDamageReduce(defender, attacker, damageReceived, damageCache, state);
|
||||
for(auto retaliated : retaliatedUnits)
|
||||
{
|
||||
if(retaliated->unitId() == attacker->unitId())
|
||||
{
|
||||
int64_t damageReceived = averageDmg(retaliation.damage);
|
||||
|
||||
vstd::amin(damageReceived, ap.attackerState->getAvailableHealth());
|
||||
|
||||
attackerDamageReduce = calculateDamageReduce(defender, retaliated, damageReceived, damageCache, state);
|
||||
ap.attackerState->damage(damageReceived);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto retaliationCollateral = state->battleEstimateDamage(defender, retaliated, 0);
|
||||
int64_t damageReceived = averageDmg(retaliationCollateral.damage);
|
||||
|
||||
vstd::amin(damageReceived, retaliated->getAvailableHealth());
|
||||
|
||||
if(defender->unitSide() == retaliated->unitSide())
|
||||
defenderDamageReduce += calculateDamageReduce(defender, retaliated, damageReceived, damageCache, state);
|
||||
else
|
||||
ap.collateralDamageReduce += calculateDamageReduce(defender, retaliated, damageReceived, damageCache, state);
|
||||
|
||||
defenderStates.at(retaliated->unitId())->damage(damageReceived);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
defenderState->afterAttack(attackInfo.shooting, true);
|
||||
}
|
||||
|
||||
@ -331,21 +375,30 @@ AttackPossibility AttackPossibility::evaluate(
|
||||
if(attackerSide == u->unitSide())
|
||||
ap.collateralDamageReduce += defenderDamageReduce;
|
||||
|
||||
if(u->unitId() == defender->unitId() ||
|
||||
(!attackInfo.shooting && CStack::isMeleeAttackPossible(u, attacker, hex)))
|
||||
if(u->unitId() == defender->unitId()
|
||||
|| (!attackInfo.shooting && CStack::isMeleeAttackPossible(u, attacker, hex)))
|
||||
{
|
||||
//FIXME: handle RANGED_RETALIATION ?
|
||||
ap.attackerDamageReduce += attackerDamageReduce;
|
||||
}
|
||||
|
||||
ap.attackerState->damage(damageReceived);
|
||||
defenderState->damage(damageDealt);
|
||||
|
||||
if (!ap.attackerState->alive() || !defenderState->alive())
|
||||
break;
|
||||
if(u->unitId() == defender->unitId())
|
||||
{
|
||||
ap.defenderDead = !defenderState->alive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if BATTLE_TRACE_LEVEL>=2
|
||||
logAi->trace("BattleAI AP: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld",
|
||||
attackInfo.attacker->unitType()->getJsonKey(),
|
||||
attackInfo.defender->unitType()->getJsonKey(),
|
||||
(int)ap.dest, (int)ap.from, (int)ap.affectedUnits.size(),
|
||||
ap.defenderDamageReduce, ap.attackerDamageReduce, ap.collateralDamageReduce, ap.shootersBlockedDmg);
|
||||
#endif
|
||||
|
||||
if(!bestAp.dest.isValid() || ap.attackValue() > bestAp.attackValue())
|
||||
bestAp = ap;
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ public:
|
||||
float attackerDamageReduce = 0; //usually by counter-attack
|
||||
float collateralDamageReduce = 0; // friendly fire (usually by two-hex attacks)
|
||||
int64_t shootersBlockedDmg = 0;
|
||||
bool defenderDead = false;
|
||||
|
||||
AttackPossibility(BattleHex from, BattleHex dest, const BattleAttackInfo & attack_);
|
||||
|
||||
|
@ -189,7 +189,7 @@ BattleAction BattleEvaluator::selectStackAction(const CStack * stack)
|
||||
else
|
||||
{
|
||||
activeActionMade = true;
|
||||
return BattleAction::makeMeleeAttack(stack, bestAttack.attack.defender->getPosition(), bestAttack.from);
|
||||
return BattleAction::makeMeleeAttack(stack, bestAttack.attack.defenderPos, bestAttack.from);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,100 +30,89 @@ float BattleExchangeVariant::trackAttack(
|
||||
{
|
||||
auto attacker = hb->getForUpdate(ap.attack.attacker->unitId());
|
||||
|
||||
const std::string cachingStringBlocksRetaliation = "type_BLOCKS_RETALIATION";
|
||||
static const auto selectorBlocksRetaliation = Selector::type()(BonusType::BLOCKS_RETALIATION);
|
||||
const bool counterAttacksBlocked = attacker->hasBonus(selectorBlocksRetaliation, cachingStringBlocksRetaliation);
|
||||
|
||||
float attackValue = 0;
|
||||
float attackValue = ap.attackValue();
|
||||
auto affectedUnits = ap.affectedUnits;
|
||||
|
||||
dpsScore.ourDamageReduce += ap.attackerDamageReduce + ap.collateralDamageReduce;
|
||||
dpsScore.enemyDamageReduce += ap.defenderDamageReduce + ap.shootersBlockedDmg;
|
||||
attackerValue[attacker->unitId()].value = attackValue;
|
||||
|
||||
affectedUnits.push_back(ap.attackerState);
|
||||
|
||||
for(auto affectedUnit : affectedUnits)
|
||||
{
|
||||
auto unitToUpdate = hb->getForUpdate(affectedUnit->unitId());
|
||||
auto damageDealt = unitToUpdate->getTotalHealth() - affectedUnit->getTotalHealth();
|
||||
|
||||
if(damageDealt > 0)
|
||||
{
|
||||
unitToUpdate->damage(damageDealt);
|
||||
}
|
||||
|
||||
if(unitToUpdate->unitSide() == attacker->unitSide())
|
||||
{
|
||||
if(unitToUpdate->unitId() == attacker->unitId())
|
||||
{
|
||||
auto defender = hb->getForUpdate(ap.attack.defender->unitId());
|
||||
|
||||
if(!defender->alive() || counterAttacksBlocked || ap.attack.shooting || !defender->ableToRetaliate())
|
||||
continue;
|
||||
|
||||
auto retaliationDamage = damageCache.getDamage(defender.get(), unitToUpdate.get(), hb);
|
||||
auto attackerDamageReduce = AttackPossibility::calculateDamageReduce(defender.get(), unitToUpdate.get(), retaliationDamage, damageCache, hb);
|
||||
|
||||
attackValue -= attackerDamageReduce;
|
||||
dpsScore.ourDamageReduce += attackerDamageReduce;
|
||||
attackerValue[unitToUpdate->unitId()].isRetaliated = true;
|
||||
|
||||
unitToUpdate->damage(retaliationDamage);
|
||||
defender->afterAttack(false, true);
|
||||
unitToUpdate->afterAttack(ap.attack.shooting, false);
|
||||
|
||||
#if BATTLE_TRACE_LEVEL>=1
|
||||
logAi->trace(
|
||||
"%s -> %s, ap retaliation, %s, dps: %2f, score: %2f",
|
||||
defender->getDescription(),
|
||||
unitToUpdate->getDescription(),
|
||||
"%s -> %s, ap retaliation, %s, dps: %lld",
|
||||
ap.attack.defender->getDescription(),
|
||||
ap.attack.attacker->getDescription(),
|
||||
ap.attack.shooting ? "shot" : "mellee",
|
||||
retaliationDamage,
|
||||
attackerDamageReduce);
|
||||
damageDealt);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
auto collateralDamage = damageCache.getDamage(attacker.get(), unitToUpdate.get(), hb);
|
||||
auto collateralDamageReduce = AttackPossibility::calculateDamageReduce(attacker.get(), unitToUpdate.get(), collateralDamage, damageCache, hb);
|
||||
|
||||
attackValue -= collateralDamageReduce;
|
||||
dpsScore.ourDamageReduce += collateralDamageReduce;
|
||||
|
||||
unitToUpdate->damage(collateralDamage);
|
||||
|
||||
#if BATTLE_TRACE_LEVEL>=1
|
||||
logAi->trace(
|
||||
"%s -> %s, ap collateral, %s, dps: %2f, score: %2f",
|
||||
attacker->getDescription(),
|
||||
"%s, ap collateral, dps: %lld",
|
||||
unitToUpdate->getDescription(),
|
||||
ap.attack.shooting ? "shot" : "mellee",
|
||||
collateralDamage,
|
||||
collateralDamageReduce);
|
||||
damageDealt);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int64_t attackDamage = damageCache.getDamage(attacker.get(), unitToUpdate.get(), hb);
|
||||
float defenderDamageReduce = AttackPossibility::calculateDamageReduce(attacker.get(), unitToUpdate.get(), attackDamage, damageCache, hb);
|
||||
|
||||
attackValue += defenderDamageReduce;
|
||||
dpsScore.enemyDamageReduce += defenderDamageReduce;
|
||||
attackerValue[attacker->unitId()].value += defenderDamageReduce;
|
||||
|
||||
unitToUpdate->damage(attackDamage);
|
||||
if(unitToUpdate->unitId() == ap.attack.defender->unitId())
|
||||
{
|
||||
if(unitToUpdate->ableToRetaliate() && !affectedUnit->ableToRetaliate())
|
||||
{
|
||||
unitToUpdate->afterAttack(ap.attack.shooting, true);
|
||||
}
|
||||
|
||||
#if BATTLE_TRACE_LEVEL>=1
|
||||
logAi->trace(
|
||||
"%s -> %s, ap attack, %s, dps: %2f, score: %2f",
|
||||
attacker->getDescription(),
|
||||
unitToUpdate->getDescription(),
|
||||
ap.attack.shooting ? "shot" : "mellee",
|
||||
attackDamage,
|
||||
defenderDamageReduce);
|
||||
logAi->trace(
|
||||
"%s -> %s, ap attack, %s, dps: %lld",
|
||||
attacker->getDescription(),
|
||||
ap.attack.defender->getDescription(),
|
||||
ap.attack.shooting ? "shot" : "mellee",
|
||||
damageDealt);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if BATTLE_TRACE_LEVEL>=1
|
||||
logAi->trace(
|
||||
"%s, ap enemy collateral, dps: %lld",
|
||||
unitToUpdate->getDescription(),
|
||||
damageDealt);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if BATTLE_TRACE_LEVEL >= 1
|
||||
logAi->trace("ap shooters blocking: %lld", ap.shootersBlockedDmg);
|
||||
logAi->trace(
|
||||
"ap score: our: %2f, enemy: %2f, collateral: %2f, blocked: %2f",
|
||||
ap.attackerDamageReduce,
|
||||
ap.defenderDamageReduce,
|
||||
ap.collateralDamageReduce,
|
||||
ap.shootersBlockedDmg);
|
||||
#endif
|
||||
|
||||
attackValue += ap.shootersBlockedDmg;
|
||||
dpsScore.enemyDamageReduce += ap.shootersBlockedDmg;
|
||||
attacker->afterAttack(ap.attack.shooting, false);
|
||||
|
||||
return attackValue;
|
||||
}
|
||||
|
||||
@ -230,6 +219,7 @@ EvaluationResult BattleExchangeEvaluator::findBestTarget(
|
||||
|
||||
auto hbWaited = std::make_shared<HypotheticBattle>(env.get(), hb);
|
||||
|
||||
hbWaited->resetActiveUnit();
|
||||
hbWaited->getForUpdate(activeStack->unitId())->waiting = true;
|
||||
hbWaited->getForUpdate(activeStack->unitId())->waitedThisTurn = true;
|
||||
|
||||
@ -259,6 +249,7 @@ EvaluationResult BattleExchangeEvaluator::findBestTarget(
|
||||
updateReachabilityMap(hb);
|
||||
|
||||
if(result.bestAttack.attack.shooting
|
||||
&& !result.bestAttack.defenderDead
|
||||
&& !activeStack->waited()
|
||||
&& hb->battleHasShootingPenalty(activeStack, result.bestAttack.dest))
|
||||
{
|
||||
@ -269,8 +260,9 @@ EvaluationResult BattleExchangeEvaluator::findBestTarget(
|
||||
for(auto & ap : targets.possibleAttacks)
|
||||
{
|
||||
float score = evaluateExchange(ap, 0, targets, damageCache, hb);
|
||||
bool sameScoreButWaited = vstd::isAlmostEqual(score, result.score) && result.wait;
|
||||
|
||||
if(score > result.score || (vstd::isAlmostEqual(score, result.score) && result.wait))
|
||||
if(score > result.score || sameScoreButWaited)
|
||||
{
|
||||
result.score = score;
|
||||
result.bestAttack = ap;
|
||||
@ -739,7 +731,7 @@ std::vector<const battle::Unit *> BattleExchangeEvaluator::getOneTurnReachableUn
|
||||
{
|
||||
std::vector<const battle::Unit *> result;
|
||||
|
||||
for(int i = 0; i < turnOrder.size(); i++, turn++)
|
||||
for(int i = 0; i < turnOrder.size(); i++)
|
||||
{
|
||||
auto & turnQueue = turnOrder[i];
|
||||
HypotheticBattle turnBattle(env.get(), cb);
|
||||
|
@ -148,7 +148,7 @@ public:
|
||||
std::shared_ptr<CBattleInfoCallback> cb,
|
||||
std::shared_ptr<Environment> env,
|
||||
float strengthRatio): cb(cb), env(env) {
|
||||
negativeEffectMultiplier = strengthRatio >= 1 ? 1 : strengthRatio;
|
||||
negativeEffectMultiplier = strengthRatio >= 1 ? 1 : strengthRatio * strengthRatio;
|
||||
}
|
||||
|
||||
EvaluationResult findBestTarget(
|
||||
|
@ -164,6 +164,11 @@ public:
|
||||
|
||||
int64_t getTreeVersion() const;
|
||||
|
||||
void resetActiveUnit()
|
||||
{
|
||||
activeUnitId = -1;
|
||||
}
|
||||
|
||||
#if SCRIPTING_ENABLED
|
||||
scripting::Pool * getContextPool() const override;
|
||||
#endif
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "../lib/TurnTimerInfo.h"
|
||||
#include "../lib/VCMIDirs.h"
|
||||
#include "../lib/campaign/CampaignState.h"
|
||||
#include "../lib/gameState/HighScore.h"
|
||||
#include "../lib/CPlayerState.h"
|
||||
#include "../lib/mapping/CMapInfo.h"
|
||||
#include "../lib/mapObjects/CGTownInstance.h"
|
||||
@ -672,39 +673,9 @@ void CServerHandler::startGameplay(VCMI_LIB_WRAP_NAMESPACE(CGameState) * gameSta
|
||||
setState(EClientState::GAMEPLAY);
|
||||
}
|
||||
|
||||
HighScoreParameter CServerHandler::prepareHighScores(PlayerColor player, bool victory)
|
||||
{
|
||||
const auto * gs = client->gameState();
|
||||
const auto * playerState = gs->getPlayerState(player);
|
||||
|
||||
HighScoreParameter param;
|
||||
param.difficulty = gs->getStartInfo()->difficulty;
|
||||
param.day = gs->getDate();
|
||||
param.townAmount = gs->howManyTowns(player);
|
||||
param.usedCheat = gs->getPlayerState(player)->cheated;
|
||||
param.hasGrail = false;
|
||||
for(const CGHeroInstance * h : playerState->heroes)
|
||||
if(h->hasArt(ArtifactID::GRAIL))
|
||||
param.hasGrail = true;
|
||||
for(const CGTownInstance * t : playerState->towns)
|
||||
if(t->builtBuildings.count(BuildingID::GRAIL))
|
||||
param.hasGrail = true;
|
||||
param.allEnemiesDefeated = true;
|
||||
for (PlayerColor otherPlayer(0); otherPlayer < PlayerColor::PLAYER_LIMIT; ++otherPlayer)
|
||||
{
|
||||
auto ps = gs->getPlayerState(otherPlayer, false);
|
||||
if(ps && otherPlayer != player && !ps->checkVanquished())
|
||||
param.allEnemiesDefeated = false;
|
||||
}
|
||||
param.scenarioName = gs->getMapHeader()->name.toString();
|
||||
param.playerName = gs->getStartInfo()->playerInfos.find(player)->second.name;
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
void CServerHandler::showHighScoresAndEndGameplay(PlayerColor player, bool victory)
|
||||
{
|
||||
HighScoreParameter param = prepareHighScores(player, victory);
|
||||
HighScoreParameter param = HighScore::prepareHighScores(client->gameState(), player, victory);
|
||||
|
||||
if(victory && client->gameState()->getStartInfo()->campState)
|
||||
{
|
||||
|
@ -40,8 +40,6 @@ class GlobalLobbyClient;
|
||||
class GameChatHandler;
|
||||
class IServerRunner;
|
||||
|
||||
class HighScoreCalculation;
|
||||
|
||||
enum class ESelectionScreen : ui8;
|
||||
enum class ELoadMode : ui8;
|
||||
|
||||
@ -128,8 +126,6 @@ class CServerHandler final : public IServerAPI, public LobbyInfo, public INetwor
|
||||
|
||||
bool isServerLocal() const;
|
||||
|
||||
HighScoreParameter prepareHighScores(PlayerColor player, bool victory);
|
||||
|
||||
public:
|
||||
/// High-level connection overlay that is capable of (de)serializing network data
|
||||
std::shared_ptr<CConnection> logicConnection;
|
||||
|
@ -34,74 +34,6 @@
|
||||
#include "../../lib/constants/EntityIdentifiers.h"
|
||||
#include "../../lib/gameState/HighScore.h"
|
||||
|
||||
auto HighScoreCalculation::calculate()
|
||||
{
|
||||
struct Result
|
||||
{
|
||||
int basic = 0;
|
||||
int total = 0;
|
||||
int sumDays = 0;
|
||||
bool cheater = false;
|
||||
};
|
||||
|
||||
Result firstResult;
|
||||
Result summary;
|
||||
const std::array<double, 5> difficultyMultipliers{0.8, 1.0, 1.3, 1.6, 2.0};
|
||||
for(auto & param : parameters)
|
||||
{
|
||||
double tmp = 200 - (param.day + 10) / (param.townAmount + 5) + (param.allEnemiesDefeated ? 25 : 0) + (param.hasGrail ? 25 : 0);
|
||||
firstResult = Result{static_cast<int>(tmp), static_cast<int>(tmp * difficultyMultipliers.at(param.difficulty)), param.day, param.usedCheat};
|
||||
summary.basic += firstResult.basic * 5.0 / parameters.size();
|
||||
summary.total += firstResult.total * 5.0 / parameters.size();
|
||||
summary.sumDays += firstResult.sumDays;
|
||||
summary.cheater |= firstResult.cheater;
|
||||
}
|
||||
|
||||
if(parameters.size() == 1)
|
||||
return firstResult;
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
struct HighScoreCreature
|
||||
{
|
||||
CreatureID creature;
|
||||
int min;
|
||||
int max;
|
||||
};
|
||||
|
||||
static std::vector<HighScoreCreature> getHighscoreCreaturesList()
|
||||
{
|
||||
JsonNode configCreatures(JsonPath::builtin("CONFIG/highscoreCreatures.json"));
|
||||
|
||||
std::vector<HighScoreCreature> ret;
|
||||
|
||||
for(auto & json : configCreatures["creatures"].Vector())
|
||||
{
|
||||
HighScoreCreature entry;
|
||||
entry.creature = CreatureID::decode(json["creature"].String());
|
||||
entry.max = json["max"].isNull() ? std::numeric_limits<int>::max() : json["max"].Integer();
|
||||
entry.min = json["min"].isNull() ? std::numeric_limits<int>::min() : json["min"].Integer();
|
||||
|
||||
ret.push_back(entry);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CreatureID HighScoreCalculation::getCreatureForPoints(int points, bool campaign)
|
||||
{
|
||||
static const std::vector<HighScoreCreature> creatures = getHighscoreCreaturesList();
|
||||
|
||||
int divide = campaign ? 5 : 1;
|
||||
|
||||
for(auto & creature : creatures)
|
||||
if(points / divide <= creature.max && points / divide >= creature.min)
|
||||
return creature.creature;
|
||||
|
||||
throw std::runtime_error("Unable to find creature for score " + std::to_string(points));
|
||||
}
|
||||
|
||||
CHighScoreScreen::CHighScoreScreen(HighScorePage highscorepage, int highlighted)
|
||||
: CWindowObject(BORDERED), highscorepage(highscorepage), highlighted(highlighted)
|
||||
{
|
||||
|
@ -21,16 +21,6 @@ class CFilledTexture;
|
||||
|
||||
class TransparentFilledRectangle;
|
||||
|
||||
class HighScoreCalculation
|
||||
{
|
||||
public:
|
||||
std::vector<HighScoreParameter> parameters;
|
||||
bool isCampaign = false;
|
||||
|
||||
auto calculate();
|
||||
static CreatureID getCreatureForPoints(int points, bool campaign);
|
||||
};
|
||||
|
||||
class CHighScoreScreen : public CWindowObject
|
||||
{
|
||||
public:
|
||||
|
@ -161,13 +161,13 @@ void CAnimation::verticalFlip()
|
||||
|
||||
void CAnimation::horizontalFlip(size_t frame, size_t group)
|
||||
{
|
||||
try
|
||||
auto i1 = images.find(group);
|
||||
if(i1 != images.end())
|
||||
{
|
||||
images.at(group).at(frame) = nullptr;
|
||||
}
|
||||
catch (const std::out_of_range &)
|
||||
{
|
||||
// ignore - image not loaded
|
||||
auto i2 = i1->second.find(frame);
|
||||
|
||||
if(i2 != i1->second.end())
|
||||
i2->second = nullptr;
|
||||
}
|
||||
|
||||
auto locator = getImageLocator(frame, group);
|
||||
@ -177,13 +177,13 @@ void CAnimation::horizontalFlip(size_t frame, size_t group)
|
||||
|
||||
void CAnimation::verticalFlip(size_t frame, size_t group)
|
||||
{
|
||||
try
|
||||
auto i1 = images.find(group);
|
||||
if(i1 != images.end())
|
||||
{
|
||||
images.at(group).at(frame) = nullptr;
|
||||
}
|
||||
catch (const std::out_of_range &)
|
||||
{
|
||||
// ignore - image not loaded
|
||||
auto i2 = i1->second.find(frame);
|
||||
|
||||
if(i2 != i1->second.end())
|
||||
i2->second = nullptr;
|
||||
}
|
||||
|
||||
auto locator = getImageLocator(frame, group);
|
||||
|
@ -99,9 +99,11 @@ set(lib_MAIN_SRCS
|
||||
|
||||
gameState/CGameState.cpp
|
||||
gameState/CGameStateCampaign.cpp
|
||||
gameState/HighScore.cpp
|
||||
gameState/InfoAboutArmy.cpp
|
||||
gameState/RumorState.cpp
|
||||
gameState/TavernHeroesPool.cpp
|
||||
gameState/GameStatistics.cpp
|
||||
|
||||
mapObjectConstructors/AObjectTypeHandler.cpp
|
||||
mapObjectConstructors/CBankInstanceConstructor.cpp
|
||||
@ -468,6 +470,7 @@ set(lib_MAIN_HEADERS
|
||||
gameState/RumorState.h
|
||||
gameState/SThievesGuildInfo.h
|
||||
gameState/TavernHeroesPool.h
|
||||
gameState/GameStatistics.h
|
||||
gameState/TavernSlot.h
|
||||
gameState/QuestInfo.h
|
||||
|
||||
|
@ -1248,19 +1248,40 @@ ReachabilityInfo CBattleInfoCallback::getFlyingReachability(const ReachabilityIn
|
||||
return ret;
|
||||
}
|
||||
|
||||
AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(const battle::Unit* attacker, BattleHex destinationTile, BattleHex attackerPos) const
|
||||
AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(
|
||||
const battle::Unit * attacker,
|
||||
BattleHex destinationTile,
|
||||
BattleHex attackerPos) const
|
||||
{
|
||||
const auto * defender = battleGetUnitByPos(destinationTile, true);
|
||||
|
||||
if(!defender)
|
||||
return AttackableTiles(); // can't attack thin air
|
||||
|
||||
return getPotentiallyAttackableHexes(
|
||||
attacker,
|
||||
defender,
|
||||
destinationTile,
|
||||
attackerPos,
|
||||
defender->getPosition());
|
||||
}
|
||||
|
||||
AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(
|
||||
const battle::Unit* attacker,
|
||||
const battle::Unit * defender,
|
||||
BattleHex destinationTile,
|
||||
BattleHex attackerPos,
|
||||
BattleHex defenderPos) const
|
||||
{
|
||||
//does not return hex attacked directly
|
||||
AttackableTiles at;
|
||||
RETURN_IF_NOT_BATTLE(at);
|
||||
|
||||
BattleHex attackOriginHex = (attackerPos != BattleHex::INVALID) ? attackerPos : attacker->getPosition(); //real or hypothetical (cursor) position
|
||||
|
||||
const auto * defender = battleGetUnitByPos(destinationTile, true);
|
||||
if (!defender)
|
||||
return at; // can't attack thin air
|
||||
|
||||
bool reverse = isToReverse(attacker, defender);
|
||||
|
||||
defenderPos = (defenderPos != BattleHex::INVALID) ? defenderPos : defender->getPosition(); //real or hypothetical (cursor) position
|
||||
|
||||
bool reverse = isToReverse(attacker, defender, attackerPos, defenderPos);
|
||||
if(reverse && attacker->doubleWide())
|
||||
{
|
||||
attackOriginHex = attacker->occupiedHex(attackOriginHex); //the other hex stack stands on
|
||||
@ -1304,19 +1325,26 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(const battle:
|
||||
else if(attacker->hasBonusOfType(BonusType::TWO_HEX_ATTACK_BREATH))
|
||||
{
|
||||
auto direction = BattleHex::mutualPosition(attackOriginHex, destinationTile);
|
||||
|
||||
if(direction == BattleHex::NONE
|
||||
&& defender->doubleWide()
|
||||
&& attacker->doubleWide()
|
||||
&& defenderPos == destinationTile)
|
||||
{
|
||||
direction = BattleHex::mutualPosition(attackOriginHex, defender->occupiedHex(defenderPos));
|
||||
}
|
||||
|
||||
if(direction != BattleHex::NONE) //only adjacent hexes are subject of dragon breath calculation
|
||||
{
|
||||
BattleHex nextHex = destinationTile.cloneInDirection(direction, false);
|
||||
|
||||
if ( defender->doubleWide() )
|
||||
{
|
||||
auto secondHex = destinationTile == defender->getPosition() ?
|
||||
defender->occupiedHex():
|
||||
defender->getPosition();
|
||||
auto secondHex = destinationTile == defenderPos ? defender->occupiedHex(defenderPos) : defenderPos;
|
||||
|
||||
// if targeted double-wide creature is attacked from above or below ( -> second hex is also adjacent to attack origin)
|
||||
// then dragon breath should target tile on the opposite side of targeted creature
|
||||
if (BattleHex::mutualPosition(attackOriginHex, secondHex) != BattleHex::NONE)
|
||||
if(BattleHex::mutualPosition(attackOriginHex, secondHex) != BattleHex::NONE)
|
||||
nextHex = secondHex.cloneInDirection(direction, false);
|
||||
}
|
||||
|
||||
@ -1348,17 +1376,29 @@ AttackableTiles CBattleInfoCallback::getPotentiallyShootableHexes(const battle::
|
||||
return at;
|
||||
}
|
||||
|
||||
std::vector<const battle::Unit*> CBattleInfoCallback::getAttackedBattleUnits(const battle::Unit* attacker, BattleHex destinationTile, bool rangedAttack, BattleHex attackerPos) const
|
||||
std::vector<const battle::Unit*> CBattleInfoCallback::getAttackedBattleUnits(
|
||||
const battle::Unit * attacker,
|
||||
const battle::Unit * defender,
|
||||
BattleHex destinationTile,
|
||||
bool rangedAttack,
|
||||
BattleHex attackerPos,
|
||||
BattleHex defenderPos) const
|
||||
{
|
||||
std::vector<const battle::Unit*> units;
|
||||
RETURN_IF_NOT_BATTLE(units);
|
||||
|
||||
if(attackerPos == BattleHex::INVALID)
|
||||
attackerPos = attacker->getPosition();
|
||||
|
||||
if(defenderPos == BattleHex::INVALID)
|
||||
defenderPos = defender->getPosition();
|
||||
|
||||
AttackableTiles at;
|
||||
|
||||
if (rangedAttack)
|
||||
at = getPotentiallyShootableHexes(attacker, destinationTile, attackerPos);
|
||||
else
|
||||
at = getPotentiallyAttackableHexes(attacker, destinationTile, attackerPos);
|
||||
at = getPotentiallyAttackableHexes(attacker, defender, destinationTile, attackerPos, defenderPos);
|
||||
|
||||
units = battleGetUnitsIf([=](const battle::Unit * unit)
|
||||
{
|
||||
@ -1384,7 +1424,7 @@ std::set<const CStack*> CBattleInfoCallback::getAttackedCreatures(const CStack*
|
||||
RETURN_IF_NOT_BATTLE(attackedCres);
|
||||
|
||||
AttackableTiles at;
|
||||
|
||||
|
||||
if(rangedAttack)
|
||||
at = getPotentiallyShootableHexes(attacker, destinationTile, attackerPos);
|
||||
else
|
||||
@ -1423,10 +1463,13 @@ static bool isHexInFront(BattleHex hex, BattleHex testHex, BattleSide::Type side
|
||||
}
|
||||
|
||||
//TODO: this should apply also to mechanics and cursor interface
|
||||
bool CBattleInfoCallback::isToReverse(const battle::Unit * attacker, const battle::Unit * defender) const
|
||||
bool CBattleInfoCallback::isToReverse(const battle::Unit * attacker, const battle::Unit * defender, BattleHex attackerHex, BattleHex defenderHex) const
|
||||
{
|
||||
BattleHex attackerHex = attacker->getPosition();
|
||||
BattleHex defenderHex = defender->getPosition();
|
||||
if(!defenderHex.isValid())
|
||||
defenderHex = defender->getPosition();
|
||||
|
||||
if(!attackerHex.isValid())
|
||||
attackerHex = attacker->getPosition();
|
||||
|
||||
if (attackerHex < 0 ) //turret
|
||||
return false;
|
||||
@ -1434,15 +1477,22 @@ bool CBattleInfoCallback::isToReverse(const battle::Unit * attacker, const battl
|
||||
if(isHexInFront(attackerHex, defenderHex, static_cast<BattleSide::Type>(attacker->unitSide())))
|
||||
return false;
|
||||
|
||||
auto defenderOtherHex = defenderHex;
|
||||
auto attackerOtherHex = defenderHex;
|
||||
|
||||
if (defender->doubleWide())
|
||||
{
|
||||
if(isHexInFront(attackerHex, defender->occupiedHex(), static_cast<BattleSide::Type>(attacker->unitSide())))
|
||||
defenderOtherHex = battle::Unit::occupiedHex(defenderHex, true, defender->unitSide());
|
||||
|
||||
if(isHexInFront(attackerHex, defenderOtherHex, static_cast<BattleSide::Type>(attacker->unitSide())))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attacker->doubleWide())
|
||||
{
|
||||
if(isHexInFront(attacker->occupiedHex(), defenderHex, static_cast<BattleSide::Type>(attacker->unitSide())))
|
||||
attackerOtherHex = battle::Unit::occupiedHex(attackerHex, true, attacker->unitSide());
|
||||
|
||||
if(isHexInFront(attackerOtherHex, defenderHex, static_cast<BattleSide::Type>(attacker->unitSide())))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1450,7 +1500,7 @@ bool CBattleInfoCallback::isToReverse(const battle::Unit * attacker, const battl
|
||||
// but this is how H3 handles it which is important, e.g. for direction of dragon breath attacks
|
||||
if (attacker->doubleWide() && defender->doubleWide())
|
||||
{
|
||||
if(isHexInFront(attacker->occupiedHex(), defender->occupiedHex(), static_cast<BattleSide::Type>(attacker->unitSide())))
|
||||
if(isHexInFront(attackerOtherHex, defenderOtherHex, static_cast<BattleSide::Type>(attacker->unitSide())))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -131,11 +131,30 @@ public:
|
||||
bool isInTacticRange(BattleHex dest) const;
|
||||
si8 battleGetTacticDist() const; //returns tactic distance for calling player or 0 if this player is not in tactic phase (for ALL_KNOWING actual distance for tactic side)
|
||||
|
||||
AttackableTiles getPotentiallyAttackableHexes(const battle::Unit* attacker, BattleHex destinationTile, BattleHex attackerPos) const; //TODO: apply rotation to two-hex attacker
|
||||
AttackableTiles getPotentiallyAttackableHexes(
|
||||
const battle::Unit* attacker,
|
||||
const battle::Unit* defender,
|
||||
BattleHex destinationTile,
|
||||
BattleHex attackerPos,
|
||||
BattleHex defenderPos) const; //TODO: apply rotation to two-hex attacker
|
||||
|
||||
AttackableTiles getPotentiallyAttackableHexes(
|
||||
const battle::Unit * attacker,
|
||||
BattleHex destinationTile,
|
||||
BattleHex attackerPos) const;
|
||||
|
||||
AttackableTiles getPotentiallyShootableHexes(const battle::Unit* attacker, BattleHex destinationTile, BattleHex attackerPos) const;
|
||||
std::vector<const battle::Unit *> getAttackedBattleUnits(const battle::Unit* attacker, BattleHex destinationTile, bool rangedAttack, BattleHex attackerPos = BattleHex::INVALID) const; //calculates range of multi-hex attacks
|
||||
|
||||
std::vector<const battle::Unit *> getAttackedBattleUnits(
|
||||
const battle::Unit* attacker,
|
||||
const battle::Unit * defender,
|
||||
BattleHex destinationTile,
|
||||
bool rangedAttack,
|
||||
BattleHex attackerPos = BattleHex::INVALID,
|
||||
BattleHex defenderPos = BattleHex::INVALID) const; //calculates range of multi-hex attacks
|
||||
|
||||
std::set<const CStack*> getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, bool rangedAttack, BattleHex attackerPos = BattleHex::INVALID) const; //calculates range of multi-hex attacks
|
||||
bool isToReverse(const battle::Unit * attacker, const battle::Unit * defender) const; //determines if attacker standing at attackerHex should reverse in order to attack defender
|
||||
bool isToReverse(const battle::Unit * attacker, const battle::Unit * defender, BattleHex attackerHex = BattleHex::INVALID, BattleHex defenderHex = BattleHex::INVALID) const; //determines if attacker standing at attackerHex should reverse in order to attack defender
|
||||
|
||||
ReachabilityInfo getReachability(const battle::Unit * unit) const;
|
||||
ReachabilityInfo getReachability(const ReachabilityInfo::Parameters & params) const;
|
||||
|
@ -875,7 +875,7 @@ void CGameState::initTowns()
|
||||
}
|
||||
//init spells
|
||||
vti->spells.resize(GameConstants::SPELL_LEVELS);
|
||||
|
||||
vti->possibleSpells -= SpellID::PRESET;
|
||||
for(ui32 z=0; z<vti->obligatorySpells.size();z++)
|
||||
{
|
||||
const auto * s = vti->obligatorySpells[z].toSpell();
|
||||
@ -1538,137 +1538,6 @@ bool CGameState::checkForStandardLoss(const PlayerColor & player) const
|
||||
return pState.checkVanquished();
|
||||
}
|
||||
|
||||
struct statsHLP
|
||||
{
|
||||
using TStat = std::pair<PlayerColor, si64>;
|
||||
//converts [<player's color, value>] to vec[place] -> platers
|
||||
static std::vector< std::vector< PlayerColor > > getRank( std::vector<TStat> stats )
|
||||
{
|
||||
std::sort(stats.begin(), stats.end(), statsHLP());
|
||||
|
||||
//put first element
|
||||
std::vector< std::vector<PlayerColor> > ret;
|
||||
std::vector<PlayerColor> tmp;
|
||||
tmp.push_back( stats[0].first );
|
||||
ret.push_back( tmp );
|
||||
|
||||
//the rest of elements
|
||||
for(int g=1; g<stats.size(); ++g)
|
||||
{
|
||||
if(stats[g].second == stats[g-1].second)
|
||||
{
|
||||
(ret.end()-1)->push_back( stats[g].first );
|
||||
}
|
||||
else
|
||||
{
|
||||
//create next occupied rank
|
||||
std::vector<PlayerColor> tmp;
|
||||
tmp.push_back(stats[g].first);
|
||||
ret.push_back(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool operator()(const TStat & a, const TStat & b) const
|
||||
{
|
||||
return a.second > b.second;
|
||||
}
|
||||
|
||||
static const CGHeroInstance * findBestHero(CGameState * gs, const PlayerColor & color)
|
||||
{
|
||||
std::vector<ConstTransitivePtr<CGHeroInstance> > &h = gs->players[color].heroes;
|
||||
if(h.empty())
|
||||
return nullptr;
|
||||
//best hero will be that with highest exp
|
||||
int best = 0;
|
||||
for(int b=1; b<h.size(); ++b)
|
||||
{
|
||||
if(h[b]->exp > h[best]->exp)
|
||||
{
|
||||
best = b;
|
||||
}
|
||||
}
|
||||
return h[best];
|
||||
}
|
||||
|
||||
//calculates total number of artifacts that belong to given player
|
||||
static int getNumberOfArts(const PlayerState * ps)
|
||||
{
|
||||
int ret = 0;
|
||||
for(auto h : ps->heroes)
|
||||
{
|
||||
ret += (int)h->artifactsInBackpack.size() + (int)h->artifactsWorn.size();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// get total strength of player army
|
||||
static si64 getArmyStrength(const PlayerState * ps)
|
||||
{
|
||||
si64 str = 0;
|
||||
|
||||
for(auto h : ps->heroes)
|
||||
{
|
||||
if(!h->inTownGarrison) //original h3 behavior
|
||||
str += h->getArmyStrength();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// get total gold income
|
||||
static int getIncome(const PlayerState * ps, int percentIncome)
|
||||
{
|
||||
int totalIncome = 0;
|
||||
const CGObjectInstance * heroOrTown = nullptr;
|
||||
|
||||
//Heroes can produce gold as well - skill, specialty or arts
|
||||
for(const auto & h : ps->heroes)
|
||||
{
|
||||
totalIncome += h->valOfBonuses(Selector::typeSubtype(BonusType::GENERATE_RESOURCE, BonusSubtypeID(GameResID(GameResID::GOLD)))) * percentIncome / 100;
|
||||
|
||||
if(!heroOrTown)
|
||||
heroOrTown = h;
|
||||
}
|
||||
|
||||
//Add town income of all towns
|
||||
for(const auto & t : ps->towns)
|
||||
{
|
||||
totalIncome += t->dailyIncome()[EGameResID::GOLD];
|
||||
|
||||
if(!heroOrTown)
|
||||
heroOrTown = t;
|
||||
}
|
||||
|
||||
/// FIXME: Dirty dirty hack
|
||||
/// Stats helper need some access to gamestate.
|
||||
std::vector<const CGObjectInstance *> ownedObjects;
|
||||
for(const CGObjectInstance * obj : heroOrTown->cb->gameState()->map->objects)
|
||||
{
|
||||
if(obj && obj->tempOwner == ps->color)
|
||||
ownedObjects.push_back(obj);
|
||||
}
|
||||
/// This is code from CPlayerSpecificInfoCallback::getMyObjects
|
||||
/// I'm really need to find out about callback interface design...
|
||||
|
||||
for(const auto * object : ownedObjects)
|
||||
{
|
||||
//Mines
|
||||
if ( object->ID == Obj::MINE )
|
||||
{
|
||||
const auto * mine = dynamic_cast<const CGMine *>(object);
|
||||
assert(mine);
|
||||
|
||||
if (mine->producedResource == EGameResID::GOLD)
|
||||
totalIncome += mine->getProducedQuantity();
|
||||
}
|
||||
}
|
||||
|
||||
return totalIncome;
|
||||
}
|
||||
};
|
||||
|
||||
void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
|
||||
{
|
||||
auto playerInactive = [&](const PlayerColor & color)
|
||||
@ -1688,7 +1557,7 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
|
||||
stat.second = VAL_GETTER; \
|
||||
stats.push_back(stat); \
|
||||
} \
|
||||
tgi.FIELD = statsHLP::getRank(stats); \
|
||||
tgi.FIELD = Statistic::getRank(stats); \
|
||||
}
|
||||
|
||||
for(auto & elem : players)
|
||||
@ -1710,7 +1579,7 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
|
||||
{
|
||||
if(playerInactive(player.second.color))
|
||||
continue;
|
||||
const CGHeroInstance * best = statsHLP::findBestHero(this, player.second.color);
|
||||
const CGHeroInstance * best = Statistic::findBestHero(this, player.second.color);
|
||||
InfoAboutHero iah;
|
||||
iah.initFromHero(best, (level >= 2) ? InfoAboutHero::EInfoLevel::DETAILED : InfoAboutHero::EInfoLevel::BASIC);
|
||||
iah.army.clear();
|
||||
@ -1731,27 +1600,19 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
|
||||
}
|
||||
if(level >= 3) //obelisks found
|
||||
{
|
||||
auto getObeliskVisited = [&](const TeamID & t)
|
||||
{
|
||||
if(map->obelisksVisited.count(t))
|
||||
return map->obelisksVisited[t];
|
||||
else
|
||||
return ui8(0);
|
||||
};
|
||||
|
||||
FILL_FIELD(obelisks, getObeliskVisited(gs->getPlayerTeam(g->second.color)->id))
|
||||
FILL_FIELD(obelisks, Statistic::getObeliskVisited(gs, gs->getPlayerTeam(g->second.color)->id))
|
||||
}
|
||||
if(level >= 4) //artifacts
|
||||
{
|
||||
FILL_FIELD(artifacts, statsHLP::getNumberOfArts(&g->second))
|
||||
FILL_FIELD(artifacts, Statistic::getNumberOfArts(&g->second))
|
||||
}
|
||||
if(level >= 4) //army strength
|
||||
{
|
||||
FILL_FIELD(army, statsHLP::getArmyStrength(&g->second))
|
||||
FILL_FIELD(army, Statistic::getArmyStrength(&g->second))
|
||||
}
|
||||
if(level >= 5) //income
|
||||
{
|
||||
FILL_FIELD(income, statsHLP::getIncome(&g->second, scenarioOps->getIthPlayersSettings(g->second.color).handicap.percentIncome))
|
||||
FILL_FIELD(income, Statistic::getIncome(gs, &g->second))
|
||||
}
|
||||
if(level >= 2) //best hero's stats
|
||||
{
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "../ConstTransitivePtr.h"
|
||||
|
||||
#include "RumorState.h"
|
||||
#include "GameStatistics.h"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@ -90,6 +91,8 @@ public:
|
||||
CBonusSystemNode globalEffects;
|
||||
RumorState currentRumor;
|
||||
|
||||
StatisticDataSet statistic;
|
||||
|
||||
static boost::shared_mutex mutex;
|
||||
|
||||
void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) override;
|
||||
@ -167,6 +170,8 @@ public:
|
||||
h & currentRumor;
|
||||
h & campaign;
|
||||
h & allocatedArtifacts;
|
||||
if (h.version >= Handler::Version::STATISTICS)
|
||||
h & statistic;
|
||||
|
||||
BONUS_TREE_DESERIALIZATION_FIX
|
||||
}
|
||||
|
370
lib/gameState/GameStatistics.cpp
Normal file
370
lib/gameState/GameStatistics.cpp
Normal file
@ -0,0 +1,370 @@
|
||||
/*
|
||||
* GameStatistics.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 "GameStatistics.h"
|
||||
#include "../CPlayerState.h"
|
||||
#include "../constants/StringConstants.h"
|
||||
#include "CGameState.h"
|
||||
#include "TerrainHandler.h"
|
||||
#include "CHeroHandler.h"
|
||||
#include "StartInfo.h"
|
||||
#include "HighScore.h"
|
||||
#include "../mapObjects/CGHeroInstance.h"
|
||||
#include "../mapObjects/CGTownInstance.h"
|
||||
#include "../mapObjects/CGObjectInstance.h"
|
||||
#include "../mapObjects/MiscObjects.h"
|
||||
#include "../mapping/CMap.h"
|
||||
#include "../entities/building/CBuilding.h"
|
||||
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void StatisticDataSet::add(StatisticDataSetEntry entry)
|
||||
{
|
||||
data.push_back(entry);
|
||||
}
|
||||
|
||||
StatisticDataSetEntry StatisticDataSet::createEntry(const PlayerState * ps, const CGameState * gs)
|
||||
{
|
||||
StatisticDataSetEntry data;
|
||||
|
||||
HighScoreParameter param = HighScore::prepareHighScores(gs, ps->color, false);
|
||||
HighScoreCalculation scenarioHighScores;
|
||||
scenarioHighScores.parameters.push_back(param);
|
||||
scenarioHighScores.isCampaign = false;
|
||||
|
||||
data.map = gs->map->name.toString();
|
||||
data.timestamp = std::time(0);
|
||||
data.day = gs->getDate(Date::DAY);
|
||||
data.player = ps->color;
|
||||
data.team = ps->team;
|
||||
data.isHuman = ps->isHuman();
|
||||
data.status = ps->status;
|
||||
data.resources = ps->resources;
|
||||
data.numberHeroes = ps->heroes.size();
|
||||
data.numberTowns = gs->howManyTowns(ps->color);
|
||||
data.numberArtifacts = Statistic::getNumberOfArts(ps);
|
||||
data.numberDwellings = gs->getPlayerState(ps->color)->dwellings.size();
|
||||
data.armyStrength = Statistic::getArmyStrength(ps, true);
|
||||
data.totalExperience = Statistic::getTotalExperience(ps);
|
||||
data.income = Statistic::getIncome(gs, ps);
|
||||
data.mapExploredRatio = Statistic::getMapExploredRatio(gs, ps->color);
|
||||
data.obeliskVisitedRatio = Statistic::getObeliskVisitedRatio(gs, ps->team);
|
||||
data.townBuiltRatio = Statistic::getTownBuiltRatio(ps);
|
||||
data.hasGrail = param.hasGrail;
|
||||
data.numMines = Statistic::getNumMines(gs, ps);
|
||||
data.score = scenarioHighScores.calculate().total;
|
||||
data.maxHeroLevel = Statistic::findBestHero(gs, ps->color) ? Statistic::findBestHero(gs, ps->color)->level : 0;
|
||||
data.numBattlesNeutral = gs->statistic.accumulatedValues.count(ps->color) ? gs->statistic.accumulatedValues.at(ps->color).numBattlesNeutral : 0;
|
||||
data.numBattlesPlayer = gs->statistic.accumulatedValues.count(ps->color) ? gs->statistic.accumulatedValues.at(ps->color).numBattlesPlayer : 0;
|
||||
data.numWinBattlesNeutral = gs->statistic.accumulatedValues.count(ps->color) ? gs->statistic.accumulatedValues.at(ps->color).numWinBattlesNeutral : 0;
|
||||
data.numWinBattlesPlayer = gs->statistic.accumulatedValues.count(ps->color) ? gs->statistic.accumulatedValues.at(ps->color).numWinBattlesPlayer : 0;
|
||||
data.numHeroSurrendered = gs->statistic.accumulatedValues.count(ps->color) ? gs->statistic.accumulatedValues.at(ps->color).numHeroSurrendered : 0;
|
||||
data.numHeroEscaped = gs->statistic.accumulatedValues.count(ps->color) ? gs->statistic.accumulatedValues.at(ps->color).numHeroEscaped : 0;
|
||||
data.spentResourcesForArmy = gs->statistic.accumulatedValues.count(ps->color) ? gs->statistic.accumulatedValues.at(ps->color).spentResourcesForArmy : TResources();
|
||||
data.spentResourcesForBuildings = gs->statistic.accumulatedValues.count(ps->color) ? gs->statistic.accumulatedValues.at(ps->color).spentResourcesForBuildings : TResources();
|
||||
data.tradeVolume = gs->statistic.accumulatedValues.count(ps->color) ? gs->statistic.accumulatedValues.at(ps->color).tradeVolume : TResources();
|
||||
data.movementPointsUsed = gs->statistic.accumulatedValues.count(ps->color) ? gs->statistic.accumulatedValues.at(ps->color).movementPointsUsed : 0;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
std::string StatisticDataSet::toCsv()
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
auto resources = std::vector<EGameResID>{EGameResID::GOLD, EGameResID::WOOD, EGameResID::MERCURY, EGameResID::ORE, EGameResID::SULFUR, EGameResID::CRYSTAL, EGameResID::GEMS};
|
||||
|
||||
ss << "Map" << ";";
|
||||
ss << "Timestamp" << ";";
|
||||
ss << "Day" << ";";
|
||||
ss << "Player" << ";";
|
||||
ss << "Team" << ";";
|
||||
ss << "IsHuman" << ";";
|
||||
ss << "Status" << ";";
|
||||
ss << "NumberHeroes" << ";";
|
||||
ss << "NumberTowns" << ";";
|
||||
ss << "NumberArtifacts" << ";";
|
||||
ss << "NumberDwellings" << ";";
|
||||
ss << "ArmyStrength" << ";";
|
||||
ss << "TotalExperience" << ";";
|
||||
ss << "Income" << ";";
|
||||
ss << "MapExploredRatio" << ";";
|
||||
ss << "ObeliskVisitedRatio" << ";";
|
||||
ss << "TownBuiltRatio" << ";";
|
||||
ss << "HasGrail" << ";";
|
||||
ss << "Score" << ";";
|
||||
ss << "MaxHeroLevel" << ";";
|
||||
ss << "NumBattlesNeutral" << ";";
|
||||
ss << "NumBattlesPlayer" << ";";
|
||||
ss << "NumWinBattlesNeutral" << ";";
|
||||
ss << "NumWinBattlesPlayer" << ";";
|
||||
ss << "NumHeroSurrendered" << ";";
|
||||
ss << "NumHeroEscaped" << ";";
|
||||
ss << "MovementPointsUsed";
|
||||
for(auto & resource : resources)
|
||||
ss << ";" << GameConstants::RESOURCE_NAMES[resource];
|
||||
for(auto & resource : resources)
|
||||
ss << ";" << GameConstants::RESOURCE_NAMES[resource] + "Mines";
|
||||
for(auto & resource : resources)
|
||||
ss << ";" << GameConstants::RESOURCE_NAMES[resource] + "SpentResourcesForArmy";
|
||||
for(auto & resource : resources)
|
||||
ss << ";" << GameConstants::RESOURCE_NAMES[resource] + "SpentResourcesForBuildings";
|
||||
for(auto & resource : resources)
|
||||
ss << ";" << GameConstants::RESOURCE_NAMES[resource] + "TradeVolume";
|
||||
ss << "\r\n";
|
||||
|
||||
for(auto & entry : data)
|
||||
{
|
||||
ss << entry.map << ";";
|
||||
ss << vstd::getFormattedDateTime(entry.timestamp, "%Y-%m-%dT%H:%M:%S") << ";";
|
||||
ss << entry.day << ";";
|
||||
ss << GameConstants::PLAYER_COLOR_NAMES[entry.player] << ";";
|
||||
ss << entry.team.getNum() << ";";
|
||||
ss << entry.isHuman << ";";
|
||||
ss << (int)entry.status << ";";
|
||||
ss << entry.numberHeroes << ";";
|
||||
ss << entry.numberTowns << ";";
|
||||
ss << entry.numberArtifacts << ";";
|
||||
ss << entry.numberDwellings << ";";
|
||||
ss << entry.armyStrength << ";";
|
||||
ss << entry.totalExperience << ";";
|
||||
ss << entry.income << ";";
|
||||
ss << entry.mapExploredRatio << ";";
|
||||
ss << entry.obeliskVisitedRatio << ";";
|
||||
ss << entry.townBuiltRatio << ";";
|
||||
ss << entry.hasGrail << ";";
|
||||
ss << entry.score << ";";
|
||||
ss << entry.maxHeroLevel << ";";
|
||||
ss << entry.numBattlesNeutral << ";";
|
||||
ss << entry.numBattlesPlayer << ";";
|
||||
ss << entry.numWinBattlesNeutral << ";";
|
||||
ss << entry.numWinBattlesPlayer << ";";
|
||||
ss << entry.numHeroSurrendered << ";";
|
||||
ss << entry.numHeroEscaped << ";";
|
||||
ss << entry.movementPointsUsed;
|
||||
for(auto & resource : resources)
|
||||
ss << ";" << entry.resources[resource];
|
||||
for(auto & resource : resources)
|
||||
ss << ";" << entry.numMines[resource];
|
||||
for(auto & resource : resources)
|
||||
ss << ";" << entry.spentResourcesForArmy[resource];
|
||||
for(auto & resource : resources)
|
||||
ss << ";" << entry.spentResourcesForBuildings[resource];
|
||||
for(auto & resource : resources)
|
||||
ss << ";" << entry.tradeVolume[resource];
|
||||
ss << "\r\n";
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::vector<const CGMine *> Statistic::getMines(const CGameState * gs, const PlayerState * ps)
|
||||
{
|
||||
std::vector<const CGMine *> tmp;
|
||||
|
||||
/// FIXME: Dirty dirty hack
|
||||
/// Stats helper need some access to gamestate.
|
||||
std::vector<const CGObjectInstance *> ownedObjects;
|
||||
for(const CGObjectInstance * obj : gs->map->objects)
|
||||
{
|
||||
if(obj && obj->tempOwner == ps->color)
|
||||
ownedObjects.push_back(obj);
|
||||
}
|
||||
/// This is code from CPlayerSpecificInfoCallback::getMyObjects
|
||||
/// I'm really need to find out about callback interface design...
|
||||
|
||||
for(const auto * object : ownedObjects)
|
||||
{
|
||||
//Mines
|
||||
if ( object->ID == Obj::MINE )
|
||||
{
|
||||
const auto * mine = dynamic_cast<const CGMine *>(object);
|
||||
assert(mine);
|
||||
|
||||
tmp.push_back(mine);
|
||||
}
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
//calculates total number of artifacts that belong to given player
|
||||
int Statistic::getNumberOfArts(const PlayerState * ps)
|
||||
{
|
||||
int ret = 0;
|
||||
for(auto h : ps->heroes)
|
||||
{
|
||||
ret += (int)h->artifactsInBackpack.size() + (int)h->artifactsWorn.size();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// get total strength of player army
|
||||
si64 Statistic::getArmyStrength(const PlayerState * ps, bool withTownGarrison)
|
||||
{
|
||||
si64 str = 0;
|
||||
|
||||
for(auto h : ps->heroes)
|
||||
{
|
||||
if(!h->inTownGarrison || withTownGarrison) //original h3 behavior
|
||||
str += h->getArmyStrength();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// get total experience of all heroes
|
||||
si64 Statistic::getTotalExperience(const PlayerState * ps)
|
||||
{
|
||||
si64 tmp = 0;
|
||||
|
||||
for(auto h : ps->heroes)
|
||||
tmp += h->exp;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// get total gold income
|
||||
int Statistic::getIncome(const CGameState * gs, const PlayerState * ps)
|
||||
{
|
||||
int percentIncome = gs->getStartInfo()->getIthPlayersSettings(ps->color).handicap.percentIncome;
|
||||
int totalIncome = 0;
|
||||
|
||||
//Heroes can produce gold as well - skill, specialty or arts
|
||||
for(const auto & h : ps->heroes)
|
||||
totalIncome += h->valOfBonuses(Selector::typeSubtype(BonusType::GENERATE_RESOURCE, BonusSubtypeID(GameResID(GameResID::GOLD)))) * percentIncome / 100;
|
||||
|
||||
//Add town income of all towns
|
||||
for(const auto & t : ps->towns)
|
||||
totalIncome += t->dailyIncome()[EGameResID::GOLD];
|
||||
|
||||
for(const CGMine * mine : getMines(gs, ps))
|
||||
if(mine->producedResource == EGameResID::GOLD)
|
||||
totalIncome += mine->getProducedQuantity();
|
||||
|
||||
return totalIncome;
|
||||
}
|
||||
|
||||
float Statistic::getMapExploredRatio(const CGameState * gs, PlayerColor player)
|
||||
{
|
||||
float visible = 0.0;
|
||||
float numTiles = 0.0;
|
||||
|
||||
for(int layer = 0; layer < (gs->map->twoLevel ? 2 : 1); layer++)
|
||||
for(int y = 0; y < gs->map->height; ++y)
|
||||
for(int x = 0; x < gs->map->width; ++x)
|
||||
{
|
||||
TerrainTile tile = gs->map->getTile(int3(x, y, layer));
|
||||
|
||||
if(tile.blocked && (!tile.visitable))
|
||||
continue;
|
||||
|
||||
if(gs->isVisible(int3(x, y, layer), player))
|
||||
visible++;
|
||||
numTiles++;
|
||||
}
|
||||
|
||||
return visible / numTiles;
|
||||
}
|
||||
|
||||
const CGHeroInstance * Statistic::findBestHero(const CGameState * gs, const PlayerColor & color)
|
||||
{
|
||||
auto &h = gs->players.at(color).heroes;
|
||||
if(h.empty())
|
||||
return nullptr;
|
||||
//best hero will be that with highest exp
|
||||
int best = 0;
|
||||
for(int b=1; b<h.size(); ++b)
|
||||
{
|
||||
if(h[b]->exp > h[best]->exp)
|
||||
{
|
||||
best = b;
|
||||
}
|
||||
}
|
||||
return h[best];
|
||||
}
|
||||
|
||||
std::vector<std::vector<PlayerColor>> Statistic::getRank(std::vector<std::pair<PlayerColor, si64>> stats)
|
||||
{
|
||||
std::sort(stats.begin(), stats.end(), [](const std::pair<PlayerColor, si64> & a, const std::pair<PlayerColor, si64> & b) { return a.second > b.second; });
|
||||
|
||||
//put first element
|
||||
std::vector< std::vector<PlayerColor> > ret;
|
||||
std::vector<PlayerColor> tmp;
|
||||
tmp.push_back( stats[0].first );
|
||||
ret.push_back( tmp );
|
||||
|
||||
//the rest of elements
|
||||
for(int g=1; g<stats.size(); ++g)
|
||||
{
|
||||
if(stats[g].second == stats[g-1].second)
|
||||
{
|
||||
(ret.end()-1)->push_back( stats[g].first );
|
||||
}
|
||||
else
|
||||
{
|
||||
//create next occupied rank
|
||||
std::vector<PlayerColor> tmp;
|
||||
tmp.push_back(stats[g].first);
|
||||
ret.push_back(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Statistic::getObeliskVisited(const CGameState * gs, const TeamID & t)
|
||||
{
|
||||
if(gs->map->obelisksVisited.count(t))
|
||||
return gs->map->obelisksVisited.at(t);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
float Statistic::getObeliskVisitedRatio(const CGameState * gs, const TeamID & t)
|
||||
{
|
||||
if(!gs->map->obeliskCount)
|
||||
return 0;
|
||||
return (float)getObeliskVisited(gs, t) / (float)gs->map->obeliskCount;
|
||||
}
|
||||
|
||||
std::map<EGameResID, int> Statistic::getNumMines(const CGameState * gs, const PlayerState * ps)
|
||||
{
|
||||
std::map<EGameResID, int> tmp;
|
||||
|
||||
for(auto & res : EGameResID::ALL_RESOURCES())
|
||||
tmp[res] = 0;
|
||||
|
||||
for(const CGMine * mine : getMines(gs, ps))
|
||||
tmp[mine->producedResource]++;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
float Statistic::getTownBuiltRatio(const PlayerState * ps)
|
||||
{
|
||||
float built = 0.0;
|
||||
float total = 0.0;
|
||||
|
||||
for(const auto & t : ps->towns)
|
||||
{
|
||||
built += t->builtBuildings.size();
|
||||
for(const auto & b : t->town->buildings)
|
||||
if(!t->forbiddenBuildings.count(b.first))
|
||||
total += 1;
|
||||
}
|
||||
|
||||
if(total < 1)
|
||||
return 0;
|
||||
|
||||
return built / total;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
156
lib/gameState/GameStatistics.h
Normal file
156
lib/gameState/GameStatistics.h
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* GameSTatistics.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
|
||||
|
||||
#include "../GameConstants.h"
|
||||
#include "../ResourceSet.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct PlayerState;
|
||||
class CGameState;
|
||||
class CGHeroInstance;
|
||||
class CGMine;
|
||||
|
||||
struct DLL_LINKAGE StatisticDataSetEntry
|
||||
{
|
||||
std::string map;
|
||||
time_t timestamp;
|
||||
int day;
|
||||
PlayerColor player;
|
||||
TeamID team;
|
||||
bool isHuman;
|
||||
EPlayerStatus status;
|
||||
TResources resources;
|
||||
int numberHeroes;
|
||||
int numberTowns;
|
||||
int numberArtifacts;
|
||||
int numberDwellings;
|
||||
si64 armyStrength;
|
||||
si64 totalExperience;
|
||||
int income;
|
||||
float mapExploredRatio;
|
||||
float obeliskVisitedRatio;
|
||||
float townBuiltRatio;
|
||||
bool hasGrail;
|
||||
std::map<EGameResID, int> numMines;
|
||||
int score;
|
||||
int maxHeroLevel;
|
||||
int numBattlesNeutral;
|
||||
int numBattlesPlayer;
|
||||
int numWinBattlesNeutral;
|
||||
int numWinBattlesPlayer;
|
||||
int numHeroSurrendered;
|
||||
int numHeroEscaped;
|
||||
TResources spentResourcesForArmy;
|
||||
TResources spentResourcesForBuildings;
|
||||
TResources tradeVolume;
|
||||
si64 movementPointsUsed;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h)
|
||||
{
|
||||
h & map;
|
||||
h & timestamp;
|
||||
h & day;
|
||||
h & player;
|
||||
h & team;
|
||||
h & isHuman;
|
||||
h & status;
|
||||
h & resources;
|
||||
h & numberHeroes;
|
||||
h & numberTowns;
|
||||
h & numberArtifacts;
|
||||
h & numberDwellings;
|
||||
h & armyStrength;
|
||||
h & totalExperience;
|
||||
h & income;
|
||||
h & mapExploredRatio;
|
||||
h & obeliskVisitedRatio;
|
||||
h & townBuiltRatio;
|
||||
h & hasGrail;
|
||||
h & numMines;
|
||||
h & score;
|
||||
h & maxHeroLevel;
|
||||
h & numBattlesNeutral;
|
||||
h & numBattlesPlayer;
|
||||
h & numWinBattlesNeutral;
|
||||
h & numWinBattlesPlayer;
|
||||
h & numHeroSurrendered;
|
||||
h & numHeroEscaped;
|
||||
h & spentResourcesForArmy;
|
||||
h & spentResourcesForBuildings;
|
||||
h & tradeVolume;
|
||||
h & movementPointsUsed;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE StatisticDataSet
|
||||
{
|
||||
std::vector<StatisticDataSetEntry> data;
|
||||
|
||||
public:
|
||||
void add(StatisticDataSetEntry entry);
|
||||
static StatisticDataSetEntry createEntry(const PlayerState * ps, const CGameState * gs);
|
||||
std::string toCsv();
|
||||
|
||||
struct PlayerAccumulatedValueStorage // holds some actual values needed for stats
|
||||
{
|
||||
int numBattlesNeutral;
|
||||
int numBattlesPlayer;
|
||||
int numWinBattlesNeutral;
|
||||
int numWinBattlesPlayer;
|
||||
int numHeroSurrendered;
|
||||
int numHeroEscaped;
|
||||
TResources spentResourcesForArmy;
|
||||
TResources spentResourcesForBuildings;
|
||||
TResources tradeVolume;
|
||||
si64 movementPointsUsed;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h)
|
||||
{
|
||||
h & numBattlesNeutral;
|
||||
h & numBattlesPlayer;
|
||||
h & numWinBattlesNeutral;
|
||||
h & numWinBattlesPlayer;
|
||||
h & numHeroSurrendered;
|
||||
h & numHeroEscaped;
|
||||
h & spentResourcesForArmy;
|
||||
h & spentResourcesForBuildings;
|
||||
h & tradeVolume;
|
||||
h & movementPointsUsed;
|
||||
}
|
||||
};
|
||||
std::map<PlayerColor, PlayerAccumulatedValueStorage> accumulatedValues;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h)
|
||||
{
|
||||
h & data;
|
||||
h & accumulatedValues;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE Statistic
|
||||
{
|
||||
static std::vector<const CGMine *> getMines(const CGameState * gs, const PlayerState * ps);
|
||||
public:
|
||||
static int getNumberOfArts(const PlayerState * ps);
|
||||
static si64 getArmyStrength(const PlayerState * ps, bool withTownGarrison = false);
|
||||
static si64 getTotalExperience(const PlayerState * ps);
|
||||
static int getIncome(const CGameState * gs, const PlayerState * ps);
|
||||
static float getMapExploredRatio(const CGameState * gs, PlayerColor player);
|
||||
static const CGHeroInstance * findBestHero(const CGameState * gs, const PlayerColor & color);
|
||||
static std::vector<std::vector<PlayerColor>> getRank(std::vector<std::pair<PlayerColor, si64>> stats);
|
||||
static int getObeliskVisited(const CGameState * gs, const TeamID & t);
|
||||
static float getObeliskVisitedRatio(const CGameState * gs, const TeamID & t);
|
||||
static std::map<EGameResID, int> getNumMines(const CGameState * gs, const PlayerState * ps);
|
||||
static float getTownBuiltRatio(const PlayerState * ps);
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
111
lib/gameState/HighScore.cpp
Normal file
111
lib/gameState/HighScore.cpp
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* HighScore.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 "HighScore.h"
|
||||
#include "../CPlayerState.h"
|
||||
#include "../constants/StringConstants.h"
|
||||
#include "CGameState.h"
|
||||
#include "StartInfo.h"
|
||||
#include "../mapping/CMapHeader.h"
|
||||
#include "../mapObjects/CGHeroInstance.h"
|
||||
#include "../mapObjects/CGTownInstance.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
HighScoreParameter HighScore::prepareHighScores(const CGameState * gs, PlayerColor player, bool victory)
|
||||
{
|
||||
const auto * playerState = gs->getPlayerState(player);
|
||||
|
||||
HighScoreParameter param;
|
||||
param.difficulty = gs->getStartInfo()->difficulty;
|
||||
param.day = gs->getDate();
|
||||
param.townAmount = gs->howManyTowns(player);
|
||||
param.usedCheat = gs->getPlayerState(player)->cheated;
|
||||
param.hasGrail = false;
|
||||
for(const CGHeroInstance * h : playerState->heroes)
|
||||
if(h->hasArt(ArtifactID::GRAIL))
|
||||
param.hasGrail = true;
|
||||
for(const CGTownInstance * t : playerState->towns)
|
||||
if(t->builtBuildings.count(BuildingID::GRAIL))
|
||||
param.hasGrail = true;
|
||||
param.allEnemiesDefeated = true;
|
||||
for (PlayerColor otherPlayer(0); otherPlayer < PlayerColor::PLAYER_LIMIT; ++otherPlayer)
|
||||
{
|
||||
auto ps = gs->getPlayerState(otherPlayer, false);
|
||||
if(ps && otherPlayer != player && !ps->checkVanquished())
|
||||
param.allEnemiesDefeated = false;
|
||||
}
|
||||
param.scenarioName = gs->getMapHeader()->name.toString();
|
||||
param.playerName = gs->getStartInfo()->playerInfos.find(player)->second.name;
|
||||
|
||||
return param;
|
||||
}
|
||||
|
||||
HighScoreCalculation::Result HighScoreCalculation::calculate()
|
||||
{
|
||||
Result firstResult;
|
||||
Result summary;
|
||||
const std::array<double, 5> difficultyMultipliers{0.8, 1.0, 1.3, 1.6, 2.0};
|
||||
for(auto & param : parameters)
|
||||
{
|
||||
double tmp = 200 - (param.day + 10) / (param.townAmount + 5) + (param.allEnemiesDefeated ? 25 : 0) + (param.hasGrail ? 25 : 0);
|
||||
firstResult = Result{static_cast<int>(tmp), static_cast<int>(tmp * difficultyMultipliers.at(param.difficulty)), param.day, param.usedCheat};
|
||||
summary.basic += firstResult.basic * 5.0 / parameters.size();
|
||||
summary.total += firstResult.total * 5.0 / parameters.size();
|
||||
summary.sumDays += firstResult.sumDays;
|
||||
summary.cheater |= firstResult.cheater;
|
||||
}
|
||||
|
||||
if(parameters.size() == 1)
|
||||
return firstResult;
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
struct HighScoreCreature
|
||||
{
|
||||
CreatureID creature;
|
||||
int min;
|
||||
int max;
|
||||
};
|
||||
|
||||
static std::vector<HighScoreCreature> getHighscoreCreaturesList()
|
||||
{
|
||||
JsonNode configCreatures(JsonPath::builtin("CONFIG/highscoreCreatures.json"));
|
||||
|
||||
std::vector<HighScoreCreature> ret;
|
||||
|
||||
for(auto & json : configCreatures["creatures"].Vector())
|
||||
{
|
||||
HighScoreCreature entry;
|
||||
entry.creature = CreatureID::decode(json["creature"].String());
|
||||
entry.max = json["max"].isNull() ? std::numeric_limits<int>::max() : json["max"].Integer();
|
||||
entry.min = json["min"].isNull() ? std::numeric_limits<int>::min() : json["min"].Integer();
|
||||
|
||||
ret.push_back(entry);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CreatureID HighScoreCalculation::getCreatureForPoints(int points, bool campaign)
|
||||
{
|
||||
static const std::vector<HighScoreCreature> creatures = getHighscoreCreaturesList();
|
||||
|
||||
int divide = campaign ? 5 : 1;
|
||||
|
||||
for(auto & creature : creatures)
|
||||
if(points / divide <= creature.max && points / divide >= creature.min)
|
||||
return creature.creature;
|
||||
|
||||
throw std::runtime_error("Unable to find creature for score " + std::to_string(points));
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -9,8 +9,12 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../GameConstants.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CGameState;
|
||||
|
||||
class DLL_LINKAGE HighScoreParameter
|
||||
{
|
||||
public:
|
||||
@ -37,5 +41,28 @@ public:
|
||||
h & playerName;
|
||||
}
|
||||
};
|
||||
class DLL_LINKAGE HighScore
|
||||
{
|
||||
public:
|
||||
static HighScoreParameter prepareHighScores(const CGameState * gs, PlayerColor player, bool victory);
|
||||
};
|
||||
|
||||
class DLL_LINKAGE HighScoreCalculation
|
||||
{
|
||||
public:
|
||||
struct Result
|
||||
{
|
||||
int basic = 0;
|
||||
int total = 0;
|
||||
int sumDays = 0;
|
||||
bool cheater = false;
|
||||
};
|
||||
|
||||
std::vector<HighScoreParameter> parameters;
|
||||
bool isCampaign = false;
|
||||
|
||||
Result calculate();
|
||||
static CreatureID getCreatureForPoints(int points, bool campaign);
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -393,7 +393,7 @@ void CBank::battleFinished(const CGHeroInstance *hero, const BattleResult &resul
|
||||
}
|
||||
}
|
||||
|
||||
void CBank::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
||||
void CBank::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
|
||||
{
|
||||
if (answer)
|
||||
{
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
bool isCoastVisitable() const override;
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
|
||||
|
||||
std::vector<Component> getPopupComponents(PlayerColor player) const override;
|
||||
|
||||
|
@ -523,7 +523,7 @@ void CGCreature::battleFinished(const CGHeroInstance *hero, const BattleResult &
|
||||
}
|
||||
}
|
||||
|
||||
void CGCreature::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
||||
void CGCreature::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
|
||||
{
|
||||
auto action = takenAction(hero);
|
||||
if(!refusedJoining && action >= JOIN_FOR_FREE) //higher means price
|
||||
|
@ -48,7 +48,7 @@ public:
|
||||
void pickRandomObject(vstd::RNG & rand) override;
|
||||
void newTurn(vstd::RNG & rand) const override;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
|
||||
CreatureID getCreature() const;
|
||||
|
||||
//stack formation depends on position,
|
||||
|
@ -516,7 +516,7 @@ void CGDwelling::battleFinished(const CGHeroInstance *hero, const BattleResult &
|
||||
}
|
||||
}
|
||||
|
||||
void CGDwelling::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
||||
void CGDwelling::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
|
||||
{
|
||||
auto relations = cb->getPlayerRelations(getOwner(), hero->getOwner());
|
||||
if(stacksCount() > 0 && relations == PlayerRelations::ENEMIES) //guards present
|
||||
|
@ -54,7 +54,7 @@ private:
|
||||
void newTurn(vstd::RNG & rand) const override;
|
||||
void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
|
||||
std::vector<Component> getPopupComponents(PlayerColor player) const override;
|
||||
|
||||
void updateGuards() const;
|
||||
|
@ -186,7 +186,7 @@ void CGPandoraBox::battleFinished(const CGHeroInstance *hero, const BattleResult
|
||||
}
|
||||
}
|
||||
|
||||
void CGPandoraBox::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
||||
void CGPandoraBox::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
|
||||
{
|
||||
if(answer)
|
||||
{
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
void initObj(vstd::RNG & rand) override;
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h)
|
||||
{
|
||||
|
@ -385,7 +385,7 @@ void CTownRewardableBuilding::heroLevelUpDone(const CGHeroInstance *hero) const
|
||||
grantRewardAfterLevelup(cb, configuration.info.at(selectedReward), town, hero);
|
||||
}
|
||||
|
||||
void CTownRewardableBuilding::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
||||
void CTownRewardableBuilding::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
|
||||
{
|
||||
if(answer == 0)
|
||||
return; // player refused
|
||||
|
@ -133,7 +133,7 @@ public:
|
||||
void initObj(vstd::RNG & rand) override;
|
||||
|
||||
/// applies player selection of reward
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
|
||||
|
||||
CTownRewardableBuilding(const BuildingID & index, BuildingSubID::EBuildingSubID subId, CGTownInstance * town, vstd::RNG & rand);
|
||||
CTownRewardableBuilding(IGameCallback *cb);
|
||||
|
@ -281,7 +281,7 @@ void CGTownInstance::setOwner(const PlayerColor & player) const
|
||||
cb->setOwner(this, player);
|
||||
}
|
||||
|
||||
void CGTownInstance::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
||||
void CGTownInstance::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
|
||||
{
|
||||
for (auto building : bonusingBuildings)
|
||||
building->blockingDialogAnswered(hero, answer);
|
||||
@ -1221,6 +1221,12 @@ void CGTownInstance::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
handler.serializeIdArray( "possibleSpells", possibleSpells);
|
||||
handler.serializeIdArray( "obligatorySpells", obligatorySpells);
|
||||
}
|
||||
|
||||
{
|
||||
auto eventsHandler = handler.enterArray("events");
|
||||
eventsHandler.syncSize(events, JsonNode::JsonType::DATA_VECTOR);
|
||||
eventsHandler.serializeStruct(events);
|
||||
}
|
||||
}
|
||||
|
||||
FactionID CGTownInstance::getFaction() const
|
||||
|
@ -65,7 +65,7 @@ public:
|
||||
std::vector<CGTownBuilding*> bonusingBuildings;
|
||||
std::vector<SpellID> possibleSpells, obligatorySpells;
|
||||
std::vector<std::vector<SpellID> > spells; //spells[level] -> vector of spells, first will be available in guild
|
||||
std::list<CCastleEvent> events;
|
||||
std::vector<CCastleEvent> events;
|
||||
std::pair<si32, si32> bonusValue;//var to store town bonuses (rampart = resources from mystic pond);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -223,7 +223,7 @@ public:
|
||||
protected:
|
||||
void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override;
|
||||
void serializeJsonOptions(JsonSerializeFormat & handler) override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
|
||||
|
||||
private:
|
||||
FactionID randomizeFaction(vstd::RNG & rand);
|
||||
|
@ -660,7 +660,7 @@ const CGCreature * CGSeerHut::getCreatureToKill(bool allowNull) const
|
||||
return dynamic_cast<const CGCreature *>(o);
|
||||
}
|
||||
|
||||
void CGSeerHut::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
||||
void CGSeerHut::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
|
||||
{
|
||||
CRewardableObject::blockingDialogAnswered(hero, answer);
|
||||
if(answer)
|
||||
@ -865,7 +865,7 @@ void CGBorderGuard::onHeroVisit(const CGHeroInstance * h) const
|
||||
}
|
||||
}
|
||||
|
||||
void CGBorderGuard::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
||||
void CGBorderGuard::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
|
||||
{
|
||||
if (answer)
|
||||
cb->removeObject(this, hero->getOwner());
|
||||
|
@ -150,7 +150,7 @@ public:
|
||||
std::vector<Component> getPopupComponents(const CGHeroInstance * hero) const override;
|
||||
void newTurn(vstd::RNG & rand) const override;
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
|
||||
void getVisitText (MetaString &text, std::vector<Component> &components, bool FirstVisit, const CGHeroInstance * h = nullptr) const override;
|
||||
|
||||
virtual void init(vstd::RNG & rand);
|
||||
@ -229,7 +229,7 @@ public:
|
||||
|
||||
void initObj(vstd::RNG & rand) override;
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
|
||||
|
||||
void getVisitText (MetaString &text, std::vector<Component> &components, bool FirstVisit, const CGHeroInstance * h = nullptr) const override;
|
||||
void getRolloverText (MetaString &text, bool onHover) const;
|
||||
|
@ -181,7 +181,7 @@ void CRewardableObject::heroLevelUpDone(const CGHeroInstance *hero) const
|
||||
grantRewardAfterLevelup(cb, configuration.info.at(selectedReward), this, hero);
|
||||
}
|
||||
|
||||
void CRewardableObject::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
||||
void CRewardableObject::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
|
||||
{
|
||||
if(answer == 0)
|
||||
{
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
void heroLevelUpDone(const CGHeroInstance *hero) const override;
|
||||
|
||||
/// applies player selection of reward
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
|
||||
|
||||
void initObj(vstd::RNG & rand) override;
|
||||
|
||||
|
@ -68,7 +68,7 @@ void IObjectInterface::preInit()
|
||||
void IObjectInterface::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
|
||||
{}
|
||||
|
||||
void IObjectInterface::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
||||
void IObjectInterface::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
|
||||
{}
|
||||
|
||||
void IObjectInterface::garrisonDialogClosed(const CGHeroInstance *hero) const
|
||||
|
@ -61,7 +61,7 @@ public:
|
||||
//Called when queries created DURING HERO VISIT are resolved
|
||||
//First parameter is always hero that visited object and triggered the query
|
||||
virtual void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const;
|
||||
virtual void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const;
|
||||
virtual void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const;
|
||||
virtual void garrisonDialogClosed(const CGHeroInstance *hero) const;
|
||||
virtual void heroLevelUpDone(const CGHeroInstance *hero) const;
|
||||
|
||||
|
@ -215,7 +215,7 @@ void CGMine::battleFinished(const CGHeroInstance *hero, const BattleResult &resu
|
||||
}
|
||||
}
|
||||
|
||||
void CGMine::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
||||
void CGMine::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
|
||||
{
|
||||
if(answer)
|
||||
cb->startBattleI(hero, this);
|
||||
@ -348,7 +348,7 @@ void CGResource::battleFinished(const CGHeroInstance *hero, const BattleResult &
|
||||
collectRes(hero->getOwner());
|
||||
}
|
||||
|
||||
void CGResource::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
||||
void CGResource::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
|
||||
{
|
||||
if(answer)
|
||||
cb->startBattleI(hero, this);
|
||||
@ -915,7 +915,7 @@ void CGArtifact::battleFinished(const CGHeroInstance *hero, const BattleResult &
|
||||
pick(hero);
|
||||
}
|
||||
|
||||
void CGArtifact::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
|
||||
void CGArtifact::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const
|
||||
{
|
||||
if(answer)
|
||||
cb->startBattleI(hero, this);
|
||||
|
@ -91,7 +91,7 @@ public:
|
||||
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
|
||||
|
||||
std::string getObjectName() const override;
|
||||
std::string getPopupText(PlayerColor player) const override;
|
||||
@ -132,7 +132,7 @@ public:
|
||||
void initObj(vstd::RNG & rand) override;
|
||||
void pickRandomObject(vstd::RNG & rand) override;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
|
||||
std::string getHoverText(PlayerColor player) const override;
|
||||
|
||||
void collectRes(const PlayerColor & player) const;
|
||||
@ -163,7 +163,7 @@ private:
|
||||
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, int32_t answer) const override;
|
||||
|
||||
void flagMine(const PlayerColor & player) const;
|
||||
void newTurn(vstd::RNG & rand) const override;
|
||||
|
@ -561,7 +561,7 @@ struct DLL_LINKAGE UpdateMapEvents : public CPackForClient
|
||||
struct DLL_LINKAGE UpdateCastleEvents : public CPackForClient
|
||||
{
|
||||
ObjectInstanceID town;
|
||||
std::list<CCastleEvent> events;
|
||||
std::vector<CCastleEvent> events;
|
||||
|
||||
void applyGs(CGameState * gs) const;
|
||||
void visitTyped(ICPackVisitor & visitor) override;
|
||||
|
@ -59,7 +59,8 @@ enum class ESerializationVersion : int32_t
|
||||
REMOVE_LIB_RNG, // 849 - removed random number generators from library classes
|
||||
HIGHSCORE_PARAMETERS, // 850 - saves parameter for campaign
|
||||
PLAYER_HANDICAP, // 851 - player handicap selection at game start
|
||||
CAMPAIGN_REGIONS, // 852 - configurable campaign regions
|
||||
STATISTICS, // 852 - removed random number generators from library classes
|
||||
CAMPAIGN_REGIONS, // 853 - configurable campaign regions
|
||||
|
||||
CURRENT = PLAYER_HANDICAP
|
||||
CURRENT = CAMPAIGN_REGIONS
|
||||
};
|
||||
|
@ -29,6 +29,9 @@ set(editor_SRCS
|
||||
validator.cpp
|
||||
inspector/inspector.cpp
|
||||
inspector/townbuildingswidget.cpp
|
||||
inspector/towneventdialog.cpp
|
||||
inspector/towneventswidget.cpp
|
||||
inspector/townspellswidget.cpp
|
||||
inspector/armywidget.cpp
|
||||
inspector/messagewidget.cpp
|
||||
inspector/rewardswidget.cpp
|
||||
@ -70,6 +73,9 @@ set(editor_HEADERS
|
||||
validator.h
|
||||
inspector/inspector.h
|
||||
inspector/townbuildingswidget.h
|
||||
inspector/towneventdialog.h
|
||||
inspector/towneventswidget.h
|
||||
inspector/townspellswidget.h
|
||||
inspector/armywidget.h
|
||||
inspector/messagewidget.h
|
||||
inspector/rewardswidget.h
|
||||
@ -79,6 +85,7 @@ set(editor_HEADERS
|
||||
inspector/PickObjectDelegate.h
|
||||
inspector/portraitwidget.h
|
||||
resourceExtractor/ResourceConverter.h
|
||||
mapeditorroles.h
|
||||
)
|
||||
|
||||
set(editor_FORMS
|
||||
@ -98,6 +105,9 @@ set(editor_FORMS
|
||||
playerparams.ui
|
||||
validator.ui
|
||||
inspector/townbuildingswidget.ui
|
||||
inspector/towneventdialog.ui
|
||||
inspector/towneventswidget.ui
|
||||
inspector/townspellswidget.ui
|
||||
inspector/armywidget.ui
|
||||
inspector/messagewidget.ui
|
||||
inspector/rewardswidget.ui
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "../lib/constants/StringConstants.h"
|
||||
|
||||
#include "townbuildingswidget.h"
|
||||
#include "towneventswidget.h"
|
||||
#include "townspellswidget.h"
|
||||
#include "armywidget.h"
|
||||
#include "messagewidget.h"
|
||||
#include "rewardswidget.h"
|
||||
@ -342,6 +344,8 @@ void Inspector::updateProperties(CGTownInstance * o)
|
||||
|
||||
auto * delegate = new TownBuildingsDelegate(*o);
|
||||
addProperty("Buildings", PropertyEditorPlaceholder(), delegate, false);
|
||||
addProperty("Spells", PropertyEditorPlaceholder(), new TownSpellsDelegate(*o), false);
|
||||
addProperty("Events", PropertyEditorPlaceholder(), new TownEventsDelegate(*o, controller), false);
|
||||
}
|
||||
|
||||
void Inspector::updateProperties(CGArtifact * o)
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "StdInc.h"
|
||||
#include "townbuildingswidget.h"
|
||||
#include "ui_townbuildingswidget.h"
|
||||
#include "mapeditorroles.h"
|
||||
#include "../lib/entities/building/CBuilding.h"
|
||||
#include "../lib/entities/faction/CTownHandler.h"
|
||||
#include "../lib/texts/CGeneralTextHandler.h"
|
||||
@ -68,6 +69,56 @@ std::string defaultBuildingIdConversion(BuildingID bId)
|
||||
}
|
||||
}
|
||||
|
||||
QStandardItem * getBuildingParentFromTreeModel(const CBuilding * building, const QStandardItemModel & model)
|
||||
{
|
||||
QStandardItem * parent = nullptr;
|
||||
std::vector<QModelIndex> stack(1);
|
||||
do
|
||||
{
|
||||
auto pindex = stack.back();
|
||||
stack.pop_back();
|
||||
auto rowCount = model.rowCount(pindex);
|
||||
for (int i = 0; i < rowCount; ++i)
|
||||
{
|
||||
QModelIndex index = model.index(i, 0, pindex);
|
||||
if (building->upgrade.getNum() == model.itemFromIndex(index)->data(MapEditorRoles::BuildingIDRole).toInt())
|
||||
{
|
||||
parent = model.itemFromIndex(index);
|
||||
break;
|
||||
}
|
||||
if (model.hasChildren(index))
|
||||
stack.push_back(index);
|
||||
}
|
||||
} while(!parent && !stack.empty());
|
||||
return parent;
|
||||
}
|
||||
|
||||
QVariantList getBuildingVariantsFromModel(const QStandardItemModel & model, int modelColumn, Qt::CheckState checkState)
|
||||
{
|
||||
QVariantList result;
|
||||
std::vector<QModelIndex> stack(1);
|
||||
do
|
||||
{
|
||||
auto pindex = stack.back();
|
||||
stack.pop_back();
|
||||
auto rowCount = model.rowCount(pindex);
|
||||
for (int i = 0; i < rowCount; ++i)
|
||||
{
|
||||
QModelIndex index = model.index(i, modelColumn, pindex);
|
||||
auto * item = model.itemFromIndex(index);
|
||||
if(item && item->checkState() == checkState)
|
||||
result.push_back(item->data(MapEditorRoles::BuildingIDRole));
|
||||
index = model.index(i, 0, pindex);
|
||||
if (model.hasChildren(index))
|
||||
stack.push_back(index);
|
||||
}
|
||||
} while(!stack.empty());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TownBuildingsWidget::TownBuildingsWidget(CGTownInstance & t, QWidget *parent) :
|
||||
town(t),
|
||||
QDialog(parent),
|
||||
@ -76,8 +127,8 @@ TownBuildingsWidget::TownBuildingsWidget(CGTownInstance & t, QWidget *parent) :
|
||||
ui->setupUi(this);
|
||||
ui->treeView->setModel(&model);
|
||||
//ui->treeView->setColumnCount(3);
|
||||
model.setHorizontalHeaderLabels(QStringList() << QStringLiteral("Type") << QStringLiteral("Enabled") << QStringLiteral("Built"));
|
||||
|
||||
model.setHorizontalHeaderLabels(QStringList() << tr("Type") << tr("Enabled") << tr("Built"));
|
||||
connect(&model, &QStandardItemModel::itemChanged, this, &TownBuildingsWidget::onItemChanged);
|
||||
//setAttribute(Qt::WA_DeleteOnClose);
|
||||
}
|
||||
|
||||
@ -96,7 +147,7 @@ QStandardItem * TownBuildingsWidget::addBuilding(const CTown & ctown, int bId, s
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString name = tr(building->getNameTranslated().c_str());
|
||||
QString name = QString::fromStdString(building->getNameTranslated());
|
||||
|
||||
if(name.isEmpty())
|
||||
name = QString::fromStdString(defaultBuildingIdConversion(buildingId));
|
||||
@ -104,17 +155,17 @@ QStandardItem * TownBuildingsWidget::addBuilding(const CTown & ctown, int bId, s
|
||||
QList<QStandardItem *> checks;
|
||||
|
||||
checks << new QStandardItem(name);
|
||||
checks.back()->setData(bId, Qt::UserRole);
|
||||
checks.back()->setData(bId, MapEditorRoles::BuildingIDRole);
|
||||
|
||||
checks << new QStandardItem;
|
||||
checks.back()->setCheckable(true);
|
||||
checks.back()->setCheckState(town.forbiddenBuildings.count(buildingId) ? Qt::Unchecked : Qt::Checked);
|
||||
checks.back()->setData(bId, Qt::UserRole);
|
||||
checks.back()->setData(bId, MapEditorRoles::BuildingIDRole);
|
||||
|
||||
checks << new QStandardItem;
|
||||
checks.back()->setCheckable(true);
|
||||
checks.back()->setCheckState(town.builtBuildings.count(buildingId) ? Qt::Checked : Qt::Unchecked);
|
||||
checks.back()->setData(bId, Qt::UserRole);
|
||||
checks.back()->setData(bId, MapEditorRoles::BuildingIDRole);
|
||||
|
||||
if(building->getBase() == buildingId)
|
||||
{
|
||||
@ -122,25 +173,7 @@ QStandardItem * TownBuildingsWidget::addBuilding(const CTown & ctown, int bId, s
|
||||
}
|
||||
else
|
||||
{
|
||||
QStandardItem * parent = nullptr;
|
||||
std::vector<QModelIndex> stack;
|
||||
stack.push_back(QModelIndex());
|
||||
while(!parent && !stack.empty())
|
||||
{
|
||||
auto pindex = stack.back();
|
||||
stack.pop_back();
|
||||
for(int i = 0; i < model.rowCount(pindex); ++i)
|
||||
{
|
||||
QModelIndex index = model.index(i, 0, pindex);
|
||||
if(building->upgrade.getNum() == model.itemFromIndex(index)->data(Qt::UserRole).toInt())
|
||||
{
|
||||
parent = model.itemFromIndex(index);
|
||||
break;
|
||||
}
|
||||
if(model.hasChildren(index))
|
||||
stack.push_back(index);
|
||||
}
|
||||
}
|
||||
QStandardItem * parent = getBuildingParentFromTreeModel(building, model);
|
||||
|
||||
if(!parent)
|
||||
parent = addBuilding(ctown, building->upgrade.getNum(), remaining);
|
||||
@ -172,36 +205,23 @@ void TownBuildingsWidget::addBuildings(const CTown & ctown)
|
||||
|
||||
std::set<BuildingID> TownBuildingsWidget::getBuildingsFromModel(int modelColumn, Qt::CheckState checkState)
|
||||
{
|
||||
auto buildingVariants = getBuildingVariantsFromModel(model, modelColumn, checkState);
|
||||
std::set<BuildingID> result;
|
||||
std::vector<QModelIndex> stack;
|
||||
stack.push_back(QModelIndex());
|
||||
while(!stack.empty())
|
||||
for (const auto & buildingId : buildingVariants)
|
||||
{
|
||||
auto pindex = stack.back();
|
||||
stack.pop_back();
|
||||
for(int i = 0; i < model.rowCount(pindex); ++i)
|
||||
{
|
||||
QModelIndex index = model.index(i, modelColumn, pindex);
|
||||
if(auto * item = model.itemFromIndex(index))
|
||||
if(item->checkState() == checkState)
|
||||
result.emplace(item->data(Qt::UserRole).toInt());
|
||||
index = model.index(i, 0, pindex); //children are linked to first column of the model
|
||||
if(model.hasChildren(index))
|
||||
stack.push_back(index);
|
||||
}
|
||||
result.insert(buildingId.toInt());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::set<BuildingID> TownBuildingsWidget::getForbiddenBuildings()
|
||||
{
|
||||
return getBuildingsFromModel(1, Qt::Unchecked);
|
||||
return getBuildingsFromModel(Column::ENABLED, Qt::Unchecked);
|
||||
}
|
||||
|
||||
std::set<BuildingID> TownBuildingsWidget::getBuiltBuildings()
|
||||
{
|
||||
return getBuildingsFromModel(2, Qt::Checked);
|
||||
return getBuildingsFromModel(Column::BUILT, Qt::Checked);
|
||||
}
|
||||
|
||||
void TownBuildingsWidget::on_treeView_expanded(const QModelIndex &index)
|
||||
@ -214,6 +234,87 @@ void TownBuildingsWidget::on_treeView_collapsed(const QModelIndex &index)
|
||||
ui->treeView->resizeColumnToContents(0);
|
||||
}
|
||||
|
||||
void TownBuildingsWidget::on_buildAll_clicked()
|
||||
{
|
||||
setAllRowsColumnCheckState(Column::BUILT, Qt::Checked);
|
||||
}
|
||||
|
||||
void TownBuildingsWidget::on_demolishAll_clicked()
|
||||
{
|
||||
setAllRowsColumnCheckState(Column::BUILT, Qt::Unchecked);
|
||||
}
|
||||
|
||||
void TownBuildingsWidget::on_enableAll_clicked()
|
||||
{
|
||||
setAllRowsColumnCheckState(Column::ENABLED, Qt::Checked);
|
||||
}
|
||||
|
||||
void TownBuildingsWidget::on_disableAll_clicked()
|
||||
{
|
||||
setAllRowsColumnCheckState(Column::ENABLED, Qt::Unchecked);
|
||||
}
|
||||
|
||||
|
||||
void TownBuildingsWidget::setRowColumnCheckState(const QStandardItem * item, Column column, Qt::CheckState checkState) {
|
||||
auto sibling = item->model()->sibling(item->row(), column, item->index());
|
||||
model.itemFromIndex(sibling)->setCheckState(checkState);
|
||||
}
|
||||
|
||||
void TownBuildingsWidget::setAllRowsColumnCheckState(Column column, Qt::CheckState checkState)
|
||||
{
|
||||
std::vector<QModelIndex> stack(1);
|
||||
do
|
||||
{
|
||||
auto parentIndex = stack.back();
|
||||
stack.pop_back();
|
||||
auto rowCount = model.rowCount(parentIndex);
|
||||
for (int i = 0; i < rowCount; ++i)
|
||||
{
|
||||
QModelIndex index = model.index(i, column, parentIndex);
|
||||
if (auto* item = model.itemFromIndex(index))
|
||||
item->setCheckState(checkState);
|
||||
index = model.index(i, 0, parentIndex);
|
||||
if (model.hasChildren(index))
|
||||
stack.push_back(index);
|
||||
}
|
||||
} while(!stack.empty());
|
||||
}
|
||||
|
||||
void TownBuildingsWidget::onItemChanged(const QStandardItem * item) {
|
||||
disconnect(&model, &QStandardItemModel::itemChanged, this, &TownBuildingsWidget::onItemChanged);
|
||||
auto rowFirstColumnIndex = item->model()->sibling(item->row(), Column::TYPE, item->index());
|
||||
QStandardItem * nextRow = model.itemFromIndex(rowFirstColumnIndex);
|
||||
if (item->checkState() == Qt::Checked) {
|
||||
while (nextRow) {
|
||||
setRowColumnCheckState(nextRow, Column(item->column()), Qt::Checked);
|
||||
if (item->column() == Column::BUILT) {
|
||||
setRowColumnCheckState(nextRow, Column::ENABLED, Qt::Checked);
|
||||
}
|
||||
nextRow = nextRow->parent();
|
||||
|
||||
}
|
||||
}
|
||||
else if (item->checkState() == Qt::Unchecked) {
|
||||
std::vector<QStandardItem*> stack;
|
||||
stack.push_back(nextRow);
|
||||
do
|
||||
{
|
||||
nextRow = stack.back();
|
||||
stack.pop_back();
|
||||
setRowColumnCheckState(nextRow, Column(item->column()), Qt::Unchecked);
|
||||
if (item->column() == Column::ENABLED) {
|
||||
setRowColumnCheckState(nextRow, Column::BUILT, Qt::Unchecked);
|
||||
}
|
||||
if (nextRow->hasChildren()) {
|
||||
for (int i = 0; i < nextRow->rowCount(); ++i) {
|
||||
stack.push_back(nextRow->child(i, Column::TYPE));
|
||||
}
|
||||
}
|
||||
|
||||
} while(!stack.empty());
|
||||
}
|
||||
connect(&model, &QStandardItemModel::itemChanged, this, &TownBuildingsWidget::onItemChanged);
|
||||
}
|
||||
|
||||
TownBuildingsDelegate::TownBuildingsDelegate(CGTownInstance & t): town(t), QStyledItemDelegate()
|
||||
{
|
||||
|
@ -19,6 +19,10 @@ class TownBuildingsWidget;
|
||||
|
||||
std::string defaultBuildingIdConversion(BuildingID bId);
|
||||
|
||||
QStandardItem * getBuildingParentFromTreeModel(const CBuilding * building, const QStandardItemModel & model);
|
||||
|
||||
QVariantList getBuildingVariantsFromModel(const QStandardItemModel & model, int modelColumn, Qt::CheckState checkState);
|
||||
|
||||
class TownBuildingsWidget : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -26,9 +30,13 @@ class TownBuildingsWidget : public QDialog
|
||||
QStandardItem * addBuilding(const CTown & ctown, int bId, std::set<si32> & remaining);
|
||||
|
||||
public:
|
||||
enum Column
|
||||
{
|
||||
TYPE, ENABLED, BUILT
|
||||
};
|
||||
explicit TownBuildingsWidget(CGTownInstance &, QWidget *parent = nullptr);
|
||||
~TownBuildingsWidget();
|
||||
|
||||
|
||||
void addBuildings(const CTown & ctown);
|
||||
std::set<BuildingID> getForbiddenBuildings();
|
||||
std::set<BuildingID> getBuiltBuildings();
|
||||
@ -38,9 +46,21 @@ private slots:
|
||||
|
||||
void on_treeView_collapsed(const QModelIndex &index);
|
||||
|
||||
void on_buildAll_clicked();
|
||||
|
||||
void on_demolishAll_clicked();
|
||||
|
||||
void on_enableAll_clicked();
|
||||
|
||||
void on_disableAll_clicked();
|
||||
|
||||
void onItemChanged(const QStandardItem * item);
|
||||
|
||||
private:
|
||||
std::set<BuildingID> getBuildingsFromModel(int modelColumn, Qt::CheckState checkState);
|
||||
|
||||
void setRowColumnCheckState(const QStandardItem * item, Column column, Qt::CheckState checkState);
|
||||
void setAllRowsColumnCheckState(Column column, Qt::CheckState checkState);
|
||||
|
||||
Ui::TownBuildingsWidget *ui;
|
||||
CGTownInstance & town;
|
||||
mutable QStandardItemModel model;
|
||||
|
@ -9,7 +9,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>480</width>
|
||||
<width>580</width>
|
||||
<height>280</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -21,7 +21,7 @@
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>480</width>
|
||||
<width>580</width>
|
||||
<height>280</height>
|
||||
</size>
|
||||
</property>
|
||||
@ -45,6 +45,38 @@
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="buildAll">
|
||||
<property name="text">
|
||||
<string>Build all</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="demolishAll">
|
||||
<property name="text">
|
||||
<string>Demolish all</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="enableAll">
|
||||
<property name="text">
|
||||
<string>Enable all</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="disableAll">
|
||||
<property name="text">
|
||||
<string>Disable all</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
289
mapeditor/inspector/towneventdialog.cpp
Normal file
289
mapeditor/inspector/towneventdialog.cpp
Normal file
@ -0,0 +1,289 @@
|
||||
/*
|
||||
* towneventdialog.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 "townbuildingswidget.h"
|
||||
#include "towneventdialog.h"
|
||||
#include "ui_towneventdialog.h"
|
||||
#include "mapeditorroles.h"
|
||||
#include "../../lib/entities/building/CBuilding.h"
|
||||
#include "../../lib/entities/faction/CTownHandler.h"
|
||||
#include "../../lib/constants/NumericConstants.h"
|
||||
#include "../../lib/constants/StringConstants.h"
|
||||
|
||||
static const int FIRST_DAY_FOR_EVENT = 1;
|
||||
static const int LAST_DAY_FOR_EVENT = 999;
|
||||
static const int MAXIMUM_EVENT_REPEAT_AFTER = 999;
|
||||
|
||||
static const int MAXIMUM_GOLD_CHANGE = 999999;
|
||||
static const int MAXIMUM_RESOURCE_CHANGE = 999;
|
||||
static const int GOLD_STEP = 100;
|
||||
static const int RESOURCE_STEP = 1;
|
||||
|
||||
static const int MAXIMUM_CREATURES_CHANGE = 999999;
|
||||
|
||||
TownEventDialog::TownEventDialog(CGTownInstance & t, QListWidgetItem * item, QWidget * parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::TownEventDialog),
|
||||
town(t),
|
||||
townEventListItem(item)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->buildingsTree->setModel(&buildingsModel);
|
||||
|
||||
params = townEventListItem->data(MapEditorRoles::TownEventRole).toMap();
|
||||
ui->eventFirstOccurrence->setMinimum(FIRST_DAY_FOR_EVENT);
|
||||
ui->eventFirstOccurrence->setMaximum(LAST_DAY_FOR_EVENT);
|
||||
ui->eventRepeatAfter->setMaximum(MAXIMUM_EVENT_REPEAT_AFTER);
|
||||
ui->eventNameText->setText(params.value("name").toString());
|
||||
ui->eventMessageText->setPlainText(params.value("message").toString());
|
||||
ui->eventAffectsCpu->setChecked(params.value("computerAffected").toBool());
|
||||
ui->eventAffectsHuman->setChecked(params.value("humanAffected").toBool());
|
||||
ui->eventFirstOccurrence->setValue(params.value("firstOccurrence").toInt()+1);
|
||||
ui->eventRepeatAfter->setValue(params.value("nextOccurrence").toInt());
|
||||
|
||||
initPlayers();
|
||||
initResources();
|
||||
initBuildings();
|
||||
initCreatures();
|
||||
}
|
||||
|
||||
TownEventDialog::~TownEventDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void TownEventDialog::initPlayers()
|
||||
{
|
||||
for (int i = 0; i < PlayerColor::PLAYER_LIMIT_I; ++i)
|
||||
{
|
||||
bool isAffected = (1 << i) & params.value("players").toInt();
|
||||
auto * item = new QListWidgetItem(QString::fromStdString(GameConstants::PLAYER_COLOR_NAMES[i]));
|
||||
item->setData(MapEditorRoles::PlayerIDRole, QVariant::fromValue(i));
|
||||
item->setCheckState(isAffected ? Qt::Checked : Qt::Unchecked);
|
||||
ui->playersAffected->addItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
void TownEventDialog::initResources()
|
||||
{
|
||||
ui->resourcesTable->setRowCount(GameConstants::RESOURCE_QUANTITY);
|
||||
auto resourcesMap = params.value("resources").toMap();
|
||||
for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i)
|
||||
{
|
||||
auto name = QString::fromStdString(GameConstants::RESOURCE_NAMES[i]);
|
||||
auto * item = new QTableWidgetItem();
|
||||
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||||
item->setText(name);
|
||||
ui->resourcesTable->setItem(i, 0, item);
|
||||
|
||||
int val = resourcesMap.value(name).toInt();
|
||||
auto * edit = new QSpinBox(ui->resourcesTable);
|
||||
edit->setMaximum(i == GameResID::GOLD ? MAXIMUM_GOLD_CHANGE : MAXIMUM_RESOURCE_CHANGE);
|
||||
edit->setMinimum(i == GameResID::GOLD ? -MAXIMUM_GOLD_CHANGE : -MAXIMUM_RESOURCE_CHANGE);
|
||||
edit->setSingleStep(i == GameResID::GOLD ? GOLD_STEP : RESOURCE_STEP);
|
||||
edit->setValue(val);
|
||||
|
||||
ui->resourcesTable->setCellWidget(i, 1, edit);
|
||||
}
|
||||
}
|
||||
|
||||
void TownEventDialog::initBuildings()
|
||||
{
|
||||
auto * ctown = town.town;
|
||||
if (!ctown)
|
||||
ctown = VLC->townh->randomTown;
|
||||
if (!ctown)
|
||||
throw std::runtime_error("No Town defined for type selected");
|
||||
auto allBuildings = ctown->getAllBuildings();
|
||||
while (!allBuildings.empty())
|
||||
{
|
||||
addBuilding(*ctown, *allBuildings.begin(), allBuildings);
|
||||
}
|
||||
ui->buildingsTree->resizeColumnToContents(0);
|
||||
|
||||
connect(&buildingsModel, &QStandardItemModel::itemChanged, this, &TownEventDialog::onItemChanged);
|
||||
}
|
||||
|
||||
QStandardItem * TownEventDialog::addBuilding(const CTown& ctown, BuildingID buildingId, std::set<si32>& remaining)
|
||||
{
|
||||
auto bId = buildingId.num;
|
||||
const CBuilding * building = ctown.buildings.at(buildingId);
|
||||
|
||||
QString name = QString::fromStdString(building->getNameTranslated());
|
||||
|
||||
if (name.isEmpty())
|
||||
name = QString::fromStdString(defaultBuildingIdConversion(buildingId));
|
||||
|
||||
QList<QStandardItem *> checks;
|
||||
|
||||
checks << new QStandardItem(name);
|
||||
checks.back()->setData(bId, MapEditorRoles::BuildingIDRole);
|
||||
|
||||
checks << new QStandardItem;
|
||||
checks.back()->setCheckable(true);
|
||||
checks.back()->setCheckState(params["buildings"].toList().contains(bId) ? Qt::Checked : Qt::Unchecked);
|
||||
checks.back()->setData(bId, MapEditorRoles::BuildingIDRole);
|
||||
|
||||
if (building->getBase() == buildingId)
|
||||
{
|
||||
buildingsModel.appendRow(checks);
|
||||
}
|
||||
else
|
||||
{
|
||||
QStandardItem * parent = getBuildingParentFromTreeModel(building, buildingsModel);
|
||||
|
||||
if (!parent)
|
||||
parent = addBuilding(ctown, building->upgrade.getNum(), remaining);
|
||||
|
||||
parent->appendRow(checks);
|
||||
}
|
||||
|
||||
remaining.erase(bId);
|
||||
return checks.front();
|
||||
}
|
||||
|
||||
void TownEventDialog::initCreatures()
|
||||
{
|
||||
auto creatures = params.value("creatures").toList();
|
||||
auto * ctown = town.town;
|
||||
for (int i = 0; i < GameConstants::CREATURES_PER_TOWN; ++i)
|
||||
{
|
||||
QString creatureNames;
|
||||
if (!ctown)
|
||||
{
|
||||
creatureNames.append(tr("Creature level %1 / Creature level %1 Upgrade").arg(i + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto creaturesOnLevel = ctown->creatures.at(i);
|
||||
for (auto& creature : creaturesOnLevel)
|
||||
{
|
||||
auto cre = VLC->creatures()->getById(creature);
|
||||
auto creatureName = QString::fromStdString(cre->getNameSingularTranslated());
|
||||
creatureNames.append(creatureNames.isEmpty() ? creatureName : " / " + creatureName);
|
||||
}
|
||||
}
|
||||
auto * item = new QTableWidgetItem();
|
||||
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||||
item->setText(creatureNames);
|
||||
ui->creaturesTable->setItem(i, 0, item);
|
||||
|
||||
auto creatureNumber = creatures.size() > i ? creatures.at(i).toInt() : 0;
|
||||
auto * edit = new QSpinBox(ui->creaturesTable);
|
||||
edit->setValue(creatureNumber);
|
||||
edit->setMaximum(MAXIMUM_CREATURES_CHANGE);
|
||||
ui->creaturesTable->setCellWidget(i, 1, edit);
|
||||
|
||||
}
|
||||
ui->creaturesTable->resizeColumnToContents(0);
|
||||
}
|
||||
|
||||
void TownEventDialog::on_TownEventDialog_finished(int result)
|
||||
{
|
||||
QVariantMap descriptor;
|
||||
descriptor["name"] = ui->eventNameText->text();
|
||||
descriptor["message"] = ui->eventMessageText->toPlainText();
|
||||
descriptor["humanAffected"] = QVariant::fromValue(ui->eventAffectsHuman->isChecked());
|
||||
descriptor["computerAffected"] = QVariant::fromValue(ui->eventAffectsCpu->isChecked());
|
||||
descriptor["firstOccurrence"] = QVariant::fromValue(ui->eventFirstOccurrence->value()-1);
|
||||
descriptor["nextOccurrence"] = QVariant::fromValue(ui->eventRepeatAfter->value());
|
||||
descriptor["players"] = playersToVariant();
|
||||
descriptor["resources"] = resourcesToVariant();
|
||||
descriptor["buildings"] = buildingsToVariant();
|
||||
descriptor["creatures"] = creaturesToVariant();
|
||||
|
||||
townEventListItem->setData(MapEditorRoles::TownEventRole, descriptor);
|
||||
auto itemText = tr("Day %1 - %2").arg(ui->eventFirstOccurrence->value(), 3).arg(ui->eventNameText->text());
|
||||
townEventListItem->setText(itemText);
|
||||
}
|
||||
|
||||
QVariant TownEventDialog::playersToVariant()
|
||||
{
|
||||
int players = 0;
|
||||
for (int i = 0; i < ui->playersAffected->count(); ++i)
|
||||
{
|
||||
auto * item = ui->playersAffected->item(i);
|
||||
if (item->checkState() == Qt::Checked)
|
||||
players |= 1 << i;
|
||||
}
|
||||
return QVariant::fromValue(players);
|
||||
}
|
||||
|
||||
QVariantMap TownEventDialog::resourcesToVariant()
|
||||
{
|
||||
auto res = params.value("resources").toMap();
|
||||
for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; ++i)
|
||||
{
|
||||
auto * itemType = ui->resourcesTable->item(i, 0);
|
||||
auto * itemQty = static_cast<QSpinBox *> (ui->resourcesTable->cellWidget(i, 1));
|
||||
|
||||
res[itemType->text()] = QVariant::fromValue(itemQty->value());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
QVariantList TownEventDialog::buildingsToVariant()
|
||||
{
|
||||
return getBuildingVariantsFromModel(buildingsModel, 1, Qt::Checked);
|
||||
}
|
||||
|
||||
QVariantList TownEventDialog::creaturesToVariant()
|
||||
{
|
||||
QVariantList creaturesList;
|
||||
for (int i = 0; i < GameConstants::CREATURES_PER_TOWN; ++i)
|
||||
{
|
||||
auto * item = static_cast<QSpinBox *>(ui->creaturesTable->cellWidget(i, 1));
|
||||
creaturesList.push_back(item->value());
|
||||
}
|
||||
return creaturesList;
|
||||
}
|
||||
|
||||
void TownEventDialog::on_okButton_clicked()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void TownEventDialog::setRowColumnCheckState(const QStandardItem * item, int column, Qt::CheckState checkState) {
|
||||
auto sibling = item->model()->sibling(item->row(), column, item->index());
|
||||
buildingsModel.itemFromIndex(sibling)->setCheckState(checkState);
|
||||
}
|
||||
|
||||
void TownEventDialog::onItemChanged(const QStandardItem * item)
|
||||
{
|
||||
disconnect(&buildingsModel, &QStandardItemModel::itemChanged, this, &TownEventDialog::onItemChanged);
|
||||
auto rowFirstColumnIndex = item->model()->sibling(item->row(), 0, item->index());
|
||||
QStandardItem * nextRow = buildingsModel.itemFromIndex(rowFirstColumnIndex);
|
||||
if (item->checkState() == Qt::Checked) {
|
||||
while (nextRow) {
|
||||
setRowColumnCheckState(nextRow,item->column(), Qt::Checked);
|
||||
nextRow = nextRow->parent();
|
||||
|
||||
}
|
||||
}
|
||||
else if (item->checkState() == Qt::Unchecked) {
|
||||
std::vector<QStandardItem *> stack;
|
||||
stack.push_back(nextRow);
|
||||
do
|
||||
{
|
||||
nextRow = stack.back();
|
||||
stack.pop_back();
|
||||
setRowColumnCheckState(nextRow, item->column(), Qt::Unchecked);
|
||||
if (nextRow->hasChildren()) {
|
||||
for (int i = 0; i < nextRow->rowCount(); ++i) {
|
||||
stack.push_back(nextRow->child(i, 0));
|
||||
}
|
||||
}
|
||||
|
||||
} while(!stack.empty());
|
||||
}
|
||||
connect(&buildingsModel, &QStandardItemModel::itemChanged, this, &TownEventDialog::onItemChanged);
|
||||
}
|
53
mapeditor/inspector/towneventdialog.h
Normal file
53
mapeditor/inspector/towneventdialog.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* towneventdialog.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
|
||||
|
||||
#include "../StdInc.h"
|
||||
#include <QDialog>
|
||||
#include "../lib/mapObjects/CGTownInstance.h"
|
||||
|
||||
namespace Ui {
|
||||
class TownEventDialog;
|
||||
}
|
||||
|
||||
class TownEventDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TownEventDialog(CGTownInstance & town, QListWidgetItem * item, QWidget * parent);
|
||||
~TownEventDialog();
|
||||
|
||||
|
||||
private slots:
|
||||
void onItemChanged(const QStandardItem * item);
|
||||
void on_TownEventDialog_finished(int result);
|
||||
void on_okButton_clicked();
|
||||
void setRowColumnCheckState(const QStandardItem * item, int column, Qt::CheckState checkState);
|
||||
|
||||
private:
|
||||
void initPlayers();
|
||||
void initResources();
|
||||
void initBuildings();
|
||||
void initCreatures();
|
||||
|
||||
QVariant playersToVariant();
|
||||
QVariantMap resourcesToVariant();
|
||||
QVariantList buildingsToVariant();
|
||||
QVariantList creaturesToVariant();
|
||||
|
||||
QStandardItem * addBuilding(const CTown & ctown, BuildingID bId, std::set<si32> & remaining);
|
||||
|
||||
Ui::TownEventDialog * ui;
|
||||
CGTownInstance & town;
|
||||
QListWidgetItem * townEventListItem;
|
||||
QMap<QString, QVariant> params;
|
||||
QStandardItemModel buildingsModel;
|
||||
};
|
266
mapeditor/inspector/towneventdialog.ui
Normal file
266
mapeditor/inspector/towneventdialog.ui
Normal file
@ -0,0 +1,266 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TownEventDialog</class>
|
||||
<widget class="QDialog" name="TownEventDialog">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>693</width>
|
||||
<height>525</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Town event</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="generalTab">
|
||||
<attribute name="title">
|
||||
<string>General</string>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="verticalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>9</x>
|
||||
<y>9</y>
|
||||
<width>511</width>
|
||||
<height>351</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="eventNameText">
|
||||
<property name="placeholderText">
|
||||
<string>Event name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="eventMessageText">
|
||||
<property name="placeholderText">
|
||||
<string>Type event message text</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="horizontalLayoutWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>370</y>
|
||||
<width>511</width>
|
||||
<height>61</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="eventFirstOccurrenceText">
|
||||
<property name="text">
|
||||
<string>Day of first occurrence</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="eventFirstOccurrence"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="eventRepeatAfterText">
|
||||
<property name="text">
|
||||
<string>Repeat after (0 = no repeat)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="eventRepeatAfter"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="verticalLayoutWidget_4">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>529</x>
|
||||
<y>9</y>
|
||||
<width>141</width>
|
||||
<height>421</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="playersAffectedText">
|
||||
<property name="text">
|
||||
<string>Affected players</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="playersAffected">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="eventAffectsHuman">
|
||||
<property name="text">
|
||||
<string>affects human</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="eventAffectsCpu">
|
||||
<property name="text">
|
||||
<string>affects AI</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QWidget" name="resourcesTab">
|
||||
<attribute name="title">
|
||||
<string>Resources</string>
|
||||
</attribute>
|
||||
<widget class="QTableWidget" name="resourcesTable">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>661</width>
|
||||
<height>421</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column/>
|
||||
<column/>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QWidget" name="buildingsTab">
|
||||
<attribute name="title">
|
||||
<string>Buildings</string>
|
||||
</attribute>
|
||||
<widget class="QTreeView" name="buildingsTree">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>661</width>
|
||||
<height>421</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QWidget" name="creaturesTab">
|
||||
<attribute name="title">
|
||||
<string>Creatures</string>
|
||||
</attribute>
|
||||
<widget class="QTableWidget" name="creaturesTable">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>10</y>
|
||||
<width>661</width>
|
||||
<height>421</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="rowCount">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<attribute name="horizontalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<attribute name="verticalHeaderVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<row/>
|
||||
<row/>
|
||||
<row/>
|
||||
<row/>
|
||||
<row/>
|
||||
<row/>
|
||||
<row/>
|
||||
<column/>
|
||||
<column/>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="okButton">
|
||||
<property name="text">
|
||||
<string>OK</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
177
mapeditor/inspector/towneventswidget.cpp
Normal file
177
mapeditor/inspector/towneventswidget.cpp
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* towneventswidget.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 "towneventswidget.h"
|
||||
#include "ui_towneventswidget.h"
|
||||
#include "towneventdialog.h"
|
||||
#include "mapeditorroles.h"
|
||||
#include "mapsettings/eventsettings.h"
|
||||
#include "../../lib/constants/NumericConstants.h"
|
||||
#include "../../lib/constants/StringConstants.h"
|
||||
|
||||
TownEventsWidget::TownEventsWidget(CGTownInstance & town, QWidget * parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::TownEventsWidget),
|
||||
town(town)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
TownEventsWidget::~TownEventsWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
QVariant toVariant(const std::set<BuildingID> & buildings)
|
||||
{
|
||||
QVariantList result;
|
||||
for (auto b : buildings)
|
||||
result.push_back(QVariant::fromValue(b.num));
|
||||
return result;
|
||||
}
|
||||
|
||||
QVariant toVariant(const std::vector<si32> & creatures)
|
||||
{
|
||||
QVariantList result;
|
||||
for (auto c : creatures)
|
||||
result.push_back(QVariant::fromValue(c));
|
||||
return result;
|
||||
}
|
||||
|
||||
std::set<BuildingID> buildingsFromVariant(const QVariant& v)
|
||||
{
|
||||
std::set<BuildingID> result;
|
||||
for (const auto & r : v.toList()) {
|
||||
result.insert(BuildingID(r.toInt()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<si32> creaturesFromVariant(const QVariant& v)
|
||||
{
|
||||
std::vector<si32> result;
|
||||
for (const auto & r : v.toList()) {
|
||||
result.push_back(r.toInt());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QVariant toVariant(const CCastleEvent& event)
|
||||
{
|
||||
QVariantMap result;
|
||||
result["name"] = QString::fromStdString(event.name);
|
||||
result["message"] = QString::fromStdString(event.message.toString());
|
||||
result["players"] = QVariant::fromValue(event.players);
|
||||
result["humanAffected"] = QVariant::fromValue(event.humanAffected);
|
||||
result["computerAffected"] = QVariant::fromValue(event.computerAffected);
|
||||
result["firstOccurrence"] = QVariant::fromValue(event.firstOccurrence);
|
||||
result["nextOccurrence"] = QVariant::fromValue(event.nextOccurrence);
|
||||
result["resources"] = toVariant(event.resources);
|
||||
result["buildings"] = toVariant(event.buildings);
|
||||
result["creatures"] = toVariant(event.creatures);
|
||||
|
||||
return QVariant(result);
|
||||
}
|
||||
|
||||
CCastleEvent eventFromVariant(CMapHeader& map, const CGTownInstance& town, const QVariant& variant)
|
||||
{
|
||||
CCastleEvent result;
|
||||
auto v = variant.toMap();
|
||||
result.name = v.value("name").toString().toStdString();
|
||||
result.message.appendTextID(mapRegisterLocalizedString("map", map, TextIdentifier("town", town.instanceName, "event", result.name, "message"), v.value("message").toString().toStdString()));
|
||||
result.players = v.value("players").toInt();
|
||||
result.humanAffected = v.value("humanAffected").toInt();
|
||||
result.computerAffected = v.value("computerAffected").toInt();
|
||||
result.firstOccurrence = v.value("firstOccurrence").toInt();
|
||||
result.nextOccurrence = v.value("nextOccurrence").toInt();
|
||||
result.resources = resourcesFromVariant(v.value("resources"));
|
||||
result.buildings = buildingsFromVariant(v.value("buildings"));
|
||||
result.creatures = creaturesFromVariant(v.value("creatures"));
|
||||
return result;
|
||||
}
|
||||
|
||||
void TownEventsWidget::obtainData()
|
||||
{
|
||||
for (const auto & event : town.events)
|
||||
{
|
||||
auto eventName = QString::fromStdString(event.name);
|
||||
auto itemText = tr("Day %1 - %2").arg(event.firstOccurrence+1, 3).arg(eventName);
|
||||
|
||||
auto * item = new QListWidgetItem(itemText);
|
||||
item->setData(MapEditorRoles::TownEventRole, toVariant(event));
|
||||
ui->eventsList->addItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
void TownEventsWidget::commitChanges(MapController& controller)
|
||||
{
|
||||
town.events.clear();
|
||||
for (int i = 0; i < ui->eventsList->count(); ++i)
|
||||
{
|
||||
const auto * item = ui->eventsList->item(i);
|
||||
town.events.push_back(eventFromVariant(*controller.map(), town, item->data(MapEditorRoles::TownEventRole)));
|
||||
}
|
||||
}
|
||||
|
||||
void TownEventsWidget::on_timedEventAdd_clicked()
|
||||
{
|
||||
CCastleEvent event;
|
||||
event.name = tr("New event").toStdString();
|
||||
auto* item = new QListWidgetItem(QString::fromStdString(event.name));
|
||||
item->setData(MapEditorRoles::TownEventRole, toVariant(event));
|
||||
ui->eventsList->addItem(item);
|
||||
on_eventsList_itemActivated(item);
|
||||
}
|
||||
|
||||
void TownEventsWidget::on_timedEventRemove_clicked()
|
||||
{
|
||||
delete ui->eventsList->takeItem(ui->eventsList->currentRow());
|
||||
}
|
||||
|
||||
void TownEventsWidget::on_eventsList_itemActivated(QListWidgetItem* item)
|
||||
{
|
||||
TownEventDialog dlg{ town, item, parentWidget() };
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
|
||||
TownEventsDelegate::TownEventsDelegate(CGTownInstance & town, MapController & c) : QStyledItemDelegate(), town(town), controller(c)
|
||||
{
|
||||
}
|
||||
|
||||
QWidget* TownEventsDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const
|
||||
{
|
||||
return new TownEventsWidget(town, parent);
|
||||
}
|
||||
|
||||
void TownEventsDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const
|
||||
{
|
||||
if (auto * ed = qobject_cast<TownEventsWidget *>(editor))
|
||||
{
|
||||
ed->obtainData();
|
||||
}
|
||||
else
|
||||
{
|
||||
QStyledItemDelegate::setEditorData(editor, index);
|
||||
}
|
||||
}
|
||||
|
||||
void TownEventsDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
|
||||
{
|
||||
if (auto * ed = qobject_cast<TownEventsWidget *>(editor))
|
||||
{
|
||||
ed->commitChanges(controller);
|
||||
}
|
||||
else
|
||||
{
|
||||
QStyledItemDelegate::setModelData(editor, model, index);
|
||||
}
|
||||
}
|
58
mapeditor/inspector/towneventswidget.h
Normal file
58
mapeditor/inspector/towneventswidget.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* towneventswidget.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
|
||||
|
||||
#include "../StdInc.h"
|
||||
#include <QDialog>
|
||||
#include "../lib/mapping/CMapDefines.h"
|
||||
#include "../lib/mapObjects/CGTownInstance.h"
|
||||
#include "../mapcontroller.h"
|
||||
|
||||
namespace Ui {
|
||||
class TownEventsWidget;
|
||||
}
|
||||
|
||||
class TownEventsWidget : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TownEventsWidget(CGTownInstance &, QWidget * parent = nullptr);
|
||||
~TownEventsWidget();
|
||||
|
||||
void obtainData();
|
||||
void commitChanges(MapController & controller);
|
||||
private slots:
|
||||
void on_timedEventAdd_clicked();
|
||||
void on_timedEventRemove_clicked();
|
||||
void on_eventsList_itemActivated(QListWidgetItem * item);
|
||||
|
||||
private:
|
||||
|
||||
Ui::TownEventsWidget * ui;
|
||||
CGTownInstance & town;
|
||||
};
|
||||
|
||||
class TownEventsDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using QStyledItemDelegate::QStyledItemDelegate;
|
||||
|
||||
TownEventsDelegate(CGTownInstance &, MapController &);
|
||||
|
||||
QWidget* createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
|
||||
void setEditorData(QWidget * editor, const QModelIndex & index) const override;
|
||||
void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override;
|
||||
|
||||
private:
|
||||
CGTownInstance & town;
|
||||
MapController & controller;
|
||||
};
|
93
mapeditor/inspector/towneventswidget.ui
Normal file
93
mapeditor/inspector/towneventswidget.ui
Normal file
@ -0,0 +1,93 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TownEventsWidget</class>
|
||||
<widget class="QDialog" name="TownEventsWidget">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>691</width>
|
||||
<height>462</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>400</width>
|
||||
<height>400</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Town events</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="timedEventText">
|
||||
<property name="text">
|
||||
<string>Timed events</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="timedEventAdd">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="timedEventRemove">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>90</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="eventsList">
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
166
mapeditor/inspector/townspellswidget.cpp
Normal file
166
mapeditor/inspector/townspellswidget.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* townspellswidget.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 "townspellswidget.h"
|
||||
#include "ui_townspellswidget.h"
|
||||
#include "inspector.h"
|
||||
#include "mapeditorroles.h"
|
||||
#include "../../lib/constants/StringConstants.h"
|
||||
#include "../../lib/spells/CSpellHandler.h"
|
||||
|
||||
TownSpellsWidget::TownSpellsWidget(CGTownInstance & town, QWidget * parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::TownSpellsWidget),
|
||||
town(town)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
possibleSpellLists = { ui->possibleSpellList1, ui->possibleSpellList2, ui->possibleSpellList3, ui->possibleSpellList4, ui->possibleSpellList5 };
|
||||
requiredSpellLists = { ui->requiredSpellList1, ui->requiredSpellList2, ui->requiredSpellList3, ui->requiredSpellList4, ui->requiredSpellList5 };
|
||||
|
||||
std::array<BuildingID, 5> mageGuilds = {BuildingID::MAGES_GUILD_1, BuildingID::MAGES_GUILD_2, BuildingID::MAGES_GUILD_3, BuildingID::MAGES_GUILD_4, BuildingID::MAGES_GUILD_5};
|
||||
for (int i = 0; i < mageGuilds.size(); i++)
|
||||
{
|
||||
ui->tabWidget->setTabEnabled(i, vstd::contains(town.getTown()->buildings, mageGuilds[i]));
|
||||
}
|
||||
}
|
||||
|
||||
TownSpellsWidget::~TownSpellsWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
||||
void TownSpellsWidget::obtainData()
|
||||
{
|
||||
initSpellLists();
|
||||
if (vstd::contains(town.possibleSpells, SpellID::PRESET)) {
|
||||
ui->customizeSpells->setChecked(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->customizeSpells->setChecked(false);
|
||||
ui->tabWidget->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void TownSpellsWidget::resetSpells()
|
||||
{
|
||||
town.possibleSpells.clear();
|
||||
town.obligatorySpells.clear();
|
||||
for (auto spellID : VLC->spellh->getDefaultAllowed())
|
||||
town.possibleSpells.push_back(spellID);
|
||||
}
|
||||
|
||||
void TownSpellsWidget::initSpellLists()
|
||||
{
|
||||
auto spells = VLC->spellh->getDefaultAllowed();
|
||||
for (int i = 0; i < GameConstants::SPELL_LEVELS; i++)
|
||||
{
|
||||
std::vector<SpellID> spellsByLevel;
|
||||
auto getSpellsByLevel = [i](auto spellID) {
|
||||
return spellID.toEntity(VLC)->getLevel() == i + 1;
|
||||
};
|
||||
vstd::copy_if(spells, std::back_inserter(spellsByLevel), getSpellsByLevel);
|
||||
possibleSpellLists[i]->clear();
|
||||
requiredSpellLists[i]->clear();
|
||||
for (auto spellID : spellsByLevel)
|
||||
{
|
||||
auto spell = spellID.toEntity(VLC);
|
||||
auto * possibleItem = new QListWidgetItem(QString::fromStdString(spell->getNameTranslated()));
|
||||
possibleItem->setData(MapEditorRoles::SpellIDRole, QVariant::fromValue(spell->getIndex()));
|
||||
possibleItem->setFlags(possibleItem->flags() | Qt::ItemIsUserCheckable);
|
||||
possibleItem->setCheckState(vstd::contains(town.possibleSpells, spell->getId()) ? Qt::Checked : Qt::Unchecked);
|
||||
possibleSpellLists[i]->addItem(possibleItem);
|
||||
|
||||
auto * requiredItem = new QListWidgetItem(QString::fromStdString(spell->getNameTranslated()));
|
||||
requiredItem->setData(MapEditorRoles::SpellIDRole, QVariant::fromValue(spell->getIndex()));
|
||||
requiredItem->setFlags(requiredItem->flags() | Qt::ItemIsUserCheckable);
|
||||
requiredItem->setCheckState(vstd::contains(town.obligatorySpells, spell->getId()) ? Qt::Checked : Qt::Unchecked);
|
||||
requiredSpellLists[i]->addItem(requiredItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TownSpellsWidget::commitChanges()
|
||||
{
|
||||
if (!ui->tabWidget->isEnabled())
|
||||
{
|
||||
resetSpells();
|
||||
return;
|
||||
}
|
||||
|
||||
auto updateTownSpellList = [](auto uiSpellLists, auto & townSpellList) {
|
||||
for (const QListWidget * spellList : uiSpellLists)
|
||||
{
|
||||
for (int i = 0; i < spellList->count(); ++i)
|
||||
{
|
||||
const auto * item = spellList->item(i);
|
||||
if (item->checkState() == Qt::Checked)
|
||||
{
|
||||
townSpellList.push_back(item->data(MapEditorRoles::SpellIDRole).toInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
town.possibleSpells.clear();
|
||||
town.obligatorySpells.clear();
|
||||
town.possibleSpells.push_back(SpellID::PRESET);
|
||||
updateTownSpellList(possibleSpellLists, town.possibleSpells);
|
||||
updateTownSpellList(requiredSpellLists, town.obligatorySpells);
|
||||
}
|
||||
|
||||
void TownSpellsWidget::on_customizeSpells_toggled(bool checked)
|
||||
{
|
||||
if (checked)
|
||||
{
|
||||
town.possibleSpells.push_back(SpellID::PRESET);
|
||||
}
|
||||
else
|
||||
{
|
||||
resetSpells();
|
||||
}
|
||||
ui->tabWidget->setEnabled(checked);
|
||||
initSpellLists();
|
||||
}
|
||||
|
||||
TownSpellsDelegate::TownSpellsDelegate(CGTownInstance & town) : QStyledItemDelegate(), town(town)
|
||||
{
|
||||
}
|
||||
|
||||
QWidget * TownSpellsDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const
|
||||
{
|
||||
return new TownSpellsWidget(town, parent);
|
||||
}
|
||||
|
||||
void TownSpellsDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const
|
||||
{
|
||||
if (auto * ed = qobject_cast<TownSpellsWidget *>(editor))
|
||||
{
|
||||
ed->obtainData();
|
||||
}
|
||||
else
|
||||
{
|
||||
QStyledItemDelegate::setEditorData(editor, index);
|
||||
}
|
||||
}
|
||||
|
||||
void TownSpellsDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const
|
||||
{
|
||||
if (auto * ed = qobject_cast<TownSpellsWidget *>(editor))
|
||||
{
|
||||
ed->commitChanges();
|
||||
}
|
||||
else
|
||||
{
|
||||
QStyledItemDelegate::setModelData(editor, model, index);
|
||||
}
|
||||
}
|
60
mapeditor/inspector/townspellswidget.h
Normal file
60
mapeditor/inspector/townspellswidget.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* townspellswidget.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
|
||||
|
||||
#include <QDialog>
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
|
||||
namespace Ui {
|
||||
class TownSpellsWidget;
|
||||
}
|
||||
|
||||
|
||||
class TownSpellsWidget : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TownSpellsWidget(CGTownInstance &, QWidget * parent = nullptr);
|
||||
~TownSpellsWidget();
|
||||
|
||||
void obtainData();
|
||||
void commitChanges();
|
||||
|
||||
private slots:
|
||||
void on_customizeSpells_toggled(bool checked);
|
||||
|
||||
private:
|
||||
Ui::TownSpellsWidget * ui;
|
||||
|
||||
CGTownInstance & town;
|
||||
|
||||
std::array<QListWidget *, 5> possibleSpellLists;
|
||||
std::array<QListWidget *, 5> requiredSpellLists;
|
||||
|
||||
void resetSpells();
|
||||
void initSpellLists();
|
||||
};
|
||||
|
||||
class TownSpellsDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using QStyledItemDelegate::QStyledItemDelegate;
|
||||
|
||||
TownSpellsDelegate(CGTownInstance&);
|
||||
|
||||
QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex& index) const override;
|
||||
void setEditorData(QWidget * editor, const QModelIndex & index) const override;
|
||||
void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override;
|
||||
|
||||
private:
|
||||
CGTownInstance& town;
|
||||
};
|
304
mapeditor/inspector/townspellswidget.ui
Normal file
304
mapeditor/inspector/townspellswidget.ui
Normal file
@ -0,0 +1,304 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TownSpellsWidget</class>
|
||||
<widget class="QDialog" name="TownSpellsWidget">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::NonModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>480</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>600</width>
|
||||
<height>480</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Spells</string>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>5</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="customizeSpells">
|
||||
<property name="text">
|
||||
<string>Customize spells</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="documentMode">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="level1">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Level 1</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_level1">
|
||||
<property name="leftMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="possibleSpellsText1">
|
||||
<property name="text">
|
||||
<string>Spell that may appear in mage guild</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="requiredSpellsText1">
|
||||
<property name="text">
|
||||
<string>Spell that must appear in mage guild</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QListWidget" name="possibleSpellList1"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QListWidget" name="requiredSpellList1"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="level2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Level 2</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_level2">
|
||||
<property name="leftMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="possibleSpellsText2">
|
||||
<property name="text">
|
||||
<string>Spell that may appear in mage guild</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="requiredSpellsText2">
|
||||
<property name="text">
|
||||
<string>Spell that must appear in mage guild</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QListWidget" name="possibleSpellList2"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QListWidget" name="requiredSpellList2"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="level3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Level 3</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_level3">
|
||||
<property name="leftMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="possibleSpellsText3">
|
||||
<property name="text">
|
||||
<string>Spell that may appear in mage guild</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="requiredSpellsText3">
|
||||
<property name="text">
|
||||
<string>Spell that must appear in mage guild</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QListWidget" name="possibleSpellList3"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QListWidget" name="requiredSpellList3"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="level4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Level 4</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_level4">
|
||||
<property name="leftMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="possibleSpellsText4">
|
||||
<property name="text">
|
||||
<string>Spell that may appear in mage guild</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="requiredSpellsText4">
|
||||
<property name="text">
|
||||
<string>Spell that must appear in mage guild</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QListWidget" name="possibleSpellList4"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QListWidget" name="requiredSpellList4"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="level5">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Level 5</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_level5">
|
||||
<property name="leftMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="possibleSpellsText5">
|
||||
<property name="text">
|
||||
<string>Spell that may appear in mage guild</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="requiredSpellsText5">
|
||||
<property name="text">
|
||||
<string>Spell that must appear in mage guild</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QListWidget" name="possibleSpellList5"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QListWidget" name="requiredSpellList5"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
20
mapeditor/mapeditorroles.h
Normal file
20
mapeditor/mapeditorroles.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* mapeditorroles.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
|
||||
|
||||
#include "StdInc.h"
|
||||
|
||||
enum MapEditorRoles
|
||||
{
|
||||
TownEventRole = Qt::UserRole + 1,
|
||||
PlayerIDRole,
|
||||
BuildingIDRole,
|
||||
SpellIDRole
|
||||
};
|
@ -15,6 +15,9 @@ namespace Ui {
|
||||
class EventSettings;
|
||||
}
|
||||
|
||||
QVariant toVariant(const TResources & resources);
|
||||
TResources resourcesFromVariant(const QVariant & v);
|
||||
|
||||
class EventSettings : public AbstractSettings
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -715,7 +715,7 @@
|
||||
<context>
|
||||
<name>MapView</name>
|
||||
<message>
|
||||
<location filename="../mapview.cpp" line="625"/>
|
||||
<location filename="../mapview.cpp" line="626"/>
|
||||
<source>Can't place object</source>
|
||||
<translation>无法放置物体</translation>
|
||||
</message>
|
||||
@ -889,38 +889,38 @@
|
||||
<translation>高级</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="36"/>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<source>Compliant</source>
|
||||
<translation>屈服的</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="37"/>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<source>Friendly</source>
|
||||
<translation>友善的</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<source>Aggressive</source>
|
||||
<translation>好斗的</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<location filename="../inspector/inspector.cpp" line="41"/>
|
||||
<source>Hostile</source>
|
||||
<translation>有敌意的</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<location filename="../inspector/inspector.cpp" line="42"/>
|
||||
<source>Savage</source>
|
||||
<translation>野蛮的</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="843"/>
|
||||
<location filename="../inspector/inspector.cpp" line="932"/>
|
||||
<location filename="../inspector/inspector.cpp" line="847"/>
|
||||
<location filename="../inspector/inspector.cpp" line="936"/>
|
||||
<source>neutral</source>
|
||||
<translation>中立</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="841"/>
|
||||
<location filename="../inspector/inspector.cpp" line="845"/>
|
||||
<source>UNFLAGGABLE</source>
|
||||
<translation>没有旗帜</translation>
|
||||
</message>
|
||||
@ -1435,6 +1435,208 @@
|
||||
<source>Buildings</source>
|
||||
<translation>建筑</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="53"/>
|
||||
<source>Build all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="60"/>
|
||||
<source>Demolish all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="67"/>
|
||||
<source>Enable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="74"/>
|
||||
<source>Disable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Type</source>
|
||||
<translation type="unfinished">类型</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Enabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Built</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventDialog</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="23"/>
|
||||
<source>Town event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="42"/>
|
||||
<source>General</source>
|
||||
<translation type="unfinished">通用</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="57"/>
|
||||
<source>Event name</source>
|
||||
<translation type="unfinished">事件名</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="64"/>
|
||||
<source>Type event message text</source>
|
||||
<translation type="unfinished">输入事件信息文本</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="85"/>
|
||||
<source>Day of first occurrence</source>
|
||||
<translation type="unfinished">首次发生天数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="99"/>
|
||||
<source>Repeat after (0 = no repeat)</source>
|
||||
<translation type="unfinished">重复周期 (0 = 不重复)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="123"/>
|
||||
<source>Affected players</source>
|
||||
<translation type="unfinished">生效玩家</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="146"/>
|
||||
<source>affects human</source>
|
||||
<translation type="unfinished">人类玩家生效</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="155"/>
|
||||
<source>affects AI</source>
|
||||
<translation type="unfinished">AI玩家生效</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="166"/>
|
||||
<source>Resources</source>
|
||||
<translation type="unfinished">资源</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="198"/>
|
||||
<source>Buildings</source>
|
||||
<translation type="unfinished">建筑</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="216"/>
|
||||
<source>Creatures</source>
|
||||
<translation type="unfinished">生物</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="255"/>
|
||||
<source>OK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="177"/>
|
||||
<source>Creature level %1 / Creature level %1 Upgrade</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="219"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="29"/>
|
||||
<source>Town events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="37"/>
|
||||
<source>Timed events</source>
|
||||
<translation type="unfinished">计时事件</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="63"/>
|
||||
<source>Add</source>
|
||||
<translation type="unfinished">添加</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="76"/>
|
||||
<source>Remove</source>
|
||||
<translation type="unfinished">移除</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="105"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="126"/>
|
||||
<source>New event</source>
|
||||
<translation type="unfinished">新事件</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownSpellsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="29"/>
|
||||
<source>Spells</source>
|
||||
<translation type="unfinished">魔法</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="47"/>
|
||||
<source>Customize spells</source>
|
||||
<translation type="unfinished">自定义魔法</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="76"/>
|
||||
<source>Level 1</source>
|
||||
<translation type="unfinished">1级</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="93"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="139"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="185"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="231"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="277"/>
|
||||
<source>Spell that may appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="100"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="146"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="192"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="238"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="284"/>
|
||||
<source>Spell that must appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="122"/>
|
||||
<source>Level 2</source>
|
||||
<translation type="unfinished">2级</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="168"/>
|
||||
<source>Level 3</source>
|
||||
<translation type="unfinished">3级</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="214"/>
|
||||
<source>Level 4</source>
|
||||
<translation type="unfinished">4级</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="260"/>
|
||||
<source>Level 5</source>
|
||||
<translation type="unfinished">5级</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Translations</name>
|
||||
@ -1698,18 +1900,6 @@
|
||||
<source>Width</source>
|
||||
<translation>宽度</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>S (36x36)</source>
|
||||
<translation type="vanished">小(36x36)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>M (72x72)</source>
|
||||
<translation type="vanished">中(72x72)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>L (108x108)</source>
|
||||
<translation type="vanished">大(108x108)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="179"/>
|
||||
<source>XL (144x144)</source>
|
||||
|
@ -715,7 +715,7 @@
|
||||
<context>
|
||||
<name>MapView</name>
|
||||
<message>
|
||||
<location filename="../mapview.cpp" line="625"/>
|
||||
<location filename="../mapview.cpp" line="626"/>
|
||||
<source>Can't place object</source>
|
||||
<translation>Nelze umístit objekt</translation>
|
||||
</message>
|
||||
@ -889,38 +889,38 @@
|
||||
<translation>Expert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="36"/>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<source>Compliant</source>
|
||||
<translation>Ochotná</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="37"/>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<source>Friendly</source>
|
||||
<translation>Přátelská</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<source>Aggressive</source>
|
||||
<translation>Agresivní</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<location filename="../inspector/inspector.cpp" line="41"/>
|
||||
<source>Hostile</source>
|
||||
<translation>Nepřátelská</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<location filename="../inspector/inspector.cpp" line="42"/>
|
||||
<source>Savage</source>
|
||||
<translation>Brutální</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="843"/>
|
||||
<location filename="../inspector/inspector.cpp" line="932"/>
|
||||
<location filename="../inspector/inspector.cpp" line="847"/>
|
||||
<location filename="../inspector/inspector.cpp" line="936"/>
|
||||
<source>neutral</source>
|
||||
<translation>neutrální</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="841"/>
|
||||
<location filename="../inspector/inspector.cpp" line="845"/>
|
||||
<source>UNFLAGGABLE</source>
|
||||
<translation>NEOZNAČITELNÝ</translation>
|
||||
</message>
|
||||
@ -1435,6 +1435,208 @@
|
||||
<source>Buildings</source>
|
||||
<translation>Budovy</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="53"/>
|
||||
<source>Build all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="60"/>
|
||||
<source>Demolish all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="67"/>
|
||||
<source>Enable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="74"/>
|
||||
<source>Disable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Type</source>
|
||||
<translation type="unfinished">Druh</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Enabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Built</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventDialog</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="23"/>
|
||||
<source>Town event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="42"/>
|
||||
<source>General</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="57"/>
|
||||
<source>Event name</source>
|
||||
<translation type="unfinished">Název události</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="64"/>
|
||||
<source>Type event message text</source>
|
||||
<translation type="unfinished">Zadejte text zprávy události</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="85"/>
|
||||
<source>Day of first occurrence</source>
|
||||
<translation type="unfinished">Den prvního výskytu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="99"/>
|
||||
<source>Repeat after (0 = no repeat)</source>
|
||||
<translation type="unfinished">Opakovat po (0 = bez opak.)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="123"/>
|
||||
<source>Affected players</source>
|
||||
<translation type="unfinished">Ovlivnění hráči</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="146"/>
|
||||
<source>affects human</source>
|
||||
<translation type="unfinished">ovlivňuje lidi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="155"/>
|
||||
<source>affects AI</source>
|
||||
<translation type="unfinished">ovlivňuje AI</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="166"/>
|
||||
<source>Resources</source>
|
||||
<translation type="unfinished">Zdroje</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="198"/>
|
||||
<source>Buildings</source>
|
||||
<translation type="unfinished">Budovy</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="216"/>
|
||||
<source>Creatures</source>
|
||||
<translation type="unfinished">Jednotky</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="255"/>
|
||||
<source>OK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="177"/>
|
||||
<source>Creature level %1 / Creature level %1 Upgrade</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="219"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="29"/>
|
||||
<source>Town events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="37"/>
|
||||
<source>Timed events</source>
|
||||
<translation type="unfinished">Načasované události</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="63"/>
|
||||
<source>Add</source>
|
||||
<translation type="unfinished">Přidat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="76"/>
|
||||
<source>Remove</source>
|
||||
<translation type="unfinished">Odebrat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="105"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="126"/>
|
||||
<source>New event</source>
|
||||
<translation type="unfinished">Nová událost</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownSpellsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="29"/>
|
||||
<source>Spells</source>
|
||||
<translation type="unfinished">Kouzla</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="47"/>
|
||||
<source>Customize spells</source>
|
||||
<translation type="unfinished">Přizpůsobit kouzla</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="76"/>
|
||||
<source>Level 1</source>
|
||||
<translation type="unfinished">Úroveň 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="93"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="139"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="185"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="231"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="277"/>
|
||||
<source>Spell that may appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="100"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="146"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="192"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="238"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="284"/>
|
||||
<source>Spell that must appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="122"/>
|
||||
<source>Level 2</source>
|
||||
<translation type="unfinished">Úroveň 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="168"/>
|
||||
<source>Level 3</source>
|
||||
<translation type="unfinished">Úroveň 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="214"/>
|
||||
<source>Level 4</source>
|
||||
<translation type="unfinished">Úroveň 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="260"/>
|
||||
<source>Level 5</source>
|
||||
<translation type="unfinished">Úroveň 5</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Translations</name>
|
||||
@ -1698,18 +1900,6 @@
|
||||
<source>Width</source>
|
||||
<translation>Šířka</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>S (36x36)</source>
|
||||
<translation type="vanished">S (36x36)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>M (72x72)</source>
|
||||
<translation type="vanished">M (72x72)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>L (108x108)</source>
|
||||
<translation type="vanished">L (108x108)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="179"/>
|
||||
<source>XL (144x144)</source>
|
||||
|
@ -715,7 +715,7 @@
|
||||
<context>
|
||||
<name>MapView</name>
|
||||
<message>
|
||||
<location filename="../mapview.cpp" line="625"/>
|
||||
<location filename="../mapview.cpp" line="626"/>
|
||||
<source>Can't place object</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -889,38 +889,38 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="36"/>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<source>Compliant</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="37"/>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<source>Friendly</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<source>Aggressive</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<location filename="../inspector/inspector.cpp" line="41"/>
|
||||
<source>Hostile</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<location filename="../inspector/inspector.cpp" line="42"/>
|
||||
<source>Savage</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="843"/>
|
||||
<location filename="../inspector/inspector.cpp" line="932"/>
|
||||
<location filename="../inspector/inspector.cpp" line="847"/>
|
||||
<location filename="../inspector/inspector.cpp" line="936"/>
|
||||
<source>neutral</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="841"/>
|
||||
<location filename="../inspector/inspector.cpp" line="845"/>
|
||||
<source>UNFLAGGABLE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -1435,6 +1435,208 @@
|
||||
<source>Buildings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="53"/>
|
||||
<source>Build all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="60"/>
|
||||
<source>Demolish all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="67"/>
|
||||
<source>Enable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="74"/>
|
||||
<source>Disable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Type</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Enabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Built</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventDialog</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="23"/>
|
||||
<source>Town event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="42"/>
|
||||
<source>General</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="57"/>
|
||||
<source>Event name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="64"/>
|
||||
<source>Type event message text</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="85"/>
|
||||
<source>Day of first occurrence</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="99"/>
|
||||
<source>Repeat after (0 = no repeat)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="123"/>
|
||||
<source>Affected players</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="146"/>
|
||||
<source>affects human</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="155"/>
|
||||
<source>affects AI</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="166"/>
|
||||
<source>Resources</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="198"/>
|
||||
<source>Buildings</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="216"/>
|
||||
<source>Creatures</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="255"/>
|
||||
<source>OK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="177"/>
|
||||
<source>Creature level %1 / Creature level %1 Upgrade</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="219"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="29"/>
|
||||
<source>Town events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="37"/>
|
||||
<source>Timed events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="63"/>
|
||||
<source>Add</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="76"/>
|
||||
<source>Remove</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="105"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="126"/>
|
||||
<source>New event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownSpellsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="29"/>
|
||||
<source>Spells</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="47"/>
|
||||
<source>Customize spells</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="76"/>
|
||||
<source>Level 1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="93"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="139"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="185"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="231"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="277"/>
|
||||
<source>Spell that may appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="100"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="146"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="192"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="238"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="284"/>
|
||||
<source>Spell that must appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="122"/>
|
||||
<source>Level 2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="168"/>
|
||||
<source>Level 3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="214"/>
|
||||
<source>Level 4</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="260"/>
|
||||
<source>Level 5</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Translations</name>
|
||||
|
@ -560,8 +560,8 @@
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="280"/>
|
||||
<source>Unsaved changes will be lost, are you sur?</source>
|
||||
<translation>Des modifications non sauvegardées vont être perdues. Êtes-vous sûr ?</translation>
|
||||
<source>Unsaved changes will be lost, are you sure?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="406"/>
|
||||
@ -715,7 +715,7 @@
|
||||
<context>
|
||||
<name>MapView</name>
|
||||
<message>
|
||||
<location filename="../mapview.cpp" line="625"/>
|
||||
<location filename="../mapview.cpp" line="626"/>
|
||||
<source>Can't place object</source>
|
||||
<translation>Impossible de placer l'objet</translation>
|
||||
</message>
|
||||
@ -889,38 +889,38 @@
|
||||
<translation>Expert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="36"/>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<source>Compliant</source>
|
||||
<translation>Compérhensif</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="37"/>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<source>Friendly</source>
|
||||
<translation>Amical</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<source>Aggressive</source>
|
||||
<translation>Aggressif</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<location filename="../inspector/inspector.cpp" line="41"/>
|
||||
<source>Hostile</source>
|
||||
<translation>Hostile</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<location filename="../inspector/inspector.cpp" line="42"/>
|
||||
<source>Savage</source>
|
||||
<translation>Sauvage</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="843"/>
|
||||
<location filename="../inspector/inspector.cpp" line="932"/>
|
||||
<location filename="../inspector/inspector.cpp" line="847"/>
|
||||
<location filename="../inspector/inspector.cpp" line="936"/>
|
||||
<source>neutral</source>
|
||||
<translation>neutre</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="841"/>
|
||||
<location filename="../inspector/inspector.cpp" line="845"/>
|
||||
<source>UNFLAGGABLE</source>
|
||||
<translation>INCLASSABLE</translation>
|
||||
</message>
|
||||
@ -1435,6 +1435,208 @@
|
||||
<source>Buildings</source>
|
||||
<translation>Bâtiments</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="53"/>
|
||||
<source>Build all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="60"/>
|
||||
<source>Demolish all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="67"/>
|
||||
<source>Enable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="74"/>
|
||||
<source>Disable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Type</source>
|
||||
<translation type="unfinished">Type</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Enabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Built</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventDialog</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="23"/>
|
||||
<source>Town event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="42"/>
|
||||
<source>General</source>
|
||||
<translation type="unfinished">Général</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="57"/>
|
||||
<source>Event name</source>
|
||||
<translation type="unfinished">Nom de l'évènement</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="64"/>
|
||||
<source>Type event message text</source>
|
||||
<translation type="unfinished">Taper le message d'évènement</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="85"/>
|
||||
<source>Day of first occurrence</source>
|
||||
<translation type="unfinished">Jour de la première occurrence</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="99"/>
|
||||
<source>Repeat after (0 = no repeat)</source>
|
||||
<translation type="unfinished">Récurrence (0 = pas de récurrence)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="123"/>
|
||||
<source>Affected players</source>
|
||||
<translation type="unfinished">Joueurs affectés</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="146"/>
|
||||
<source>affects human</source>
|
||||
<translation type="unfinished">afttecte les joueurs</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="155"/>
|
||||
<source>affects AI</source>
|
||||
<translation type="unfinished">affecte l'ordinateur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="166"/>
|
||||
<source>Resources</source>
|
||||
<translation type="unfinished">Resources</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="198"/>
|
||||
<source>Buildings</source>
|
||||
<translation type="unfinished">Bâtiments</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="216"/>
|
||||
<source>Creatures</source>
|
||||
<translation type="unfinished">Créatures</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="255"/>
|
||||
<source>OK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="177"/>
|
||||
<source>Creature level %1 / Creature level %1 Upgrade</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="219"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="29"/>
|
||||
<source>Town events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="37"/>
|
||||
<source>Timed events</source>
|
||||
<translation type="unfinished">Evenements timés</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="63"/>
|
||||
<source>Add</source>
|
||||
<translation type="unfinished">Ajouter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="76"/>
|
||||
<source>Remove</source>
|
||||
<translation type="unfinished">Supprimer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="105"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="126"/>
|
||||
<source>New event</source>
|
||||
<translation type="unfinished">Nouvel évènement</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownSpellsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="29"/>
|
||||
<source>Spells</source>
|
||||
<translation type="unfinished">Sorts</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="47"/>
|
||||
<source>Customize spells</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="76"/>
|
||||
<source>Level 1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="93"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="139"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="185"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="231"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="277"/>
|
||||
<source>Spell that may appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="100"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="146"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="192"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="238"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="284"/>
|
||||
<source>Spell that must appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="122"/>
|
||||
<source>Level 2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="168"/>
|
||||
<source>Level 3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="214"/>
|
||||
<source>Level 4</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="260"/>
|
||||
<source>Level 5</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Translations</name>
|
||||
@ -1698,18 +1900,6 @@
|
||||
<source>Width</source>
|
||||
<translation>Largeur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>S (36x36)</source>
|
||||
<translation type="vanished">Petite (36x36)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>M (72x72)</source>
|
||||
<translation type="vanished">Moyenne (72x72)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>L (108x108)</source>
|
||||
<translation type="vanished">Grande (108x108)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="179"/>
|
||||
<source>XL (144x144)</source>
|
||||
|
@ -715,7 +715,7 @@
|
||||
<context>
|
||||
<name>MapView</name>
|
||||
<message>
|
||||
<location filename="../mapview.cpp" line="625"/>
|
||||
<location filename="../mapview.cpp" line="626"/>
|
||||
<source>Can't place object</source>
|
||||
<translation>Objekt kann nicht platziert werden</translation>
|
||||
</message>
|
||||
@ -889,38 +889,38 @@
|
||||
<translation>Experte</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="36"/>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<source>Compliant</source>
|
||||
<translation>Konform</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="37"/>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<source>Friendly</source>
|
||||
<translation>Freundlich</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<source>Aggressive</source>
|
||||
<translation>Aggressiv</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<location filename="../inspector/inspector.cpp" line="41"/>
|
||||
<source>Hostile</source>
|
||||
<translation>Feindlich</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<location filename="../inspector/inspector.cpp" line="42"/>
|
||||
<source>Savage</source>
|
||||
<translation>Wild</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="843"/>
|
||||
<location filename="../inspector/inspector.cpp" line="932"/>
|
||||
<location filename="../inspector/inspector.cpp" line="847"/>
|
||||
<location filename="../inspector/inspector.cpp" line="936"/>
|
||||
<source>neutral</source>
|
||||
<translation>neutral</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="841"/>
|
||||
<location filename="../inspector/inspector.cpp" line="845"/>
|
||||
<source>UNFLAGGABLE</source>
|
||||
<translation>UNFLAGGBAR</translation>
|
||||
</message>
|
||||
@ -1435,6 +1435,208 @@
|
||||
<source>Buildings</source>
|
||||
<translation>Gebäude</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="53"/>
|
||||
<source>Build all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="60"/>
|
||||
<source>Demolish all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="67"/>
|
||||
<source>Enable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="74"/>
|
||||
<source>Disable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Type</source>
|
||||
<translation type="unfinished">Typ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Enabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Built</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventDialog</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="23"/>
|
||||
<source>Town event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="42"/>
|
||||
<source>General</source>
|
||||
<translation type="unfinished">Allgemein</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="57"/>
|
||||
<source>Event name</source>
|
||||
<translation type="unfinished">Name des Ereignisses</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="64"/>
|
||||
<source>Type event message text</source>
|
||||
<translation type="unfinished">Ereignistext eingeben</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="85"/>
|
||||
<source>Day of first occurrence</source>
|
||||
<translation type="unfinished">Tag des ersten Auftretens</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="99"/>
|
||||
<source>Repeat after (0 = no repeat)</source>
|
||||
<translation type="unfinished">Wiederholung nach (0 = keine Wiederholung)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="123"/>
|
||||
<source>Affected players</source>
|
||||
<translation type="unfinished">Betroffene Spieler</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="146"/>
|
||||
<source>affects human</source>
|
||||
<translation type="unfinished">beeinflusst Menschen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="155"/>
|
||||
<source>affects AI</source>
|
||||
<translation type="unfinished">beeinflusst KI</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="166"/>
|
||||
<source>Resources</source>
|
||||
<translation type="unfinished">Ressourcen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="198"/>
|
||||
<source>Buildings</source>
|
||||
<translation type="unfinished">Gebäude</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="216"/>
|
||||
<source>Creatures</source>
|
||||
<translation type="unfinished">Kreaturen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="255"/>
|
||||
<source>OK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="177"/>
|
||||
<source>Creature level %1 / Creature level %1 Upgrade</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="219"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="29"/>
|
||||
<source>Town events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="37"/>
|
||||
<source>Timed events</source>
|
||||
<translation type="unfinished">Zeitlich begrenzte Ereignisse</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="63"/>
|
||||
<source>Add</source>
|
||||
<translation type="unfinished">Hinzufügen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="76"/>
|
||||
<source>Remove</source>
|
||||
<translation type="unfinished">Entfernen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="105"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="126"/>
|
||||
<source>New event</source>
|
||||
<translation type="unfinished">Neues Ereignis</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownSpellsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="29"/>
|
||||
<source>Spells</source>
|
||||
<translation type="unfinished">Zaubersprüche</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="47"/>
|
||||
<source>Customize spells</source>
|
||||
<translation type="unfinished">Zaubersprüche anpassen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="76"/>
|
||||
<source>Level 1</source>
|
||||
<translation type="unfinished">Level 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="93"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="139"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="185"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="231"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="277"/>
|
||||
<source>Spell that may appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="100"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="146"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="192"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="238"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="284"/>
|
||||
<source>Spell that must appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="122"/>
|
||||
<source>Level 2</source>
|
||||
<translation type="unfinished">Level 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="168"/>
|
||||
<source>Level 3</source>
|
||||
<translation type="unfinished">Level 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="214"/>
|
||||
<source>Level 4</source>
|
||||
<translation type="unfinished">Level 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="260"/>
|
||||
<source>Level 5</source>
|
||||
<translation type="unfinished">Level 5</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Translations</name>
|
||||
@ -1698,18 +1900,6 @@
|
||||
<source>Width</source>
|
||||
<translation>Breite</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>S (36x36)</source>
|
||||
<translation type="vanished">S (36x36)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>M (72x72)</source>
|
||||
<translation type="vanished">M (72x72)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>L (108x108)</source>
|
||||
<translation type="vanished">L (108x108)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="179"/>
|
||||
<source>XL (144x144)</source>
|
||||
|
@ -715,7 +715,7 @@
|
||||
<context>
|
||||
<name>MapView</name>
|
||||
<message>
|
||||
<location filename="../mapview.cpp" line="625"/>
|
||||
<location filename="../mapview.cpp" line="626"/>
|
||||
<source>Can't place object</source>
|
||||
<translation>Nie można umieścić obiektu</translation>
|
||||
</message>
|
||||
@ -889,38 +889,38 @@
|
||||
<translation>Ekspert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="36"/>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<source>Compliant</source>
|
||||
<translation>Przyjazny</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="37"/>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<source>Friendly</source>
|
||||
<translation>Przychylny</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<source>Aggressive</source>
|
||||
<translation>Agresywny</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<location filename="../inspector/inspector.cpp" line="41"/>
|
||||
<source>Hostile</source>
|
||||
<translation>Wrogi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<location filename="../inspector/inspector.cpp" line="42"/>
|
||||
<source>Savage</source>
|
||||
<translation>Nienawistny</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="843"/>
|
||||
<location filename="../inspector/inspector.cpp" line="932"/>
|
||||
<location filename="../inspector/inspector.cpp" line="847"/>
|
||||
<location filename="../inspector/inspector.cpp" line="936"/>
|
||||
<source>neutral</source>
|
||||
<translation>neutralny</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="841"/>
|
||||
<location filename="../inspector/inspector.cpp" line="845"/>
|
||||
<source>UNFLAGGABLE</source>
|
||||
<translation>NIEOFLAGOWYWALNY</translation>
|
||||
</message>
|
||||
@ -1435,6 +1435,208 @@
|
||||
<source>Buildings</source>
|
||||
<translation>Budynki</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="53"/>
|
||||
<source>Build all</source>
|
||||
<translation>Zbuduj wsyzstkie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="60"/>
|
||||
<source>Demolish all</source>
|
||||
<translation>Zburz wszystkie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="67"/>
|
||||
<source>Enable all</source>
|
||||
<translation>Włącz wszystkie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="74"/>
|
||||
<source>Disable all</source>
|
||||
<translation>Wyłącz wszystkie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Type</source>
|
||||
<translation>Typ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Enabled</source>
|
||||
<translation>Włączony</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Built</source>
|
||||
<translation>Zbudowany</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventDialog</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="23"/>
|
||||
<source>Town event</source>
|
||||
<translation>Zdarzenie miasta</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="42"/>
|
||||
<source>General</source>
|
||||
<translation>Ogólne</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="57"/>
|
||||
<source>Event name</source>
|
||||
<translation>Nazwa zdarzenia</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="64"/>
|
||||
<source>Type event message text</source>
|
||||
<translation>Wpisz treść komunikatu zdarzenia</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="85"/>
|
||||
<source>Day of first occurrence</source>
|
||||
<translation>Dzień pierwszego wystąpienia</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="99"/>
|
||||
<source>Repeat after (0 = no repeat)</source>
|
||||
<translation>Powtórz po... (0 = nigdy)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="123"/>
|
||||
<source>Affected players</source>
|
||||
<translation>Dotyczy graczy</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="146"/>
|
||||
<source>affects human</source>
|
||||
<translation>dotyczy graczy ludzkich</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="155"/>
|
||||
<source>affects AI</source>
|
||||
<translation>dotyczy graczy AI</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="166"/>
|
||||
<source>Resources</source>
|
||||
<translation>Zasoby</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="198"/>
|
||||
<source>Buildings</source>
|
||||
<translation>Budynki</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="216"/>
|
||||
<source>Creatures</source>
|
||||
<translation>Stworzenia</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="255"/>
|
||||
<source>OK</source>
|
||||
<translation>OK</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="177"/>
|
||||
<source>Creature level %1 / Creature level %1 Upgrade</source>
|
||||
<translation>Stworzenie poziomu %1 / Ulepszone stworzenie poziomu %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="219"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation>Dzień %1 - %2</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="29"/>
|
||||
<source>Town events</source>
|
||||
<translation>Zdarzenia miasta</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="37"/>
|
||||
<source>Timed events</source>
|
||||
<translation>Zdarzenia czasowe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="63"/>
|
||||
<source>Add</source>
|
||||
<translation>Dodaj</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="76"/>
|
||||
<source>Remove</source>
|
||||
<translation>Usuń</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="105"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation>Dzień %1 - %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="126"/>
|
||||
<source>New event</source>
|
||||
<translation>Nowe zdarzenie</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownSpellsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="29"/>
|
||||
<source>Spells</source>
|
||||
<translation>Zaklęcia</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="47"/>
|
||||
<source>Customize spells</source>
|
||||
<translation>Własne zaklęcia</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="76"/>
|
||||
<source>Level 1</source>
|
||||
<translation>Poziom 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="93"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="139"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="185"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="231"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="277"/>
|
||||
<source>Spell that may appear in mage guild</source>
|
||||
<translation>Zaklecia, które mogą pojawić się w gildii magów</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="100"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="146"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="192"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="238"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="284"/>
|
||||
<source>Spell that must appear in mage guild</source>
|
||||
<translation>Zaklecia, które muszą pojawić się w gildii magów</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="122"/>
|
||||
<source>Level 2</source>
|
||||
<translation>Poziom 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="168"/>
|
||||
<source>Level 3</source>
|
||||
<translation>Poziom 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="214"/>
|
||||
<source>Level 4</source>
|
||||
<translation>Poziom 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="260"/>
|
||||
<source>Level 5</source>
|
||||
<translation>Poziom 5</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Translations</name>
|
||||
@ -1698,18 +1900,6 @@
|
||||
<source>Width</source>
|
||||
<translation>Szerokość</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>S (36x36)</source>
|
||||
<translation type="vanished">S (36x36)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>M (72x72)</source>
|
||||
<translation type="vanished">M (72x72)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>L (108x108)</source>
|
||||
<translation type="vanished">L (108x108)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="179"/>
|
||||
<source>XL (144x144)</source>
|
||||
|
@ -715,7 +715,7 @@
|
||||
<context>
|
||||
<name>MapView</name>
|
||||
<message>
|
||||
<location filename="../mapview.cpp" line="625"/>
|
||||
<location filename="../mapview.cpp" line="626"/>
|
||||
<source>Can't place object</source>
|
||||
<translation>Não é possível colocar objeto</translation>
|
||||
</message>
|
||||
@ -889,38 +889,38 @@
|
||||
<translation>Experiente</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="36"/>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<source>Compliant</source>
|
||||
<translation>Conformista</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="37"/>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<source>Friendly</source>
|
||||
<translation>Amigável</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<source>Aggressive</source>
|
||||
<translation>Agressivo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<location filename="../inspector/inspector.cpp" line="41"/>
|
||||
<source>Hostile</source>
|
||||
<translation>Hostil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<location filename="../inspector/inspector.cpp" line="42"/>
|
||||
<source>Savage</source>
|
||||
<translation>Selvagem</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="843"/>
|
||||
<location filename="../inspector/inspector.cpp" line="932"/>
|
||||
<location filename="../inspector/inspector.cpp" line="847"/>
|
||||
<location filename="../inspector/inspector.cpp" line="936"/>
|
||||
<source>neutral</source>
|
||||
<translation>neutro</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="841"/>
|
||||
<location filename="../inspector/inspector.cpp" line="845"/>
|
||||
<source>UNFLAGGABLE</source>
|
||||
<translation>NÃO TEM BANDEIRA</translation>
|
||||
</message>
|
||||
@ -1435,6 +1435,208 @@
|
||||
<source>Buildings</source>
|
||||
<translation>Estruturas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="53"/>
|
||||
<source>Build all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="60"/>
|
||||
<source>Demolish all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="67"/>
|
||||
<source>Enable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="74"/>
|
||||
<source>Disable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Type</source>
|
||||
<translation type="unfinished">Tipo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Enabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Built</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventDialog</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="23"/>
|
||||
<source>Town event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="42"/>
|
||||
<source>General</source>
|
||||
<translation type="unfinished">Geral</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="57"/>
|
||||
<source>Event name</source>
|
||||
<translation type="unfinished">Nome do evento</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="64"/>
|
||||
<source>Type event message text</source>
|
||||
<translation type="unfinished">Introduza o texto da mensagem do evento</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="85"/>
|
||||
<source>Day of first occurrence</source>
|
||||
<translation type="unfinished">Dia da primeira ocorrência</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="99"/>
|
||||
<source>Repeat after (0 = no repeat)</source>
|
||||
<translation type="unfinished">Repetir após (0 = não repetir)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="123"/>
|
||||
<source>Affected players</source>
|
||||
<translation type="unfinished">Jogadores afetados</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="146"/>
|
||||
<source>affects human</source>
|
||||
<translation type="unfinished">afeta humano</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="155"/>
|
||||
<source>affects AI</source>
|
||||
<translation type="unfinished">afeta IA</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="166"/>
|
||||
<source>Resources</source>
|
||||
<translation type="unfinished">Recursos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="198"/>
|
||||
<source>Buildings</source>
|
||||
<translation type="unfinished">Estruturas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="216"/>
|
||||
<source>Creatures</source>
|
||||
<translation type="unfinished">Criaturas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="255"/>
|
||||
<source>OK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="177"/>
|
||||
<source>Creature level %1 / Creature level %1 Upgrade</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="219"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="29"/>
|
||||
<source>Town events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="37"/>
|
||||
<source>Timed events</source>
|
||||
<translation type="unfinished">Eventos Temporizados</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="63"/>
|
||||
<source>Add</source>
|
||||
<translation type="unfinished">Adicionar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="76"/>
|
||||
<source>Remove</source>
|
||||
<translation type="unfinished">Remover</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="105"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="126"/>
|
||||
<source>New event</source>
|
||||
<translation type="unfinished">Novo Evento</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownSpellsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="29"/>
|
||||
<source>Spells</source>
|
||||
<translation type="unfinished">Feitiços</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="47"/>
|
||||
<source>Customize spells</source>
|
||||
<translation type="unfinished">Personalizar feitiços</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="76"/>
|
||||
<source>Level 1</source>
|
||||
<translation type="unfinished">Nível 1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="93"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="139"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="185"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="231"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="277"/>
|
||||
<source>Spell that may appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="100"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="146"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="192"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="238"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="284"/>
|
||||
<source>Spell that must appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="122"/>
|
||||
<source>Level 2</source>
|
||||
<translation type="unfinished">Nível 2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="168"/>
|
||||
<source>Level 3</source>
|
||||
<translation type="unfinished">Nível 3</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="214"/>
|
||||
<source>Level 4</source>
|
||||
<translation type="unfinished">Nível 4</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="260"/>
|
||||
<source>Level 5</source>
|
||||
<translation type="unfinished">Nível 5</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Translations</name>
|
||||
@ -1698,18 +1900,6 @@
|
||||
<source>Width</source>
|
||||
<translation>Largura</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>S (36x36)</source>
|
||||
<translation type="vanished">P (36x36)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>M (72x72)</source>
|
||||
<translation type="vanished">M (72x72)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>L (108x108)</source>
|
||||
<translation type="vanished">G (108x108)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="179"/>
|
||||
<source>XL (144x144)</source>
|
||||
|
@ -715,7 +715,7 @@
|
||||
<context>
|
||||
<name>MapView</name>
|
||||
<message>
|
||||
<location filename="../mapview.cpp" line="625"/>
|
||||
<location filename="../mapview.cpp" line="626"/>
|
||||
<source>Can't place object</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -889,38 +889,38 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="36"/>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<source>Compliant</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="37"/>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<source>Friendly</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<source>Aggressive</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<location filename="../inspector/inspector.cpp" line="41"/>
|
||||
<source>Hostile</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<location filename="../inspector/inspector.cpp" line="42"/>
|
||||
<source>Savage</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="843"/>
|
||||
<location filename="../inspector/inspector.cpp" line="932"/>
|
||||
<location filename="../inspector/inspector.cpp" line="847"/>
|
||||
<location filename="../inspector/inspector.cpp" line="936"/>
|
||||
<source>neutral</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="841"/>
|
||||
<location filename="../inspector/inspector.cpp" line="845"/>
|
||||
<source>UNFLAGGABLE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -1435,6 +1435,208 @@
|
||||
<source>Buildings</source>
|
||||
<translation>Постройки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="53"/>
|
||||
<source>Build all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="60"/>
|
||||
<source>Demolish all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="67"/>
|
||||
<source>Enable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="74"/>
|
||||
<source>Disable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Type</source>
|
||||
<translation type="unfinished">Тип</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Enabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Built</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventDialog</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="23"/>
|
||||
<source>Town event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="42"/>
|
||||
<source>General</source>
|
||||
<translation type="unfinished">Общее</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="57"/>
|
||||
<source>Event name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="64"/>
|
||||
<source>Type event message text</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="85"/>
|
||||
<source>Day of first occurrence</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="99"/>
|
||||
<source>Repeat after (0 = no repeat)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="123"/>
|
||||
<source>Affected players</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="146"/>
|
||||
<source>affects human</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="155"/>
|
||||
<source>affects AI</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="166"/>
|
||||
<source>Resources</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="198"/>
|
||||
<source>Buildings</source>
|
||||
<translation type="unfinished">Постройки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="216"/>
|
||||
<source>Creatures</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="255"/>
|
||||
<source>OK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="177"/>
|
||||
<source>Creature level %1 / Creature level %1 Upgrade</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="219"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="29"/>
|
||||
<source>Town events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="37"/>
|
||||
<source>Timed events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="63"/>
|
||||
<source>Add</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="76"/>
|
||||
<source>Remove</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="105"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="126"/>
|
||||
<source>New event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownSpellsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="29"/>
|
||||
<source>Spells</source>
|
||||
<translation type="unfinished">Заклинания</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="47"/>
|
||||
<source>Customize spells</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="76"/>
|
||||
<source>Level 1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="93"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="139"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="185"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="231"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="277"/>
|
||||
<source>Spell that may appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="100"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="146"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="192"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="238"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="284"/>
|
||||
<source>Spell that must appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="122"/>
|
||||
<source>Level 2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="168"/>
|
||||
<source>Level 3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="214"/>
|
||||
<source>Level 4</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="260"/>
|
||||
<source>Level 5</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Translations</name>
|
||||
@ -1698,18 +1900,6 @@
|
||||
<source>Width</source>
|
||||
<translation>Ширина</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>S (36x36)</source>
|
||||
<translation type="vanished">Мал. (36x36)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>M (72x72)</source>
|
||||
<translation type="vanished">Ср. (72x72)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>L (108x108)</source>
|
||||
<translation type="vanished">Бол. (108x108)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="179"/>
|
||||
<source>XL (144x144)</source>
|
||||
|
@ -715,7 +715,7 @@
|
||||
<context>
|
||||
<name>MapView</name>
|
||||
<message>
|
||||
<location filename="../mapview.cpp" line="625"/>
|
||||
<location filename="../mapview.cpp" line="626"/>
|
||||
<source>Can't place object</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -889,38 +889,38 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="36"/>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<source>Compliant</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="37"/>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<source>Friendly</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<source>Aggressive</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<location filename="../inspector/inspector.cpp" line="41"/>
|
||||
<source>Hostile</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<location filename="../inspector/inspector.cpp" line="42"/>
|
||||
<source>Savage</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="843"/>
|
||||
<location filename="../inspector/inspector.cpp" line="932"/>
|
||||
<location filename="../inspector/inspector.cpp" line="847"/>
|
||||
<location filename="../inspector/inspector.cpp" line="936"/>
|
||||
<source>neutral</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="841"/>
|
||||
<location filename="../inspector/inspector.cpp" line="845"/>
|
||||
<source>UNFLAGGABLE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -1435,6 +1435,208 @@
|
||||
<source>Buildings</source>
|
||||
<translation>Edificios</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="53"/>
|
||||
<source>Build all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="60"/>
|
||||
<source>Demolish all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="67"/>
|
||||
<source>Enable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="74"/>
|
||||
<source>Disable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Type</source>
|
||||
<translation type="unfinished">Tipo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Enabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Built</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventDialog</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="23"/>
|
||||
<source>Town event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="42"/>
|
||||
<source>General</source>
|
||||
<translation type="unfinished">General</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="57"/>
|
||||
<source>Event name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="64"/>
|
||||
<source>Type event message text</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="85"/>
|
||||
<source>Day of first occurrence</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="99"/>
|
||||
<source>Repeat after (0 = no repeat)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="123"/>
|
||||
<source>Affected players</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="146"/>
|
||||
<source>affects human</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="155"/>
|
||||
<source>affects AI</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="166"/>
|
||||
<source>Resources</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="198"/>
|
||||
<source>Buildings</source>
|
||||
<translation type="unfinished">Edificios</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="216"/>
|
||||
<source>Creatures</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="255"/>
|
||||
<source>OK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="177"/>
|
||||
<source>Creature level %1 / Creature level %1 Upgrade</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="219"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="29"/>
|
||||
<source>Town events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="37"/>
|
||||
<source>Timed events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="63"/>
|
||||
<source>Add</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="76"/>
|
||||
<source>Remove</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="105"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="126"/>
|
||||
<source>New event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownSpellsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="29"/>
|
||||
<source>Spells</source>
|
||||
<translation type="unfinished">Hechizos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="47"/>
|
||||
<source>Customize spells</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="76"/>
|
||||
<source>Level 1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="93"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="139"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="185"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="231"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="277"/>
|
||||
<source>Spell that may appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="100"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="146"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="192"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="238"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="284"/>
|
||||
<source>Spell that must appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="122"/>
|
||||
<source>Level 2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="168"/>
|
||||
<source>Level 3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="214"/>
|
||||
<source>Level 4</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="260"/>
|
||||
<source>Level 5</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Translations</name>
|
||||
@ -1698,18 +1900,6 @@
|
||||
<source>Width</source>
|
||||
<translation>Ancho</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>S (36x36)</source>
|
||||
<translation type="vanished">S (36x36)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>M (72x72)</source>
|
||||
<translation type="vanished">M (72x72)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>L (108x108)</source>
|
||||
<translation type="vanished">L (108x108)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="179"/>
|
||||
<source>XL (144x144)</source>
|
||||
|
@ -715,7 +715,7 @@
|
||||
<context>
|
||||
<name>MapView</name>
|
||||
<message>
|
||||
<location filename="../mapview.cpp" line="625"/>
|
||||
<location filename="../mapview.cpp" line="626"/>
|
||||
<source>Can't place object</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -889,38 +889,38 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="36"/>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<source>Compliant</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="37"/>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<source>Friendly</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<source>Aggressive</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<location filename="../inspector/inspector.cpp" line="41"/>
|
||||
<source>Hostile</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<location filename="../inspector/inspector.cpp" line="42"/>
|
||||
<source>Savage</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="843"/>
|
||||
<location filename="../inspector/inspector.cpp" line="932"/>
|
||||
<location filename="../inspector/inspector.cpp" line="847"/>
|
||||
<location filename="../inspector/inspector.cpp" line="936"/>
|
||||
<source>neutral</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="841"/>
|
||||
<location filename="../inspector/inspector.cpp" line="845"/>
|
||||
<source>UNFLAGGABLE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -1435,6 +1435,208 @@
|
||||
<source>Buildings</source>
|
||||
<translation>Будівлі</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="53"/>
|
||||
<source>Build all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="60"/>
|
||||
<source>Demolish all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="67"/>
|
||||
<source>Enable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="74"/>
|
||||
<source>Disable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Type</source>
|
||||
<translation type="unfinished">Тип</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Enabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Built</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventDialog</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="23"/>
|
||||
<source>Town event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="42"/>
|
||||
<source>General</source>
|
||||
<translation type="unfinished">Загальний</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="57"/>
|
||||
<source>Event name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="64"/>
|
||||
<source>Type event message text</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="85"/>
|
||||
<source>Day of first occurrence</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="99"/>
|
||||
<source>Repeat after (0 = no repeat)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="123"/>
|
||||
<source>Affected players</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="146"/>
|
||||
<source>affects human</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="155"/>
|
||||
<source>affects AI</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="166"/>
|
||||
<source>Resources</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="198"/>
|
||||
<source>Buildings</source>
|
||||
<translation type="unfinished">Будівлі</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="216"/>
|
||||
<source>Creatures</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="255"/>
|
||||
<source>OK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="177"/>
|
||||
<source>Creature level %1 / Creature level %1 Upgrade</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="219"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="29"/>
|
||||
<source>Town events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="37"/>
|
||||
<source>Timed events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="63"/>
|
||||
<source>Add</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="76"/>
|
||||
<source>Remove</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="105"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="126"/>
|
||||
<source>New event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownSpellsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="29"/>
|
||||
<source>Spells</source>
|
||||
<translation type="unfinished">Закляття</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="47"/>
|
||||
<source>Customize spells</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="76"/>
|
||||
<source>Level 1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="93"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="139"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="185"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="231"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="277"/>
|
||||
<source>Spell that may appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="100"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="146"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="192"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="238"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="284"/>
|
||||
<source>Spell that must appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="122"/>
|
||||
<source>Level 2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="168"/>
|
||||
<source>Level 3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="214"/>
|
||||
<source>Level 4</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="260"/>
|
||||
<source>Level 5</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Translations</name>
|
||||
@ -1698,18 +1900,6 @@
|
||||
<source>Width</source>
|
||||
<translation>Ширина</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>S (36x36)</source>
|
||||
<translation type="vanished">М (36x36)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>M (72x72)</source>
|
||||
<translation type="vanished">С (72x72)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>L (108x108)</source>
|
||||
<translation type="vanished">В (108x108)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="179"/>
|
||||
<source>XL (144x144)</source>
|
||||
|
@ -715,7 +715,7 @@
|
||||
<context>
|
||||
<name>MapView</name>
|
||||
<message>
|
||||
<location filename="../mapview.cpp" line="625"/>
|
||||
<location filename="../mapview.cpp" line="626"/>
|
||||
<source>Can't place object</source>
|
||||
<translation>Không thể đặt vật thể</translation>
|
||||
</message>
|
||||
@ -889,38 +889,38 @@
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="36"/>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<source>Compliant</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="37"/>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<source>Friendly</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="38"/>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<source>Aggressive</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="39"/>
|
||||
<location filename="../inspector/inspector.cpp" line="41"/>
|
||||
<source>Hostile</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="40"/>
|
||||
<location filename="../inspector/inspector.cpp" line="42"/>
|
||||
<source>Savage</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="843"/>
|
||||
<location filename="../inspector/inspector.cpp" line="932"/>
|
||||
<location filename="../inspector/inspector.cpp" line="847"/>
|
||||
<location filename="../inspector/inspector.cpp" line="936"/>
|
||||
<source>neutral</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/inspector.cpp" line="841"/>
|
||||
<location filename="../inspector/inspector.cpp" line="845"/>
|
||||
<source>UNFLAGGABLE</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -1435,6 +1435,208 @@
|
||||
<source>Buildings</source>
|
||||
<translation>Công trình</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="53"/>
|
||||
<source>Build all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="60"/>
|
||||
<source>Demolish all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="67"/>
|
||||
<source>Enable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.ui" line="74"/>
|
||||
<source>Disable all</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Type</source>
|
||||
<translation type="unfinished">Loại</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Enabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townbuildingswidget.cpp" line="77"/>
|
||||
<source>Built</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventDialog</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="23"/>
|
||||
<source>Town event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="42"/>
|
||||
<source>General</source>
|
||||
<translation type="unfinished">Chung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="57"/>
|
||||
<source>Event name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="64"/>
|
||||
<source>Type event message text</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="85"/>
|
||||
<source>Day of first occurrence</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="99"/>
|
||||
<source>Repeat after (0 = no repeat)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="123"/>
|
||||
<source>Affected players</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="146"/>
|
||||
<source>affects human</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="155"/>
|
||||
<source>affects AI</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="166"/>
|
||||
<source>Resources</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="198"/>
|
||||
<source>Buildings</source>
|
||||
<translation type="unfinished">Công trình</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="216"/>
|
||||
<source>Creatures</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.ui" line="255"/>
|
||||
<source>OK</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="177"/>
|
||||
<source>Creature level %1 / Creature level %1 Upgrade</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventdialog.cpp" line="219"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownEventsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="29"/>
|
||||
<source>Town events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="37"/>
|
||||
<source>Timed events</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="63"/>
|
||||
<source>Add</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.ui" line="76"/>
|
||||
<source>Remove</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="105"/>
|
||||
<source>Day %1 - %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/towneventswidget.cpp" line="126"/>
|
||||
<source>New event</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TownSpellsWidget</name>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="29"/>
|
||||
<source>Spells</source>
|
||||
<translation type="unfinished">Phép</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="47"/>
|
||||
<source>Customize spells</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="76"/>
|
||||
<source>Level 1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="93"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="139"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="185"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="231"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="277"/>
|
||||
<source>Spell that may appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="100"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="146"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="192"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="238"/>
|
||||
<location filename="../inspector/townspellswidget.ui" line="284"/>
|
||||
<source>Spell that must appear in mage guild</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="122"/>
|
||||
<source>Level 2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="168"/>
|
||||
<source>Level 3</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="214"/>
|
||||
<source>Level 4</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../inspector/townspellswidget.ui" line="260"/>
|
||||
<source>Level 5</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Translations</name>
|
||||
@ -1698,18 +1900,6 @@
|
||||
<source>Width</source>
|
||||
<translation>Rộng</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>S (36x36)</source>
|
||||
<translation type="vanished">Nhỏ (36x36)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>M (72x72)</source>
|
||||
<translation type="vanished">Vừa (72x72)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>L (108x108)</source>
|
||||
<translation type="vanished">Lớn (108x108)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../windownewmap.ui" line="179"/>
|
||||
<source>XL (144x144)</source>
|
||||
|
@ -669,6 +669,19 @@ void CGameHandler::onPlayerTurnEnded(PlayerColor which)
|
||||
heroPool->onNewWeek(which);
|
||||
}
|
||||
|
||||
void CGameHandler::addStatistics()
|
||||
{
|
||||
for (auto & elem : gs->players)
|
||||
{
|
||||
if (elem.first == PlayerColor::NEUTRAL || !elem.first.isValidPlayer())
|
||||
continue;
|
||||
|
||||
auto data = StatisticDataSet::createEntry(&elem.second, gs);
|
||||
|
||||
gameState()->statistic.add(data);
|
||||
}
|
||||
}
|
||||
|
||||
void CGameHandler::onNewTurn()
|
||||
{
|
||||
logGlobal->trace("Turn %d", gs->day+1);
|
||||
@ -1013,6 +1026,8 @@ void CGameHandler::onNewTurn()
|
||||
}
|
||||
|
||||
synchronizeArtifactHandlerLists(); //new day events may have changed them. TODO better of managing that
|
||||
|
||||
addStatistics();
|
||||
}
|
||||
|
||||
void CGameHandler::start(bool resume)
|
||||
@ -1345,6 +1360,7 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, EMovementMode moveme
|
||||
|
||||
turnTimerHandler->setEndTurnAllowed(h->getOwner(), !movingOntoWater && !movingOntoObstacle);
|
||||
doMove(TryMoveHero::SUCCESS, lookForGuards, visitDest, LEAVING_TILE);
|
||||
gs->statistic.accumulatedValues[asker].movementPointsUsed += tmh.movePoints;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -2457,7 +2473,10 @@ bool CGameHandler::buildStructure(ObjectInstanceID tid, BuildingID requestedID,
|
||||
|
||||
//Take cost
|
||||
if(!force)
|
||||
{
|
||||
giveResources(t->tempOwner, -requestedBuilding->resources);
|
||||
gs->statistic.accumulatedValues[t->tempOwner].spentResourcesForBuildings += requestedBuilding->resources;
|
||||
}
|
||||
|
||||
//We know what has been built, apply changes. Do this as final step to properly update town window
|
||||
sendAndApply(&ns);
|
||||
@ -2559,7 +2578,9 @@ bool CGameHandler::recruitCreatures(ObjectInstanceID objid, ObjectInstanceID dst
|
||||
}
|
||||
|
||||
//recruit
|
||||
giveResources(army->tempOwner, -(c->getFullRecruitCost() * cram));
|
||||
TResources cost = (c->getFullRecruitCost() * cram);
|
||||
giveResources(army->tempOwner, -cost);
|
||||
gs->statistic.accumulatedValues[army->tempOwner].spentResourcesForArmy += cost;
|
||||
|
||||
SetAvailableCreatures sac;
|
||||
sac.tid = objid;
|
||||
@ -2612,6 +2633,7 @@ bool CGameHandler::upgradeCreature(ObjectInstanceID objid, SlotID pos, CreatureI
|
||||
|
||||
//take resources
|
||||
giveResources(player, -totalCost);
|
||||
gs->statistic.accumulatedValues[player].spentResourcesForArmy += totalCost;
|
||||
|
||||
//upgrade creature
|
||||
changeStackType(StackLocation(obj, pos), upgID.toCreature());
|
||||
@ -3236,6 +3258,9 @@ bool CGameHandler::tradeResources(const IMarket *market, ui32 amountToSell, Play
|
||||
giveResource(player, toSell, -b1 * amountToBoy);
|
||||
giveResource(player, toBuy, b2 * amountToBoy);
|
||||
|
||||
gs->statistic.accumulatedValues[player].tradeVolume[toSell] += -b1 * amountToBoy;
|
||||
gs->statistic.accumulatedValues[player].tradeVolume[toBuy] += b2 * amountToBoy;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3424,7 +3449,7 @@ void CGameHandler::handleTimeEvents()
|
||||
|
||||
void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
|
||||
{
|
||||
town->events.sort(evntCmp);
|
||||
std::sort(town->events.begin(), town->events.end(), evntCmp);
|
||||
while(town->events.size() && town->events.front().firstOccurrence == gs->day)
|
||||
{
|
||||
PlayerColor player = town->tempOwner;
|
||||
@ -3485,7 +3510,7 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
|
||||
|
||||
if (ev.nextOccurrence)
|
||||
{
|
||||
town->events.pop_front();
|
||||
town->events.erase(town->events.begin());
|
||||
|
||||
ev.firstOccurrence += ev.nextOccurrence;
|
||||
auto it = town->events.begin();
|
||||
@ -3495,7 +3520,7 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n)
|
||||
}
|
||||
else
|
||||
{
|
||||
town->events.pop_front();
|
||||
town->events.erase(town->events.begin());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,6 +226,7 @@ public:
|
||||
void onPlayerTurnStarted(PlayerColor which);
|
||||
void onPlayerTurnEnded(PlayerColor which);
|
||||
void onNewTurn();
|
||||
void addStatistics();
|
||||
|
||||
void handleTimeEvents();
|
||||
void handleTownEvents(CGTownInstance *town, NewTurn &n);
|
||||
|
@ -447,16 +447,16 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
|
||||
addArtifactToTransfer(packCommander, artSlot.first, artSlot.second.getArt());
|
||||
sendArtifacts(packCommander);
|
||||
}
|
||||
}
|
||||
auto armyObj = battle.battleGetArmyObject(battle.otherSide(battleResult->winner));
|
||||
for(const auto & armySlot : armyObj->stacks)
|
||||
{
|
||||
BulkMoveArtifacts packsArmy(finishingBattle->winnerHero->getOwner(), finishingBattle->loserHero->id, finishingBattle->winnerHero->id, false);
|
||||
packsArmy.srcArtHolder = armyObj->id;
|
||||
packsArmy.srcCreature = armySlot.first;
|
||||
for(const auto & artSlot : armySlot.second->artifactsWorn)
|
||||
addArtifactToTransfer(packsArmy, artSlot.first, armySlot.second->getArt(artSlot.first));
|
||||
sendArtifacts(packsArmy);
|
||||
auto armyObj = battle.battleGetArmyObject(battle.otherSide(battleResult->winner));
|
||||
for(const auto & armySlot : armyObj->stacks)
|
||||
{
|
||||
BulkMoveArtifacts packsArmy(finishingBattle->winnerHero->getOwner(), finishingBattle->loserHero->id, finishingBattle->winnerHero->id, false);
|
||||
packsArmy.srcArtHolder = armyObj->id;
|
||||
packsArmy.srcCreature = armySlot.first;
|
||||
for(const auto & artSlot : armySlot.second->artifactsWorn)
|
||||
addArtifactToTransfer(packsArmy, artSlot.first, armySlot.second->getArt(artSlot.first));
|
||||
sendArtifacts(packsArmy);
|
||||
}
|
||||
}
|
||||
// Display loot
|
||||
if(!arts.empty())
|
||||
@ -497,6 +497,22 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
|
||||
gameHandler->sendAndApply(&ro);
|
||||
}
|
||||
|
||||
// add statistic
|
||||
if(battle.sideToPlayer(0) == PlayerColor::NEUTRAL || battle.sideToPlayer(1) == PlayerColor::NEUTRAL)
|
||||
{
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(0)].numBattlesNeutral++;
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(1)].numBattlesNeutral++;
|
||||
if(!finishingBattle->isDraw())
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(finishingBattle->winnerSide)].numWinBattlesNeutral++;
|
||||
}
|
||||
else
|
||||
{
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(0)].numBattlesPlayer++;
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(1)].numBattlesPlayer++;
|
||||
if(!finishingBattle->isDraw())
|
||||
gameHandler->gameState()->statistic.accumulatedValues[battle.sideToPlayer(finishingBattle->winnerSide)].numWinBattlesPlayer++;
|
||||
}
|
||||
|
||||
BattleResultAccepted raccepted;
|
||||
raccepted.battleID = battle.getBattle()->getBattleID();
|
||||
raccepted.heroResult[0].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(BattleSide::ATTACKER));
|
||||
@ -556,10 +572,16 @@ void BattleResultProcessor::battleAfterLevelUp(const BattleID & battleID, const
|
||||
gameHandler->checkVictoryLossConditions(playerColors);
|
||||
|
||||
if (result.result == EBattleResult::SURRENDER)
|
||||
{
|
||||
gameHandler->gameState()->statistic.accumulatedValues[finishingBattle->loser].numHeroSurrendered++;
|
||||
gameHandler->heroPool->onHeroSurrendered(finishingBattle->loser, finishingBattle->loserHero);
|
||||
}
|
||||
|
||||
if (result.result == EBattleResult::ESCAPE)
|
||||
{
|
||||
gameHandler->gameState()->statistic.accumulatedValues[finishingBattle->loser].numHeroEscaped++;
|
||||
gameHandler->heroPool->onHeroEscaped(finishingBattle->loser, finishingBattle->loserHero);
|
||||
}
|
||||
|
||||
if (result.winner != 2 && finishingBattle->winnerHero && finishingBattle->winnerHero->stacks.empty()
|
||||
&& (!finishingBattle->winnerHero->commander || !finishingBattle->winnerHero->commander->alive))
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "../../lib/networkPacks/PacksForClient.h"
|
||||
#include "../../lib/networkPacks/StackLocation.h"
|
||||
#include "../../lib/serializer/Connection.h"
|
||||
#include "../lib/VCMIDirs.h"
|
||||
|
||||
PlayerMessageProcessor::PlayerMessageProcessor(CGameHandler * gameHandler)
|
||||
:gameHandler(gameHandler)
|
||||
@ -133,12 +134,30 @@ void PlayerMessageProcessor::commandCheaters(PlayerColor player, const std::vect
|
||||
broadcastSystemMessage("No cheaters registered!");
|
||||
}
|
||||
|
||||
void PlayerMessageProcessor::commandStatistic(PlayerColor player, const std::vector<std::string> & words)
|
||||
{
|
||||
bool isHost = gameHandler->gameLobby()->isPlayerHost(player);
|
||||
if(!isHost)
|
||||
return;
|
||||
|
||||
const boost::filesystem::path outPath = VCMIDirs::get().userCachePath() / "statistic";
|
||||
boost::filesystem::create_directories(outPath);
|
||||
|
||||
const boost::filesystem::path filePath = outPath / (vstd::getDateTimeISO8601Basic(std::time(nullptr)) + ".csv");
|
||||
std::ofstream file(filePath.c_str());
|
||||
std::string csv = gameHandler->gameState()->statistic.toCsv();
|
||||
file << csv;
|
||||
|
||||
broadcastSystemMessage("Statistic files can be found in " + outPath.string() + " directory\n");
|
||||
}
|
||||
|
||||
void PlayerMessageProcessor::commandHelp(PlayerColor player, const std::vector<std::string> & words)
|
||||
{
|
||||
broadcastSystemMessage("Available commands to host:");
|
||||
broadcastSystemMessage("'!exit' - immediately ends current game");
|
||||
broadcastSystemMessage("'!kick <player>' - kick specified player from the game");
|
||||
broadcastSystemMessage("'!save <filename>' - save game under specified filename");
|
||||
broadcastSystemMessage("'!statistic' - save game statistics as csv file");
|
||||
broadcastSystemMessage("Available commands to all players:");
|
||||
broadcastSystemMessage("'!help' - display this help");
|
||||
broadcastSystemMessage("'!cheaters' - list players that entered cheat command during game");
|
||||
@ -319,6 +338,8 @@ void PlayerMessageProcessor::handleCommand(PlayerColor player, const std::string
|
||||
commandSave(player, words);
|
||||
if(words[0] == "!cheaters")
|
||||
commandCheaters(player, words);
|
||||
if(words[0] == "!statistic")
|
||||
commandStatistic(player, words);
|
||||
}
|
||||
|
||||
void PlayerMessageProcessor::cheatGiveSpells(PlayerColor player, const CGHeroInstance * hero)
|
||||
|
@ -62,6 +62,7 @@ class PlayerMessageProcessor
|
||||
void commandKick(PlayerColor player, const std::vector<std::string> & words);
|
||||
void commandSave(PlayerColor player, const std::vector<std::string> & words);
|
||||
void commandCheaters(PlayerColor player, const std::vector<std::string> & words);
|
||||
void commandStatistic(PlayerColor player, const std::vector<std::string> & words);
|
||||
void commandHelp(PlayerColor player, const std::vector<std::string> & words);
|
||||
void commandVote(PlayerColor player, const std::vector<std::string> & words);
|
||||
|
||||
|
@ -40,11 +40,32 @@ public:
|
||||
bonusFake.addNewBonus(b);
|
||||
}
|
||||
|
||||
void addCreatureAbility(BonusType bonusType)
|
||||
{
|
||||
addNewBonus(
|
||||
std::make_shared<Bonus>(
|
||||
BonusDuration::PERMANENT,
|
||||
bonusType,
|
||||
BonusSource::CREATURE_ABILITY,
|
||||
0,
|
||||
CreatureID(0)));
|
||||
}
|
||||
|
||||
void makeAlive()
|
||||
{
|
||||
EXPECT_CALL(*this, alive()).WillRepeatedly(Return(true));
|
||||
}
|
||||
|
||||
void setupPoisition(BattleHex pos)
|
||||
{
|
||||
EXPECT_CALL(*this, getPosition()).WillRepeatedly(Return(pos));
|
||||
}
|
||||
|
||||
void makeDoubleWide()
|
||||
{
|
||||
EXPECT_CALL(*this, doubleWide()).WillRepeatedly(Return(true));
|
||||
}
|
||||
|
||||
void makeWarMachine()
|
||||
{
|
||||
addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SIEGE_WEAPON, BonusSource::CREATURE_ABILITY, 1, BonusSourceID()));
|
||||
@ -183,6 +204,190 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class AttackableHexesTest : public CBattleInfoCallbackTest
|
||||
{
|
||||
public:
|
||||
UnitFake & addRegularMelee(BattleHex hex, uint8_t side)
|
||||
{
|
||||
auto & unit = unitsFake.add(side);
|
||||
|
||||
unit.makeAlive();
|
||||
unit.setDefaultState();
|
||||
unit.setupPoisition(hex);
|
||||
unit.redirectBonusesToFake();
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
UnitFake & addDragon(BattleHex hex, uint8_t side)
|
||||
{
|
||||
auto & unit = addRegularMelee(hex, side);
|
||||
|
||||
unit.addCreatureAbility(BonusType::TWO_HEX_ATTACK_BREATH);
|
||||
unit.makeDoubleWide();
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
Units getAttackedUnits(UnitFake & attacker, UnitFake & defender, BattleHex defenderHex)
|
||||
{
|
||||
startBattle();
|
||||
redirectUnitsToFake();
|
||||
|
||||
return subject.getAttackedBattleUnits(
|
||||
&attacker, &defender,
|
||||
defenderHex, false,
|
||||
attacker.getPosition(),
|
||||
defender.getPosition());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(AttackableHexesTest, DragonRightRegular_RightHorithontalBreath)
|
||||
{
|
||||
// X A D #
|
||||
UnitFake & attacker = addDragon(35, 0);
|
||||
UnitFake & defender = addRegularMelee(36, 1);
|
||||
UnitFake & next = addRegularMelee(37, 1);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.getPosition());
|
||||
|
||||
EXPECT_TRUE(vstd::contains(attacked, &next));
|
||||
}
|
||||
|
||||
TEST_F(AttackableHexesTest, DragonDragonBottomRightHead_BottomRightBreathFromHead)
|
||||
{
|
||||
// X A
|
||||
// D X target D
|
||||
// #
|
||||
UnitFake & attacker = addDragon(35, 0);
|
||||
UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.getPosition());
|
||||
|
||||
EXPECT_TRUE(vstd::contains(attacked, &next));
|
||||
}
|
||||
|
||||
TEST_F(AttackableHexesTest, DragonDragonVerticalDownHead_VerticalDownBreathFromHead)
|
||||
{
|
||||
// X A
|
||||
// D X target D
|
||||
// #
|
||||
UnitFake & attacker = addDragon(35, 0);
|
||||
UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), 1);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.getPosition());
|
||||
|
||||
EXPECT_TRUE(vstd::contains(attacked, &next));
|
||||
}
|
||||
|
||||
TEST_F(AttackableHexesTest, DragonDragonVerticalDownHeadReverse_VerticalDownBreathFromHead)
|
||||
{
|
||||
// A X
|
||||
// X D target D
|
||||
// #
|
||||
UnitFake & attacker = addDragon(36, 1);
|
||||
UnitFake & defender = addDragon(attacker.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 0);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), 0);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.getPosition());
|
||||
|
||||
EXPECT_TRUE(vstd::contains(attacked, &next));
|
||||
}
|
||||
|
||||
TEST_F(AttackableHexesTest, DragonDragonVerticalDownBack_VerticalDownBreath)
|
||||
{
|
||||
// X A
|
||||
// D X target X
|
||||
// #
|
||||
UnitFake & attacker = addDragon(37, 0);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT), 1);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.occupiedHex());
|
||||
|
||||
EXPECT_TRUE(vstd::contains(attacked, &next));
|
||||
}
|
||||
|
||||
TEST_F(AttackableHexesTest, DragonDragonHeadBottomRight_BottomRightBreathFromHead)
|
||||
{
|
||||
// X A
|
||||
// D X target D
|
||||
// #
|
||||
UnitFake & attacker = addDragon(37, 0);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT), 1);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.getPosition());
|
||||
|
||||
EXPECT_TRUE(vstd::contains(attacked, &next));
|
||||
}
|
||||
|
||||
TEST_F(AttackableHexesTest, DragonVerticalDownDragonBackReverse_VerticalDownBreath)
|
||||
{
|
||||
// A X
|
||||
// X D target X
|
||||
// #
|
||||
UnitFake & attacker = addDragon(36, 1);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_RIGHT), 0);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), 0);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.occupiedHex());
|
||||
|
||||
EXPECT_TRUE(vstd::contains(attacked, &next));
|
||||
}
|
||||
|
||||
TEST_F(AttackableHexesTest, DragonRightBottomDragonHeadReverse_RightBottomBreathFromHeadHex)
|
||||
{
|
||||
// A X
|
||||
// X D target D
|
||||
UnitFake & attacker = addDragon(36, 1);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_RIGHT), 0);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_LEFT), 0);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.getPosition());
|
||||
|
||||
EXPECT_TRUE(vstd::contains(attacked, &next));
|
||||
}
|
||||
|
||||
TEST_F(AttackableHexesTest, DragonLeftBottomDragonBackToBack_LeftBottomBreathFromBackHex)
|
||||
{
|
||||
// X A
|
||||
// D X target X
|
||||
// #
|
||||
UnitFake & attacker = addDragon(8, 0);
|
||||
UnitFake & defender = addDragon(attacker.occupiedHex().cloneInDirection(BattleHex::BOTTOM_LEFT).cloneInDirection(BattleHex::LEFT), 1);
|
||||
UnitFake & next = addRegularMelee(defender.getPosition().cloneInDirection(BattleHex::BOTTOM_RIGHT), 1);
|
||||
|
||||
auto attacked = getAttackedUnits(attacker, defender, defender.occupiedHex());
|
||||
|
||||
EXPECT_TRUE(vstd::contains(attacked, &next));
|
||||
}
|
||||
|
||||
TEST_F(AttackableHexesTest, DefenderPositionOverride_BreathCountsHypoteticDefenderPosition)
|
||||
{
|
||||
// # N
|
||||
// X D target D
|
||||
// A X
|
||||
UnitFake & attacker = addDragon(35, 1);
|
||||
UnitFake & defender = addDragon(8, 0);
|
||||
UnitFake & next = addDragon(2, 0);
|
||||
|
||||
startBattle();
|
||||
redirectUnitsToFake();
|
||||
|
||||
auto attacked = subject.getAttackedBattleUnits(
|
||||
&attacker,
|
||||
&defender,
|
||||
19,
|
||||
false,
|
||||
attacker.getPosition(),
|
||||
19);
|
||||
|
||||
EXPECT_TRUE(vstd::contains(attacked, &next));
|
||||
}
|
||||
|
||||
class BattleFinishedTest : public CBattleInfoCallbackTest
|
||||
{
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user