Skip to content

Commit ac7f8d5

Browse files
Merge branch 'master' into public-release
2 parents 620f59e + d5c70b6 commit ac7f8d5

File tree

14 files changed

+210
-78
lines changed

14 files changed

+210
-78
lines changed

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

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import Match from '../../../playback/Match'
44
import { CurrentMap, StaticMap } from '../../../playback/Map'
55
import Round from '../../../playback/Round'
66
import Bodies from '../../../playback/Bodies'
7-
import { BATTLECODE_YEAR, DIRECTIONS } from '../../../constants'
7+
import { BATTLECODE_YEAR, DIRECTIONS, TEAM_COLOR_NAMES } from '../../../constants'
88
import { nativeAPI } from '../runner/native-api-wrapper'
99
import { Vector } from '../../../playback/Vector'
10+
import { RobotType } from 'battlecode-schema/js/battlecode/schema'
1011

1112
export function loadFileAsMap(file: File): Promise<Game> {
1213
return new Promise((resolve, reject) => {
@@ -54,8 +55,6 @@ function verifyMap(map: CurrentMap, bodies: Bodies): string {
5455

5556
// Validate map elements
5657
let numWalls = 0
57-
let numPaintTowers = 0
58-
let numMoneyTowers = 0
5958
const mapSize = map.width * map.height
6059
for (let i = 0; i < mapSize; i++) {
6160
const pos = map.indexToLocation(i)
@@ -104,8 +103,6 @@ function verifyMap(map: CurrentMap, bodies: Bodies): string {
104103
}
105104
}
106105

107-
numPaintTowers += body && body.robotType === schema.RobotType.PAINT_TOWER ? 1 : 0
108-
numMoneyTowers += body && body.robotType === schema.RobotType.MONEY_TOWER ? 1 : 0
109106
numWalls += wall
110107
}
111108

@@ -117,24 +114,61 @@ function verifyMap(map: CurrentMap, bodies: Bodies): string {
117114
}
118115

119116
// Validate initial bodies
120-
if (numPaintTowers !== 2) {
121-
return `Expected exactly 2 paint towers, found ${numPaintTowers}`
122-
}
123-
if (numMoneyTowers !== 2) {
124-
return `Expected exactly 2 money towers, found ${numMoneyTowers}`
125-
}
117+
const numPaintTowers = [0, 0]
118+
const numMoneyTowers = [0, 0]
126119
for (const body of bodies.bodies.values()) {
127-
// Check distance to nearby ruins
120+
// Check distance to nearby ruins, towers, and walls
121+
122+
if (body.robotType === RobotType.PAINT_TOWER) {
123+
numPaintTowers[body.team.id - 1]++
124+
} else if (body.robotType === RobotType.MONEY_TOWER) {
125+
numMoneyTowers[body.team.id - 1]++
126+
} else {
127+
return `Tower at (${body.pos.x}, ${body.pos.y}) has invalid type!`
128+
}
128129

129130
for (const checkRuin of map.staticMap.ruins) {
130-
if (squareIntersects(checkRuin, body.pos, 2)) {
131+
if (squareIntersects(checkRuin, body.pos, 4)) {
131132
return (
132133
`Tower at (${body.pos.x}, ${body.pos.y}) is too close to ruin ` +
133134
`at (${checkRuin.x}, ${checkRuin.y}), must be ` +
134-
`>= 3 away`
135+
`>= 5 away`
136+
)
137+
}
138+
}
139+
140+
for (const checkBody of bodies.bodies.values()) {
141+
if (checkBody === body) continue
142+
if (squareIntersects(checkBody.pos, body.pos, 4)) {
143+
return (
144+
`Tower at (${body.pos.x}, ${body.pos.y}) is too close to ruin ` +
145+
`at (${checkBody.pos.x}, ${checkBody.pos.y}), must be ` +
146+
`>= 5 away`
135147
)
136148
}
137149
}
150+
151+
const wall = map.staticMap.walls.findIndex(
152+
(v, i) => !!v && squareIntersects(map.indexToLocation(i), body.pos, 2)
153+
)
154+
if (wall !== -1) {
155+
const pos = map.indexToLocation(wall)
156+
return (
157+
`Tower at (${body.pos.x}, ${body.pos.y}) is too close to wall ` +
158+
`at (${pos.x}, ${pos.y}), must be ` +
159+
`>= 3 away`
160+
)
161+
}
162+
}
163+
164+
for (const teamIdx of [0, 1]) {
165+
if (numPaintTowers[teamIdx] !== 2) {
166+
return `Expected exactly 2 ${TEAM_COLOR_NAMES[teamIdx]} paint towers, found ${numPaintTowers[teamIdx]}`
167+
}
168+
169+
if (numMoneyTowers[teamIdx] !== 2) {
170+
return `Expected exactly 2 ${TEAM_COLOR_NAMES[teamIdx]} money towers, found ${numMoneyTowers[teamIdx]}`
171+
}
138172
}
139173

140174
return ''

client/src/components/sidebar/map-editor/map-editor.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ export const MapEditorPage: React.FC<Props> = (props) => {
160160
GameRunner.setMatch(editGame.current.currentMatch)
161161

162162
const round = editGame.current.currentMatch!.currentRound
163-
const brushes = round.map.getEditorBrushes().concat(round.bodies.getEditorBrushes(round.map.staticMap))
163+
const brushes = round.map.getEditorBrushes(round).concat(round.bodies.getEditorBrushes(round))
164164
brushes[0].open = true
165165
setBrushes(brushes)
166166
setCleared(round.bodies.isEmpty() && round.map.isEmpty())

client/src/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const CLIENT_VERSION = '1.0.0'
1+
export const CLIENT_VERSION = '1.1.0'
22
export const SPEC_VERSION = '1'
33
export const BATTLECODE_YEAR: number = 2025
44
export const MAP_SIZE_RANGE = {

client/src/playback/Bodies.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,8 @@ export default class Bodies {
187187
return this.bodies.size === 0
188188
}
189189

190-
getEditorBrushes(map: StaticMap): MapEditorBrush[] {
191-
return [new TowerBrush(this, map)]
190+
getEditorBrushes(round: Round): MapEditorBrush[] {
191+
return [new TowerBrush(round)]
192192
}
193193

194194
toInitialBodyTable(builder: flatbuffers.Builder): number {
@@ -381,6 +381,15 @@ export class Body {
381381
const squares2 = this.getAllLocationsWithinRadiusSquared(match, pos, this.metadata.visionRadiusSquared())
382382
this.drawEdges(match, ctx, lightly, squares2)
383383

384+
// Currently vision/message radius are always the same
385+
/*
386+
ctx.beginPath()
387+
ctx.strokeStyle = 'brown'
388+
ctx.lineWidth = 0.1
389+
const squares3 = this.getAllLocationsWithinRadiusSquared(match, pos, this.metadata.messageRadiusSquared())
390+
this.drawEdges(match, ctx, lightly, squares3)
391+
*/
392+
384393
ctx.globalAlpha = 1
385394
}
386395

client/src/playback/Brushes.ts

Lines changed: 59 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Bodies from './Bodies'
99
import { CurrentMap, StaticMap } from './Map'
1010
import { Vector } from './Vector'
1111
import { Team } from './Game'
12+
import Round from './Round'
1213

1314
const applyInRadius = (
1415
map: CurrentMap | StaticMap,
@@ -40,7 +41,35 @@ const squareIntersects = (check: Vector, center: Vector, radius: number) => {
4041
)
4142
}
4243

44+
const checkValidRuinPlacement = (check: Vector, map: StaticMap, bodies: Bodies) => {
45+
// Check if ruin is too close to the border
46+
if (check.x <= 1 || check.x >= map.width - 2 || check.y <= 1 || check.y >= map.height - 2) {
47+
return false
48+
}
49+
50+
// Check if this is a valid ruin location
51+
const idx = map.locationToIndex(check.x, check.y)
52+
const ruin = map.ruins.findIndex((l) => squareIntersects(l, check, 4))
53+
const wall = map.walls.findIndex((v, i) => !!v && squareIntersects(map.indexToLocation(i), check, 2))
54+
const paint = map.initialPaint[idx]
55+
56+
let tower = undefined
57+
for (const b of bodies.bodies.values()) {
58+
if (squareIntersects(check, b.pos, 4)) {
59+
tower = b
60+
break
61+
}
62+
}
63+
64+
if (tower || ruin !== -1 || wall !== -1 || paint) {
65+
return false
66+
}
67+
68+
return true
69+
}
70+
4371
export class WallsBrush extends SymmetricMapEditorBrush<StaticMap> {
72+
private readonly bodies: Bodies
4473
public readonly name = 'Walls'
4574
public readonly fields = {
4675
shouldAdd: {
@@ -54,8 +83,9 @@ export class WallsBrush extends SymmetricMapEditorBrush<StaticMap> {
5483
}
5584
}
5685

57-
constructor(map: StaticMap) {
58-
super(map)
86+
constructor(round: Round) {
87+
super(round.map.staticMap)
88+
this.bodies = round.bodies
5989
}
6090

6191
public symmetricApply(x: number, y: number, fields: Record<string, MapEditorBrushField>) {
@@ -64,7 +94,17 @@ export class WallsBrush extends SymmetricMapEditorBrush<StaticMap> {
6494
const pos = this.map.indexToLocation(idx)
6595
const ruin = this.map.ruins.findIndex((l) => squareIntersects(l, pos, 2))
6696
const paint = this.map.initialPaint[idx]
67-
if (ruin !== -1 || paint) return true
97+
98+
let tower = undefined
99+
for (const b of this.bodies.bodies.values()) {
100+
if (squareIntersects(pos, b.pos, 2)) {
101+
tower = b
102+
break
103+
}
104+
}
105+
106+
if (tower || ruin !== -1 || paint) return true
107+
68108
this.map.walls[idx] = 1
69109
}
70110

@@ -94,6 +134,7 @@ export class WallsBrush extends SymmetricMapEditorBrush<StaticMap> {
94134
}
95135

96136
export class RuinsBrush extends SymmetricMapEditorBrush<StaticMap> {
137+
private readonly bodies: Bodies
97138
public readonly name = 'Ruins'
98139
public readonly fields = {
99140
shouldAdd: {
@@ -102,26 +143,14 @@ export class RuinsBrush extends SymmetricMapEditorBrush<StaticMap> {
102143
}
103144
}
104145

105-
constructor(map: StaticMap) {
106-
super(map)
146+
constructor(round: Round) {
147+
super(round.map.staticMap)
148+
this.bodies = round.bodies
107149
}
108150

109151
public symmetricApply(x: number, y: number, fields: Record<string, MapEditorBrushField>) {
110152
const add = (x: number, y: number) => {
111-
// Check if ruin is too close to the border
112-
if (x <= 1 || x >= this.map.width - 2 || y <= 1 || y >= this.map.height - 2) {
113-
return true
114-
}
115-
116-
// Check if this is a valid ruin location
117-
const pos = { x, y }
118-
const idx = this.map.locationToIndex(x, y)
119-
const ruin = this.map.ruins.findIndex((l) => squareIntersects(l, pos, 4))
120-
const wall = this.map.walls.findIndex(
121-
(v, i) => !!v && squareIntersects(this.map.indexToLocation(i), pos, 2)
122-
)
123-
const paint = this.map.initialPaint[idx]
124-
if (ruin !== -1 || wall !== -1 || paint) {
153+
if (!checkValidRuinPlacement({ x, y }, this.map, this.bodies)) {
125154
return true
126155
}
127156

@@ -145,6 +174,7 @@ export class RuinsBrush extends SymmetricMapEditorBrush<StaticMap> {
145174
}
146175

147176
export class PaintBrush extends SymmetricMapEditorBrush<CurrentMap> {
177+
private readonly bodies: Bodies
148178
public readonly name = 'Paint'
149179
public readonly fields = {
150180
shouldAdd: {
@@ -171,8 +201,9 @@ export class PaintBrush extends SymmetricMapEditorBrush<CurrentMap> {
171201
}
172202
}
173203

174-
constructor(map: CurrentMap) {
175-
super(map)
204+
constructor(round: Round) {
205+
super(round.map)
206+
this.bodies = round.bodies
176207
}
177208

178209
public symmetricApply(x: number, y: number, fields: Record<string, MapEditorBrushField>, robotOne: boolean) {
@@ -217,6 +248,7 @@ export class PaintBrush extends SymmetricMapEditorBrush<CurrentMap> {
217248
}
218249

219250
export class TowerBrush extends SymmetricMapEditorBrush<StaticMap> {
251+
private readonly bodies: Bodies
220252
public readonly name = 'Towers'
221253
public readonly fields = {
222254
isTower: {
@@ -238,26 +270,20 @@ export class TowerBrush extends SymmetricMapEditorBrush<StaticMap> {
238270
}
239271
}
240272

241-
constructor(
242-
private readonly bodies: Bodies,
243-
map: StaticMap
244-
) {
245-
super(map)
273+
constructor(round: Round) {
274+
super(round.map.staticMap)
275+
this.bodies = round.bodies
246276
}
247277

248278
public symmetricApply(x: number, y: number, fields: Record<string, MapEditorBrushField>, robotOne: boolean) {
249279
const towerType: schema.RobotType = fields.towerType.value
250280
const isTower: boolean = fields.isTower.value
251281

252282
const add = (x: number, y: number, team: Team) => {
253-
// Check if this is a valid tower location
254283
const pos = { x, y }
255-
const idx = this.map.locationToIndex(x, y)
256-
const body = this.bodies.getBodyAtLocation(x, y)
257-
const wall = this.map.walls[idx]
258-
const ruin = this.map.ruins.findIndex((l) => squareIntersects(l, pos, 2))
259-
260-
if (body || wall || ruin !== -1) return null
284+
if (!checkValidRuinPlacement(pos, this.map, this.bodies)) {
285+
return null
286+
}
261287

262288
const id = this.bodies.getNextID()
263289
this.bodies.spawnBodyFromValues(id, towerType, team, pos)

client/src/playback/Map.ts

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { DIVIDER_COLOR, TILE_COLOR, WALLS_COLOR, PAINT_COLORS, TEAM_COLORS, TEAM
99
import * as renderUtils from '../util/RenderUtil'
1010
import { getImageIfLoaded } from '../util/ImageLoader'
1111
import { ClientConfig } from '../client-config'
12+
import Round from './Round'
1213

1314
export type Dimension = {
1415
minCorner: Vector
@@ -121,14 +122,18 @@ export class CurrentMap {
121122
}
122123

123124
if (config.showPaintMarkers) {
125+
// Scale text by 0.5 because sometimes 0.5px text does not work
126+
124127
const markerA = this.markers[0][schemaIdx]
125128
if (markerA) {
126129
ctx.fillStyle = TEAM_COLORS[0]
127130
const label = markerA === 1 ? '1' : '2' // Primary/secondary
128-
ctx.font = '0.5px monospace'
131+
ctx.font = '1px monospace'
129132
ctx.shadowColor = 'black'
130133
ctx.shadowBlur = 4
131-
ctx.fillText(label, coords.x + 0.05, coords.y + 0.95)
134+
ctx.scale(0.5, 0.5)
135+
ctx.fillText(label, (coords.x + 0.05) * 2, (coords.y + 0.95) * 2)
136+
ctx.scale(2, 2)
132137
ctx.shadowColor = ''
133138
ctx.shadowBlur = 0
134139
}
@@ -137,10 +142,12 @@ export class CurrentMap {
137142
if (markerB) {
138143
ctx.fillStyle = TEAM_COLORS[1]
139144
const label = markerB === 3 ? '1' : '2' // Primary/secondary
140-
ctx.font = '0.5px monospace'
145+
ctx.font = '1px monospace'
141146
ctx.shadowColor = 'black'
142147
ctx.shadowBlur = 4
143-
ctx.fillText(label, coords.x + 0.65, coords.y + 0.95)
148+
ctx.scale(0.5, 0.5)
149+
ctx.fillText(label, (coords.x + 0.65) * 2, (coords.y + 0.95) * 2)
150+
ctx.scale(2, 2)
144151
ctx.shadowColor = ''
145152
ctx.shadowBlur = 0
146153
}
@@ -185,14 +192,8 @@ export class CurrentMap {
185192
return info
186193
}
187194

188-
getEditorBrushes() {
189-
const brushes: MapEditorBrush[] = [
190-
// ruins brush
191-
// tower brush
192-
new PaintBrush(this),
193-
new RuinsBrush(this.staticMap),
194-
new WallsBrush(this.staticMap)
195-
]
195+
getEditorBrushes(round: Round) {
196+
const brushes: MapEditorBrush[] = [new PaintBrush(round), new RuinsBrush(round), new WallsBrush(round)]
196197
return brushes.concat(this.staticMap.getEditorBrushes())
197198
}
198199

0 commit comments

Comments
 (0)