Skip to content

Commit 31f7a65

Browse files
authored
Huge bugfix release: merge
Huge bugfix release
2 parents 5540a76 + a390310 commit 31f7a65

32 files changed

+267
-199
lines changed

.github/workflows/release-engine.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ env:
1414
RELEASE_ARTIFACT_ID: battlecode26
1515

1616
# IS_PUBLIC is whether to release deployments publicly. Set to exactly the text "YES" to do so.
17-
IS_PUBLIC: YES
17+
IS_PUBLIC: NO
1818

1919
jobs:
2020
release-java:

client/src/components/sidebar/map-editor/MapGenerator.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Game, { Team } from '../../../playback/Game'
33
import Match from '../../../playback/Match'
44
import { CurrentMap, StaticMap } from '../../../playback/Map'
55
import Round from '../../../playback/Round'
6-
import Bodies from '../../../playback/Bodies'
6+
import Bodies, { Body } from '../../../playback/Bodies'
77
import { BATTLECODE_YEAR, DIRECTIONS, TEAM_COLOR_NAMES } from '../../../constants'
88
import { nativeAPI } from '../runner/native-api-wrapper'
99
import { Vector } from '../../../playback/Vector'
@@ -180,6 +180,13 @@ function verifyMap(map: CurrentMap, bodies: Bodies): string {
180180
`>= 3 away`
181181
)
182182
}
183+
184+
if (body.robotType === schema.RobotType.CAT) {
185+
if (!map.staticMap.catWaypoints.get(body.id) || map.staticMap.catWaypoints.get(body.id)?.length === 0) {
186+
return `Cat with id ${body.id} has no waypoints`
187+
}
188+
}
189+
183190
}
184191

185192
return ''

client/src/playback/Actions.ts

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,15 +183,40 @@ export const ACTION_DEFINITIONS: Record<schema.Action, typeof Action<ActionUnion
183183
}
184184
},
185185
[schema.Action.RatNap]: class RatNapAction extends Action<schema.RatNap> {
186+
private static readonly OFFSET = { x: -0.35, y: 0 }
186187
apply(round: Round): void {
187188
// move the target onto the source adjust target's size using scale factor
188189
const src = round.bodies.getById(this.robotId)
189190
const target = round.bodies.getById(this.actionData.id()) // rat getting napped
191+
192+
target.lastPos = { ...target.pos }
193+
target.pos = { x: src.pos.x + RatNapAction.OFFSET.x, y: src.pos.y + RatNapAction.OFFSET.y }
194+
target.size = 0.6
190195
}
191196
draw(match: Match, ctx: CanvasRenderingContext2D): void {
192197
//target rat moves onto src rat, circle around carried group thing
193-
const src = match.currentRound.bodies.getById(this.robotId)
194-
const target = match.currentRound.bodies.getById(this.actionData.id()) // rat getting napped
198+
const src = match.currentRound.bodies.getById(this.robotId)
199+
const srcCoords = renderUtils.getRenderCoords(src.pos.x, src.pos.y, match.map.dimension, true)
200+
const t = match.getInterpolationFactor()
201+
const bump = Math.sin(t * Math.PI * 8) * 0.03
202+
const half = 0.5 + bump
203+
const radius = 0.08 // corner radius
204+
205+
ctx.save()
206+
ctx.shadowBlur = 12
207+
ctx.shadowColor = src.team.color
208+
ctx.strokeStyle = src.team.color
209+
ctx.globalAlpha = 0.7
210+
ctx.lineWidth = 0.04
211+
ctx.beginPath()
212+
ctx.moveTo(srcCoords.x - half + radius, srcCoords.y - half)
213+
ctx.arcTo(srcCoords.x + half, srcCoords.y - half, srcCoords.x + half, srcCoords.y + half, radius)
214+
ctx.arcTo(srcCoords.x + half, srcCoords.y + half, srcCoords.x - half, srcCoords.y + half, radius)
215+
ctx.arcTo(srcCoords.x - half, srcCoords.y + half, srcCoords.x - half, srcCoords.y - half, radius)
216+
ctx.arcTo(srcCoords.x - half, srcCoords.y - half, srcCoords.x + half, srcCoords.y - half, radius)
217+
ctx.stroke()
218+
ctx.restore()
219+
ctx.restore()
195220
}
196221
},
197222
[schema.Action.RatCollision]: class RatCollisionAction extends Action<schema.RatCollision> {
@@ -200,6 +225,33 @@ export const ACTION_DEFINITIONS: Record<schema.Action, typeof Action<ActionUnion
200225
const src = match.currentRound.bodies.getById(this.robotId)
201226
const pos = match.map.indexToLocation(this.actionData.loc())
202227
const coords = renderUtils.getRenderCoords(pos.x, pos.y, match.map.dimension, true)
228+
const t = match.getInterpolationFactor()
229+
230+
ctx.save()
231+
// dusty base color that fills the cell and fades out
232+
const baseAlpha = 0.4 * (1 - t)
233+
ctx.fillStyle = `rgba(150,130,110,${baseAlpha})`
234+
ctx.fillRect(coords.x - 0.5, coords.y - 0.5, 1, 1)
235+
236+
// these are the random rocks that fill the cell
237+
const rockCount = 10
238+
for (let i = 0; i < rockCount; i++) {
239+
const rx = coords.x - 0.5 + Math.random() * 1
240+
const ry = coords.y - 0.5 + Math.random() * 1
241+
const size = 0.08 + Math.random() * 0.15
242+
const shade = 90 + Math.floor(Math.random() * 50)
243+
const alpha = 0.7 * (1 - t)
244+
ctx.fillStyle = `rgba(${shade},${shade - 10},${shade - 20},${alpha})`
245+
ctx.fillRect(rx, ry, size, size)
246+
}
247+
248+
// ring outside the cell (also fades out)
249+
ctx.strokeStyle = src.team.color
250+
ctx.globalAlpha = 0.35 * (1 - t)
251+
ctx.lineWidth = 0.04
252+
ctx.strokeRect(coords.x - 0.5, coords.y - 0.5, 1, 1)
253+
ctx.restore()
254+
203255
}
204256
},
205257
[schema.Action.PlaceDirt]: class PlaceDirtAction extends Action<schema.PlaceDirt> {
@@ -284,8 +336,8 @@ export const ACTION_DEFINITIONS: Record<schema.Action, typeof Action<ActionUnion
284336
const target = round.bodies.getById(this.actionData.id())
285337
const amount = this.actionData.amount()
286338

287-
body.cheese -= amount
288-
target.cheese += amount
339+
body.cheese -= Math.min(body.cheese, amount)
340+
target.cheese += Math.min(body.cheese, amount)
289341
}
290342
draw(match: Match, ctx: CanvasRenderingContext2D): void {
291343
const srcBody = match.currentRound.bodies.getById(this.robotId)

client/src/playback/Bodies.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,8 @@ export default class Bodies {
9999

100100
return body
101101
}
102+
102103
checkBodyCollisionAtLocation(type: schema.RobotType, pos: Vector): boolean {
103-
const bodyClass = BODY_DEFINITIONS[type] ?? assert.fail(`Body type ${type} not found in BODY_DEFINITIONS`)
104-
const tempBody = new bodyClass(this.game, pos, this.game.getTeamByID(1), 0)
105-
const bodySize = tempBody.size
106104
const occupiedSpaces: Vector[] = []
107105

108106
for (const otherBody of this.bodies.values()) {
@@ -154,6 +152,34 @@ export default class Bodies {
154152
return false
155153
}
156154

155+
checkBodyOutofBoundsAtLocation(type: schema.RobotType, pos: Vector): boolean {
156+
const map = this.game.currentMatch?.map
157+
if(!map) return false
158+
159+
const dimension = map.dimension
160+
const occupiedSpaces: Vector[] = []
161+
162+
if (type == schema.RobotType.RAT) {
163+
if(!map.inBounds(pos.x, pos.y)) return false
164+
}
165+
if (type == schema.RobotType.CAT) {
166+
for (let xoff = 0; xoff <= 1; xoff++) {
167+
for (let yoff = 0; yoff <= 1; yoff++) {
168+
if(!map.inBounds(pos.x+xoff, pos.y+yoff)) return false
169+
}
170+
}
171+
}
172+
if (type == schema.RobotType.RAT_KING) {
173+
for (let xoff = -1; xoff <= 1; xoff++) {
174+
for (let yoff = -1; yoff <= 1; yoff++) {
175+
if(!map.inBounds(pos.x+xoff, pos.y+yoff)) return false
176+
}
177+
}
178+
}
179+
180+
return true
181+
}
182+
157183
markBodyAsDead(id: number): void {
158184
const body = this.getById(id)
159185
body.dead = true

client/src/playback/Brushes.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,12 @@ export class CatBrush extends SymmetricMapEditorBrush<StaticMap> {
546546
const add = (x: number, y: number, team: Team) => {
547547
const pos = { x, y }
548548

549-
if (this.bodies.checkBodyCollisionAtLocation(schema.RobotType.CAT, pos)) return null
549+
if (
550+
this.bodies.checkBodyCollisionAtLocation(schema.RobotType.CAT, pos)||
551+
!this.bodies.checkBodyOutofBoundsAtLocation(schema.RobotType.CAT, pos)
552+
) {
553+
return null
554+
}
550555

551556
const id = this.bodies.getNextID()
552557
this.bodies.spawnBodyFromValues(id, schema.RobotType.CAT, team, pos, 0, robotOne ? 0 : 1)
@@ -650,7 +655,8 @@ export class RatKingBrush extends SymmetricMapEditorBrush<StaticMap> {
650655
const pos = { x, y }
651656
if (
652657
this.bodies.getBodyAtLocation(x, y) ||
653-
this.bodies.checkBodyCollisionAtLocation(schema.RobotType.RAT_KING, pos)
658+
this.bodies.checkBodyCollisionAtLocation(schema.RobotType.RAT_KING, pos) ||
659+
!this.bodies.checkBodyOutofBoundsAtLocation(schema.RobotType.RAT_KING, pos)
654660
) {
655661
return null
656662
}

client/src/playback/GameRenderer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ class GameRendererClass {
185185
const ctx = this.ctx(CanvasLayers.Background)
186186
const match = GameRunner.match
187187
if (!match || !ctx) return
188-
match.currentRound.map.staticMap.draw(ctx)
188+
match.currentRound.map.staticMap.draw(ctx, GameConfig.config)
189189
this.render()
190190
}
191191

client/src/playback/Map.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export class CurrentMap {
4141
public readonly markers: [Int8Array, Int8Array] // Each team has markers
4242
public readonly ratTrapData: Int8Array
4343
public readonly catTrapData: Int8Array
44-
public readonly cheeseData: Int8Array
44+
public readonly cheeseData: Int32Array
4545
public readonly resourcePatterns: ResourcePatternData[]
4646

4747
get width(): number {
@@ -60,7 +60,7 @@ export class CurrentMap {
6060

6161
this.staticMap = from
6262
this.dirt = new Int8Array(from.initialDirt)
63-
this.cheeseData = new Int8Array(from.cheese)
63+
this.cheeseData = new Int32Array(from.cheese)
6464
this.markers = [new Int8Array(this.width * this.height), new Int8Array(this.width * this.height)]
6565
this.resourcePatterns = []
6666
this.ratTrapData = new Int8Array(this.width * this.height)
@@ -70,7 +70,7 @@ export class CurrentMap {
7070

7171
this.staticMap = from.staticMap
7272
this.dirt = new Int8Array(from.dirt)
73-
this.cheeseData = new Int8Array(from.cheeseData)
73+
this.cheeseData = new Int32Array(from.cheeseData)
7474
this.markers = [new Int8Array(from.markers[0]), new Int8Array(from.markers[1])]
7575

7676
// Assumes ResourcePatternData is immutable
@@ -284,6 +284,8 @@ export class CurrentMap {
284284

285285
const dirt = this.dirt[schemaIdx]
286286
const wall = this.staticMap.walls[schemaIdx]
287+
const ratTrap = this.ratTrapData[schemaIdx]
288+
const catTrap = this.catTrapData[schemaIdx]
287289
const cheeseMine = this.staticMap.cheeseMines.find((r) => r.x === square.x && r.y === square.y)
288290
const cheese = this.cheeseData[schemaIdx]
289291
const srp = this.resourcePatterns.find((r) => r.center.x === square.x && r.center.y === square.y)
@@ -313,6 +315,12 @@ export class CurrentMap {
313315
if (dirt) {
314316
info.push('Dirt')
315317
}
318+
if (ratTrap) {
319+
info.push('Rat Trap')
320+
}
321+
if (ratTrap) {
322+
info.push('Cat Trap')
323+
}
316324
if (cheese) {
317325
info.push(`Cheese: ${cheese}`)
318326
}
@@ -552,7 +560,7 @@ export class StaticMap {
552560
}
553561
}
554562

555-
draw(ctx: CanvasRenderingContext2D) {
563+
draw(ctx: CanvasRenderingContext2D, config: ClientConfig) {
556564
// Fill background
557565
ctx.fillStyle = Colors.TILES_COLOR.get()
558566
ctx.fillRect(
@@ -569,10 +577,15 @@ export class StaticMap {
569577

570578
// Render rounded (clipped) wall
571579
if (this.walls[schemaIdx]) {
572-
renderUtils.renderRounded(ctx, i, j, this, this.walls, () => {
580+
if (config.enableFancyPaint) {
581+
renderUtils.renderRounded(ctx, i, j, this, this.walls, () => {
582+
ctx.fillStyle = Colors.WALLS_COLOR.get()
583+
ctx.fillRect(coords.x, coords.y, 1.0, 1.0)
584+
})
585+
} else {
573586
ctx.fillStyle = Colors.WALLS_COLOR.get()
574587
ctx.fillRect(coords.x, coords.y, 1.0, 1.0)
575-
})
588+
}
576589
}
577590

578591
// Draw grid

crossplay_temp/started_java.txt

Whitespace-only changes.

engine/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ jar {
7676

7777
javadoc {
7878
includes = ["**/common/**"]
79-
options.windowTitle = "Battlecode 2025"
79+
options.windowTitle = "Battlecode 2026"
8080
options.classpath = sourceSets.main.compileClasspath as List
8181
options.doclet = "jdk.javadoc.doclet.StandardDoclet"
8282
options.taglets = ["battlecode.doc.CostlyMethodTaglet"]

engine/src/main/battlecode/common/RobotController.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ public interface RobotController {
130130
*
131131
* @battlecode.doc.costlymethod
132132
*/
133-
public int getGlobalCheese();
133+
int getGlobalCheese();
134134

135135
/**
136136
* Returns the amount of cheese the robot has access to.
@@ -139,7 +139,7 @@ public interface RobotController {
139139
*
140140
* @battlecode.doc.costlymethod
141141
*/
142-
public int getAllCheese();
142+
int getAllCheese();
143143

144144
/**
145145
* Returns the amount of dirt that this robot's team has.
@@ -1034,5 +1034,3 @@ void setIndicatorLine(MapLocation startLoc, MapLocation endLoc, int red, int gre
10341034
*/
10351035
void setTimelineMarker(String label, int red, int green, int blue);
10361036
}
1037-
// TODO: update bytecode costs, particularly for new methods + methods that got
1038-
// renamed from last year

0 commit comments

Comments
 (0)