Implement custom cards in replays

This commit is contained in:
Andrio Celos 2024-02-08 17:23:14 +11:00
parent 7f7563952f
commit 548a3116b2
2 changed files with 77 additions and 15 deletions

View File

@ -16,6 +16,7 @@ class ReplayLoader {
const version = this.readUint8();
const players: Player[] = [ ];
const customCards: Card[] = [ ];
let goalWinCount = null;
switch (version) {
case 1: {
@ -35,7 +36,7 @@ class ReplayLoader {
const initialDrawOrder = [ ];
const drawOrder = [ ];
for (let j = 0; j < 15; j++) {
cards.push(this.readCard());
cards.push(this.readCard(version, customCards));
}
for (let j = 0; j < 2; j++) {
const n = this.readUint8();
@ -69,7 +70,7 @@ class ReplayLoader {
playerData.push({ deck: new Deck("Deck", 0, cards, new Array(15).fill(1)), initialDrawOrder, drawOrder, won: false });
}
const turns = this.readTurns(numPlayers);
const turns = this.readTurns(numPlayers, version, customCards);
currentReplay.games.push({ stage, playerData, turns });
break;
}
@ -91,7 +92,7 @@ class ReplayLoader {
const drawOrder = [ ];
let won = false;
for (let j = 0; j < 15; j++) {
cards.push(this.readCard());
cards.push(this.readCard(version, customCards));
}
for (let j = 0; j < 2; j++) {
const n = this.readUint8();
@ -108,12 +109,12 @@ class ReplayLoader {
}
playerData.push({ deck: new Deck("Deck", 0, cards, new Array(15).fill(1)), initialDrawOrder, drawOrder, won });
}
const turns = this.readTurns(numPlayers);
const turns = this.readTurns(numPlayers, version, customCards);
currentReplay.games.push({ stage, playerData, turns });
}
break;
}
case 3: {
case 3: case 4: {
const n = this.readUint8();
const numPlayers = n & 0x0F;
goalWinCount = n >> 4;
@ -122,6 +123,33 @@ class ReplayLoader {
currentReplay = { gameNumber: 0, decks: [ ], games: [ ], turns: [ ], placements: [ ], watchingPlayer: 0 };
this.readPlayers(numPlayers, players);
// Custom cards
if (version >= 4) {
const numCustomCards = this.read7BitEncodedInt();
for (let i = 0; i < numCustomCards; i++) {
const name = this.readString();
const rarity = <Rarity> this.readUint8();
const specialCost = this.readUint8();
const textScale = this.readFloat();
const inkColour1 = this.readColour();
const inkColour2 = this.readColour();
const grid = [ ];
for (let x = 0; x < 8; x++) {
const row = [ ];
for (let y = 0; y < 8; y += 4) {
const b = this.readUint8();
row.push(<Space> ((b & 0x03) << 2));
row.push(<Space> (b & 0x0c));
row.push(<Space> ((b & 0x30) >> 2));
row.push(<Space> ((b & 0xc0) >> 4));
}
grid.push(row);
}
const card = new Card(RECEIVED_CUSTOM_CARD_START - i, name, textScale, inkColour1, inkColour2, rarity, specialCost, grid);
customCards.push(card);
}
}
// Decks
const decks = [ ];
const numDecks = this.read7BitEncodedInt();
@ -129,7 +157,7 @@ class ReplayLoader {
const name = this.readString();
const sleeves = this.readUint8();
const cards = [ ];
for (let i = 0; i < 15; i++) cards.push(this.readCard());
for (let i = 0; i < 15; i++) cards.push(this.readCard(version, customCards));
const upgrades = [ ];
for (let i = 0; i < 4; i++) {
const b = this.readUint8();
@ -165,7 +193,7 @@ class ReplayLoader {
}
playerData.push({ deck, initialDrawOrder, drawOrder, won });
}
const turns = this.readTurns(numPlayers);
const turns = this.readTurns(numPlayers, version, customCards);
currentReplay.games.push({ stage, playerData, turns });
}
break;
@ -199,6 +227,16 @@ class ReplayLoader {
private readUint8() { return this.dataView.getUint8(this.pos++); }
private readInt8() { return this.dataView.getInt8(this.pos++); }
private readInt16() {
const v = this.dataView.getInt16(this.pos, true);
this.pos += 2;
return v;
}
private readFloat() {
const v = this.dataView.getFloat32(this.pos, true);
this.pos += 4;
return v;
}
private readColour(): Colour { return { r: this.readUint8(), g: this.readUint8(), b: this.readUint8() }; }
private readString(length?: number) {
length ??= this.read7BitEncodedInt();
@ -244,12 +282,12 @@ class ReplayLoader {
}
}
private readTurns(numPlayers: number) {
private readTurns(numPlayers: number, version: number, customCards: Card[]) {
const turns = [ ];
for (let i = 0; i < 12; i++) {
const turn = [ ];
for (let j = 0; j < numPlayers; j++) {
const card = this.readCard();
const card = this.readCard(version, customCards);
const b = this.readUint8();
const x = this.readInt8();
const y = this.readInt8();
@ -265,8 +303,13 @@ class ReplayLoader {
return turns;
}
private readCard() {
const num = this.readUint8();
return cardDatabase.get(num > cardDatabase.lastOfficialCardNumber ? num - 256 : num);
private readCard(version: number, customCards: Card[]) {
if (version >= 4) {
const num = this.readInt16();
return num <= RECEIVED_CUSTOM_CARD_START ? customCards[RECEIVED_CUSTOM_CARD_START - num] : cardDatabase.get(num);
} else {
const num = this.readUint8();
return cardDatabase.get(num > cardDatabase.lastOfficialCardNumber ? num - 256 : num);
}
}
}

View File

@ -643,7 +643,7 @@ public class Game(int maxPlayers) {
}
public void WriteReplayData(Stream stream) {
const int VERSION = 3;
const int VERSION = 4;
if (this.State < GameState.SetEnded)
throw new InvalidOperationException("Can't save a replay until the set has ended.");
@ -669,13 +669,32 @@ public class Game(int maxPlayers) {
writer.Write(nameBytes);
}
// Custom cards
writer.Write7BitEncodedInt(this.customCards.Count);
foreach (var card in this.customCards) {
writer.Write(card.Name);
writer.Write((byte) card.Rarity);
writer.Write((byte) card.SpecialCost);
writer.Write(card.TextScale);
writer.Write((byte) card.InkColour1.GetValueOrDefault().R);
writer.Write((byte) card.InkColour1.GetValueOrDefault().G);
writer.Write((byte) card.InkColour1.GetValueOrDefault().B);
writer.Write((byte) card.InkColour2.GetValueOrDefault().R);
writer.Write((byte) card.InkColour2.GetValueOrDefault().G);
writer.Write((byte) card.InkColour2.GetValueOrDefault().B);
for (var x = 0; x < 8; x++) {
for (var y = 0; y < 8; y += 4)
writer.Write((byte) ((int) card.GetSpace(x, y, 0) >> 2 | (int) card.GetSpace(x, y + 1, 0) | (int) card.GetSpace(x, y + 2, 0) << 2 | (int) card.GetSpace(x, y + 3, 0) << 4));
}
}
// Deck cache
writer.Write7BitEncodedInt(this.deckCache.Count);
foreach (var deck in this.deckCache) {
writer.Write(deck.Name);
writer.Write((byte) deck.Sleeves);
foreach (var card in deck.Cards)
writer.Write((byte) card.Number);
writer.Write((short) card.Number);
int upgradesPacked = 0;
for (var i = 0; i < 15; i++)
@ -699,7 +718,7 @@ public class Game(int maxPlayers) {
for (int j = 0; j < 12; j++) {
foreach (var player in this.Players) {
var move = player.Games[i].turns[j];
writer.Write((byte) move.CardNumber);
writer.Write((short) move.CardNumber);
writer.Write((byte) ((move.Rotation & 3) | (move.IsPass ? 0x80 : 0) | (move.IsSpecialAttack ? 0x40 : 0) | (move.IsTimeout ? 0x20 : 0)));
writer.Write((sbyte) move.X);
writer.Write((sbyte) move.Y);