valtech-components 4.0.611 → 4.0.612
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/components/organisms/mini-games/christianity-bot.mjs +69 -0
- package/esm2022/lib/components/organisms/mini-games/christianity-catalog.mjs +247 -0
- package/esm2022/lib/components/organisms/mini-games/christianity-game.component.mjs +26 -397
- package/esm2022/lib/components/organisms/mini-games/christianity-tutorial.mjs +132 -0
- package/esm2022/lib/version.mjs +2 -2
- package/fesm2022/valtech-components.mjs +260 -188
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/organisms/mini-games/chessimals-game.component.d.ts +1 -1
- package/lib/components/organisms/mini-games/christianity-bot.d.ts +15 -0
- package/lib/components/organisms/mini-games/christianity-catalog.d.ts +18 -0
- package/lib/components/organisms/mini-games/christianity-game.component.d.ts +1 -9
- package/lib/components/organisms/mini-games/christianity-tutorial.d.ts +38 -0
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -59,7 +59,7 @@ import fixWebmDuration from 'fix-webm-duration';
|
|
|
59
59
|
* Current version of valtech-components.
|
|
60
60
|
* This is automatically updated during the publish process.
|
|
61
61
|
*/
|
|
62
|
-
const VERSION = '4.0.
|
|
62
|
+
const VERSION = '4.0.612';
|
|
63
63
|
|
|
64
64
|
// Control de estado de refresco (singleton a nivel de módulo)
|
|
65
65
|
let isRefreshing = false;
|
|
@@ -74959,14 +74959,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
74959
74959
|
|
|
74960
74960
|
const GENESIS_CATALOG_URL = 'assets/games/christianity/data/01-genesis.cards.json';
|
|
74961
74961
|
const GENESIS_ICON_URL = 'assets/games/christianity/icons/1-icon.png';
|
|
74962
|
-
const TUTORIAL_CHARACTER_LIMIT = 12;
|
|
74963
|
-
const TUTORIAL_OFFERING_LIMIT = 6;
|
|
74964
|
-
const TUTORIAL_OPENING_HAND_SIZE = 5;
|
|
74965
|
-
const TUTORIAL_LEADER_CHOICE_COUNT = 2;
|
|
74966
|
-
const TUTORIAL_LEADER_CHOICE_SECONDS = 15;
|
|
74967
|
-
const TUTORIAL_SEED = 20260728;
|
|
74968
74962
|
const SPLASH_MIN_DURATION_MS = 720;
|
|
74969
|
-
const CHRISTIANITY_PREVIEW_NEUTRAL_TILT = { rotateX: 0, rotateY: 0, shiftX: 0, shiftY: 0 };
|
|
74970
74963
|
const STARTER_CARDS = {
|
|
74971
74964
|
o_simple: {
|
|
74972
74965
|
id: 'o_simple',
|
|
@@ -75173,6 +75166,244 @@ const STARTING_GAME = {
|
|
|
75173
75166
|
},
|
|
75174
75167
|
log: ['Partida iniciada.'],
|
|
75175
75168
|
};
|
|
75169
|
+
function formatScripture(bible) {
|
|
75170
|
+
if (!bible?.book || !bible.reference)
|
|
75171
|
+
return undefined;
|
|
75172
|
+
return `${bible.book} ${bible.reference}${bible.version ? ` ${bible.version}` : ''}`;
|
|
75173
|
+
}
|
|
75174
|
+
function normalizeCatalogCard(card, catalog) {
|
|
75175
|
+
const editionIcon = card.editionIcon ?? catalog.edition?.icon ?? GENESIS_ICON_URL;
|
|
75176
|
+
const verseText = card.verseText ?? card.bible?.text;
|
|
75177
|
+
const scripture = card.scripture ?? formatScripture(card.bible);
|
|
75178
|
+
const offeringValue = card.type === 'offering'
|
|
75179
|
+
? (card.offeringValue ?? card.life ?? card.cost ?? 1)
|
|
75180
|
+
: card.offeringValue;
|
|
75181
|
+
const life = card.type === 'leader'
|
|
75182
|
+
? (card.leaderLife ?? card.life ?? 10)
|
|
75183
|
+
: card.type === 'offering'
|
|
75184
|
+
? offeringValue
|
|
75185
|
+
: (card.life ?? 0);
|
|
75186
|
+
return {
|
|
75187
|
+
...card,
|
|
75188
|
+
cost: card.type === 'offering' ? 0 : (card.cost ?? 0),
|
|
75189
|
+
offeringValue,
|
|
75190
|
+
life,
|
|
75191
|
+
leaderLife: card.type === 'leader' ? (card.leaderLife ?? life) : card.leaderLife,
|
|
75192
|
+
attack: card.type === 'character' ? (card.attack ?? 0) : card.attack,
|
|
75193
|
+
abilityName: card.abilityName ?? card.abilities?.[0]?.name,
|
|
75194
|
+
abilityText: card.abilityText ?? card.abilities?.[0]?.text,
|
|
75195
|
+
verseText,
|
|
75196
|
+
scripture,
|
|
75197
|
+
edition: card.edition ?? catalog.edition?.id ?? 'GEN',
|
|
75198
|
+
editionNumber: card.editionNumber ?? catalog.edition?.number,
|
|
75199
|
+
editionIcon,
|
|
75200
|
+
imageUrl: card.imageUrl ?? card.art?.imageUrl,
|
|
75201
|
+
author: card.author ?? card.art?.artistCredit,
|
|
75202
|
+
year: card.year ?? '2026',
|
|
75203
|
+
frontTemplate: card.frontTemplate ?? 'genesis-classic',
|
|
75204
|
+
};
|
|
75205
|
+
}
|
|
75206
|
+
|
|
75207
|
+
const TUTORIAL_CHARACTER_LIMIT = 12;
|
|
75208
|
+
const TUTORIAL_OFFERING_LIMIT = 6;
|
|
75209
|
+
const TUTORIAL_OPENING_HAND_SIZE = 5;
|
|
75210
|
+
const TUTORIAL_LEADER_CHOICE_COUNT = 2;
|
|
75211
|
+
const TUTORIAL_LEADER_CHOICE_SECONDS = 15;
|
|
75212
|
+
const TUTORIAL_SEED = 20260728;
|
|
75213
|
+
function isClassicGalleryCard(card) {
|
|
75214
|
+
return (card.frontTemplate ?? 'genesis-classic') === 'genesis-classic';
|
|
75215
|
+
}
|
|
75216
|
+
function cardSortKey(card, nameResolver = c => c.name) {
|
|
75217
|
+
const collector = card.collectorNumber ?? card.id;
|
|
75218
|
+
return `${card.edition ?? ''}-${collector.padStart(8, '0')}-${nameResolver(card)}`;
|
|
75219
|
+
}
|
|
75220
|
+
function tutorialLeaderCards(cards, nameResolver = c => c.name) {
|
|
75221
|
+
const leaders = cards
|
|
75222
|
+
.filter(card => card.type === 'leader' && isClassicGalleryCard(card))
|
|
75223
|
+
.sort((a, b) => cardSortKey(a, nameResolver).localeCompare(cardSortKey(b, nameResolver), 'es'));
|
|
75224
|
+
if (leaders.length >= 2)
|
|
75225
|
+
return leaders.slice(0, 4);
|
|
75226
|
+
return cards.filter(card => card.type === 'leader').slice(0, 4);
|
|
75227
|
+
}
|
|
75228
|
+
function findCardByName(cards, namePart, nameResolver = c => c.name) {
|
|
75229
|
+
return cards.find(card => nameResolver(card).toLowerCase().includes(namePart.toLowerCase()));
|
|
75230
|
+
}
|
|
75231
|
+
function shuffleCards(cards, seed) {
|
|
75232
|
+
const result = [...cards];
|
|
75233
|
+
let state = seed >>> 0;
|
|
75234
|
+
for (let i = result.length - 1; i > 0; i--) {
|
|
75235
|
+
state = (state * 1664525 + 1013904223) >>> 0;
|
|
75236
|
+
const j = state % (i + 1);
|
|
75237
|
+
[result[i], result[j]] = [result[j], result[i]];
|
|
75238
|
+
}
|
|
75239
|
+
return result;
|
|
75240
|
+
}
|
|
75241
|
+
function ensureOpeningOffering(cards, start, size) {
|
|
75242
|
+
const hand = cards.slice(start, start + size);
|
|
75243
|
+
if (hand.some(card => card.type === 'offering'))
|
|
75244
|
+
return;
|
|
75245
|
+
const offeringIndex = cards.findIndex((card, i) => i >= start + size && card.type === 'offering');
|
|
75246
|
+
if (offeringIndex < 0)
|
|
75247
|
+
return;
|
|
75248
|
+
[cards[start], cards[offeringIndex]] = [cards[offeringIndex], cards[start]];
|
|
75249
|
+
}
|
|
75250
|
+
function prepareTutorialOpeningDeck(cards) {
|
|
75251
|
+
const result = [...cards];
|
|
75252
|
+
ensureOpeningOffering(result, 0, TUTORIAL_OPENING_HAND_SIZE);
|
|
75253
|
+
ensureOpeningOffering(result, TUTORIAL_OPENING_HAND_SIZE, TUTORIAL_OPENING_HAND_SIZE);
|
|
75254
|
+
return result;
|
|
75255
|
+
}
|
|
75256
|
+
function createTutorialPlayer(seat, leader, hand, battleZone, nameResolver = c => c.name) {
|
|
75257
|
+
const base = STARTING_GAME.players[seat];
|
|
75258
|
+
const leaderLife = leader?.leaderLife ?? leader?.life ?? base.leaderMaxHp;
|
|
75259
|
+
return {
|
|
75260
|
+
...structuredClone(base),
|
|
75261
|
+
leaderCardId: leader?.id,
|
|
75262
|
+
leaderName: leader ? nameResolver(leader) : base.leaderName,
|
|
75263
|
+
leaderHp: leaderLife,
|
|
75264
|
+
leaderMaxHp: leaderLife,
|
|
75265
|
+
offerings: [],
|
|
75266
|
+
offeringPlayedThisTurn: false,
|
|
75267
|
+
hand,
|
|
75268
|
+
handCount: hand ? undefined : 4,
|
|
75269
|
+
battleZone,
|
|
75270
|
+
};
|
|
75271
|
+
}
|
|
75272
|
+
function createTutorialGame(cards, options = {}, context = {}) {
|
|
75273
|
+
const nameResolver = context.nameResolver ?? (c => c.name);
|
|
75274
|
+
const cardById = context.cardById;
|
|
75275
|
+
const leaders = tutorialLeaderCards(cards, nameResolver);
|
|
75276
|
+
const playerLeader = (cardById && options.playerLeaderId ? cardById(options.playerLeaderId) : undefined) ??
|
|
75277
|
+
findCardByName(leaders, 'Adán', nameResolver) ??
|
|
75278
|
+
findCardByName(leaders, 'Adan', nameResolver) ??
|
|
75279
|
+
leaders[0];
|
|
75280
|
+
const opponentLeader = (cardById && options.opponentLeaderId ? cardById(options.opponentLeaderId) : undefined) ??
|
|
75281
|
+
findCardByName(leaders, 'Noé', nameResolver) ??
|
|
75282
|
+
findCardByName(leaders, 'Noe', nameResolver) ??
|
|
75283
|
+
leaders.find(c => c.id !== playerLeader?.id) ??
|
|
75284
|
+
leaders[0];
|
|
75285
|
+
const offerings = cards
|
|
75286
|
+
.filter(c => c.type === 'offering' && isClassicGalleryCard(c))
|
|
75287
|
+
.slice(0, TUTORIAL_OFFERING_LIMIT);
|
|
75288
|
+
const places = cards.filter(c => c.type === 'place');
|
|
75289
|
+
const characters = cards
|
|
75290
|
+
.filter(c => c.type === 'character' &&
|
|
75291
|
+
isClassicGalleryCard(c) &&
|
|
75292
|
+
(c.cost ?? 0) <= 4 &&
|
|
75293
|
+
(c.attack ?? 0) >= 0 &&
|
|
75294
|
+
(c.life ?? 0) > 0)
|
|
75295
|
+
.slice(0, TUTORIAL_CHARACTER_LIMIT);
|
|
75296
|
+
const tutorialDeck = [...offerings, ...characters, ...offerings, ...characters.slice(0, 6)].slice(0, 28);
|
|
75297
|
+
const shuffledDeck = prepareTutorialOpeningDeck(shuffleCards(tutorialDeck, options.seed ?? TUTORIAL_SEED));
|
|
75298
|
+
const playerHand = shuffledDeck.slice(0, TUTORIAL_OPENING_HAND_SIZE).map(c => c.id);
|
|
75299
|
+
const opponentHand = shuffledDeck
|
|
75300
|
+
.slice(TUTORIAL_OPENING_HAND_SIZE, TUTORIAL_OPENING_HAND_SIZE * 2)
|
|
75301
|
+
.map(c => c.id);
|
|
75302
|
+
const sharedDeck = shuffledDeck.slice(TUTORIAL_OPENING_HAND_SIZE * 2).map(c => c.id);
|
|
75303
|
+
const firstPlayer = options.firstPlayer ?? 'P1';
|
|
75304
|
+
const firstPlayerName = firstPlayer === 'P1'
|
|
75305
|
+
? STARTING_GAME.players.P1.displayName
|
|
75306
|
+
: STARTING_GAME.players.P2.displayName;
|
|
75307
|
+
const messages = context.messages;
|
|
75308
|
+
const log = messages
|
|
75309
|
+
? [`${messages.turnOf} ${firstPlayerName}.`, messages.tutorialLoaded]
|
|
75310
|
+
: [`Turno de ${firstPlayerName}.`, 'Tutorial cargado.'];
|
|
75311
|
+
return {
|
|
75312
|
+
...structuredClone(STARTING_GAME),
|
|
75313
|
+
status: 'in_progress',
|
|
75314
|
+
turnOwner: firstPlayer,
|
|
75315
|
+
turnCount: 1,
|
|
75316
|
+
matchScore: { P1: 0, P2: 0 },
|
|
75317
|
+
sharedDeck,
|
|
75318
|
+
placeZone: places[0] ? [places[0].id] : [],
|
|
75319
|
+
historyZone: [],
|
|
75320
|
+
players: {
|
|
75321
|
+
P1: createTutorialPlayer('P1', playerLeader, playerHand, [], nameResolver),
|
|
75322
|
+
P2: createTutorialPlayer('P2', opponentLeader, opponentHand, [], nameResolver),
|
|
75323
|
+
},
|
|
75324
|
+
log,
|
|
75325
|
+
};
|
|
75326
|
+
}
|
|
75327
|
+
function createTutorialSetup(leaders) {
|
|
75328
|
+
const coinWinner = TUTORIAL_SEED % 2 === 0 ? 'P1' : 'P2';
|
|
75329
|
+
const firstPlayer = coinWinner === 'P1' ? 'P2' : 'P1';
|
|
75330
|
+
return {
|
|
75331
|
+
coinWinner,
|
|
75332
|
+
leaderPicker: coinWinner,
|
|
75333
|
+
firstPlayer,
|
|
75334
|
+
availableLeaders: leaders.slice(0, TUTORIAL_LEADER_CHOICE_COUNT).map(c => c.id),
|
|
75335
|
+
};
|
|
75336
|
+
}
|
|
75337
|
+
|
|
75338
|
+
function resolveBotPlays(game, log, nameResolver = c => c.name, cardById = id => ({
|
|
75339
|
+
id,
|
|
75340
|
+
name: id,
|
|
75341
|
+
type: 'character',
|
|
75342
|
+
cost: 0,
|
|
75343
|
+
life: 0,
|
|
75344
|
+
attack: 0,
|
|
75345
|
+
})) {
|
|
75346
|
+
const hand = [...(game.players.P2.hand ?? [])];
|
|
75347
|
+
const offeringId = hand.find(cardId => {
|
|
75348
|
+
const card = cardById(cardId);
|
|
75349
|
+
return card.type === 'offering' && canPlayCard(game, 'P2', card);
|
|
75350
|
+
});
|
|
75351
|
+
if (offeringId) {
|
|
75352
|
+
const card = cardById(offeringId);
|
|
75353
|
+
const result = playCardFromHand(game, 'P2', card, {
|
|
75354
|
+
displayName: nameResolver(card),
|
|
75355
|
+
});
|
|
75356
|
+
if (result.played) {
|
|
75357
|
+
Object.assign(game, result.game);
|
|
75358
|
+
log.push(...result.log);
|
|
75359
|
+
}
|
|
75360
|
+
}
|
|
75361
|
+
const playableCharacters = [...(game.players.P2.hand ?? [])]
|
|
75362
|
+
.map(cardId => cardById(cardId))
|
|
75363
|
+
.filter(card => card.type === 'character' && canPlayCard(game, 'P2', card))
|
|
75364
|
+
.sort((l, r) => (r.attack ?? 0) - (l.attack ?? 0) || (r.life ?? 0) - (l.life ?? 0));
|
|
75365
|
+
const character = playableCharacters[0];
|
|
75366
|
+
if (character) {
|
|
75367
|
+
const result = playCardFromHand(game, 'P2', character, {
|
|
75368
|
+
displayName: nameResolver(character),
|
|
75369
|
+
});
|
|
75370
|
+
if (result.played) {
|
|
75371
|
+
Object.assign(game, result.game);
|
|
75372
|
+
log.push(...result.log);
|
|
75373
|
+
}
|
|
75374
|
+
}
|
|
75375
|
+
}
|
|
75376
|
+
function resolveBotAttack(game, log, impacts, messages) {
|
|
75377
|
+
const bot = game.players.P2;
|
|
75378
|
+
const player = game.players.P1;
|
|
75379
|
+
const attacker = bot.battleZone
|
|
75380
|
+
.filter(card => card.canAttack && card.attack > 0)
|
|
75381
|
+
.sort((l, r) => (l.slot ?? 0) - (r.slot ?? 0))[0];
|
|
75382
|
+
if (!attacker) {
|
|
75383
|
+
log.push(messages.botNoAttackers);
|
|
75384
|
+
return;
|
|
75385
|
+
}
|
|
75386
|
+
const target = player.battleZone
|
|
75387
|
+
.filter(card => card.currentHp > 0)
|
|
75388
|
+
.sort((l, r) => l.currentHp - r.currentHp || (l.slot ?? 0) - (r.slot ?? 0))[0];
|
|
75389
|
+
if (target) {
|
|
75390
|
+
impacts.push({ text: `-${attacker.attack}`, tone: 'damage', seat: 'P1', target: 'battle' });
|
|
75391
|
+
impacts.push({ text: `-${target.attack}`, tone: 'damage', seat: 'P2', target: 'battle' });
|
|
75392
|
+
target.currentHp -= attacker.attack;
|
|
75393
|
+
attacker.currentHp -= target.attack;
|
|
75394
|
+
attacker.canAttack = false;
|
|
75395
|
+
log.push(`${attacker.name} ${messages.combatsAgainst} ${target.name}.`);
|
|
75396
|
+
cleanupDestroyed(player, game);
|
|
75397
|
+
cleanupDestroyed(bot, game);
|
|
75398
|
+
return;
|
|
75399
|
+
}
|
|
75400
|
+
impacts.push({ text: `-${attacker.attack}`, tone: 'damage', seat: 'P1', target: 'leader' });
|
|
75401
|
+
player.leaderHp = Math.max(0, player.leaderHp - attacker.attack);
|
|
75402
|
+
attacker.canAttack = false;
|
|
75403
|
+
log.push(`${attacker.name} ${messages.attacksYourLeader}`);
|
|
75404
|
+
}
|
|
75405
|
+
|
|
75406
|
+
const CHRISTIANITY_PREVIEW_NEUTRAL_TILT = { rotateX: 0, rotateY: 0, shiftX: 0, shiftY: 0 };
|
|
75176
75407
|
class ChristianityGameComponent {
|
|
75177
75408
|
isPreviewAbilityPlaceholder(ability) {
|
|
75178
75409
|
return ability?.title === this.t('christianityNoAbilityTitle') && !ability.canUse;
|
|
@@ -75694,99 +75925,20 @@ class ChristianityGameComponent {
|
|
|
75694
75925
|
}, remaining);
|
|
75695
75926
|
}
|
|
75696
75927
|
normalizeCatalogCard(card, catalog) {
|
|
75697
|
-
|
|
75698
|
-
const verseText = card.verseText ?? card.bible?.text;
|
|
75699
|
-
const scripture = card.scripture ?? this.formatScripture(card.bible);
|
|
75700
|
-
const offeringValue = card.type === 'offering' ? (card.offeringValue ?? card.life ?? card.cost ?? 1) : card.offeringValue;
|
|
75701
|
-
const life = card.type === 'leader'
|
|
75702
|
-
? (card.leaderLife ?? card.life ?? 10)
|
|
75703
|
-
: card.type === 'offering'
|
|
75704
|
-
? offeringValue
|
|
75705
|
-
: (card.life ?? 0);
|
|
75706
|
-
return {
|
|
75707
|
-
...card,
|
|
75708
|
-
cost: card.type === 'offering' ? 0 : (card.cost ?? 0),
|
|
75709
|
-
offeringValue,
|
|
75710
|
-
life,
|
|
75711
|
-
leaderLife: card.type === 'leader' ? (card.leaderLife ?? life) : card.leaderLife,
|
|
75712
|
-
attack: card.type === 'character' ? (card.attack ?? 0) : card.attack,
|
|
75713
|
-
abilityName: card.abilityName ?? card.abilities?.[0]?.name,
|
|
75714
|
-
abilityText: card.abilityText ?? card.abilities?.[0]?.text,
|
|
75715
|
-
verseText,
|
|
75716
|
-
scripture,
|
|
75717
|
-
edition: card.edition ?? catalog.edition?.id ?? 'GEN',
|
|
75718
|
-
editionNumber: card.editionNumber ?? catalog.edition?.number,
|
|
75719
|
-
editionIcon,
|
|
75720
|
-
imageUrl: card.imageUrl ?? card.art?.imageUrl,
|
|
75721
|
-
author: card.author ?? card.art?.artistCredit,
|
|
75722
|
-
year: card.year ?? '2026',
|
|
75723
|
-
frontTemplate: card.frontTemplate ?? 'genesis-classic',
|
|
75724
|
-
};
|
|
75928
|
+
return normalizeCatalogCard(card, catalog);
|
|
75725
75929
|
}
|
|
75726
75930
|
formatScripture(bible) {
|
|
75727
|
-
|
|
75728
|
-
return undefined;
|
|
75729
|
-
return `${bible.book} ${bible.reference}${bible.version ? ` ${bible.version}` : ''}`;
|
|
75931
|
+
return formatScripture(bible);
|
|
75730
75932
|
}
|
|
75731
75933
|
createTutorialGame(cards, options = {}) {
|
|
75732
|
-
|
|
75733
|
-
|
|
75734
|
-
|
|
75735
|
-
this.
|
|
75736
|
-
|
|
75737
|
-
leaders[0];
|
|
75738
|
-
const offerings = cards
|
|
75739
|
-
.filter(card => card.type === 'offering' && this.isClassicGalleryCard(card))
|
|
75740
|
-
.slice(0, TUTORIAL_OFFERING_LIMIT);
|
|
75741
|
-
const places = cards.filter(card => card.type === 'place');
|
|
75742
|
-
const characters = cards
|
|
75743
|
-
.filter(card => card.type === 'character' &&
|
|
75744
|
-
this.isClassicGalleryCard(card) &&
|
|
75745
|
-
(card.cost ?? 0) <= 4 &&
|
|
75746
|
-
(card.attack ?? 0) >= 0 &&
|
|
75747
|
-
(card.life ?? 0) > 0)
|
|
75748
|
-
.slice(0, TUTORIAL_CHARACTER_LIMIT);
|
|
75749
|
-
const tutorialDeck = [...offerings, ...characters, ...offerings, ...characters.slice(0, 6)].slice(0, 28);
|
|
75750
|
-
const shuffledDeck = this.prepareTutorialOpeningDeck(this.shuffleCards(tutorialDeck, options.seed ?? TUTORIAL_SEED));
|
|
75751
|
-
const playerHand = shuffledDeck.slice(0, TUTORIAL_OPENING_HAND_SIZE).map(card => card.id);
|
|
75752
|
-
const opponentHand = shuffledDeck
|
|
75753
|
-
.slice(TUTORIAL_OPENING_HAND_SIZE, TUTORIAL_OPENING_HAND_SIZE * 2)
|
|
75754
|
-
.map(card => card.id);
|
|
75755
|
-
const sharedDeck = shuffledDeck.slice(TUTORIAL_OPENING_HAND_SIZE * 2).map(card => card.id);
|
|
75756
|
-
return {
|
|
75757
|
-
...structuredClone(STARTING_GAME),
|
|
75758
|
-
status: 'in_progress',
|
|
75759
|
-
turnOwner: options.firstPlayer ?? 'P1',
|
|
75760
|
-
turnCount: 1,
|
|
75761
|
-
matchScore: { P1: 0, P2: 0 },
|
|
75762
|
-
sharedDeck,
|
|
75763
|
-
placeZone: places[0] ? [places[0].id] : [],
|
|
75764
|
-
historyZone: [],
|
|
75765
|
-
players: {
|
|
75766
|
-
P1: this.createTutorialPlayer('P1', playerLeader, playerHand, []),
|
|
75767
|
-
P2: this.createTutorialPlayer('P2', opponentLeader, opponentHand, []),
|
|
75768
|
-
},
|
|
75769
|
-
log: [
|
|
75770
|
-
`${this.t('christianityTurnOf')} ${(options.firstPlayer ?? 'P1') === 'P1' ? STARTING_GAME.players.P1.displayName : STARTING_GAME.players.P2.displayName}.`,
|
|
75771
|
-
this.t('christianityTutorialLoaded'),
|
|
75772
|
-
],
|
|
75773
|
-
};
|
|
75934
|
+
return createTutorialGame(cards, options, {
|
|
75935
|
+
messages: { turnOf: this.t('christianityTurnOf'), tutorialLoaded: this.t('christianityTutorialLoaded') },
|
|
75936
|
+
nameResolver: c => this.translatedCardText(c).name,
|
|
75937
|
+
cardById: id => this.cardById(id),
|
|
75938
|
+
});
|
|
75774
75939
|
}
|
|
75775
75940
|
createTutorialPlayer(seat, leader, hand, battleZone) {
|
|
75776
|
-
|
|
75777
|
-
const leaderLife = leader?.leaderLife ?? leader?.life ?? base.leaderMaxHp;
|
|
75778
|
-
return {
|
|
75779
|
-
...structuredClone(base),
|
|
75780
|
-
leaderCardId: leader?.id,
|
|
75781
|
-
leaderName: leader ? this.translatedCardText(leader).name : base.leaderName,
|
|
75782
|
-
leaderHp: leaderLife,
|
|
75783
|
-
leaderMaxHp: leaderLife,
|
|
75784
|
-
offerings: [],
|
|
75785
|
-
offeringPlayedThisTurn: false,
|
|
75786
|
-
hand,
|
|
75787
|
-
handCount: hand ? undefined : 4,
|
|
75788
|
-
battleZone,
|
|
75789
|
-
};
|
|
75941
|
+
return createTutorialPlayer(seat, leader, hand, battleZone, c => this.translatedCardText(c).name);
|
|
75790
75942
|
}
|
|
75791
75943
|
createOfferingInstance(card, seat, instanceId) {
|
|
75792
75944
|
const value = card.offeringValue ?? card.life ?? 1;
|
|
@@ -75818,50 +75970,25 @@ class ChristianityGameComponent {
|
|
|
75818
75970
|
};
|
|
75819
75971
|
}
|
|
75820
75972
|
findCard(cards, namePart) {
|
|
75821
|
-
return cards
|
|
75973
|
+
return findCardByName(cards, namePart, c => this.translatedCardText(c).name);
|
|
75822
75974
|
}
|
|
75823
75975
|
cardById(cardId) {
|
|
75824
75976
|
return cardId ? (this.cardCatalog()[cardId] ?? STARTER_CARDS[cardId]) : undefined;
|
|
75825
75977
|
}
|
|
75826
75978
|
tutorialLeaderCards(cards) {
|
|
75827
|
-
|
|
75828
|
-
.filter(card => card.type === 'leader' && this.isClassicGalleryCard(card))
|
|
75829
|
-
.sort((left, right) => this.cardSortKey(left).localeCompare(this.cardSortKey(right), 'es'));
|
|
75830
|
-
if (leaders.length >= 2)
|
|
75831
|
-
return leaders.slice(0, 4);
|
|
75832
|
-
return cards.filter(card => card.type === 'leader').slice(0, 4);
|
|
75979
|
+
return tutorialLeaderCards(cards, c => this.translatedCardText(c).name);
|
|
75833
75980
|
}
|
|
75834
75981
|
shuffleCards(cards, seed) {
|
|
75835
|
-
|
|
75836
|
-
let state = seed >>> 0;
|
|
75837
|
-
for (let index = result.length - 1; index > 0; index--) {
|
|
75838
|
-
state = (state * 1664525 + 1013904223) >>> 0;
|
|
75839
|
-
const swapIndex = state % (index + 1);
|
|
75840
|
-
[result[index], result[swapIndex]] = [result[swapIndex], result[index]];
|
|
75841
|
-
}
|
|
75842
|
-
return result;
|
|
75982
|
+
return shuffleCards(cards, seed);
|
|
75843
75983
|
}
|
|
75844
75984
|
prepareTutorialOpeningDeck(cards) {
|
|
75845
|
-
|
|
75846
|
-
this.ensureOpeningOffering(result, 0, TUTORIAL_OPENING_HAND_SIZE);
|
|
75847
|
-
this.ensureOpeningOffering(result, TUTORIAL_OPENING_HAND_SIZE, TUTORIAL_OPENING_HAND_SIZE);
|
|
75848
|
-
return result;
|
|
75849
|
-
}
|
|
75850
|
-
ensureOpeningOffering(cards, start, size) {
|
|
75851
|
-
const hand = cards.slice(start, start + size);
|
|
75852
|
-
if (hand.some(card => card.type === 'offering'))
|
|
75853
|
-
return;
|
|
75854
|
-
const offeringIndex = cards.findIndex((card, index) => index >= start + size && card.type === 'offering');
|
|
75855
|
-
if (offeringIndex < 0)
|
|
75856
|
-
return;
|
|
75857
|
-
[cards[start], cards[offeringIndex]] = [cards[offeringIndex], cards[start]];
|
|
75985
|
+
return prepareTutorialOpeningDeck(cards);
|
|
75858
75986
|
}
|
|
75859
75987
|
cardSortKey(card) {
|
|
75860
|
-
|
|
75861
|
-
return `${card.edition ?? ''}-${collector.padStart(8, '0')}-${this.translatedCardText(card).name}`;
|
|
75988
|
+
return cardSortKey(card, c => this.translatedCardText(c).name);
|
|
75862
75989
|
}
|
|
75863
75990
|
isClassicGalleryCard(card) {
|
|
75864
|
-
return (card
|
|
75991
|
+
return isClassicGalleryCard(card);
|
|
75865
75992
|
}
|
|
75866
75993
|
cardDefinition(cardId) {
|
|
75867
75994
|
return this.cardCatalog()[cardId] ?? STARTER_CARDS[cardId] ?? STARTER_CARDS['p_scout'];
|
|
@@ -76689,14 +76816,7 @@ class ChristianityGameComponent {
|
|
|
76689
76816
|
}
|
|
76690
76817
|
createTutorialSetup() {
|
|
76691
76818
|
const leaders = this.tutorialLeaderCards(this.allCatalogCards()).slice(0, TUTORIAL_LEADER_CHOICE_COUNT);
|
|
76692
|
-
|
|
76693
|
-
const firstPlayer = coinWinner === 'P1' ? 'P2' : 'P1';
|
|
76694
|
-
return {
|
|
76695
|
-
coinWinner,
|
|
76696
|
-
leaderPicker: coinWinner,
|
|
76697
|
-
firstPlayer,
|
|
76698
|
-
availableLeaders: leaders.map(card => card.id),
|
|
76699
|
-
};
|
|
76819
|
+
return createTutorialSetup(leaders);
|
|
76700
76820
|
}
|
|
76701
76821
|
chooseRivalTutorialLeader() {
|
|
76702
76822
|
const setup = this.tutorialSetup();
|
|
@@ -77116,62 +77236,14 @@ class ChristianityGameComponent {
|
|
|
77116
77236
|
this.pushImpactEvents(impacts);
|
|
77117
77237
|
}
|
|
77118
77238
|
resolveBotPlays(game, log) {
|
|
77119
|
-
|
|
77120
|
-
const hand = [...(bot.hand ?? [])];
|
|
77121
|
-
const offeringId = hand.find(cardId => this.cardDefinition(cardId).type === 'offering' && canPlayCard(game, 'P2', this.cardDefinition(cardId)));
|
|
77122
|
-
if (offeringId) {
|
|
77123
|
-
const card = this.cardDefinition(offeringId);
|
|
77124
|
-
const result = playCardFromHand(game, 'P2', card, {
|
|
77125
|
-
displayName: this.translatedCardText(card).name,
|
|
77126
|
-
});
|
|
77127
|
-
if (result.played) {
|
|
77128
|
-
Object.assign(game, result.game);
|
|
77129
|
-
log.push(...result.log);
|
|
77130
|
-
}
|
|
77131
|
-
}
|
|
77132
|
-
const playableCharacters = [...(game.players.P2.hand ?? [])]
|
|
77133
|
-
.map(cardId => this.cardDefinition(cardId))
|
|
77134
|
-
.filter(card => card.type === 'character' && canPlayCard(game, 'P2', card))
|
|
77135
|
-
.sort((left, right) => (right.attack ?? 0) - (left.attack ?? 0) || (right.life ?? 0) - (left.life ?? 0));
|
|
77136
|
-
const character = playableCharacters[0];
|
|
77137
|
-
if (character) {
|
|
77138
|
-
const result = playCardFromHand(game, 'P2', character, {
|
|
77139
|
-
displayName: this.translatedCardText(character).name,
|
|
77140
|
-
});
|
|
77141
|
-
if (result.played) {
|
|
77142
|
-
Object.assign(game, result.game);
|
|
77143
|
-
log.push(...result.log);
|
|
77144
|
-
}
|
|
77145
|
-
}
|
|
77239
|
+
resolveBotPlays(game, log, c => this.translatedCardText(c).name, id => this.cardDefinition(id));
|
|
77146
77240
|
}
|
|
77147
77241
|
resolveBotAttack(game, log, impacts) {
|
|
77148
|
-
|
|
77149
|
-
|
|
77150
|
-
|
|
77151
|
-
.
|
|
77152
|
-
|
|
77153
|
-
if (!attacker) {
|
|
77154
|
-
log.push(this.t('christianityBotNoAttackers'));
|
|
77155
|
-
return;
|
|
77156
|
-
}
|
|
77157
|
-
const target = player.battleZone
|
|
77158
|
-
.filter(card => card.currentHp > 0)
|
|
77159
|
-
.sort((left, right) => left.currentHp - right.currentHp || (left.slot ?? 0) - (right.slot ?? 0))[0];
|
|
77160
|
-
if (target) {
|
|
77161
|
-
impacts.push({ text: `-${attacker.attack}`, tone: 'damage', seat: 'P1', target: 'battle' });
|
|
77162
|
-
impacts.push({ text: `-${target.attack}`, tone: 'damage', seat: 'P2', target: 'battle' });
|
|
77163
|
-
target.currentHp -= attacker.attack;
|
|
77164
|
-
attacker.currentHp -= target.attack;
|
|
77165
|
-
attacker.canAttack = false;
|
|
77166
|
-
log.push(`${attacker.name} ${this.t('christianityCombatsAgainst')} ${target.name}.`);
|
|
77167
|
-
cleanupDestroyed(player, game);
|
|
77168
|
-
cleanupDestroyed(bot, game);
|
|
77169
|
-
return;
|
|
77170
|
-
}
|
|
77171
|
-
impacts.push({ text: `-${attacker.attack}`, tone: 'damage', seat: 'P1', target: 'leader' });
|
|
77172
|
-
player.leaderHp = Math.max(0, player.leaderHp - attacker.attack);
|
|
77173
|
-
attacker.canAttack = false;
|
|
77174
|
-
log.push(`${attacker.name} ${this.t('christianityAttacksYourLeader')}`);
|
|
77242
|
+
resolveBotAttack(game, log, impacts, {
|
|
77243
|
+
botNoAttackers: this.t('christianityBotNoAttackers'),
|
|
77244
|
+
combatsAgainst: this.t('christianityCombatsAgainst'),
|
|
77245
|
+
attacksYourLeader: this.t('christianityAttacksYourLeader'),
|
|
77246
|
+
});
|
|
77175
77247
|
}
|
|
77176
77248
|
ruleMessages() {
|
|
77177
77249
|
return {
|