homicide is now real

This commit is contained in:
Hexugory 2023-03-30 17:48:40 -05:00
parent 50321d04b2
commit 47da949b6d
4 changed files with 100 additions and 22 deletions

View File

@ -1,8 +1,14 @@
import { Message, TextChannel } from "discord.js";
import { Character, CHARACTERS, PotencyStatus, Target } from "./characters";
import { Message, TextBasedChannel } from "discord.js";
import { Character, CHARACTERS, Effect, PotencyStatus, Target } from "./characters";
import { Player } from "./models/player";
import { Unit } from "./models/unit";
export enum BattleState {
Ongoing,
Team1Win,
Team2Win
}
interface StatusEffects {
poison: number
regeneration: number
@ -15,6 +21,7 @@ interface PotencyEffects {
resistanceChange: PotencyStatus[]
accuracyChange: PotencyStatus[]
speedChange: PotencyStatus[]
damageChange: PotencyStatus[]
}
class BattleUnit {
@ -41,13 +48,14 @@ class BattleUnit {
potencyEffects: PotencyEffects = {
resistanceChange: [],
accuracyChange: [],
speedChange: []
speedChange: [],
damageChange: []
}
active = true
}
export class Battle {
constructor (channel: TextChannel, player1: Player, player2: Player, team1: [Unit, Unit, Unit], team2: [Unit, Unit, Unit]) {
constructor (channel: TextBasedChannel, player1: Player, player2: Player, team1: [Unit, Unit, Unit], team2: [Unit, Unit, Unit]) {
this.channel = channel;
this.player1 = player1;
this.player2 = player2;
@ -56,9 +64,15 @@ export class Battle {
this.units = this.team1.concat(this.team2) as [BattleUnit, BattleUnit, BattleUnit, BattleUnit, BattleUnit, BattleUnit];
}
simulateRound () {
simulateRound (): BattleState {
this.log = '';
this.tickStatuses(this.units);
this.checkAlive(this.units);
this.useSkills(this.units);
if (!this.team1.filter(e => {return e.active})[0]) return BattleState.Team2Win;
else if (!this.team2.filter(e => {return e.active})[0]) return BattleState.Team1Win;
else return BattleState.Ongoing;
}
tickStatuses (units: BattleUnit[]) {
@ -94,7 +108,7 @@ export class Battle {
for (let i = 0; i < units.length; i++) {
const rolls = []
let modifiedSpeed = units[i].speed
for (const change of units[i].potencyEffects.accuracyChange) {
for (const change of units[i].potencyEffects.speedChange) {
modifiedSpeed -= change.potency;
}
for (let o = 0; o < modifiedSpeed; o++) {
@ -106,8 +120,12 @@ export class Battle {
order.sort((a, b) => {return b[1] - a[1]});
console.debug(order);
for (const initiative of order) {
const unit = units[initiative[1]];
const unit = units[initiative[0]];
if (!unit.active) continue;
const skill = unit.character.skills[Math.floor(Math.random()*unit.character.skills.length)];
const team = initiative[0] < 3 ? 1 : 2
const target = team === 1 ? this.team2[Math.floor(Math.random()*this.team2.length)] : this.team1[Math.floor(Math.random()*this.team1.length)];
@ -121,35 +139,52 @@ export class Battle {
for (const effect of skill.effects) {
switch (effect.target){
case Target.Self:
this.runEffect([unit]);
this.runEffect(effect, unit, [unit]);
break;
case Target.Team:
this.runEffect(team === 1 ? this.team1 : this.team2);
this.runEffect(effect, unit, team === 1 ? this.team1 : this.team2);
break;
case Target.OneTeammate:
this.runEffect([allyTarget]);
this.runEffect(effect, unit, [allyTarget]);
break;
case Target.OneOpponent:
this.runEffect([target]);
this.runEffect(effect, unit, [target]);
break;
case Target.AllOpponents:
this.runEffect(team === 1 ? this.team2 : this.team1);
this.runEffect(effect, unit, team === 1 ? this.team2 : this.team1);
break;
case Target.TrueRandomOpponent:
this.runEffect([team === 1 ? this.team2[Math.floor(Math.random()*this.team2.length)] : this.team1[Math.floor(Math.random()*this.team1.length)]]);
this.runEffect(effect, unit, [team === 1 ? this.team2[Math.floor(Math.random()*this.team2.length)] : this.team1[Math.floor(Math.random()*this.team1.length)]]);
break;
}
}
this.checkAlive(this.units);
}
}
runEffect (effect: Effect, self: BattleUnit, targets: BattleUnit[]) {
if (effect.damage) {
for (const target of targets) {
let damage = effect.damage;
for (const statChange of self.potencyEffects.damageChange) {
Math.round(damage *= 1+(statChange.potency/100));
}
for (const statChange of target.potencyEffects.resistanceChange) {
Math.round(damage *= 1-(statChange.potency/100));
}
this.appendLog(`${target.character.nameShort} took ${damage} damage!`);
target.health -= damage;
}
}
}
runEffect (targets: BattleUnit[]) {
}
checkAlive (units: BattleUnit[]) {
for (const unit of units) {
if (unit.health <= 0) unit.active = false;
if (!unit.active) continue;
console.debug(unit.health);
if (unit.health > 0) continue;
unit.active = false;
this.appendLog(`${unit.character.nameShort} has been defeated!`);
}
}
@ -157,13 +192,14 @@ export class Battle {
appendLog (str: string) {
if (this.log) this.log += '\n';
this.log += str;
console.debug(str);
return this.log;
}
message?: Message
log = ""
channel: TextChannel
channel: TextBasedChannel
player1: Player
player2: Player
team1: [BattleUnit, BattleUnit, BattleUnit]

View File

@ -34,16 +34,17 @@ const Effect = z.object({
resistanceChange: z.optional(PotencyStatus),
accuracyChange: z.optional(PotencyStatus),
speedChange: z.optional(PotencyStatus),
damageChange: z.optional(PotencyStatus),
function: z.optional(z.string())
}).strict();
type Effect = z.infer<typeof Effect>;
export type Effect = z.infer<typeof Effect>;
const Skill = z.object({
name: z.string(),
accuracy: z.optional(z.number().int()),
effects: z.array(Effect)
}).strict();
type Skill = z.infer<typeof Skill>;
export type Skill = z.infer<typeof Skill>;
const Character = z.object({
id: z.number().int(),

39
src/slash/battletest.ts Normal file
View File

@ -0,0 +1,39 @@
import { ApplicationCommandOptionData, ApplicationCommandOptionType, CommandInteraction } from "discord.js"
import { Battle, BattleState } from "../battle"
import { CBClient } from "../cbclient"
import { CHARACTERS } from "../characters"
import { Player } from "../models/player"
import { Unit } from "../models/unit"
import { createArgumentsObject, SlashCommand } from "./slash"
export class BattleTestCommand implements SlashCommand {
name = 'battletest'
description = 'shhh'
permission = []
ownerOnly = false
guildOnly = false
guildID = "739645806100873328" //for testing
args: ApplicationCommandOptionData[] = []
async execute(int: CommandInteraction) {
const client = int.client as CBClient;
const you = await client.findOrCreatePlayer(int.user.id);
const units = (await Unit.findAll());
const battle = new Battle(int.channel!, you, you, units.slice(0, 3) as [Unit, Unit, Unit], units.slice(3, 6) as [Unit, Unit, Unit]);
await int.reply({
content: 'gottem'
});
let state: BattleState = BattleState.Ongoing;
while (state === BattleState.Ongoing) {
state = battle.simulateRound();
await int.channel?.send(battle.log);
}
switch (state) {
case BattleState.Team1Win:
return await int.channel?.send('gamer 1 wins');
case BattleState.Team2Win:
return await int.channel?.send('gamer 2 wins');
}
}
};

View File

@ -1,3 +1,4 @@
import { BattleTestCommand } from "./battletest";
import { InitCommand } from "./init";
import { RandomCaseCommand } from "./randomcase";
import { RollCommand } from "./roll";
@ -6,5 +7,6 @@ import { SlashCommand } from "./slash";
export const SlashCommandList: SlashCommand[] = [
new RandomCaseCommand(),
new InitCommand(),
new RollCommand()
new RollCommand(),
new BattleTestCommand()
];