snapkitty
hardware
erlang
File size: 3,475 Bytes
b8a03fa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import { clamp } from './deterministic.js';
import { emitWorldEvent, findRequired } from './state-utils.js';
import type { CommandResult, EntityId, UniverseState } from './types.js';

export class FactionSystem {
  constructor(private state: UniverseState) {}

  replaceState(state: UniverseState): void {
    this.state = state;
  }

  changePlayerReputation(factionId: EntityId, delta: number, reason: string): CommandResult {
    const faction = findRequired(this.state.factions, factionId, 'Faction');
    const previous = this.state.player.factionReputation[faction.id] ?? 0;
    const next = clamp(previous + delta, -100, 100);
    this.state.player.factionReputation[faction.id] = next;
    const event = emitWorldEvent(this.state, 'faction-reputation-changed', faction.id, this.state.player.id, `${faction.name} reputation changed by ${delta}: ${reason}`, { data: { previous, next, delta } });
    return { ok: true, message: event.summary, eventIds: [event.id] };
  }

  setRelation(firstFactionId: EntityId, secondFactionId: EntityId, value: number, reason: string): CommandResult {
    if (firstFactionId === secondFactionId) return { ok: false, message: 'A faction cannot set a relation with itself.', eventIds: [] };
    const first = findRequired(this.state.factions, firstFactionId, 'Faction');
    const second = findRequired(this.state.factions, secondFactionId, 'Faction');
    const normalized = clamp(value, -100, 100);
    first.relations[second.id] = normalized;
    second.relations[first.id] = normalized;
    const event = emitWorldEvent(this.state, normalized >= 25 ? 'faction-agreement' : 'faction-relation-changed', first.id, second.id, `${first.name} and ${second.name} relation set to ${normalized}: ${reason}`, { data: { value: normalized } });
    return { ok: true, message: event.summary, eventIds: [event.id] };
  }

  declareConflict(firstFactionId: EntityId, secondFactionId: EntityId, reason: string): CommandResult {
    const first = findRequired(this.state.factions, firstFactionId, 'Faction');
    const second = findRequired(this.state.factions, secondFactionId, 'Faction');
    if (!first.activeConflictIds.includes(second.id)) first.activeConflictIds.push(second.id);
    if (!second.activeConflictIds.includes(first.id)) second.activeConflictIds.push(first.id);
    first.relations[second.id] = -80;
    second.relations[first.id] = -80;
    const event = emitWorldEvent(this.state, 'faction-conflict-declared', first.id, second.id, `${first.name} entered conflict with ${second.name}: ${reason}`, { severity: 0.8 });
    return { ok: true, message: event.summary, eventIds: [event.id] };
  }

  sanction(factionId: EntityId, targetId: EntityId, active: boolean): CommandResult {
    const faction = findRequired(this.state.factions, factionId, 'Faction');
    faction.sanctions = active ? [...new Set([...faction.sanctions, targetId])] : faction.sanctions.filter((id) => id !== targetId);
    for (const market of this.state.economy.markets.filter((candidate) => candidate.factionId === faction.id)) {
      market.sanctions = active ? [...new Set([...market.sanctions, targetId])] : market.sanctions.filter((id) => id !== targetId);
    }
    const event = emitWorldEvent(this.state, active ? 'faction-sanction-imposed' : 'faction-sanction-lifted', faction.id, targetId, `${faction.name} ${active ? 'imposed' : 'lifted'} sanctions on ${targetId}.`);
    return { ok: true, message: event.summary, eventIds: [event.id] };
  }
}