mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-24 08:32:34 +02:00
Merge beta into develop
This commit is contained in:
commit
dfa2e2a349
@ -212,11 +212,13 @@ AttackPossibility AttackPossibility::evaluate(const BattleAttackInfo & attackInf
|
||||
// check how much damage we gain from blocking enemy shooters on this hex
|
||||
bestAp.shootersBlockedDmg = evaluateBlockedShootersDmg(attackInfo, hex, state);
|
||||
|
||||
logAi->debug("BattleAI best AP: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld",
|
||||
#if BATTLE_TRACE_LEVEL>=1
|
||||
logAi->trace("BattleAI best 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)bestAp.dest, (int)bestAp.from, (int)bestAp.affectedUnits.size(),
|
||||
bestAp.defenderDamageReduce, bestAp.attackerDamageReduce, bestAp.collateralDamageReduce, bestAp.shootersBlockedDmg);
|
||||
#endif
|
||||
|
||||
//TODO other damage related to attack (eg. fire shield and other abilities)
|
||||
return bestAp;
|
||||
|
@ -90,6 +90,7 @@ void CBattleAI::initBattleInterface(std::shared_ptr<Environment> ENV, std::share
|
||||
wasUnlockingGs = CB->unlockGsWhenWaiting;
|
||||
CB->waitTillRealize = true;
|
||||
CB->unlockGsWhenWaiting = false;
|
||||
movesSkippedByDefense = 0;
|
||||
}
|
||||
|
||||
BattleAction CBattleAI::activeStack( const CStack * stack )
|
||||
@ -182,6 +183,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
||||
if(bestSpellcast.is_initialized() && bestSpellcast->value > bestAttack.damageDiff())
|
||||
{
|
||||
// return because spellcast value is damage dealt and score is dps reduce
|
||||
movesSkippedByDefense = 0;
|
||||
return BattleAction::makeCreatureSpellcast(stack, bestSpellcast->dest, bestSpellcast->spell->id);
|
||||
}
|
||||
|
||||
@ -197,14 +199,15 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
||||
}
|
||||
else if(bestAttack.attack.shooting)
|
||||
{
|
||||
|
||||
result = BattleAction::makeShotAttack(stack, bestAttack.attack.defender);
|
||||
action = "shot";
|
||||
movesSkippedByDefense = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = BattleAction::makeMeleeAttack(stack, bestAttack.attack.defender->getPosition(), bestAttack.from);
|
||||
action = "melee";
|
||||
movesSkippedByDefense = 0;
|
||||
}
|
||||
|
||||
logAi->debug("BattleAI: %s -> %s x %d, %s, from %d curpos %d dist %d speed %d: +%lld -%lld = %lld",
|
||||
@ -218,6 +221,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
||||
}
|
||||
else if(bestSpellcast.is_initialized())
|
||||
{
|
||||
movesSkippedByDefense = 0;
|
||||
return BattleAction::makeCreatureSpellcast(stack, bestSpellcast->dest, bestSpellcast->spell->id);
|
||||
}
|
||||
|
||||
@ -236,12 +240,8 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
||||
}
|
||||
}
|
||||
|
||||
if(score > EvaluationResult::INEFFECTIVE_SCORE)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if(!stack->hasBonusOfType(Bonus::FLYING)
|
||||
if(score <= EvaluationResult::INEFFECTIVE_SCORE
|
||||
&& !stack->hasBonusOfType(Bonus::FLYING)
|
||||
&& stack->unitSide() == BattleSide::ATTACKER
|
||||
&& cb->battleGetSiegeLevel() >= CGTownInstance::CITADEL)
|
||||
{
|
||||
@ -249,10 +249,12 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
||||
|
||||
if(brokenWallMoat.size())
|
||||
{
|
||||
movesSkippedByDefense = 0;
|
||||
|
||||
if(stack->doubleWide() && vstd::contains(brokenWallMoat, stack->getPosition()))
|
||||
return BattleAction::makeMove(stack, stack->getPosition().cloneInDirection(BattleHex::RIGHT));
|
||||
result = BattleAction::makeMove(stack, stack->getPosition().cloneInDirection(BattleHex::RIGHT));
|
||||
else
|
||||
return goTowardsNearest(stack, brokenWallMoat);
|
||||
result = goTowardsNearest(stack, brokenWallMoat);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -265,6 +267,15 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
|
||||
logAi->error("Exception occurred in %s %s",__FUNCTION__, e.what());
|
||||
}
|
||||
|
||||
if(result.actionType == EActionType::DEFEND)
|
||||
{
|
||||
movesSkippedByDefense++;
|
||||
}
|
||||
else if(result.actionType != EActionType::WAIT)
|
||||
{
|
||||
movesSkippedByDefense = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -286,7 +297,9 @@ BattleAction CBattleAI::goTowardsNearest(const CStack * stack, std::vector<Battl
|
||||
for(auto hex : hexes)
|
||||
{
|
||||
if(vstd::contains(avHexes, hex))
|
||||
{
|
||||
return BattleAction::makeMove(stack, hex);
|
||||
}
|
||||
|
||||
if(stack->coversPos(hex))
|
||||
{
|
||||
@ -409,6 +422,8 @@ BattleAction CBattleAI::useCatapult(const CStack * stack)
|
||||
attack.side = side;
|
||||
attack.stackNumber = stack->ID;
|
||||
|
||||
movesSkippedByDefense = 0;
|
||||
|
||||
return attack;
|
||||
}
|
||||
|
||||
@ -716,6 +731,7 @@ void CBattleAI::attemptCastingSpell()
|
||||
spellcast.side = side;
|
||||
spellcast.stackNumber = (!side) ? -1 : -2;
|
||||
cb->battleMakeAction(&spellcast);
|
||||
movesSkippedByDefense = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -809,12 +825,21 @@ boost::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
|
||||
}
|
||||
}
|
||||
|
||||
bs.turnsSkippedByDefense = movesSkippedByDefense / bs.ourStacks.size();
|
||||
|
||||
if(!bs.canFlee || !bs.canSurrender)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
return cb->makeSurrenderRetreatDecision(bs);
|
||||
auto result = cb->makeSurrenderRetreatDecision(bs);
|
||||
|
||||
if(!result && bs.canFlee && bs.turnsSkippedByDefense > 30)
|
||||
{
|
||||
return BattleAction::makeRetreat(bs.ourSide);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
@ -60,6 +60,7 @@ class CBattleAI : public CBattleGameInterface
|
||||
|
||||
//Previous setting of cb
|
||||
bool wasWaitingForRealize, wasUnlockingGs;
|
||||
int movesSkippedByDefense;
|
||||
|
||||
public:
|
||||
CBattleAI();
|
||||
|
@ -355,6 +355,13 @@ int64_t BattleExchangeEvaluator::calculateExchange(
|
||||
logAi->trace("Battle exchange at %lld", ap.attack.shooting ? ap.dest : ap.from);
|
||||
#endif
|
||||
|
||||
if(cb->battleGetMySide() == BattlePerspective::LEFT_SIDE
|
||||
&& cb->battleGetGateState() == EGateState::BLOCKED
|
||||
&& ap.attack.defender->coversPos(ESiegeHex::GATE_BRIDGE))
|
||||
{
|
||||
return EvaluationResult::INEFFECTIVE_SCORE;
|
||||
}
|
||||
|
||||
std::vector<const battle::Unit *> ourStacks;
|
||||
std::vector<const battle::Unit *> enemyStacks;
|
||||
|
||||
|
@ -42,7 +42,7 @@ struct EvaluationResult
|
||||
bool defend;
|
||||
|
||||
EvaluationResult(const AttackPossibility & ap)
|
||||
:wait(false), score(0), bestAttack(ap), defend(false)
|
||||
:wait(false), score(INEFFECTIVE_SCORE), bestAttack(ap), defend(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@ -18,7 +18,7 @@ import java.util.List;
|
||||
|
||||
import eu.vcmi.vcmi.content.AsyncLauncherInitialization;
|
||||
import eu.vcmi.vcmi.settings.AdventureAiController;
|
||||
import eu.vcmi.vcmi.settings.CodepageSettingController;
|
||||
import eu.vcmi.vcmi.settings.LanguageSettingController;
|
||||
import eu.vcmi.vcmi.settings.CopyDataController;
|
||||
import eu.vcmi.vcmi.settings.ExportDataController;
|
||||
import eu.vcmi.vcmi.settings.LauncherSettingController;
|
||||
@ -45,7 +45,7 @@ public class ActivityLauncher extends ActivityWithToolbar
|
||||
private TextView mErrorMessage;
|
||||
private Config mConfig;
|
||||
private LauncherSettingController<ScreenResSettingController.ScreenRes, Config> mCtrlScreenRes;
|
||||
private LauncherSettingController<String, Config> mCtrlCodepage;
|
||||
private LauncherSettingController<String, Config> mCtrlLanguage;
|
||||
private LauncherSettingController<PointerModeSettingController.PointerMode, Config> mCtrlPointerMode;
|
||||
private LauncherSettingController<Void, Void> mCtrlStart;
|
||||
private LauncherSettingController<Float, Config> mCtrlPointerMulti;
|
||||
@ -203,7 +203,7 @@ public class ActivityLauncher extends ActivityWithToolbar
|
||||
(mCtrlExport = new ExportDataController(this)).init(R.id.launcher_btn_export);
|
||||
new ModsBtnController(this, v -> startActivity(new Intent(ActivityLauncher.this, ActivityMods.class))).init(R.id.launcher_btn_mods);
|
||||
mCtrlScreenRes = new ScreenResSettingController(this).init(R.id.launcher_btn_res, mConfig);
|
||||
mCtrlCodepage = new CodepageSettingController(this).init(R.id.launcher_btn_cp, mConfig);
|
||||
mCtrlLanguage = new LanguageSettingController(this).init(R.id.launcher_btn_cp, mConfig);
|
||||
mCtrlPointerMode = new PointerModeSettingController(this).init(R.id.launcher_btn_pointer_mode, mConfig);
|
||||
mCtrlPointerMulti = new PointerMultiplierSettingController(this).init(R.id.launcher_btn_pointer_multi, mConfig);
|
||||
mCtrlSoundVol = new SoundSettingController(this).init(R.id.launcher_btn_volume_sound, mConfig);
|
||||
@ -211,7 +211,7 @@ public class ActivityLauncher extends ActivityWithToolbar
|
||||
mAiController = new AdventureAiController(this).init(R.id.launcher_btn_adventure_ai, mConfig);
|
||||
|
||||
mActualSettings.clear();
|
||||
mActualSettings.add(mCtrlCodepage);
|
||||
mActualSettings.add(mCtrlLanguage);
|
||||
mActualSettings.add(mCtrlScreenRes);
|
||||
mActualSettings.add(mCtrlPointerMode);
|
||||
mActualSettings.add(mCtrlPointerMulti);
|
||||
@ -267,7 +267,7 @@ public class ActivityLauncher extends ActivityWithToolbar
|
||||
private void onConfigUpdated()
|
||||
{
|
||||
updateCtrlConfig(mCtrlScreenRes, mConfig);
|
||||
updateCtrlConfig(mCtrlCodepage, mConfig);
|
||||
updateCtrlConfig(mCtrlLanguage, mConfig);
|
||||
updateCtrlConfig(mCtrlPointerMode, mConfig);
|
||||
updateCtrlConfig(mCtrlPointerMulti, mConfig);
|
||||
updateCtrlConfig(mCtrlSoundVol, mConfig);
|
||||
|
@ -50,7 +50,7 @@ import eu.vcmi.vcmi.util.ServerResponse;
|
||||
public class ActivityMods extends ActivityWithToolbar
|
||||
{
|
||||
private static final boolean ENABLE_REPO_DOWNLOADING = true;
|
||||
private static final String REPO_URL = "https://raw.githubusercontent.com/vcmi/vcmi-mods-repository/develop/github.json";
|
||||
private static final String REPO_URL = "https://raw.githubusercontent.com/vcmi/vcmi-mods-repository/develop/vcmi-1.2.json";
|
||||
private VCMIModsRepo mRepo;
|
||||
private RecyclerView mRecycler;
|
||||
|
||||
|
@ -14,13 +14,13 @@ import eu.vcmi.vcmi.util.Log;
|
||||
*/
|
||||
public class Config
|
||||
{
|
||||
public static final String DEFAULT_CODEPAGE = "CP1250";
|
||||
public static final String DEFAULT_LANGUAGE = "english";
|
||||
public static final int DEFAULT_MUSIC_VALUE = 5;
|
||||
public static final int DEFAULT_SOUND_VALUE = 5;
|
||||
public static final int DEFAULT_SCREEN_RES_W = 800;
|
||||
public static final int DEFAULT_SCREEN_RES_H = 600;
|
||||
|
||||
public String mCodepage;
|
||||
public String mLanguage;
|
||||
public int mResolutionWidth;
|
||||
public int mResolutionHeight;
|
||||
public boolean mSwipeEnabled;
|
||||
@ -85,7 +85,7 @@ public class Config
|
||||
final Config config = new Config();
|
||||
final JSONObject general = accessNode(obj, "general");
|
||||
final JSONObject server = accessNode(obj, "server");
|
||||
config.mCodepage = loadEntry(general, "encoding", DEFAULT_CODEPAGE);
|
||||
config.mLanguage = loadEntry(general, "language", DEFAULT_LANGUAGE);
|
||||
config.mVolumeSound = loadEntry(general, "sound", DEFAULT_SOUND_VALUE);
|
||||
config.mVolumeMusic = loadEntry(general, "music", DEFAULT_MUSIC_VALUE);
|
||||
config.mSwipeEnabled = loadEntry(general, "swipe", true);
|
||||
@ -101,9 +101,9 @@ public class Config
|
||||
return config;
|
||||
}
|
||||
|
||||
public void updateCodepage(final String s)
|
||||
public void updateLanguage(final String s)
|
||||
{
|
||||
mCodepage = s;
|
||||
mLanguage = s;
|
||||
mIsModified = true;
|
||||
}
|
||||
|
||||
@ -202,9 +202,9 @@ public class Config
|
||||
final JSONObject screenRes = screenResNode == null ? new JSONObject() : screenResNode;
|
||||
final JSONObject server = serverNode == null ? new JSONObject() : serverNode;
|
||||
|
||||
if (mCodepage != null)
|
||||
if (mLanguage != null)
|
||||
{
|
||||
general.put("encoding", mCodepage);
|
||||
general.put("language", mLanguage);
|
||||
}
|
||||
|
||||
general.put("swipe", mSwipeEnabled);
|
||||
@ -230,4 +230,4 @@ public class Config
|
||||
|
||||
return root.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,40 +0,0 @@
|
||||
package eu.vcmi.vcmi.settings;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import eu.vcmi.vcmi.R;
|
||||
|
||||
/**
|
||||
* @author F
|
||||
*/
|
||||
public class CodepageSettingDialog extends LauncherSettingDialog<String>
|
||||
{
|
||||
private static final List<String> AVAILABLE_CODEPAGES = new ArrayList<>();
|
||||
|
||||
static
|
||||
{
|
||||
AVAILABLE_CODEPAGES.add("CP1250");
|
||||
AVAILABLE_CODEPAGES.add("CP1251");
|
||||
AVAILABLE_CODEPAGES.add("CP1252");
|
||||
AVAILABLE_CODEPAGES.add("GBK");
|
||||
AVAILABLE_CODEPAGES.add("GB2312");
|
||||
}
|
||||
|
||||
public CodepageSettingDialog()
|
||||
{
|
||||
super(AVAILABLE_CODEPAGES);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int dialogTitleResId()
|
||||
{
|
||||
return R.string.launcher_btn_cp_title;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CharSequence itemName(final String item)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
@ -8,9 +8,9 @@ import eu.vcmi.vcmi.R;
|
||||
/**
|
||||
* @author F
|
||||
*/
|
||||
public class CodepageSettingController extends LauncherSettingWithDialogController<String, Config>
|
||||
public class LanguageSettingController extends LauncherSettingWithDialogController<String, Config>
|
||||
{
|
||||
public CodepageSettingController(final AppCompatActivity activity)
|
||||
public LanguageSettingController(final AppCompatActivity activity)
|
||||
{
|
||||
super(activity);
|
||||
}
|
||||
@ -18,20 +18,20 @@ public class CodepageSettingController extends LauncherSettingWithDialogControll
|
||||
@Override
|
||||
protected LauncherSettingDialog<String> dialog()
|
||||
{
|
||||
return new CodepageSettingDialog();
|
||||
return new LanguageSettingDialog();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemChosen(final String item)
|
||||
{
|
||||
mConfig.updateCodepage(item);
|
||||
mConfig.updateLanguage(item);
|
||||
updateContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String mainText()
|
||||
{
|
||||
return mActivity.getString(R.string.launcher_btn_cp_title);
|
||||
return mActivity.getString(R.string.launcher_btn_language_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -41,8 +41,8 @@ public class CodepageSettingController extends LauncherSettingWithDialogControll
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return mConfig.mCodepage == null || mConfig.mCodepage.isEmpty()
|
||||
? mActivity.getString(R.string.launcher_btn_cp_subtitle_unknown)
|
||||
: mActivity.getString(R.string.launcher_btn_cp_subtitle, mConfig.mCodepage);
|
||||
return mConfig.mLanguage == null || mConfig.mLanguage.isEmpty()
|
||||
? mActivity.getString(R.string.launcher_btn_language_subtitle_unknown)
|
||||
: mActivity.getString(R.string.launcher_btn_language_subtitle, mConfig.mLanguage);
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package eu.vcmi.vcmi.settings;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import eu.vcmi.vcmi.R;
|
||||
|
||||
/**
|
||||
* @author F
|
||||
*/
|
||||
public class LanguageSettingDialog extends LauncherSettingDialog<String>
|
||||
{
|
||||
private static final List<String> AVAILABLE_LANGUAGES = new ArrayList<>();
|
||||
|
||||
static
|
||||
{
|
||||
AVAILABLE_LANGUAGES.add("english");
|
||||
AVAILABLE_LANGUAGES.add("chinese");
|
||||
AVAILABLE_LANGUAGES.add("french");
|
||||
AVAILABLE_LANGUAGES.add("german");
|
||||
AVAILABLE_LANGUAGES.add("korean");
|
||||
AVAILABLE_LANGUAGES.add("polish");
|
||||
AVAILABLE_LANGUAGES.add("russian");
|
||||
AVAILABLE_LANGUAGES.add("spanish");
|
||||
AVAILABLE_LANGUAGES.add("ukrainian");
|
||||
AVAILABLE_LANGUAGES.add("other_cp1250");
|
||||
AVAILABLE_LANGUAGES.add("other_cp1251");
|
||||
AVAILABLE_LANGUAGES.add("other_cp1252");
|
||||
}
|
||||
|
||||
public LanguageSettingDialog()
|
||||
{
|
||||
super(AVAILABLE_LANGUAGES);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int dialogTitleResId()
|
||||
{
|
||||
return R.string.launcher_btn_language_title;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CharSequence itemName(final String item)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
@ -10,9 +10,9 @@
|
||||
<string name="launcher_btn_start_subtitle">Aktuelle VCMI-Version: %1$s</string>
|
||||
<string name="launcher_btn_mods_title">Mods</string>
|
||||
<string name="launcher_btn_mods_subtitle">Neue Burgen, Kreaturen, Objekte und Erweiterungen hinzufügen</string>
|
||||
<string name="launcher_btn_cp_title">Zeichensatz</string>
|
||||
<string name="launcher_btn_cp_subtitle_unknown">Aktuell: unbekannt</string>
|
||||
<string name="launcher_btn_cp_subtitle">Aktuell: %1$s</string>
|
||||
<string name="launcher_btn_language_title">Sprache</string>
|
||||
<string name="launcher_btn_language_subtitle_unknown">Aktuell: unbekannt</string>
|
||||
<string name="launcher_btn_language_subtitle">Aktuell: %1$s</string>
|
||||
<string name="launcher_btn_pointermode_title">Zeigermodus ändern</string>
|
||||
<string name="launcher_btn_pointermode_subtitle">Aktuell: %1$s</string>
|
||||
<string name="launcher_btn_pointermulti_subtitle">Aktuell: %1$s</string>
|
||||
|
@ -10,9 +10,9 @@
|
||||
<string name="launcher_btn_start_subtitle">Obecna wersja VCMI: %1$s</string>
|
||||
<string name="launcher_btn_mods_title">Mody</string>
|
||||
<string name="launcher_btn_mods_subtitle">Zainstaluj nowe frakcje, obiekty, dodatki</string>
|
||||
<string name="launcher_btn_cp_title">Strona kodowa</string>
|
||||
<string name="launcher_btn_cp_subtitle_unknown">Obecnie: nieznane</string>
|
||||
<string name="launcher_btn_cp_subtitle">Obecnie: %1$s</string>
|
||||
<string name="launcher_btn_language_title">Język</string>
|
||||
<string name="launcher_btn_language_subtitle_unknown">Obecnie: nieznane</string>
|
||||
<string name="launcher_btn_language_subtitle">Obecnie: %1$s</string>
|
||||
<string name="launcher_btn_pointermode_title">Zmień tryb kursora</string>
|
||||
<string name="launcher_btn_pointermode_subtitle">Obecnie: %1$s</string>
|
||||
<string name="launcher_btn_pointermulti_title">Mnożnik prędkości kursora</string>
|
||||
|
@ -10,9 +10,9 @@
|
||||
<string name="launcher_btn_start_subtitle">Текущая версия VCMI: %1$s</string>
|
||||
<string name="launcher_btn_mods_title">Моды</string>
|
||||
<string name="launcher_btn_mods_subtitle">Добавить новые замки, существа, объекты, расширения</string>
|
||||
<string name="launcher_btn_cp_title">Кодовая страница</string>
|
||||
<string name="launcher_btn_cp_subtitle_unknown">Текущая: неизвестно</string>
|
||||
<string name="launcher_btn_cp_subtitle">Текущая: %1$s</string>
|
||||
<string name="launcher_btn_language_title">Язык</string>
|
||||
<string name="launcher_btn_language_subtitle_unknown">Текущая: неизвестно</string>
|
||||
<string name="launcher_btn_language_subtitle">Текущая: %1$s</string>
|
||||
<string name="launcher_btn_pointermode_title">Изменить режим управления указателем</string>
|
||||
<string name="launcher_btn_pointermode_subtitle">Currently: %1$s</string>
|
||||
<string name="launcher_btn_pointermulti_subtitle">Текущая: %1$s</string>
|
||||
@ -60,4 +60,4 @@
|
||||
<string name="launcher_btn_import_title">Загрузить данные VCMI во внутреннее хранилище</string>
|
||||
<string name="launcher_btn_import_description">Скопировать данные VCMI во внутреннее хранилище. Вы можете загрузить старую папку vcmi-data от версии 0.99 или файлы Героев</string>
|
||||
<string name="launcher_progress_copy">Копируем %1$s</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
@ -10,9 +10,9 @@
|
||||
<string name="launcher_btn_start_subtitle">Поточна версія VCMI: %1$s</string>
|
||||
<string name="launcher_btn_mods_title">Моди</string>
|
||||
<string name="launcher_btn_mods_subtitle">Додати нові замки, істот, об’єкти, розширення</string>
|
||||
<string name="launcher_btn_cp_title">Кодова сторінка</string>
|
||||
<string name="launcher_btn_cp_subtitle_unknown">Поточна: невідомо</string>
|
||||
<string name="launcher_btn_cp_subtitle">Поточна: %1$s</string>
|
||||
<string name="launcher_btn_language_title">Мова</string>
|
||||
<string name="launcher_btn_language_subtitle_unknown">Поточна: невідомо</string>
|
||||
<string name="launcher_btn_language_subtitle">Поточна: %1$s</string>
|
||||
<string name="launcher_btn_pointermode_title">Змінити режим керування курсором</string>
|
||||
<string name="launcher_btn_pointermode_subtitle">Поточна: %1$s</string>
|
||||
<string name="launcher_btn_pointermulti_subtitle">Поточна: %1$s</string>
|
||||
@ -60,4 +60,4 @@
|
||||
<string name="launcher_btn_import_title">Завантажити дані VCMI у внутрішнє сховище</string>
|
||||
<string name="launcher_btn_import_description">Копіювати дані VCMI у внутрішнє сховище. Ви можете завантажити стару папку vcmi-data від версії 0.99 чи файли героїв</string>
|
||||
<string name="launcher_progress_copy">Копіюємо %1$s</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
@ -15,9 +15,9 @@
|
||||
<string name="launcher_btn_start_subtitle">Current VCMI version: %1$s</string>
|
||||
<string name="launcher_btn_mods_title">Mods</string>
|
||||
<string name="launcher_btn_mods_subtitle">Install new factions, objects, extras</string>
|
||||
<string name="launcher_btn_cp_title">Codepage</string>
|
||||
<string name="launcher_btn_cp_subtitle_unknown">Currently: unknown</string>
|
||||
<string name="launcher_btn_cp_subtitle">Currently: %1$s</string>
|
||||
<string name="launcher_btn_language_title">Language</string>
|
||||
<string name="launcher_btn_language_subtitle_unknown">Currently: unknown</string>
|
||||
<string name="launcher_btn_language_subtitle">Currently: %1$s</string>
|
||||
<string name="launcher_btn_pointermode_title">Change pointer mode</string>
|
||||
<string name="launcher_btn_pointermode_subtitle">Currently: %1$s</string>
|
||||
<string name="launcher_btn_pointermulti_title">Relative pointer speed multiplier</string>
|
||||
|
@ -446,15 +446,7 @@ void CMusicHandler::queueNext(std::unique_ptr<MusicEntry> queued)
|
||||
|
||||
void CMusicHandler::queueNext(CMusicHandler *owner, const std::string & setName, const std::string & musicURI, bool looped, bool fromStart)
|
||||
{
|
||||
try
|
||||
{
|
||||
queueNext(std::make_unique<MusicEntry>(owner, setName, musicURI, looped, fromStart));
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
logGlobal->error("Failed to queue music. setName=%s\tmusicURI=%s", setName, musicURI);
|
||||
logGlobal->error("Exception: %s", e.what());
|
||||
}
|
||||
queueNext(std::make_unique<MusicEntry>(owner, setName, musicURI, looped, fromStart));
|
||||
}
|
||||
|
||||
void CMusicHandler::stopMusic(int fade_ms)
|
||||
@ -563,12 +555,20 @@ void MusicEntry::load(std::string musicURI)
|
||||
}
|
||||
|
||||
currentName = musicURI;
|
||||
music = nullptr;
|
||||
|
||||
logGlobal->trace("Loading music file %s", musicURI);
|
||||
|
||||
auto musicFile = MakeSDLRWops(CResourceHandler::get()->load(ResourceID(std::move(musicURI), EResType::MUSIC)));
|
||||
|
||||
music = Mix_LoadMUS_RW(musicFile, SDL_TRUE);
|
||||
try
|
||||
{
|
||||
auto musicFile = MakeSDLRWops(CResourceHandler::get()->load(ResourceID(std::move(musicURI), EResType::MUSIC)));
|
||||
music = Mix_LoadMUS_RW(musicFile, SDL_TRUE);
|
||||
}
|
||||
catch(std::exception &e)
|
||||
{
|
||||
logGlobal->error("Failed to load music. setName=%s\tmusicURI=%s", setName, musicURI);
|
||||
logGlobal->error("Exception: %s", e.what());
|
||||
}
|
||||
|
||||
if(!music)
|
||||
{
|
||||
|
@ -947,7 +947,7 @@ void CPlayerInterface::battleStacksEffectsSet( const SetStackEffect & sse )
|
||||
void CPlayerInterface::battleTriggerEffect (const BattleTriggerEffect & bte)
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
//TODO why is this different (no return on LOPLINT != this) ?
|
||||
BATTLE_EVENT_POSSIBLE_RETURN;
|
||||
|
||||
RETURN_IF_QUICK_COMBAT;
|
||||
battleInt->effectsController->battleTriggerEffect(bte);
|
||||
@ -1038,6 +1038,12 @@ void CPlayerInterface::yourTacticPhase(int distance)
|
||||
boost::this_thread::sleep(boost::posix_time::millisec(1));
|
||||
}
|
||||
|
||||
void CPlayerInterface::forceEndTacticPhase()
|
||||
{
|
||||
if (battleInt)
|
||||
battleInt->tacticsMode = false;
|
||||
}
|
||||
|
||||
void CPlayerInterface::showInfoDialog(EInfoWindowMode type, const std::string &text, const std::vector<Component> & components, int soundID)
|
||||
{
|
||||
EVENT_HANDLER_CALLED_BY_CLIENT;
|
||||
|
@ -226,6 +226,7 @@ public:
|
||||
void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack
|
||||
void battleGateStateChanged(const EGateState state) override;
|
||||
void yourTacticPhase(int distance) override;
|
||||
void forceEndTacticPhase() override;
|
||||
|
||||
//-------------//
|
||||
void showArtifactAssemblyDialog(const Artifact * artifact, const Artifact * assembledArtifact, CFunctionList<bool()> onYes);
|
||||
|
@ -7,6 +7,7 @@
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "Global.h"
|
||||
#include "StdInc.h"
|
||||
#include "Client.h"
|
||||
|
||||
@ -31,6 +32,7 @@
|
||||
#include "../lib/registerTypes/RegisterTypes.h"
|
||||
#include "../lib/serializer/Connection.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vcmi/events/EventBus.h>
|
||||
|
||||
#if SCRIPTING_ENABLED
|
||||
@ -369,6 +371,9 @@ void CClient::endGame()
|
||||
logNetwork->info("Deleted mapHandler and gameState.");
|
||||
}
|
||||
|
||||
//threads cleanup has to be after gs cleanup and before battleints cleanup to stop tacticThread
|
||||
cleanThreads();
|
||||
|
||||
playerint.clear();
|
||||
battleints.clear();
|
||||
battleCallbacks.clear();
|
||||
@ -593,7 +598,8 @@ void CClient::battleStarted(const BattleInfo * info)
|
||||
|
||||
if(info->tacticDistance && vstd::contains(battleints, info->sides[info->tacticsSide].color))
|
||||
{
|
||||
boost::thread(&CClient::commenceTacticPhaseForInt, this, battleints[info->sides[info->tacticsSide].color]);
|
||||
PlayerColor color = info->sides[info->tacticsSide].color;
|
||||
playerTacticThreads[color] = std::make_unique<boost::thread>(&CClient::commenceTacticPhaseForInt, this, battleints[color]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -754,6 +760,23 @@ void CClient::removeGUI()
|
||||
LOCPLINT = nullptr;
|
||||
}
|
||||
|
||||
void CClient::cleanThreads()
|
||||
{
|
||||
stopAllBattleActions();
|
||||
|
||||
while (!playerTacticThreads.empty())
|
||||
{
|
||||
PlayerColor color = playerTacticThreads.begin()->first;
|
||||
|
||||
//set tacticcMode of the players to false to stop tacticThread
|
||||
if (vstd::contains(battleints, color))
|
||||
battleints[color]->forceEndTacticPhase();
|
||||
|
||||
playerTacticThreads[color]->join();
|
||||
playerTacticThreads.erase(color);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VCMI_ANDROID
|
||||
#ifndef SINGLE_PROCESS_APP
|
||||
extern "C" JNIEXPORT void JNICALL Java_eu_vcmi_vcmi_NativeMethods_notifyServerClosed(JNIEnv * env, jclass cls)
|
||||
|
@ -9,6 +9,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vcmi/Environment.h>
|
||||
|
||||
#include "../lib/IGameCallback.h"
|
||||
@ -242,6 +243,8 @@ public:
|
||||
void showInfoDialog(const std::string & msg, PlayerColor player) override {};
|
||||
void removeGUI();
|
||||
|
||||
void cleanThreads();
|
||||
|
||||
#if SCRIPTING_ENABLED
|
||||
scripting::Pool * getGlobalContextPool() const override;
|
||||
scripting::Pool * getContextPool() const override;
|
||||
@ -263,6 +266,8 @@ private:
|
||||
|
||||
std::map<PlayerColor, std::shared_ptr<boost::thread>> playerActionThreads;
|
||||
|
||||
std::map<PlayerColor, std::unique_ptr<boost::thread>> playerTacticThreads;
|
||||
|
||||
void waitForMoveAndSend(PlayerColor color);
|
||||
void reinitScripting();
|
||||
};
|
||||
|
@ -12,7 +12,9 @@
|
||||
#include "../lib/NetPackVisitor.h"
|
||||
|
||||
class CClient;
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class CGameState;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class ApplyOnLobbyHandlerNetPackVisitor : public VCMI_LIB_WRAP_NAMESPACE(ICPackVisitor)
|
||||
{
|
||||
@ -53,4 +55,4 @@ public:
|
||||
virtual void visitLobbyStartGame(LobbyStartGame & pack) override;
|
||||
virtual void visitLobbyUpdateState(LobbyUpdateState & pack) override;
|
||||
virtual void visitLobbyShowMessage(LobbyShowMessage & pack) override;
|
||||
};
|
||||
};
|
||||
|
@ -38,6 +38,9 @@ void CInGameConsole::showAll(SDL_Surface * to)
|
||||
|
||||
void CInGameConsole::show(SDL_Surface * to)
|
||||
{
|
||||
if (LOCPLINT->cingconsole != this)
|
||||
return;
|
||||
|
||||
int number = 0;
|
||||
|
||||
boost::unique_lock<boost::mutex> lock(texts_mx);
|
||||
@ -107,7 +110,11 @@ void CInGameConsole::print(const std::string & txt)
|
||||
|
||||
void CInGameConsole::keyPressed (const SDL_Keycode & key)
|
||||
{
|
||||
if(!captureAllKeys && key != SDLK_TAB) return; //because user is not entering any text
|
||||
if (LOCPLINT->cingconsole != this)
|
||||
return;
|
||||
|
||||
if(!captureAllKeys && key != SDLK_TAB)
|
||||
return; //because user is not entering any text
|
||||
|
||||
switch(key)
|
||||
{
|
||||
@ -192,6 +199,9 @@ void CInGameConsole::keyPressed (const SDL_Keycode & key)
|
||||
|
||||
void CInGameConsole::textInputed(const std::string & inputtedText)
|
||||
{
|
||||
if (LOCPLINT->cingconsole != this)
|
||||
return;
|
||||
|
||||
if(!captureAllKeys || enteredText.empty())
|
||||
return;
|
||||
enteredText.resize(enteredText.size()-1);
|
||||
|
@ -173,7 +173,7 @@ CInfoBar::VisibleComponentInfo::VisibleComponentInfo(const std::vector<Component
|
||||
auto fullRect = Rect(CInfoBar::offset, CInfoBar::offset, data_width - 2 * CInfoBar::offset, data_height - 2 * CInfoBar::offset);
|
||||
auto textRect = fullRect;
|
||||
auto imageRect = fullRect;
|
||||
auto font = FONT_SMALL;
|
||||
auto font = tiny ? FONT_TINY : FONT_SMALL;
|
||||
auto maxComponents = 2;
|
||||
|
||||
if(!compsToDisplay.empty())
|
||||
@ -210,11 +210,9 @@ CInfoBar::VisibleComponentInfo::VisibleComponentInfo(const std::vector<Component
|
||||
|
||||
comps = std::make_shared<CComponentBox>(vect, imageRect, 4, 4, 1, maxComponents);
|
||||
}
|
||||
else
|
||||
font = tiny ? FONT_TINY : font;
|
||||
|
||||
if(!message.empty())
|
||||
text = std::make_shared<CTextBox>(message, textRect, 0, font, ETextAlignment::CENTER, Colors::WHITE);
|
||||
text = std::make_shared<CMultiLineLabel>(textRect, font, ETextAlignment::CENTER, Colors::WHITE, message);
|
||||
}
|
||||
|
||||
void CInfoBar::playNewDaySound()
|
||||
|
@ -27,7 +27,7 @@ class CComponentBox;
|
||||
class CHeroTooltip;
|
||||
class CTownTooltip;
|
||||
class CLabel;
|
||||
class CTextBox;
|
||||
class CMultiLineLabel;
|
||||
|
||||
/// Info box which shows next week/day information, hold the current date
|
||||
class CInfoBar : public CIntObject
|
||||
@ -112,7 +112,7 @@ private:
|
||||
class VisibleComponentInfo : public CVisibleInfo
|
||||
{
|
||||
std::shared_ptr<CComponentBox> comps;
|
||||
std::shared_ptr<CTextBox> text;
|
||||
std::shared_ptr<CMultiLineLabel> text;
|
||||
public:
|
||||
struct Cache
|
||||
{
|
||||
|
@ -130,6 +130,7 @@ void BattleActionsController::endCastingSpell()
|
||||
if(owner.stacksController->getActiveStack())
|
||||
possibleActions = getPossibleActionsForStack(owner.stacksController->getActiveStack()); //restore actions after they were cleared
|
||||
|
||||
selectedStack = nullptr;
|
||||
GH.fakeMouseMove();
|
||||
}
|
||||
|
||||
|
@ -89,6 +89,7 @@ void BattleWindow::createQueue()
|
||||
|
||||
//create stack queue and adjust our own position
|
||||
bool embedQueue;
|
||||
bool showQueue = settings["battle"]["showQueue"].Bool();
|
||||
std::string queueSize = settings["battle"]["queueSize"].String();
|
||||
|
||||
if(queueSize == "auto")
|
||||
@ -97,13 +98,16 @@ void BattleWindow::createQueue()
|
||||
embedQueue = GH.screenDimensions().y < 700 || queueSize == "small";
|
||||
|
||||
queue = std::make_shared<StackQueue>(embedQueue, owner);
|
||||
if(!embedQueue && settings["battle"]["showQueue"].Bool())
|
||||
if(!embedQueue && showQueue)
|
||||
{
|
||||
//re-center, taking into account stack queue position
|
||||
pos.y -= queue->pos.h;
|
||||
pos.h += queue->pos.h;
|
||||
pos = center();
|
||||
}
|
||||
|
||||
if (!showQueue)
|
||||
queue->disable();
|
||||
}
|
||||
|
||||
BattleWindow::~BattleWindow()
|
||||
@ -143,8 +147,8 @@ void BattleWindow::hideQueue()
|
||||
pos.y += queue->pos.h;
|
||||
pos.h -= queue->pos.h;
|
||||
pos = center();
|
||||
GH.totalRedraw();
|
||||
}
|
||||
GH.totalRedraw();
|
||||
}
|
||||
|
||||
void BattleWindow::showQueue()
|
||||
@ -230,9 +234,12 @@ void BattleWindow::tacticPhaseStarted()
|
||||
auto menuTactics = widget<CIntObject>("menuTactics");
|
||||
auto tacticNext = widget<CIntObject>("tacticNext");
|
||||
auto tacticEnd = widget<CIntObject>("tacticEnd");
|
||||
auto alternativeAction = widget<CIntObject>("alternativeAction");
|
||||
|
||||
menuBattle->disable();
|
||||
console->disable();
|
||||
if (alternativeAction)
|
||||
alternativeAction->disable();
|
||||
|
||||
menuTactics->enable();
|
||||
tacticNext->enable();
|
||||
@ -248,9 +255,12 @@ void BattleWindow::tacticPhaseEnded()
|
||||
auto menuTactics = widget<CIntObject>("menuTactics");
|
||||
auto tacticNext = widget<CIntObject>("tacticNext");
|
||||
auto tacticEnd = widget<CIntObject>("tacticEnd");
|
||||
auto alternativeAction = widget<CIntObject>("alternativeAction");
|
||||
|
||||
menuBattle->enable();
|
||||
console->enable();
|
||||
if (alternativeAction)
|
||||
alternativeAction->enable();
|
||||
|
||||
menuTactics->disable();
|
||||
tacticNext->disable();
|
||||
|
@ -712,7 +712,11 @@ void CGuiHandler::moveCursorToPosition(const Point & position)
|
||||
|
||||
bool CGuiHandler::isKeyboardCtrlDown() const
|
||||
{
|
||||
#ifdef VCMI_MAC
|
||||
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LGUI] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RGUI];
|
||||
#else
|
||||
return SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_LCTRL] || SDL_GetKeyboardState(nullptr)[SDL_SCANCODE_RCTRL];
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CGuiHandler::isKeyboardAltDown() const
|
||||
|
@ -31,6 +31,8 @@ static std::map<std::string, int> KeycodeMap{
|
||||
{"left", SDLK_LEFT},
|
||||
{"right", SDLK_RIGHT},
|
||||
{"space", SDLK_SPACE},
|
||||
{"escape", SDLK_ESCAPE},
|
||||
{"backspace", SDLK_BACKSPACE},
|
||||
{"enter", SDLK_RETURN}
|
||||
};
|
||||
|
||||
@ -220,10 +222,16 @@ int InterfaceObjectConfigurable::readKeycode(const JsonNode & config) const
|
||||
auto s = config.String();
|
||||
if(s.size() == 1) //keyboard symbol
|
||||
return s[0];
|
||||
return KeycodeMap[s];
|
||||
|
||||
if (KeycodeMap.count(s))
|
||||
return KeycodeMap[s];
|
||||
|
||||
logGlobal->error("Invalid keycode '%s' in interface configuration!", config.String());
|
||||
return SDLK_UNKNOWN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
logGlobal->error("Invalid keycode format in interface configuration! Expected string or integer!", config.String());
|
||||
return SDLK_UNKNOWN;
|
||||
}
|
||||
|
||||
std::shared_ptr<CPicture> InterfaceObjectConfigurable::buildPicture(const JsonNode & config) const
|
||||
|
@ -394,6 +394,10 @@ void TemplatesDropBox::ListItem::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
dropBox.setTemplate(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
dropBox.clickLeft(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -449,8 +453,14 @@ void TemplatesDropBox::clickLeft(tribool down, bool previousState)
|
||||
{
|
||||
if(down && !hovered)
|
||||
{
|
||||
assert(GH.topInt().get() == this);
|
||||
GH.popInt(GH.topInt());
|
||||
auto w = widget<CSlider>("slider");
|
||||
|
||||
// pop the interface only if the mouse is not clicking on the slider
|
||||
if (!w || !w->mouseState(MouseButton::LEFT))
|
||||
{
|
||||
assert(GH.topInt().get() == this);
|
||||
GH.popInt(GH.topInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
|
||||
#include "../../lib/Point.h"
|
||||
#include "../../lib/TextOperations.h"
|
||||
//
|
||||
|
||||
size_t IFont::getStringWidth(const std::string & data) const
|
||||
{
|
||||
|
@ -70,7 +70,7 @@ CBitmapFont::CBitmapFont(const std::string & filename):
|
||||
|
||||
loadModFont("core", resource);
|
||||
|
||||
for (auto const & modName : VLC->modh->getActiveMods())
|
||||
for(const auto & modName : VLC->modh->getActiveMods())
|
||||
{
|
||||
if (CResourceHandler::get(modName)->existsResource(resource))
|
||||
loadModFont(modName, resource);
|
||||
@ -94,6 +94,24 @@ size_t CBitmapFont::getGlyphWidth(const char * data) const
|
||||
return iter->second.leftOffset + iter->second.width + iter->second.rightOffset;
|
||||
}
|
||||
|
||||
bool CBitmapFont::canRepresentCharacter(const char *data) const
|
||||
{
|
||||
CodePoint localChar = TextOperations::getUnicodeCodepoint(data, 4);
|
||||
|
||||
auto iter = chars.find(localChar);
|
||||
|
||||
return iter != chars.end();
|
||||
}
|
||||
|
||||
bool CBitmapFont::canRepresentString(const std::string & data) const
|
||||
{
|
||||
for(size_t i=0; i<data.size(); i += TextOperations::getUnicodeCharacterSize(data[i]))
|
||||
if (!canRepresentCharacter(data.data() + i))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBitmapFont::renderCharacter(SDL_Surface * surface, const BitmapChar & character, const SDL_Color & color, int &posX, int &posY) const
|
||||
{
|
||||
Rect clipRect;
|
||||
|
@ -41,6 +41,11 @@ public:
|
||||
size_t getLineHeight() const override;
|
||||
size_t getGlyphWidth(const char * data) const override;
|
||||
|
||||
/// returns true if this font contains provided utf-8 character
|
||||
bool canRepresentCharacter(const char * data) const;
|
||||
bool canRepresentString(const std::string & data) const;
|
||||
|
||||
friend class CBitmapHanFont;
|
||||
friend class CTrueTypeFont;
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include "StdInc.h"
|
||||
#include "CTrueTypeFont.h"
|
||||
|
||||
#include "CBitmapFont.h"
|
||||
|
||||
#include "../render/Colors.h"
|
||||
#include "../renderSDL/SDL_Extensions.h"
|
||||
|
||||
@ -52,30 +54,45 @@ int CTrueTypeFont::getFontStyle(const JsonNode &config)
|
||||
CTrueTypeFont::CTrueTypeFont(const JsonNode & fontConfig):
|
||||
data(loadData(fontConfig)),
|
||||
font(loadFont(fontConfig), TTF_CloseFont),
|
||||
dropShadow(fontConfig["blend"].Bool()),
|
||||
blended(fontConfig["blend"].Bool())
|
||||
{
|
||||
assert(font);
|
||||
|
||||
TTF_SetFontStyle(font.get(), getFontStyle(fontConfig));
|
||||
|
||||
std::string fallbackName = fontConfig["fallback"].String();
|
||||
|
||||
if (!fallbackName.empty())
|
||||
fallbackFont = std::make_unique<CBitmapFont>(fallbackName);
|
||||
}
|
||||
|
||||
CTrueTypeFont::~CTrueTypeFont() = default;
|
||||
|
||||
size_t CTrueTypeFont::getLineHeight() const
|
||||
{
|
||||
if (fallbackFont)
|
||||
fallbackFont->getLineHeight();
|
||||
|
||||
return TTF_FontHeight(font.get());
|
||||
}
|
||||
|
||||
size_t CTrueTypeFont::getGlyphWidth(const char *data) const
|
||||
{
|
||||
if (fallbackFont && fallbackFont->canRepresentCharacter(data))
|
||||
return fallbackFont->getGlyphWidth(data);
|
||||
|
||||
return getStringWidth(std::string(data, TextOperations::getUnicodeCharacterSize(*data)));
|
||||
/*
|
||||
int advance;
|
||||
TTF_GlyphMetrics(font.get(), *data, nullptr, nullptr, nullptr, nullptr, &advance);
|
||||
return advance;
|
||||
*/
|
||||
}
|
||||
|
||||
size_t CTrueTypeFont::getStringWidth(const std::string & data) const
|
||||
{
|
||||
if (fallbackFont && fallbackFont->canRepresentString(data))
|
||||
return fallbackFont->getStringWidth(data);
|
||||
|
||||
int width;
|
||||
TTF_SizeUTF8(font.get(), data.c_str(), &width, nullptr);
|
||||
return width;
|
||||
@ -83,7 +100,13 @@ size_t CTrueTypeFont::getStringWidth(const std::string & data) const
|
||||
|
||||
void CTrueTypeFont::renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const
|
||||
{
|
||||
if (color.r != 0 && color.g != 0 && color.b != 0) // not black - add shadow
|
||||
if (fallbackFont && fallbackFont->canRepresentString(data))
|
||||
{
|
||||
fallbackFont->renderText(surface, data, color, pos);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dropShadow && color.r != 0 && color.g != 0 && color.b != 0) // not black - add shadow
|
||||
renderText(surface, data, Colors::BLACK, pos + Point(1,1));
|
||||
|
||||
if (!data.empty())
|
||||
|
@ -15,14 +15,18 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
class JsonNode;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class CBitmapFont;
|
||||
|
||||
typedef struct _TTF_Font TTF_Font;
|
||||
|
||||
class CTrueTypeFont : public IFont
|
||||
{
|
||||
std::unique_ptr<CBitmapFont> fallbackFont;
|
||||
const std::pair<std::unique_ptr<ui8[]>, ui64> data;
|
||||
|
||||
const std::unique_ptr<TTF_Font, void (*)(TTF_Font*)> font;
|
||||
const bool blended;
|
||||
const bool dropShadow;
|
||||
|
||||
std::pair<std::unique_ptr<ui8[]>, ui64> loadData(const JsonNode & config);
|
||||
TTF_Font * loadFont(const JsonNode & config);
|
||||
@ -31,6 +35,7 @@ class CTrueTypeFont : public IFont
|
||||
void renderText(SDL_Surface * surface, const std::string & data, const SDL_Color & color, const Point & pos) const override;
|
||||
public:
|
||||
CTrueTypeFont(const JsonNode & fontConfig);
|
||||
~CTrueTypeFont();
|
||||
|
||||
size_t getLineHeight() const override;
|
||||
size_t getGlyphWidth(const char * data) const override;
|
||||
|
@ -63,7 +63,8 @@ int64_t CHeroWithMaybePickedArtifact::getTreeVersion() const
|
||||
|
||||
si32 CHeroWithMaybePickedArtifact::manaLimit() const
|
||||
{
|
||||
return hero->manaLimit();
|
||||
//TODO: reduplicate code with CGHeroInstance
|
||||
return si32(getPrimSkillLevel(PrimarySkill::KNOWLEDGE) * (valOfBonuses(Bonus::MANA_PER_KNOWLEDGE)));
|
||||
}
|
||||
|
||||
CHeroWithMaybePickedArtifact::CHeroWithMaybePickedArtifact(CWindowWithArtifacts * Cww, const CGHeroInstance * Hero)
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
|
||||
int64_t getTreeVersion() const override;
|
||||
|
||||
si32 manaLimit() const override;
|
||||
si32 manaLimit() const;
|
||||
};
|
||||
|
||||
class CHeroWindow : public CStatusbarWindow, public CGarrisonHolder, public CWindowWithArtifacts
|
||||
|
@ -99,14 +99,19 @@ int BattleOptionsTab::getAnimSpeed() const
|
||||
|
||||
int BattleOptionsTab::getQueueSizeId() const
|
||||
{
|
||||
std::string text = settings["battle"]["queueSize"].String();
|
||||
if(text == "none")
|
||||
std::string sizeText = settings["battle"]["queueSize"].String();
|
||||
bool visible = settings["battle"]["showQueue"].Bool();
|
||||
|
||||
if(!visible)
|
||||
return -1;
|
||||
if(text == "auto")
|
||||
|
||||
if(sizeText == "none")
|
||||
return -1;
|
||||
if(sizeText == "auto")
|
||||
return 0;
|
||||
if(text == "small")
|
||||
if(sizeText == "small")
|
||||
return 1;
|
||||
if(text == "big")
|
||||
if(sizeText == "big")
|
||||
return 2;
|
||||
|
||||
return 0;
|
||||
|
@ -1377,6 +1377,18 @@
|
||||
"subtype" : 1,
|
||||
"val" : 0,
|
||||
"valueType" : "BASE_NUMBER"
|
||||
},
|
||||
{
|
||||
"type" : "MAGIC_RESISTANCE",
|
||||
"val" : 0,
|
||||
"valueType" : "INDEPENDENT_MIN",
|
||||
"propagator": "BATTLE_WIDE"
|
||||
},
|
||||
{
|
||||
"type" : "SPELL_RESISTANCE_AURA",
|
||||
"val" : 0,
|
||||
"valueType" : "INDEPENDENT_MIN",
|
||||
"propagator": "BATTLE_WIDE"
|
||||
}
|
||||
],
|
||||
"index" : 93,
|
||||
|
@ -18,7 +18,8 @@
|
||||
"value" : 100,
|
||||
"rarity" : 100
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"blockedVisitable" : true,
|
||||
"onVisitedMessage" : 22,
|
||||
"visitMode" : "bonus",
|
||||
@ -49,7 +50,8 @@
|
||||
"value" : 100,
|
||||
"rarity" : 100
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 30,
|
||||
"visitMode" : "bonus",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -81,7 +83,8 @@
|
||||
"value" : 100,
|
||||
"rarity" : 100
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 50,
|
||||
"visitMode" : "bonus",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -112,7 +115,8 @@
|
||||
"value" : 100,
|
||||
"rarity" : 100
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 56,
|
||||
"visitMode" : "bonus",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -164,7 +168,8 @@
|
||||
"value" : 100,
|
||||
"rarity" : 50
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 58,
|
||||
"visitMode" : "bonus",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -195,7 +200,8 @@
|
||||
"value" : 100,
|
||||
"rarity" : 100
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 63,
|
||||
"visitMode" : "bonus",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -250,7 +256,8 @@
|
||||
"value" : 100,
|
||||
"rarity" : 20
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 82,
|
||||
"visitMode" : "bonus",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -280,7 +287,8 @@
|
||||
"value" : 100,
|
||||
"rarity" : 50
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 95,
|
||||
"visitMode" : "bonus",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -312,10 +320,10 @@
|
||||
"value" : 200,
|
||||
"rarity" : 40
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"visitMode" : "bonus",
|
||||
"selectMode" : "selectFirst",
|
||||
|
||||
"onVisited" : [
|
||||
{
|
||||
"message" : 139,
|
||||
@ -370,7 +378,8 @@
|
||||
"value" : 100,
|
||||
"rarity" : 100
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 141,
|
||||
"visitMode" : "bonus",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -406,7 +415,8 @@
|
||||
"value" : 100,
|
||||
"rarity" : 100
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 111,
|
||||
"visitMode" : "bonus",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -440,7 +450,8 @@
|
||||
"value" : 500,
|
||||
"rarity" : 50
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 167,
|
||||
"visitMode" : "bonus",
|
||||
"selectMode" : "selectFirst",
|
||||
|
@ -18,7 +18,8 @@
|
||||
"value" : 3000,
|
||||
"rarity" : 50
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onSelectMessage" : 0,
|
||||
"onVisitedMessage" : 1,
|
||||
"visitMode" : "hero",
|
||||
@ -51,6 +52,7 @@
|
||||
"value" : 1500,
|
||||
"rarity" : 100
|
||||
},
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 40,
|
||||
"visitMode" : "hero",
|
||||
@ -81,7 +83,8 @@
|
||||
"value" : 1500,
|
||||
"rarity" : 100
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 60,
|
||||
"visitMode" : "hero",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -110,7 +113,8 @@
|
||||
"value" : 12000,
|
||||
"rarity" : 20
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 67,
|
||||
"onEmptyMessage" : 68,
|
||||
"visitMode" : "hero",
|
||||
@ -154,7 +158,8 @@
|
||||
"value" : 1500,
|
||||
"rarity" : 100
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 81,
|
||||
"visitMode" : "hero",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -184,7 +189,8 @@
|
||||
"value" : 1500,
|
||||
"rarity" : 100
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 101,
|
||||
"visitMode" : "hero",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -214,6 +220,7 @@
|
||||
"value" : 2500,
|
||||
"rarity" : 50
|
||||
},
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onEmpty" : [
|
||||
{
|
||||
@ -270,7 +277,8 @@
|
||||
"value" : 1000,
|
||||
"rarity" : 50
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onSelectMessage" : 71,
|
||||
"onVisitedMessage" : 72,
|
||||
"onEmptyMessage" : 73,
|
||||
@ -309,6 +317,7 @@
|
||||
"value" : 1000,
|
||||
"rarity" : 50
|
||||
},
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onSelectMessage" : 158,
|
||||
"onVisitedMessage" : 159,
|
||||
@ -348,6 +357,7 @@
|
||||
"value" : 1500,
|
||||
"rarity" : 200
|
||||
},
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 144,
|
||||
"visitMode" : "hero",
|
||||
|
@ -17,7 +17,8 @@
|
||||
"value" : 250,
|
||||
"rarity" : 100
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onEmptyMessage" : 79,
|
||||
"onVisitedMessage" : 78,
|
||||
"visitMode" : "bonus",
|
||||
@ -54,7 +55,8 @@
|
||||
// "value" : 500,
|
||||
// "rarity" : 50
|
||||
//},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onEmptyMessage" : 76,
|
||||
"onVisitedMessage" : 75,
|
||||
"resetParameters" : {
|
||||
@ -92,7 +94,8 @@
|
||||
"value" : 500,
|
||||
"rarity" : 50
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 93,
|
||||
"resetParameters" : {
|
||||
"period" : 7,
|
||||
@ -133,7 +136,8 @@
|
||||
"value" : 1500,
|
||||
"rarity" : 80
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 169,
|
||||
"resetParameters" : {
|
||||
"period" : 7,
|
||||
@ -174,7 +178,8 @@
|
||||
"value" : 750,
|
||||
"rarity" : 50
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 165,
|
||||
"resetParameters" : {
|
||||
"period" : 7,
|
||||
|
@ -17,7 +17,8 @@
|
||||
"value" : 500,
|
||||
"rarity" : 100
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 65,
|
||||
"visitMode" : "once",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -32,7 +33,7 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -52,7 +53,8 @@
|
||||
"value" : 500,
|
||||
"rarity" : 100
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 38,
|
||||
"blockedVisitable" : true,
|
||||
"visitMode" : "once",
|
||||
@ -92,7 +94,8 @@
|
||||
"value" : 500,
|
||||
"rarity" : 50
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onVisitedMessage" : 156,
|
||||
"visitMode" : "once",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -142,7 +145,8 @@
|
||||
"value" : 6000,
|
||||
"rarity" : 20
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"onSelectMessage" : 161,
|
||||
"visitMode" : "once",
|
||||
"selectMode" : "selectFirst",
|
||||
|
@ -19,7 +19,8 @@
|
||||
"value" : 2000,
|
||||
"rarity" : 500
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"blockedVisitable" : true,
|
||||
"visitMode" : "unlimited",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -60,7 +61,8 @@
|
||||
"value" : 2000,
|
||||
"rarity" : 100
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"blockedVisitable" : true,
|
||||
"visitMode" : "unlimited",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -117,7 +119,8 @@
|
||||
"value" : 1500,
|
||||
"rarity" : 500
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"blockedVisitable" : true,
|
||||
"visitMode" : "unlimited",
|
||||
"selectMode" : "selectFirst",
|
||||
@ -167,6 +170,7 @@
|
||||
"value" : 1500,
|
||||
"rarity" : 50
|
||||
},
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"blockedVisitable" : true,
|
||||
"visitMode" : "unlimited",
|
||||
@ -217,7 +221,8 @@
|
||||
"value" : 1500,
|
||||
"rarity" : 1000
|
||||
},
|
||||
|
||||
"compatibilityIdentifiers" : [ "object" ],
|
||||
|
||||
"blockedVisitable" : true,
|
||||
"onSelectMessage" : 146,
|
||||
"visitMode" : "unlimited",
|
||||
|
@ -153,7 +153,7 @@
|
||||
"imageOrder": [1, 0, 2, 3],
|
||||
"help": "core.help.325",
|
||||
"callback": "closeWindow",
|
||||
"hotkey": ["esc", "backspace"]
|
||||
"hotkey": ["escape", "backspace"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -35,7 +35,10 @@ The following platforms are supported and known to work, others might require ch
|
||||
if you want x86, otherwise pick **vcmi-deps-windows-conan.tgz**
|
||||
- [Android](https://github.com/vcmi/vcmi-dependencies/releases)
|
||||
|
||||
3. Only if you have Apple Silicon Mac and trying to build for macOS or iOS: follow [instructions how to build Qt host tools for Apple Silicon](https://github.com/vcmi/vcmi-ios-deps#note-for-arm-macs), on step 3 copy them to `~/.conan/data/qt/5.15.x/_/_/package/SOME_HASH/bin` (`5.15.x` and `SOME_HASH` are placeholders).
|
||||
3. Only if you have Apple Silicon Mac and trying to build for macOS or iOS:
|
||||
|
||||
1. Open file `~/.conan/data/qt/5.15.x/_/_/export/conanfile.py` (`5.15.x` is a placeholder), search for string `Designer` (there should be only one match), comment this line and the one above it by inserting `#` in the beginning, and save the file.
|
||||
2. (optional) If you don't want to use Rosetta, follow [instructions how to build Qt host tools for Apple Silicon](https://github.com/vcmi/vcmi-ios-deps#note-for-arm-macs), on step 3 copy them to `~/.conan/data/qt/5.15.x/_/_/package/SOME_HASH/bin` (`5.15.x` and `SOME_HASH` are placeholders). Make sure **not** to copy `qt.conf`!
|
||||
|
||||
## Generate CMake integration
|
||||
|
||||
|
@ -66,6 +66,8 @@ public:
|
||||
virtual void getCastDescription(const Spell * spell, const std::vector<const battle::Unit *> & attacked, MetaString & text) const = 0;
|
||||
|
||||
virtual void spendMana(ServerCallback * server, const int32_t spellCost) const = 0;
|
||||
|
||||
virtual int32_t manaLimit() const = 0;
|
||||
|
||||
///used to identify actual hero caster
|
||||
virtual const CGHeroInstance * getHeroCaster() const = 0;
|
||||
|
@ -14,21 +14,6 @@
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
@ -124,154 +109,166 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QTreeView" name="allModsView">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerItem</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="expandsOnDoubleClick">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tabInfo">
|
||||
<attribute name="title">
|
||||
<string>Description</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QTextBrowser" name="modInfoBrowser">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="html">
|
||||
<string notr="true"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QTreeView" name="allModsView">
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerItem</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="expandsOnDoubleClick">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tabInfo">
|
||||
<attribute name="title">
|
||||
<string>Description</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QTextBrowser" name="modInfoBrowser">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="html">
|
||||
<string notr="true"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;">
|
||||
hr { height: 1px; border-width: 0; }
|
||||
</style></head><body style=" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;">
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Ubuntu'; font-size:11pt;"><br /></p></body></html></string>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabChangelog">
|
||||
<attribute name="title">
|
||||
<string>Changelog</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QTextBrowser" name="changelogBrowser"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabScreenshots">
|
||||
<attribute name="title">
|
||||
<string>Screenshots</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QListWidget" name="screenshotsList">
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>240</width>
|
||||
<height>180</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::IconMode</enum>
|
||||
</property>
|
||||
<property name="uniformItemSizes">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<widget class="QWidget" name="tabChangelog">
|
||||
<attribute name="title">
|
||||
<string>Changelog</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QTextBrowser" name="changelogBrowser"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabScreenshots">
|
||||
<attribute name="title">
|
||||
<string>Screenshots</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QListWidget" name="screenshotsList">
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>240</width>
|
||||
<height>180</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="viewMode">
|
||||
<enum>QListView::IconMode</enum>
|
||||
</property>
|
||||
<property name="uniformItemSizes">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="progressWidget" native="true">
|
||||
@ -279,7 +276,7 @@ p, li { white-space: pre-wrap; }
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
@ -306,7 +303,7 @@ p, li { white-space: pre-wrap; }
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
|
@ -960,9 +960,6 @@ void CCreatureHandler::loadStackExperience(CCreature * creature, const JsonNode
|
||||
{
|
||||
for (const JsonNode &exp : input.Vector())
|
||||
{
|
||||
auto bonus = JsonUtils::parseBonus (exp["bonus"]);
|
||||
bonus->source = Bonus::STACK_EXPERIENCE;
|
||||
bonus->duration = Bonus::PERMANENT;
|
||||
const JsonVector &values = exp["values"].Vector();
|
||||
int lowerLimit = 1;//, upperLimit = 255;
|
||||
if (values[0].getType() == JsonNode::JsonType::DATA_BOOL)
|
||||
@ -971,8 +968,14 @@ void CCreatureHandler::loadStackExperience(CCreature * creature, const JsonNode
|
||||
{
|
||||
if(val.Bool())
|
||||
{
|
||||
// parse each bonus separately
|
||||
// we can not create copies since identifiers resolution does not tracks copies
|
||||
// leading to unset identifier values in copies
|
||||
auto bonus = JsonUtils::parseBonus (exp["bonus"]);
|
||||
bonus->source = Bonus::STACK_EXPERIENCE;
|
||||
bonus->duration = Bonus::PERMANENT;
|
||||
bonus->limiter = std::make_shared<RankRangeLimiter>(RankRangeLimiter(lowerLimit));
|
||||
creature->addNewBonus (std::make_shared<Bonus>(*bonus)); //bonuses must be unique objects
|
||||
creature->addNewBonus (bonus);
|
||||
break; //TODO: allow bonuses to turn off?
|
||||
}
|
||||
++lowerLimit;
|
||||
@ -985,9 +988,14 @@ void CCreatureHandler::loadStackExperience(CCreature * creature, const JsonNode
|
||||
{
|
||||
if (val.Float() != lastVal)
|
||||
{
|
||||
bonus->val = static_cast<int>(val.Float()) - lastVal;
|
||||
JsonNode bonusInput = exp["bonus"];
|
||||
bonusInput["val"].Float() = static_cast<int>(val.Float()) - lastVal;
|
||||
|
||||
auto bonus = JsonUtils::parseBonus (bonusInput);
|
||||
bonus->source = Bonus::STACK_EXPERIENCE;
|
||||
bonus->duration = Bonus::PERMANENT;
|
||||
bonus->limiter.reset (new RankRangeLimiter(lowerLimit));
|
||||
creature->addNewBonus (std::make_shared<Bonus>(*bonus));
|
||||
creature->addNewBonus (bonus);
|
||||
}
|
||||
lastVal = static_cast<int>(val.Float());
|
||||
++lowerLimit;
|
||||
|
@ -82,6 +82,7 @@ public:
|
||||
//battle call-ins
|
||||
virtual BattleAction activeStack(const CStack * stack)=0; //called when it's turn of that stack
|
||||
virtual void yourTacticPhase(int distance){}; //called when interface has opportunity to use Tactics skill -> use cb->battleMakeTacticAction from this function
|
||||
virtual void forceEndTacticPhase(){}; //force the tatic phase to end to clean up the tactic phase thread
|
||||
};
|
||||
|
||||
/// Central class for managing human player / AI interface logic
|
||||
|
@ -790,11 +790,6 @@ int IBonusBearer::getMaxDamage(bool ranged) const
|
||||
return valOfBonuses(selector, cachingStr);
|
||||
}
|
||||
|
||||
si32 IBonusBearer::manaLimit() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IBonusBearer::getPrimSkillLevel(PrimarySkill::PrimarySkill id) const
|
||||
{
|
||||
static const CSelector selectorAllSkills = Selector::type()(Bonus::PRIMARY_SKILL);
|
||||
|
@ -764,7 +764,6 @@ public:
|
||||
virtual si32 magicResistance() const;
|
||||
ui32 Speed(int turn = 0, bool useBind = false) const; //get speed of creature with all modificators
|
||||
|
||||
virtual si32 manaLimit() const; //maximum mana value for this hero (basically 10*knowledge)
|
||||
int getPrimSkillLevel(PrimarySkill::PrimarySkill id) const;
|
||||
|
||||
virtual int64_t getTreeVersion() const = 0;
|
||||
|
@ -367,7 +367,12 @@ class IVCMIDirsUNIX : public IVCMIDirs
|
||||
bool IVCMIDirsUNIX::developmentMode() const
|
||||
{
|
||||
// We want to be able to run VCMI from single directory. E.g to run from build output directory
|
||||
return bfs::exists("AI") && bfs::exists("config") && bfs::exists("Mods") && bfs::exists("vcmiserver") && bfs::exists("vcmiclient");
|
||||
const bool result = bfs::exists("AI") && bfs::exists("config") && bfs::exists("Mods") && bfs::exists("vcmiclient");
|
||||
#if SINGLE_PROCESS_APP
|
||||
return result;
|
||||
#else
|
||||
return result && bfs::exists("vcmiserver");
|
||||
#endif
|
||||
}
|
||||
|
||||
bfs::path IVCMIDirsUNIX::clientPath() const { return binaryPath() / "vcmiclient"; }
|
||||
|
@ -29,6 +29,7 @@ public:
|
||||
std::vector<const battle::Unit *> enemyStacks;
|
||||
const CGHeroInstance * ourHero;
|
||||
const CGHeroInstance * enemyHero;
|
||||
int turnsSkippedByDefense;
|
||||
|
||||
BattleStateInfoForRetreat();
|
||||
uint64_t getOurStrength() const;
|
||||
|
@ -488,6 +488,11 @@ void CUnitState::getCastDescription(const spells::Spell * spell, const std::vect
|
||||
text.addReplacement(MetaString::SPELL_NAME, spell->getIndex());
|
||||
}
|
||||
|
||||
int32_t CUnitState::manaLimit() const
|
||||
{
|
||||
return 0; //TODO: creature casting with mana mode (for mods)
|
||||
}
|
||||
|
||||
bool CUnitState::ableToRetaliate() const
|
||||
{
|
||||
return alive()
|
||||
|
@ -195,6 +195,7 @@ public:
|
||||
const CGHeroInstance * getHeroCaster() const override;
|
||||
void getCasterName(MetaString & text) const override;
|
||||
void getCastDescription(const spells::Spell * spell, const std::vector<const Unit *> & attacked, MetaString & text) const override;
|
||||
int32_t manaLimit() const override;
|
||||
|
||||
bool ableToRetaliate() const override;
|
||||
bool alive() const override;
|
||||
|
@ -165,6 +165,8 @@ void CObjectClassesHandler::loadSubObject(const std::string & scope, const std::
|
||||
obj->objects.push_back(object);
|
||||
|
||||
registerObject(scope, obj->getJsonKey(), object->getSubTypeName(), object->subtype);
|
||||
for (auto const & compatID : entry["compatibilityIdentifiers"].Vector())
|
||||
registerObject(scope, obj->getJsonKey(), compatID.String(), object->subtype);
|
||||
}
|
||||
|
||||
void CObjectClassesHandler::loadSubObject(const std::string & scope, const std::string & identifier, const JsonNode & entry, ObjectClass * obj, size_t index)
|
||||
@ -176,6 +178,8 @@ void CObjectClassesHandler::loadSubObject(const std::string & scope, const std::
|
||||
obj->objects[index] = object;
|
||||
|
||||
registerObject(scope, obj->getJsonKey(), object->getSubTypeName(), object->subtype);
|
||||
for (auto const & compatID : entry["compatibilityIdentifiers"].Vector())
|
||||
registerObject(scope, obj->getJsonKey(), compatID.String(), object->subtype);
|
||||
}
|
||||
|
||||
TObjectTypeHandler CObjectClassesHandler::loadSubObjectFromJson(const std::string & scope, const std::string & identifier, const JsonNode & entry, ObjectClass * obj, size_t index)
|
||||
|
@ -133,6 +133,11 @@ int3 CGObjectInstance::getPosition() const
|
||||
return pos;
|
||||
}
|
||||
|
||||
int3 CGObjectInstance::getTopVisiblePos() const
|
||||
{
|
||||
return pos - appearance->getTopVisibleOffset();
|
||||
}
|
||||
|
||||
void CGObjectInstance::setOwner(const PlayerColor & ow)
|
||||
{
|
||||
tempOwner = ow;
|
||||
|
@ -160,6 +160,7 @@ public:
|
||||
bool visitableAt(int x, int y) const; //returns true if object is visitable at location (x, y) (h3m pos)
|
||||
int3 visitablePos() const override;
|
||||
int3 getPosition() const override;
|
||||
int3 getTopVisiblePos() const;
|
||||
bool blockingAt(int x, int y) const; //returns true if object is blocking location (x, y) (h3m pos)
|
||||
bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos)
|
||||
std::set<int3> getBlockedPos() const; //returns set of positions blocked by this object
|
||||
|
@ -155,8 +155,14 @@ void CRewardableObject::onHeroVisit(const CGHeroInstance *h) const
|
||||
BlockingDialog sd(canRefuse, rewards.size() > 1);
|
||||
sd.player = h->tempOwner;
|
||||
sd.text = dialog;
|
||||
for (auto index : rewards)
|
||||
sd.components.push_back(info[index].reward.getDisplayedComponent(h));
|
||||
|
||||
if (rewards.size() > 1)
|
||||
for (auto index : rewards)
|
||||
sd.components.push_back(info[index].reward.getDisplayedComponent(h));
|
||||
|
||||
if (rewards.size() == 1)
|
||||
info[rewards[0]].reward.loadComponents(sd.components, h);
|
||||
|
||||
cb->showBlockingDialog(&sd);
|
||||
};
|
||||
|
||||
|
@ -524,6 +524,22 @@ bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const
|
||||
return dirMap[dy][dx] != 0;
|
||||
}
|
||||
|
||||
void ObjectTemplate::calculateTopVisibleOffset()
|
||||
{
|
||||
for(int y = static_cast<int>(getHeight()) - 1; y >= 0; y--) //Templates start from bottom-right corner
|
||||
{
|
||||
for(int x = 0; x < static_cast<int>(getWidth()); x++)
|
||||
{
|
||||
if (isVisibleAt(x, y))
|
||||
{
|
||||
topVisibleOffset = int3(x, y, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
topVisibleOffset = int3(0, 0, 0);
|
||||
}
|
||||
|
||||
void ObjectTemplate::calculateVisitableOffset()
|
||||
{
|
||||
for(int y = 0; y < static_cast<int>(getHeight()); y++)
|
||||
@ -559,6 +575,7 @@ void ObjectTemplate::recalculate()
|
||||
calculateBlockedOffsets();
|
||||
calculateBlockMapOffset();
|
||||
calculateVisitableOffset();
|
||||
calculateTopVisibleOffset();
|
||||
|
||||
if (visitable && visitDir == 0)
|
||||
logMod->warn("Template for %s is visitable but has no visitable directions!", animationFile);
|
||||
|
@ -87,7 +87,12 @@ public:
|
||||
inline int3 getBlockMapOffset() const
|
||||
{
|
||||
return blockMapOffset;
|
||||
};
|
||||
}
|
||||
|
||||
inline int3 getTopVisibleOffset() const
|
||||
{
|
||||
return topVisibleOffset;
|
||||
}
|
||||
|
||||
// Checks if object is visitable from certain direction. X and Y must be between -1..+1
|
||||
bool isVisitableFrom(si8 X, si8 Y) const;
|
||||
@ -137,6 +142,7 @@ private:
|
||||
std::set<int3> blockedOffsets;
|
||||
int3 blockMapOffset;
|
||||
int3 visitableOffset;
|
||||
int3 topVisibleOffset;
|
||||
|
||||
void recalculate();
|
||||
|
||||
@ -146,6 +152,7 @@ private:
|
||||
void calculateBlockedOffsets();
|
||||
void calculateBlockMapOffset();
|
||||
void calculateVisitableOffset();
|
||||
void calculateTopVisibleOffset();
|
||||
|
||||
public:
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
|
@ -160,7 +160,7 @@ std::string CMapGenerator::getMapDescription() const
|
||||
std::stringstream ss;
|
||||
ss << boost::str(boost::format(std::string("Map created by the Random Map Generator.\nTemplate was %s, Random seed was %d, size %dx%d") +
|
||||
", levels %d, players %d, computers %d, water %s, monster %s, VCMI map") % mapTemplate->getName() %
|
||||
randomSeed % map->map().width % map->map().height % map->map().levels() % static_cast<int>(mapGenOptions.getPlayerCount()) %
|
||||
randomSeed % map->map().width % map->map().height % static_cast<int>(map->map().levels()) % static_cast<int>(mapGenOptions.getPlayerCount()) %
|
||||
static_cast<int>(mapGenOptions.getCompOnlyPlayerCount()) % waterContentStr[mapGenOptions.getWaterContent()] %
|
||||
monsterStrengthStr[monsterStrengthIndex]);
|
||||
|
||||
|
@ -112,6 +112,9 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object
|
||||
continue;
|
||||
|
||||
obj.setPosition(tile);
|
||||
|
||||
if (obj.getVisibleTop().y < 0)
|
||||
continue;
|
||||
|
||||
if(!searchArea.contains(obj.getArea()) || !searchArea.overlap(obj.getAccessibleArea()))
|
||||
continue;
|
||||
@ -131,6 +134,9 @@ int3 ObjectManager::findPlaceForObject(const rmg::Area & searchArea, rmg::Object
|
||||
for(const auto & tile : searchArea.getTiles())
|
||||
{
|
||||
obj.setPosition(tile);
|
||||
|
||||
if (obj.getVisibleTop().y < 0)
|
||||
continue;
|
||||
|
||||
if(!searchArea.contains(obj.getArea()) || !searchArea.overlap(obj.getAccessibleArea()))
|
||||
continue;
|
||||
|
@ -45,6 +45,11 @@ const Area & Object::Instance::getBlockedArea() const
|
||||
return dBlockedAreaCache;
|
||||
}
|
||||
|
||||
int3 Object::Instance::getTopTile() const
|
||||
{
|
||||
return object().getTopVisiblePos();
|
||||
}
|
||||
|
||||
int3 Object::Instance::getPosition(bool isAbsolute) const
|
||||
{
|
||||
if(isAbsolute)
|
||||
@ -284,6 +289,19 @@ const Area & Object::getArea() const
|
||||
return dFullAreaCache;
|
||||
}
|
||||
|
||||
const int3 Object::getVisibleTop() const
|
||||
{
|
||||
int3 topTile(-1, 10000, -1); //Start at the bottom
|
||||
for (const auto& i : dInstances)
|
||||
{
|
||||
if (i.getTopTile().y < topTile.y)
|
||||
{
|
||||
topTile = i.getTopTile();
|
||||
}
|
||||
}
|
||||
return topTile;
|
||||
}
|
||||
|
||||
void Object::Instance::finalize(RmgMap & map)
|
||||
{
|
||||
if(!map.isOnMap(getPosition(true)))
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
void setTemplate(TerrainId terrain); //cache invalidation
|
||||
void setAnyTemplate(); //cache invalidation
|
||||
|
||||
int3 getTopTile() const;
|
||||
int3 getPosition(bool isAbsolute = false) const;
|
||||
void setPosition(const int3 & position); //cache invalidation
|
||||
void setPositionRaw(const int3 & position); //no cache invalidation
|
||||
@ -75,6 +76,7 @@ public:
|
||||
void setTemplate(const TerrainId & terrain);
|
||||
|
||||
const Area & getArea() const; //lazy cache invalidation
|
||||
const int3 getVisibleTop() const;
|
||||
|
||||
void finalize(RmgMap & map);
|
||||
void clear();
|
||||
|
@ -254,19 +254,23 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
if(!creature->getAIValue() || tierValues.empty()) //bug #2681
|
||||
return 0; //this box won't be generated
|
||||
|
||||
//Follow the rules from https://heroes.thelazy.net/index.php/Pandora%27s_Box
|
||||
|
||||
int actualTier = creature->getLevel() > tierValues.size() ?
|
||||
tierValues.size() - 1 :
|
||||
creature->getLevel() - 1;
|
||||
float creaturesAmount = (static_cast<float>(tierValues[actualTier])) / creature->getAIValue();
|
||||
if(creaturesAmount <= 5)
|
||||
tierValues.size() - 1 :
|
||||
creature->getLevel() - 1;
|
||||
float creaturesAmount = std::floor((static_cast<float>(tierValues[actualTier])) / creature->getAIValue());
|
||||
if (creaturesAmount < 1)
|
||||
{
|
||||
creaturesAmount = boost::math::round(creaturesAmount); //allow single monsters
|
||||
if(creaturesAmount < 1)
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
else if(creaturesAmount <= 5)
|
||||
{
|
||||
//No change
|
||||
}
|
||||
else if(creaturesAmount <= 12)
|
||||
{
|
||||
(creaturesAmount /= 2) *= 2;
|
||||
creaturesAmount = std::ceil(creaturesAmount / 2) * 2;
|
||||
}
|
||||
else if(creaturesAmount <= 50)
|
||||
{
|
||||
|
@ -273,6 +273,8 @@ public:
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & identifier;
|
||||
if (version > 820)
|
||||
h & modScope;
|
||||
h & id;
|
||||
h & level;
|
||||
h & power;
|
||||
|
@ -58,6 +58,11 @@ int64_t ObstacleCasterProxy::getEffectValue(const Spell * spell) const
|
||||
return obs.minimalDamage;
|
||||
}
|
||||
|
||||
int32_t SilentCaster::manaLimit() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
SilentCaster::SilentCaster(PlayerColor owner_, const Caster * hero_):
|
||||
ProxyCaster(hero_),
|
||||
owner(std::move(owner_))
|
||||
@ -87,6 +92,5 @@ PlayerColor SilentCaster::getCasterOwner() const
|
||||
return owner;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -28,6 +28,7 @@ public:
|
||||
void getCastDescription(const Spell * spell, const std::vector<const battle::Unit *> & attacked, MetaString & text) const override;
|
||||
void spendMana(ServerCallback * server, const int spellCost) const override;
|
||||
PlayerColor getCasterOwner() const override;
|
||||
int32_t manaLimit() const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ObstacleCasterProxy : public SilentCaster
|
||||
@ -47,4 +48,4 @@ private:
|
||||
};
|
||||
|
||||
}//
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -126,6 +126,14 @@ const CGHeroInstance * ProxyCaster::getHeroCaster() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int32_t ProxyCaster::manaLimit() const
|
||||
{
|
||||
if(actualCaster)
|
||||
return actualCaster->manaLimit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -36,6 +36,7 @@ public:
|
||||
void getCastDescription(const Spell * spell, const std::vector<const battle::Unit *> & attacked, MetaString & text) const override;
|
||||
void spendMana(ServerCallback * server, const int32_t spellCost) const override;
|
||||
const CGHeroInstance * getHeroCaster() const override;
|
||||
int32_t manaLimit() const override;
|
||||
|
||||
protected:
|
||||
const Caster * actualCaster;
|
||||
|
@ -23,15 +23,11 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
static const std::string EFFECT_NAME = "core:catapult";
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
VCMI_REGISTER_SPELL_EFFECT(Catapult, EFFECT_NAME);
|
||||
|
||||
bool Catapult::applicable(Problem & problem, const Mechanics * m) const
|
||||
{
|
||||
const auto *town = m->battle()->battleGetDefendedTown();
|
||||
|
@ -19,15 +19,11 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
static const std::string EFFECT_NAME = "core:clone";
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
VCMI_REGISTER_SPELL_EFFECT(Clone, EFFECT_NAME);
|
||||
|
||||
void Clone::apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
|
||||
{
|
||||
for(const Destination & dest : target)
|
||||
|
@ -22,15 +22,11 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
static const std::string EFFECT_NAME = "core:damage";
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
VCMI_REGISTER_SPELL_EFFECT(Damage, EFFECT_NAME);
|
||||
|
||||
void Damage::apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
|
||||
{
|
||||
StacksInjured stacksInjured;
|
||||
|
@ -19,15 +19,11 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
static const std::string EFFECT_NAME = "core:demonSummon";
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
VCMI_REGISTER_SPELL_EFFECT(DemonSummon, EFFECT_NAME);
|
||||
|
||||
void DemonSummon::apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
|
||||
{
|
||||
BattleUnitsChanged pack;
|
||||
|
@ -23,15 +23,11 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
static const std::string EFFECT_NAME = "core:dispel";
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
VCMI_REGISTER_SPELL_EFFECT(Dispel, EFFECT_NAME);
|
||||
|
||||
void Dispel::apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
|
||||
{
|
||||
const bool describe = server->describeChanges();
|
||||
|
@ -35,9 +35,6 @@ class Effects;
|
||||
class Effect;
|
||||
class Registry;
|
||||
|
||||
template<typename F>
|
||||
class RegisterEffect;
|
||||
|
||||
using TargetType = spells::AimType;
|
||||
|
||||
class DLL_LINKAGE Effect
|
||||
|
@ -22,16 +22,11 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
static const std::string EFFECT_NAME = "core:heal";
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
VCMI_REGISTER_SPELL_EFFECT(Heal, EFFECT_NAME);
|
||||
|
||||
void Heal::apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
|
||||
{
|
||||
apply(m->getEffectValue(), server, m, target);
|
||||
|
@ -22,15 +22,11 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
static const std::string EFFECT_NAME = "core:moat";
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
VCMI_REGISTER_SPELL_EFFECT(Moat, EFFECT_NAME);
|
||||
|
||||
static void serializeMoatHexes(JsonSerializeFormat & handler, const std::string & fieldName, std::vector<std::vector<BattleHex>> & moatHexes)
|
||||
{
|
||||
{
|
||||
|
@ -21,15 +21,11 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
static const std::string EFFECT_NAME = "core:obstacle";
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
VCMI_REGISTER_SPELL_EFFECT(Obstacle, EFFECT_NAME);
|
||||
|
||||
using RelativeShape = std::vector<std::vector<BattleHex::EDir>>;
|
||||
|
||||
static void serializeRelativeShape(JsonSerializeFormat & handler, const std::string & fieldName, RelativeShape & value)
|
||||
|
@ -11,6 +11,24 @@
|
||||
|
||||
#include "Registry.h"
|
||||
|
||||
#include "Catapult.h"
|
||||
#include "Clone.h"
|
||||
#include "Damage.h"
|
||||
#include "DemonSummon.h"
|
||||
#include "Dispel.h"
|
||||
#include "Effect.h"
|
||||
#include "Effects.h"
|
||||
#include "Heal.h"
|
||||
#include "Moat.h"
|
||||
#include "LocationEffect.h"
|
||||
#include "Obstacle.h"
|
||||
#include "RemoveObstacle.h"
|
||||
#include "Sacrifice.h"
|
||||
#include "Summon.h"
|
||||
#include "Teleport.h"
|
||||
#include "Timed.h"
|
||||
#include "UnitEffect.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
namespace spells
|
||||
@ -23,6 +41,23 @@ namespace detail
|
||||
class RegistryImpl : public Registry
|
||||
{
|
||||
public:
|
||||
RegistryImpl()
|
||||
{
|
||||
add("core:catapult", std::make_shared<EffectFactory<Catapult>>());
|
||||
add("core:clone", std::make_shared<EffectFactory<Clone>>());
|
||||
add("core:damage", std::make_shared<EffectFactory<Damage>>());
|
||||
add("core:demonSummon", std::make_shared<EffectFactory<DemonSummon>>());
|
||||
add("core:dispel", std::make_shared<EffectFactory<Dispel>>());
|
||||
add("core:heal", std::make_shared<EffectFactory<Heal>>());
|
||||
add("core:moat", std::make_shared<EffectFactory<Moat>>());
|
||||
add("core:obstacle", std::make_shared<EffectFactory<Obstacle>>());
|
||||
add("core:removeObstacle", std::make_shared<EffectFactory<RemoveObstacle>>());
|
||||
add("core:sacrifice", std::make_shared<EffectFactory<Sacrifice>>());
|
||||
add("core:summon", std::make_shared<EffectFactory<Summon>>());
|
||||
add("core:teleport", std::make_shared<EffectFactory<Teleport>>());
|
||||
add("core:timed", std::make_shared<EffectFactory<Timed>>());
|
||||
}
|
||||
|
||||
const IEffectFactory * find(const std::string & name) const override
|
||||
{
|
||||
auto iter = data.find(name);
|
||||
|
@ -12,13 +12,6 @@
|
||||
|
||||
#include "Effect.h"
|
||||
|
||||
#define VCMI_REGISTER_SPELL_EFFECT(Type, Name) \
|
||||
namespace\
|
||||
{\
|
||||
RegisterEffect<Type> register ## Type(Name);\
|
||||
}\
|
||||
\
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
namespace spells
|
||||
@ -60,17 +53,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template<typename E>
|
||||
class RegisterEffect
|
||||
{
|
||||
public:
|
||||
RegisterEffect(const std::string & name)
|
||||
{
|
||||
auto f = std::make_shared<EffectFactory<E>>();
|
||||
GlobalRegistry::get()->add(name, f);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,15 +22,11 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
static const std::string EFFECT_NAME = "core:removeObstacle";
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
VCMI_REGISTER_SPELL_EFFECT(RemoveObstacle, EFFECT_NAME);
|
||||
|
||||
bool RemoveObstacle::applicable(Problem & problem, const Mechanics * m) const
|
||||
{
|
||||
if (getTargets(m, EffectTarget(), true).empty())
|
||||
|
@ -21,16 +21,11 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
static const std::string EFFECT_NAME = "core:sacrifice";
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
VCMI_REGISTER_SPELL_EFFECT(Sacrifice, EFFECT_NAME);
|
||||
|
||||
void Sacrifice::adjustTargetTypes(std::vector<TargetType> & types) const
|
||||
{
|
||||
if(!types.empty())
|
||||
|
@ -24,16 +24,11 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
static const std::string EFFECT_NAME = "core:summon";
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
VCMI_REGISTER_SPELL_EFFECT(Summon, EFFECT_NAME);
|
||||
|
||||
void Summon::adjustAffectedHexes(std::set<BattleHex> & hexes, const Mechanics * m, const Target & spellTarget) const
|
||||
{
|
||||
//no hexes affected
|
||||
|
@ -18,16 +18,10 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
//TODO: Teleport effect
|
||||
|
||||
static const std::string EFFECT_NAME = "core:teleport";
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
VCMI_REGISTER_SPELL_EFFECT(Teleport, EFFECT_NAME);
|
||||
|
||||
|
||||
void Teleport::adjustTargetTypes(std::vector<TargetType> & types) const
|
||||
{
|
||||
|
@ -20,15 +20,11 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
static const std::string EFFECT_NAME = "core:timed";
|
||||
|
||||
namespace spells
|
||||
{
|
||||
namespace effects
|
||||
{
|
||||
|
||||
VCMI_REGISTER_SPELL_EFFECT(Timed, EFFECT_NAME);
|
||||
|
||||
static void describeEffect(std::vector<MetaString> & log, const Mechanics * m, const std::vector<Bonus> & bonuses, const battle::Unit * target)
|
||||
{
|
||||
auto addLogLine = [&](const int32_t baseTextID, const boost::logic::tribool & plural)
|
||||
|
@ -560,7 +560,10 @@ void MainWindow::loadObjectsTree()
|
||||
connect(b, &QPushButton::clicked, this, [this, terrain]{ terrainButtonClicked(terrain->getId()); });
|
||||
|
||||
//filter
|
||||
ui->terrainFilterCombo->addItem(QString::fromStdString(terrain->getNameTranslated()));
|
||||
QString displayName = QString::fromStdString(terrain->getNameTranslated());
|
||||
QString uniqueName = QString::fromStdString(terrain->getJsonKey());
|
||||
|
||||
ui->terrainFilterCombo->addItem(displayName, QVariant(uniqueName));
|
||||
}
|
||||
//add spacer to keep terrain button on the top
|
||||
ui->terrainLayout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
|
||||
@ -936,23 +939,24 @@ void MainWindow::treeViewSelected(const QModelIndex & index, const QModelIndex &
|
||||
preparePreview(index);
|
||||
}
|
||||
|
||||
void MainWindow::on_terrainFilterCombo_currentTextChanged(const QString &arg1)
|
||||
void MainWindow::on_terrainFilterCombo_currentIndexChanged(int index)
|
||||
{
|
||||
if(!objectBrowser)
|
||||
return;
|
||||
|
||||
QString uniqueName = ui->terrainFilterCombo->itemData(index).toString();
|
||||
|
||||
objectBrowser->terrain = TerrainId(ETerrainId::ANY_TERRAIN);
|
||||
if (!arg1.isEmpty())
|
||||
if (!uniqueName.isEmpty())
|
||||
{
|
||||
for (auto const & terrain : VLC->terrainTypeHandler->objects)
|
||||
if (terrain->getJsonKey() == arg1.toStdString())
|
||||
if (terrain->getJsonKey() == uniqueName.toStdString())
|
||||
objectBrowser->terrain = terrain->getId();
|
||||
}
|
||||
objectBrowser->invalidate();
|
||||
objectBrowser->sort(0);
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::on_filter_textChanged(const QString &arg1)
|
||||
{
|
||||
if(!objectBrowser)
|
||||
|
@ -83,7 +83,7 @@ private slots:
|
||||
|
||||
void on_toolErase_clicked();
|
||||
|
||||
void on_terrainFilterCombo_currentTextChanged(const QString &arg1);
|
||||
void on_terrainFilterCombo_currentIndexChanged(int index);
|
||||
|
||||
void on_filter_textChanged(const QString &arg1);
|
||||
|
||||
|
@ -4842,8 +4842,9 @@ bool CGameHandler::makeBattleAction(BattleAction &ba)
|
||||
{
|
||||
const CSpell * spell = SpellID(healerAbility->subtype).toSpell();
|
||||
spells::BattleCast parameters(gs->curB, healer, spells::Mode::SPELL_LIKE_ATTACK, spell); //We can heal infinitely by first aid tent
|
||||
auto dest = battle::Destination(destStack, target.at(0).hexValue);
|
||||
parameters.setSpellLevel(0);
|
||||
parameters.cast(spellEnv, target);
|
||||
parameters.cast(spellEnv, {dest});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user