Skip to content

Commit

Permalink
merge: cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
chase-moskal committed Apr 20, 2024
2 parents f903886 + fd31acd commit 77b851f
Show file tree
Hide file tree
Showing 19 changed files with 485 additions and 382 deletions.
12 changes: 11 additions & 1 deletion s/dom/elements/benev-humanoid/menus/notes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ export const NotesMenu = nexus.shadow_view(use => (game: Game) => {
<hr/>
<section>
<h1>
<span>cleanups, fixes, refinements.</span>
<small>2024-04-20</small>
</h1>
<p>fixed onehanded combos. disabled stabs from combos due to an animation bug.</p>
<p>re-enabled turncaps. stamina is still temporarily disabled.</p>
</section>
<section>
<h1>
<span>rewrote the combat code.</span>
Expand All @@ -76,11 +85,12 @@ export const NotesMenu = nexus.shadow_view(use => (game: Game) => {
<p>this work is surprisingly tricky..</p>
<p>we now have <strong>combos</strong>. you can spam-click, or just hold the attack button. combos take less time than a full recovery/windup.</p>
<p>we also now have <strong>feints</strong>. press the parry button during an attack's windup.</p>
<p>movement speed has been dialed back a bit.</p>
</section>
<section>
<h1>
<span>the berserkers provide feedback.</span>
<span>the berserkers have arrived.</span>
<small>2024-04-19</small>
</h1>
<p>since our last update, we invited a small gang of high level chivalry and mordhau players to playtest this prototype. we had a lot of fun doing screenshares and chatting about game design. in the discord they have the <code>berserkers</code> role.</p>
Expand Down
21 changes: 3 additions & 18 deletions s/dom/elements/benev-humanoid/views/reticle/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,22 +60,17 @@ export const Reticle = nexus.shadow_view(use => (game: Game, menus: Menus) => {
color: white;
z-index: 1;
}
.angle.lock > svg {
transform: translate(0, -0.6em);
}
`)

const {enabled, size, opacity, data} = game.ui.reticle
const activity = data?.activity
const meleeAim = data?.meleeAim

const {mode, angleAlpha, angleBravo, angleLock} = (() => {
const {mode, angleAlpha, angleLock} = (() => {
const angle = meleeAim?.angle ?? null
if (activity?.kind === "equip") {
return {
angleAlpha: null,
angleBravo: null,
angleLock: null,
mode: "plain",
}
Expand All @@ -84,19 +79,16 @@ export const Reticle = nexus.shadow_view(use => (game: Game, menus: Menus) => {
const {protective} = new ParryReport(activity)
return {
angleAlpha: null,
angleBravo: null,
angleLock: null,
mode: protective
? "parry-protective"
: "parry"
}
}
else if (activity?.kind === "melee") {
const {activeManeuver} = meleeReport(activity)
const a = angle ?? 0
const {logicalSnapshot: activeManeuver} = meleeReport(activity)
return {
angleAlpha: a,
angleBravo: null,
angleAlpha: null,
angleLock: activeManeuver.next?.maneuver.angle
?? activeManeuver.chart.maneuver.angle,
mode: activeManeuver.phase === "release"
Expand All @@ -107,7 +99,6 @@ export const Reticle = nexus.shadow_view(use => (game: Game, menus: Menus) => {
return {
mode: "plain",
angleAlpha: angle,
angleBravo: null,
angleLock: null,
}
})()
Expand All @@ -117,7 +108,6 @@ export const Reticle = nexus.shadow_view(use => (game: Game, menus: Menus) => {
: `opacity: 0;`

const angleAlphaStyle = stylize(angleAlpha)
const angleBravoStyle = stylize(angleBravo)
const angleLockStyle = stylize(angleLock)

return enabled ? html`
Expand All @@ -134,11 +124,6 @@ export const Reticle = nexus.shadow_view(use => (game: Game, menus: Menus) => {
style="${angleAlphaStyle}">
${icon_tabler_chevron_up}
</div>
<div
class="angle bravo graphic"
style="${angleBravoStyle}">
${icon_tabler_chevron_up}
</div>
<div
class="angle lock graphic"
style="${angleLockStyle}">
Expand Down
98 changes: 43 additions & 55 deletions s/ecs/logic/combat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,11 @@ import {Controllable, Intent} from "../components/plain_components.js"
import {standardEquipDuration} from "../../models/activity/standards.js"
import {InventoryManager} from "../../models/armory/inventory-manager.js"
import {meleeReport} from "../../models/activity/reports/melee/melee-report.js"
import {ManeuverQuery} from "../../models/activity/reports/melee/parts/types.js"
import {isComboReady} from "../../models/activity/reports/melee/parts/is-combo-ready.js"
import {isMeleeReport, makeActivityReport} from "../../models/activity/utils/make-activity-report.js"
import {canComboFromStab, canComboFromSwing, canComboToStab, canComboToSwing, minimumFeint} from "../../models/activity/reports/melee/constants.js"
import {Inventory, ActivityComponent, MeleeAim, MeleeIntent, ProtectiveBubble, NextActivity} from "../components/topics/warrior.js"

const isSwingComboable = true
const isStabComboable = false
const comboableReleaseThreshold = 2 / 3
const minimumFeint = 0

export function isComboReady({phase, phaseProgress, chart, next}: ManeuverQuery) {
const {comboable} = chart.maneuver
return (
comboable &&
next === null &&
phase === "release" &&
phaseProgress >= comboableReleaseThreshold
)
}

export const combat = system("combat", ({realm}) => [

system("intentions", () => [
Expand Down Expand Up @@ -68,6 +54,15 @@ export const combat = system("combat", ({realm}) => [
meleeAim.angle = scalar.clamp(glanceAngle, ...zone)
}),

behavior("launch queued activity")
.select({ActivityComponent, NextActivity})
.logic(() => ({components}) => {
if (!components.activityComponent && components.nextActivity) {
components.activityComponent = components.nextActivity
components.nextActivity = null
}
}),

behavior("initiate activity")
.select({MeleeAim, MeleeIntent, Inventory, ActivityComponent, NextActivity})
.logic(() => ({components}) => {
Expand All @@ -83,11 +78,12 @@ export const combat = system("combat", ({realm}) => [
const next = activity()
const invalid = (
isMeleeReport(report) &&
report.predicament.procedure === "feint" &&
report.flow.procedure === "feint" &&
next.kind === "parry"
)
if (!invalid)
if (!invalid) {
components.nextActivity = next
}
}
}
else {
Expand All @@ -111,7 +107,7 @@ export const combat = system("combat", ({realm}) => [
applyActivity(() => ({
kind: "melee",
weapon,
maneuvers: [{technique: "swing", comboable: isSwingComboable, angle}],
maneuvers: [{technique: "swing", comboable: canComboFromSwing, angle}],
seconds: 0,
cancelled: null,
}))
Expand All @@ -121,7 +117,7 @@ export const combat = system("combat", ({realm}) => [
applyActivity(() => ({
kind: "melee",
weapon,
maneuvers: [{technique: "stab", comboable: isStabComboable, angle}],
maneuvers: [{technique: "stab", comboable: canComboFromStab, angle}],
seconds: 0,
cancelled: null,
}))
Expand Down Expand Up @@ -168,15 +164,6 @@ export const combat = system("combat", ({realm}) => [
}),
]),

behavior("launch queued activity")
.select({ActivityComponent, NextActivity})
.logic(() => ({components}) => {
if (!components.activityComponent && components.nextActivity) {
components.activityComponent = components.nextActivity
components.nextActivity = null
}
}),

behavior("activity seconds increase")
.select({ActivityComponent})
.logic(tick => ({components: {activityComponent: activity}}) => {
Expand Down Expand Up @@ -237,29 +224,30 @@ export const combat = system("combat", ({realm}) => [
.select({Inventory, ActivityComponent, MeleeIntent, MeleeAim})
.logic(() => ({components}) => {
const {meleeIntent, activityComponent: activity} = components
if (activity && activity.kind === "melee") {
const melee = meleeReport(activity)
if (isComboReady(melee.activeManeuver)) {
if (meleeIntent.swing) {
const {angle: oldAngle} = melee.activeManeuver.chart.maneuver
const {angle: newAngle} = components.meleeAim
const sameSide = (oldAngle < 0) === (newAngle < 0)
activity.maneuvers.push({
technique: "swing",
comboable: isSwingComboable,
angle: sameSide
? -newAngle
: newAngle,
})
}
else if (meleeIntent.stab) {
activity.maneuvers.push({
technique: "stab",
comboable: isStabComboable,
angle: components.meleeAim.angle,
})
}
}
const isMeleeActivity = activity && activity.kind === "melee"
if (!isMeleeActivity) return
const melee = meleeReport(activity)
if (!isComboReady(melee.logicalSnapshot)) return

if (canComboToSwing && meleeIntent.swing) {
const {angle: oldAngle} = melee.logicalSnapshot.chart.maneuver
const {angle: newAngle} = components.meleeAim
const sameSide = (oldAngle < 0) === (newAngle < 0)
activity.maneuvers.push({
technique: "swing",
comboable: canComboFromSwing,
angle: sameSide
? -newAngle
: newAngle,
})
}

else if (canComboToStab && meleeIntent.stab) {
activity.maneuvers.push({
technique: "stab",
comboable: canComboFromStab,
angle: components.meleeAim.angle,
})
}
}),

Expand All @@ -268,9 +256,9 @@ export const combat = system("combat", ({realm}) => [
.logic(() => ({components: {meleeIntent, activityComponent: activity}}) => {
if (meleeIntent.feint && activity && activity.kind === "melee" && activity.cancelled === null) {
const melee = meleeReport(activity)
const goodPhase = melee.activeManeuver.phase === "windup"
const goodTiming = melee.activeManeuver.phaseTime >= (melee.activeManeuver.chart.timing.windup * minimumFeint)
if (goodPhase && goodTiming && melee.predicament.procedure === "normal") {
const goodPhase = melee.logicalSnapshot.phase === "windup"
const goodTiming = melee.logicalSnapshot.phaseTime >= (melee.logicalSnapshot.chart.timing.windup * minimumFeint)
if (goodPhase && goodTiming && melee.flow.procedure === "normal") {
activity.cancelled = activity.seconds
}
}
Expand Down
2 changes: 1 addition & 1 deletion s/ecs/logic/melee_tracers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const melee_tracers = system("melee tracers", ({world, realm}) => [

const melee = meleeReport(activityComponent)
const active = (
melee.activeManeuver.phase === "release" &&
melee.logicalSnapshot.phase === "release" &&
melee.activity.cancelled === null
)

Expand Down
93 changes: 58 additions & 35 deletions s/ecs/logic/turncaps.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,67 @@

import {scalar, spline} from "@benev/toolbox"

import {behavior, system} from "../hub.js"
import {Intent} from "../components/plain_components.js"
import {Inventory} from "../components/topics/warrior.js"
import {ParryReport} from "../../models/activity/reports/parry.js"
import {InventoryManager} from "../../models/armory/inventory-manager.js"
import {ActivityComponent, Inventory} from "../components/topics/warrior.js"
import {meleeReport} from "../../models/activity/reports/melee/melee-report.js"

export const turncaps = system("turncaps", () => [
// behavior("turncaps slow down your aim during melee")
// .select({Intent, Inventory})
// .logic(({seconds}) => ({components}) => {
// const {meleeAction: action} = components
// const inventory = new InventoryManager(components.inventory)

// if (Melee.is.attack(action) || Melee.is.parry(action)) {
// const {weapon} = inventory
// const [x, y] = components.intent.glance

// const turncap = (
// Melee.is.parry(action) ? weapon.parry.turncap
// : Melee.is.swing(action) ? weapon.swing.turncap
// : weapon.stab.turncap
// )

// if (turncap !== null) {
// const ease_in_and_out = scalar.bottom(
// spline.linear(action.weights.progress, [
// [0.0, 10],
// [0.1, 1],
// [0.9, 1],
// [1.0, 10],
// ])
// )
// // console.log(ease_in_and_out.toFixed(2))
// const cap = (turncap * ease_in_and_out) * seconds
// components.intent.glance = [
// scalar.clamp(x, -cap, cap),
// scalar.clamp(y, -cap, cap),
// ]
// }
// }
// }),
behavior("turncaps slow down your aim during melee")
.select({Intent, Inventory, ActivityComponent})
.logic(({seconds}) => ({components}) => {
const {activityComponent: activity} = components
const inventory = new InventoryManager(components.inventory)

if (!activity)
return

const isMelee = activity.kind === "melee"
const isParry = activity.kind === "parry"

if (!(isMelee || isParry))
return

const {weapon} = inventory
const [x, y] = components.intent.glance

const {turncap, progress} = (() => {
if (isParry) {
const parry = new ParryReport(activity)
return {
progress: parry.progress,
turncap: weapon.parry.turncap,
}
}
else {
const melee = meleeReport(activity)
const {technique} = melee.logicalSnapshot.chart.maneuver
return {
progress: melee.logicalSnapshot.progress,
turncap: technique === "swing"
? weapon.swing.turncap
: weapon.stab.turncap,
}
}
})()

if (turncap !== null) {
const ease_in_and_out = scalar.bottom(
spline.linear(progress, [
[0.0, 10],
[0.1, 1],
[0.9, 1],
[1.0, 10],
])
)
const cap = (turncap * ease_in_and_out) * seconds
components.intent.glance = [
scalar.clamp(x, -cap, cap),
scalar.clamp(y, -cap, cap),
]
}
}),
])

2 changes: 1 addition & 1 deletion s/models/activity/reports/equip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class EquipReport {
this.progress = scalar.clamp(seconds / duration)
this.readyToSwitch = this.progress > 0.5
this.done = this.progress >= 1
this.almostDone = this.progress >= (8 / 10)
this.almostDone = this.progress >= (5 / 10)
}
}

11 changes: 11 additions & 0 deletions s/models/activity/reports/melee/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

export const canComboFromSwing = true
export const canComboToSwing = true

export const canComboFromStab = false
export const canComboToStab = false

export const comboableReleaseThreshold = 1 / 2
export const minimumFeint = 0
export const maximumFeint = 1

Loading

0 comments on commit 77b851f

Please sign in to comment.