Skip to content

Commit

Permalink
Fix multi step timings
Browse files Browse the repository at this point in the history
  • Loading branch information
krypciak committed Oct 19, 2023
1 parent 5664209 commit 1d2672f
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 94 deletions.
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 14 additions & 7 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,12 @@ import { PuzzleBeeper } from './puzzle'
import { LoudWalls } from './loudwalls'
import { SoundManager } from './sound-manager'

function addVimBindings() {
if (window.vim) { /* optional dependency https://github.com/krypciak/cc-vim */
}
}

export default class CrossedEyes {
dir: string
mod: Mod1

puzzleBeeper!: PuzzleBeeper

constructor(mod: Mod1) {
this.dir = mod.baseDirectory
this.mod = mod
Expand All @@ -23,15 +20,25 @@ export default class CrossedEyes {
}

async prestart() {
addVimBindings()
this.addVimAliases()
MenuOptions.initPrestart()
SoundManager.preloadSounds()
new SpacialAudio().initSpacialAudio()
new LoudWalls().initLoudWalls()
new PuzzleBeeper().initPrestart()

this.puzzleBeeper = new PuzzleBeeper()
this.puzzleBeeper.initPrestart()
}

async poststart() {
MenuOptions.initPoststart()
}

addVimAliases() {
if (window.vim) { /* optional dependency https://github.com/krypciak/cc-vim */
vim.addAlias('crossedeyes', 'reset-puzzle', 'Reset puzzle step index', (ingame: boolean) => ingame && blitzkrieg.currSel.name == 'puzzle', () => {
this.puzzleBeeper.stepI = 0
})
}
}
}
197 changes: 125 additions & 72 deletions src/puzzle.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import type * as _ from 'cc-blitzkrieg'
import { MenuOptions } from './options'
import { mapNumber } from './spacial-audio'
import { PuzzleSelection, PuzzleSelectionStep } from 'cc-blitzkrieg/types/puzzle-selection'
import type { PuzzleSelection, PuzzleSelectionStep } from 'cc-blitzkrieg/types/puzzle-selection'
import { SoundManager } from './sound-manager'

function isAiming(): boolean {
return ig.input.state('aim') || ig.gamepad.isRightStickDown()
}

class AimHandler {
constructor(public pb: PuzzleBeeper) {}

puzzleStartTime!: number

farAwayFreq: number = 1300
maxFreq: number = 0

lastBeepTime: number = 0
shootSoundPlayed: boolean = false

minDegDistToSpeedup: number = 110
lockInDegDist: number = 10
Expand All @@ -30,79 +37,106 @@ class AimHandler {
}
}
})
ig.ENTITY.Player.inject({
update() {
this.parent()
if (self.lockedIn && sc.control.thrown()) {
self.lockedIn = false
self.pb.stepI++
}
}
})
}

handleAim(step: PuzzleSelectionStep) {
if (!ig.game || !ig.game.playerEntity || !this.pb.moveToHandler.lockedIn || !MenuOptions.puzzleEnabled) { return }
if (!this.pb.moveToHandler.lockedIn) { this.lockedIn = false; return }
if (!ig.game || !ig.game.playerEntity || !MenuOptions.puzzleEnabled) { return }

const nowt: number = sc.stats.getMap('player', 'playtime') * 1000

if (this.lockedIn) {
if (sc.control.thrown()) {
this.lockedIn = false
this.pb.moveToHandler.lockedIn = false
this.pb.stepI++
if (this.pb.stepI == 1) {
this.puzzleStartTime = nowt
}
return
}
const wait = 200
if (! this.shootSoundPlayed) {
const lastStep = this.pb.currentSel.data.recordLog!.steps[this.pb.stepI - 1]
let play: boolean = false
if (lastStep && !lastStep.split) {
const realDiffTime = Math.round((nowt - this.puzzleStartTime) * sc.options.get('assist-puzzle-speed'))
const diff = realDiffTime - step.endFrame
// console.log(diff, step.endFrame, realDiffTime)
if (diff > -wait) {
play = true
}
} else { play = true }

if (!this.shootSoundPlayed && play) {
this.shootSoundPlayed = true

SoundManager.appendQueue([
{ wait, name: 'hitCounterEcho', speed: 1.1, condition: () => this.lockedIn },
])
}
}
} else {
this.shootSoundPlayed = false
}


if (! step || ! step.pos) { return }
const targetDeg = step.shootAngle
const targetDeg = (step.shootAngle! + 360) % 360
if (! targetDeg) { return }

const r: number = 15
const theta: number = targetDeg * (Math.PI / 180)

this.newAim = Vec2.createC(
r * Math.cos(theta),
r * Math.sin(theta),
)
this.newAim = Vec2.createC(r * Math.cos(theta), r * Math.sin(theta))


const aiming: boolean = ig.input.state('aim') || ig.gamepad.isRightStickDown()
if (! aiming) {
if (! isAiming()) {
this.lockedIn = false
return
}
if (!ig.game || !ig.game.playerEntity || !MenuOptions.puzzleEnabled) { return }
const deg = ig.game.playerEntity.aimDegrees /* set by cc-blitzkrieg */
const deg = (ig.game.playerEntity.aimDegrees + 360) % 360 /* set by cc-blitzkrieg */
if (! deg) { return }

const dist: number = /* distance between target and current aim */
Math.min(Math.abs(deg - targetDeg),
Math.abs(360 - deg - targetDeg))
const dist: number = Math.min(
Math.abs(deg - targetDeg),
360 - Math.abs(deg - targetDeg)
) /* distance between target and current aim */

if (dist <= this.lockInDegDist) {
if (! this.lockedIn) {
this.lockedIn = true
this.normalBeepSlience = true
SoundManager.playSoundQueue([
{ name: 'countdown1', relativePos: true, pos: this.newAim, wait: 200 },
{ name: 'countdown2', relativePos: true, pos: this.newAim, wait: 100 },
{ name: SoundManager.getElementName(step.element), speed: 1.2,
condition: () => step.element !== sc.model.player.currentElementMode,
SoundManager.appendQueue([
{ name: 'countdown1', relativePos: true, pos: this.newAim },
{ wait: 200, name: 'countdown2', relativePos: true, pos: this.newAim },
{ wait: 100, name: SoundManager.getElementName(step.element), speed: 1.2,
condition: () => isAiming() && step.element !== sc.model.player.currentElementMode,
action: () => {
this.normalBeepSlience = false
this.lastBeepTime = Date.now()
this.lastBeepTime = ig.game.now
},
},
])
}
} else if (this.lockedIn) {
this.lockedIn = false
this.normalBeepSlience = true
SoundManager.playSoundQueue([
{ name: 'countdown2', relativePos: true, pos: this.newAim, wait: 200 },
{ name: 'countdown2', relativePos: true, pos: this.newAim,

SoundManager.clearQueue()
SoundManager.appendQueue([
{ name: 'countdown2', relativePos: true, pos: this.newAim },
{ wait: 200, name: 'countdown1', relativePos: true, pos: this.newAim,
action: () => {
this.normalBeepSlience = false
this.lastBeepTime = Date.now()
this.lastBeepTime = ig.game.now
}},
])
return
}
if (this.lockedIn || this.normalBeepSlience) { return }

const now: number = Date.now()
const timeDiff = now - this.lastBeepTime
const timeDiff = nowt - this.lastBeepTime
const time: number = dist >= this.minDegDistToSpeedup ? this.farAwayFreq :
Math.max(
mapNumber(deg, targetDeg - this.minDegDistToSpeedup, targetDeg, this.farAwayFreq, this.maxFreq),
Expand All @@ -111,7 +145,7 @@ class AimHandler {
if (timeDiff >= time) {
const speed: number = 1
SoundManager.playSoundAtRelative('computerBeep', speed, this.newAim)
this.lastBeepTime = now
this.lastBeepTime = nowt
}
}
}
Expand All @@ -123,13 +157,15 @@ class MoveToHandler {
maxFreq: number = 0

lastBeepTime: number = 0
normalBeepSlience: boolean = false

minDistToSpeedup: number = 8 * 16
lockInDist: number = 2 * 16
lockinDist: number = 2 * 16
relockDist: number = 0.5 * 16

lockedIn: boolean = false
normalBeepSlience: boolean = false
freezePlayer: boolean = false
softLockout: boolean = false
allowRelock: boolean = false

handleMoveTo(step: PuzzleSelectionStep) {
const pos: Vec3 & { level: number } = step.pos
Expand All @@ -138,50 +174,66 @@ class MoveToHandler {
const dist: number = Vec3.distance(pos, playerPos)

const self = this
if (dist <= this.lockInDist) {
if (! this.lockedIn) {
this.lockedIn = true
ig.game.playerEntity.setPos(pos.x, pos.y, pos.z)
this.normalBeepSlience = true
SoundManager.playSound('countdown1', 1.2, pos)
ig.game.playerEntity.coll.vel = Vec3.create()
sc.model.player.setCore(sc.PLAYER_CORE.MOVE, false)


SoundManager.playSoundQueue([
{ name: 'countdown1', pos, speed: 1.2, wait: 150 },
{ name: 'countdown2', pos, speed: 1.2,
action() {
self.normalBeepSlience = false
self.lastBeepTime = Date.now()
},},
])
setTimeout(() => sc.model.player.setCore(sc.PLAYER_CORE.MOVE, true), 1000)
let lockout: boolean = false
if (dist <= this.lockinDist && pos.z == playerPos.z) {
Vec3.add(playerPos, ig.game.playerEntity.coll.vel)
const distWithVel: number = Vec3.distance(pos, playerPos)
if (! this.softLockout || distWithVel <= this.relockDist) {
if (! this.lockedIn) {
this.lockedIn = true
this.softLockout = false

ig.game.playerEntity.setPos(pos.x, pos.y, pos.z)
ig.game.playerEntity.coll.vel = Vec3.create()
sc.model.player.setCore(sc.PLAYER_CORE.MOVE, false)
setTimeout(() => sc.model.player.setCore(sc.PLAYER_CORE.MOVE, true), 700)

this.normalBeepSlience = true
SoundManager.appendQueue([
{ name: 'countdown1', pos, speed: 1.2, },
{ wait: 150, name: 'countdown2', pos, speed: 1.2,
action() {
self.normalBeepSlience = false
self.lastBeepTime = ig.game.now
},},
])
return
} else if (dist !== 0) {
lockout = true
this.softLockout = true
}
}
} else if (this.lockedIn) {
} else {
if (this.lockedIn) {
lockout = true
}
this.softLockout = false
}
if (lockout) {
this.lockedIn = false
this.normalBeepSlience = true

SoundManager.playSoundQueue([
{ name: 'countdown2', pos, speed: 1.2, wait: 150 },
{ name: 'countdown1', pos, speed: 1.2, action: () => {
SoundManager.appendQueue([
{ name: 'countdown2', pos, speed: 1.2 },
{ wait: 150, name: 'countdown1', pos, speed: 1.2, action: () => {
this.normalBeepSlience = false
this.lastBeepTime = Date.now()
this.lastBeepTime = ig.game.now
}},
])
return
}
if (this.lockedIn || this.normalBeepSlience) { return }
if (this.lockedIn) { return }
if (this.normalBeepSlience) { return }

const now: number = Date.now()
const timeDiff = now - this.lastBeepTime
const nowt: number = ig.game.now
const timeDiff = nowt - this.lastBeepTime
const time: number = dist >= this.minDistToSpeedup ? this.farAwayFreq :
mapNumber(dist, this.minDistToSpeedup, 0, this.farAwayFreq, this.maxFreq)

if (timeDiff >= time) {
const speed: number = 1
SoundManager.playSound('trainCudeHide', speed, pos)
this.lastBeepTime = now
this.lastBeepTime = nowt
}
}
}
Expand Down Expand Up @@ -213,17 +265,18 @@ export class PuzzleBeeper {
self.currentSel = sel
self.stepI = 0
if (self.currentSel.data.completionType === blitzkrieg.PuzzleCompletionType.Normal) {
self.cachedSolution = blitzkrieg.PuzzleSelectionManager.getPuzzleSolveCondition(sel) as keyof ig.KnownVars
self.cachedSolution = blitzkrieg.PuzzleSelectionManager.getPuzzleSolveCondition(sel).substring(1) as keyof ig.KnownVars
}
}
switch (self.currentSel.data.completionType) {
case blitzkrieg.PuzzleCompletionType.Normal: {
if (ig.vars.get(self.cachedSolution!)) {
if (self.stepI > 0) {
SoundManager.playSoundQueue([
{ name: 'botSuccess', wait: 150 },
{ name: 'counter', wait: 20 },
{ name: 'botSuccess' },
SoundManager.clearQueue()
SoundManager.appendQueue([
{ name: 'botSuccess' },
{ wait: 20, name: 'counter' },
{ wait: 150, name: 'botSuccess' },
])
self.stepI = 0
}
Expand Down
Loading

0 comments on commit 1d2672f

Please sign in to comment.