Skip to content

Commit

Permalink
Merge pull request #53 from bananu7/dynamic-building-grid
Browse files Browse the repository at this point in the history
Dynamic building grid
  • Loading branch information
bananu7 authored Aug 6, 2023
2 parents cb3d18c + e3e9852 commit 33ee399
Show file tree
Hide file tree
Showing 26 changed files with 828 additions and 463 deletions.
62 changes: 34 additions & 28 deletions packages/client/src/Multiplayer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import geckos, { Data, ClientChannel } from '@geckos.io/client'
import { Game, CommandPacket, IdentificationPacket, UpdatePacket, UnitId, Position } from '@bananu7-rts/server/src/types'
import { Game, MatchMetadata, CommandPacket, IdentificationPacket, UpdatePacket, UnitId, Position } from '@bananu7-rts/server/src/types'
import { HTTP_API_URL, GECKOS_URL, GECKOS_PORT } from './config'

export type OnChatMessage = (msg: string) => void;
Expand Down Expand Up @@ -177,9 +177,15 @@ class AbstractControl {
protected channel?: ClientChannel;
protected leaveMatchHandler?: () => void;

async getMatchState() {
console.log("[multiplayer] Getting match state");
return fetch(`${HTTP_API_URL}/getMatchState?` + new URLSearchParams({ matchId: this.matchId })).then(r => r.json());
async debugGetMatchState() {
console.log("[multiplayer] Getting debug match state");
return fetch(`${HTTP_API_URL}/debugGetMatchState?` + new URLSearchParams({ matchId: this.matchId })).then(r => r.json());
}

async getMatchMetadata(): Promise<MatchMetadata> {
console.log("[multiplayer] Getting match metadata");
// TODO - API urls should be in shared constants
return fetch(`${HTTP_API_URL}/getMatchMetadata?` + new URLSearchParams({ matchId: this.matchId })).then(r => r.json());
}

protected _getChannel(): ClientChannel {
Expand Down Expand Up @@ -250,7 +256,7 @@ export class MatchControl extends AbstractControl {

moveCommand(unitIds: UnitId[], target: Position, shift: boolean) {
const cmd : CommandPacket = {
action: {
command: {
typ: 'Move',
target
},
Expand All @@ -262,7 +268,7 @@ export class MatchControl extends AbstractControl {

stopCommand(unitIds: UnitId[]) {
const cmd : CommandPacket = {
action: {
command: {
typ: 'Stop',
},
unitIds,
Expand All @@ -273,7 +279,7 @@ export class MatchControl extends AbstractControl {

followCommand(unitIds: UnitId[], target: UnitId, shift: boolean) {
const cmd : CommandPacket = {
action: {
command: {
typ: 'Follow',
target
},
Expand All @@ -285,10 +291,10 @@ export class MatchControl extends AbstractControl {

attackCommand(unitIds: UnitId[], target: UnitId, shift: boolean) {
const cmd : CommandPacket = {
action: {
typ: 'Attack',
target
},
command: {
typ: 'Attack',
target
},
unitIds,
shift,
};
Expand All @@ -297,10 +303,10 @@ export class MatchControl extends AbstractControl {

attackMoveCommand(unitIds: UnitId[], target: Position, shift: boolean) {
const cmd : CommandPacket = {
action: {
typ: 'AttackMove',
target
},
command: {
typ: 'AttackMove',
target
},
unitIds,
shift,
};
Expand All @@ -309,10 +315,10 @@ export class MatchControl extends AbstractControl {

produceCommand(unitIds: UnitId[], unitToProduce: string) {
const cmd : CommandPacket = {
action: {
typ: 'Produce',
unitToProduce
},
command: {
typ: 'Produce',
unitToProduce
},
unitIds,
shift: false,
};
Expand All @@ -321,11 +327,11 @@ export class MatchControl extends AbstractControl {

buildCommand(unitIds: UnitId[], building: string, position: Position, shift: boolean) {
const cmd : CommandPacket = {
action: {
typ: 'Build',
building,
position
},
command: {
typ: 'Build',
building,
position
},
unitIds,
shift,
};
Expand All @@ -334,10 +340,10 @@ export class MatchControl extends AbstractControl {

harvestCommand(unitIds: UnitId[], target: UnitId, shift: boolean) {
const cmd : CommandPacket = {
action: {
typ: 'Harvest',
target,
},
command: {
typ: 'Harvest',
target,
},
unitIds,
shift,
};
Expand Down
16 changes: 6 additions & 10 deletions packages/client/src/components/BottomUnitView.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Game, CommandPacket, IdentificationPacket, UpdatePacket, UnitId, Unit, UnitState, Position, ProductionFacility, Hp, Builder } from '@bananu7-rts/server/src/types'
import { Game, CommandPacket, IdentificationPacket, UpdatePacket, UnitId, Unit, Position, ProductionFacility, Hp, Builder } from '@bananu7-rts/server/src/types'
import { Multiplayer } from '../Multiplayer'

type Props = {
selectedUnits: Set<UnitId>,
setSelectedUnits: (us: Set<UnitId>) => void,
units: UnitState[],
units: Unit[],
ownerIndex: number,
}

Expand All @@ -22,7 +22,7 @@ export function BottomUnitView (props: Props) {
return (<SingleUnitView unit={u} owned={owned}/>);
} else {
// TODO duplication with CommandPalette
const units: UnitState[] =
const units: Unit[] =
Array.from(props.selectedUnits)
.map(id => {
const unit = props.units.find(u => u.id === id);
Expand Down Expand Up @@ -89,7 +89,7 @@ function ProductionProgressBar(props: {percent: number}) {
}


function SingleUnitView(props: {unit: UnitState, owned: boolean}) {
function SingleUnitView(props: {unit: Unit, owned: boolean}) {
const health = props.unit.components.find(c => c.type === "Hp") as Hp | undefined;

const productionComponent = props.unit.components.find(c => c.type === "ProductionFacility") as ProductionFacility;
Expand All @@ -110,17 +110,13 @@ function SingleUnitView(props: {unit: UnitState, owned: boolean}) {
<h2>{props.unit.kind}</h2>
{ health && <HealthBar hp={health.hp} maxHp={health.maxHp} /> }
{ health && <h3>{health.hp}/{health.maxHp}</h3> }
<span>{props.unit.id}</span><br/>
<span>{props.unit.position.x}</span><br/>
<span>{props.unit.position.y}</span>
{ props.owned && <span>{props.unit.status}</span> }
{ props.owned && productionProgress && <ProductionProgressBar percent={productionProgress} /> }
</div>
);
}

// TODO select on click
function UnitIcon(props: {unit: UnitState, onClick: (e: React.MouseEvent<HTMLElement>) => void}) {
function UnitIcon(props: {unit: Unit, onClick: (e: React.MouseEvent<HTMLElement>) => void}) {
const u = props.unit;

// TODO component getters to shared code
Expand All @@ -138,7 +134,7 @@ function UnitIcon(props: {unit: UnitState, onClick: (e: React.MouseEvent<HTMLEle
}

type MultiUnitViewProps = {
units: UnitState[];
units: Unit[];
select: (id: UnitId) => void;
deselect: (id: UnitId) => void;
}
Expand Down
41 changes: 20 additions & 21 deletions packages/client/src/components/CommandPalette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import {
UpdatePacket,
UnitId,
Unit,
UnitState,
Position,
ProductionFacility,
Builder,
} from '@bananu7-rts/server/src/types'
import { MatchControl } from '../Multiplayer'
import { SelectedAction } from '../game/SelectedAction'
import { SelectedCommand } from '../game/SelectedCommand'

type ButtonProps = {
x?: number,
Expand Down Expand Up @@ -42,9 +41,9 @@ function Button(props: ButtonProps) {
type Props = {
resources: number, // used to check if the player can afford stuff
selectedUnits: Set<UnitId>,
selectedAction: SelectedAction | undefined,
setSelectedAction: (a: SelectedAction | undefined) => void,
units: UnitState[],
selectedCommand: SelectedCommand | undefined,
setSelectedCommand: (a: SelectedCommand | undefined) => void,
units: Unit[],
ctrl: MatchControl,
ownerIndex: number,
notify: (text: string) => void,
Expand All @@ -54,7 +53,7 @@ export function CommandPalette(props: Props) {
return <div></div>;
}

const units: UnitState[] =
const units: Unit[] =
Array.from(props.selectedUnits)
.map(id => {
const unit = props.units.find(u => u.id === id);
Expand All @@ -77,7 +76,7 @@ export function CommandPalette(props: Props) {

const stop = () => {
props.ctrl.stopCommand(Array.from(props.selectedUnits));
props.setSelectedAction(undefined);
props.setSelectedCommand(undefined);
}

const productionUnits = (() => {
Expand Down Expand Up @@ -144,7 +143,7 @@ export function CommandPalette(props: Props) {
})();

const build = (building: string, position: Position) =>
props.setSelectedAction({ action: 'Build', building });
props.setSelectedCommand({ command: 'Build', building });

// TODO - second click to determine position
const buildButtons = availableBuildings.map(bp => {
Expand All @@ -153,9 +152,9 @@ export function CommandPalette(props: Props) {
const time = Math.floor(bp.buildTime / 1000);

const active =
props.selectedAction &&
props.selectedAction.action === 'Build' &&
props.selectedAction.building === b || false;
props.selectedCommand &&
props.selectedCommand.command === 'Build' &&
props.selectedCommand.building === b || false;

const canAfford = props.resources >= cost;

Expand Down Expand Up @@ -188,10 +187,10 @@ export function CommandPalette(props: Props) {
let hint = "";
/* TODO - contextual hints disabled for now
maybe a tutorial mode would help?
if (props.selectedAction) {
switch (props.selectedAction.action) {
if (props.SelectedCommand) {
switch (props.SelectedCommand.command) {
case 'Build':
hint = `Left-click on the map to build a ${props.selectedAction.building}.`;
hint = `Left-click on the map to build a ${props.SelectedCommand.building}.`;
break;
case 'Move':
hint = "Left-click on the map to move, or on a unit to follow it.";
Expand All @@ -214,8 +213,8 @@ export function CommandPalette(props: Props) {
<Button
key="Move"
x={1} y={1}
active={props.selectedAction && props.selectedAction.action === 'Move' || false}
onClick={() => props.setSelectedAction({ action: 'Move'})}
active={props.selectedCommand && props.selectedCommand.command === 'Move' || false}
onClick={() => props.setSelectedCommand({ command: 'Move'})}
>
<span style={{fontSize: "2.3em"}}></span>
<span className="tooltip">Move a unit to a specific location or order it to follow a unit.</span>
Expand All @@ -227,8 +226,8 @@ export function CommandPalette(props: Props) {
<Button
key="Harvest"
x={1} y={2}
active={props.selectedAction && props.selectedAction.action === 'Harvest' || false}
onClick={() => props.setSelectedAction({ action: 'Harvest'})}
active={props.selectedCommand && props.selectedCommand.command === 'Harvest' || false}
onClick={() => props.setSelectedCommand({ command: 'Harvest'})}
>
<span style={{fontSize: "2.3em"}}>⛏️</span>
<span className="tooltip">Harvest a resource node</span>
Expand All @@ -243,16 +242,16 @@ export function CommandPalette(props: Props) {
onClick={stop}
>
<span style={{fontSize: "2.3em"}}></span>
<span className="tooltip">Stop the current action and all the queued ones.</span>
<span className="tooltip">Stop the current command and all the queued ones.</span>
</Button>

{
canAttack &&
<Button
key="attack"
x={3} y={1}
active={props.selectedAction && props.selectedAction.action === 'Attack' || false}
onClick={() => props.setSelectedAction({ action: 'Attack'})}
active={props.selectedCommand && props.selectedCommand.command === 'Attack' || false}
onClick={() => props.setSelectedCommand({ command: 'Attack'})}
>
<span style={{fontSize: "2.3em"}}>⚔️</span>
<span className="tooltip">Attack an enemy unit or move towards a point and attack any enemy units on the way</span>
Expand Down
Loading

0 comments on commit 33ee399

Please sign in to comment.