aaaaaaaaaaaaaaaaaa
This commit is contained in:
@ -12,6 +12,7 @@ export class Game {
|
||||
this.us = null;
|
||||
this.players = {};
|
||||
this.state = WAITING;
|
||||
this.contendedRegion = null;
|
||||
|
||||
this.allPlaced = false;
|
||||
}
|
||||
|
@ -165,6 +165,11 @@ document.addEventListener("ACT", async (ev) => {
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("RESOLVE", (ev) => {
|
||||
const data = ev.detail;
|
||||
game.contendedRegion.handleResolve(data);
|
||||
});
|
||||
|
||||
// todo has to filter by player
|
||||
document.addEventListener("PROOF", async (ev) => {
|
||||
const data = ev.detail;
|
||||
|
@ -113,6 +113,10 @@ export class Region {
|
||||
this.neighbours = new Set();
|
||||
this.continent = continent;
|
||||
|
||||
this.attackResolver = null;
|
||||
this.attackerRes = null;
|
||||
this.defenderRes = null;
|
||||
|
||||
REGIONS[name] = this;
|
||||
}
|
||||
|
||||
@ -172,6 +176,48 @@ export class Region {
|
||||
verify(plainText, a) {
|
||||
this.strength.verify(this.name, plainText, a);
|
||||
}
|
||||
|
||||
async handleResolve(resolution) {
|
||||
await navigator.locks.request(`region-${this.name}`, () => {
|
||||
if (resolution.author === this.owner.id) {
|
||||
this.defenderRes = resolution;
|
||||
} else {
|
||||
this.attackerRes = resolution;
|
||||
}
|
||||
|
||||
if (
|
||||
this.attackResolver !== null &&
|
||||
this.defenderRes !== null &&
|
||||
this.attackerRes !== null
|
||||
) {
|
||||
this.attackResolver({
|
||||
attackerRes: this.attackerRes,
|
||||
defenderRes: this.defenderRes,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async resolveAttack() {
|
||||
let promise;
|
||||
await navigator.locks.request(`region-${this.name}`, () => {
|
||||
if (this.attackerRes === null || this.defenderRes === null) {
|
||||
let resolver;
|
||||
promise = new Promise((resolve) => {
|
||||
resolver = resolve;
|
||||
});
|
||||
this.attackResolver = resolver;
|
||||
} else {
|
||||
promise = new Promise((resolve) => {
|
||||
resolve({
|
||||
attackerRes: this.attackerRes,
|
||||
defenderRes: this.defenderRes,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
window.Region = Region;
|
||||
|
@ -161,4 +161,28 @@ export class Packet {
|
||||
region: region,
|
||||
});
|
||||
}
|
||||
|
||||
static createRegionProof(proof) {
|
||||
return this._sign({
|
||||
...this._createBase("RESOLVE"),
|
||||
action: "MAINTAIN",
|
||||
proof: proof,
|
||||
});
|
||||
}
|
||||
|
||||
static createRegionYield() {
|
||||
return this._sign({
|
||||
...this._createBase("RESOLVE"),
|
||||
action: "YIELD",
|
||||
proof: proof,
|
||||
});
|
||||
}
|
||||
|
||||
static createRegionCapture(cipherText) {
|
||||
return this._sign({
|
||||
...this._createBase("RESOLVE"),
|
||||
action: "CAPTURE",
|
||||
cipherText: cipherText,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import { PaillierPubKey, ReadOnlyCiphertext } from "../crypto/paillier.js";
|
||||
import { Region } from "./map.js";
|
||||
import { showDefenseDom } from "./dom.js";
|
||||
import {
|
||||
proveBitLength,
|
||||
proveFortify,
|
||||
proveRange,
|
||||
proveRegions,
|
||||
@ -325,6 +326,8 @@ export class Player {
|
||||
return false;
|
||||
}
|
||||
|
||||
game.contendedRegion = defender;
|
||||
|
||||
// If we're the defender, we need to send a packet to state our defense.
|
||||
if (defender.owner === game.us) {
|
||||
showDefenseDom(defender.name);
|
||||
@ -340,8 +343,6 @@ export class Player {
|
||||
defenderStrength = await defender.owner.getDefense();
|
||||
}
|
||||
|
||||
console.log(defenderStrength);
|
||||
|
||||
/* How do Risk attacks work?
|
||||
- Offender signs 1-3 armies, defender signs 1-2 armies
|
||||
- Both roll respective dice
|
||||
@ -387,10 +388,16 @@ export class Player {
|
||||
// Handle aftermath.
|
||||
if (defender.owner === game.us) {
|
||||
if (defender.strength.cipherText.plainText === 0n) {
|
||||
// Handle region loss
|
||||
// State we don't control the region. This makes programming easier.
|
||||
socket.emit("message", Packet.createRegionYield());
|
||||
} else {
|
||||
let ct = defender.strength.cipherText.clone();
|
||||
ct.update(new Ciphertext(ct.pubKey, -2n, 0n));
|
||||
// Prove we still control the region
|
||||
let proof = proveRange(defender.strength.cipherText, 2n ** 32n);
|
||||
let proof = proveBitLength(ct);
|
||||
|
||||
// Send proof we maintain it
|
||||
socket.emit("message", Packet.createRegionProof(proof));
|
||||
}
|
||||
} else if (this === game.us) {
|
||||
if (defender.strength.assumedStrength === 0n) {
|
||||
@ -400,14 +407,29 @@ export class Player {
|
||||
new Ciphertext(this.paillierPubKey, offenderRolls.length + 1),
|
||||
defender.name
|
||||
);
|
||||
|
||||
// Send the new ciphertext
|
||||
socket.emit(
|
||||
"message",
|
||||
Packet.createRegionCapture(defender.strength.cipherText)
|
||||
);
|
||||
} else {
|
||||
// State we didn't capture. Again, makes programming easier.
|
||||
socket.emit("message", Packet.createRegionYield());
|
||||
}
|
||||
} else {
|
||||
await defender.resolveConflict();
|
||||
let resolutions = await defender.resolveAttack();
|
||||
|
||||
console.log(resolutions);
|
||||
}
|
||||
|
||||
// Reset the promises in case they attack again.
|
||||
defender.owner.defenderPromise = null;
|
||||
defender.owner.defenderAmount = null;
|
||||
defender.defenderRes = null;
|
||||
defender.attackerRes = null;
|
||||
defender.attackResolver = null;
|
||||
game.contendedRegion = null;
|
||||
}
|
||||
|
||||
async setDefense(amount) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { cryptoRandom } from "../crypto/random_primes.js";
|
||||
import { Region } from "./map.js";
|
||||
|
||||
const ROUNDS = 24;
|
||||
const ROUNDS = 12;
|
||||
|
||||
function cryptoRange(upper) {
|
||||
// This is ridiculous: why implement a BigInt primitive, have it behave like a number, and then _not_ offer
|
||||
|
Reference in New Issue
Block a user