mirror of
https://github.com/Terncode/pixel.horse.git
synced 2026-09-25 06:05:52 +02:00
Archive commit
This commit is contained in:
@@ -0,0 +1,294 @@
|
||||
import { ServerEntity, ServerMap, IClient } from './serverInterfaces';
|
||||
import { World } from './world';
|
||||
import { Rect, SignEntityOptions, MessageType, CreateEntityMethod, PonyOptions, Point } from '../common/interfaces';
|
||||
import { roundPosition } from '../common/positionUtils';
|
||||
import { getRegionGlobal } from '../common/worldMap';
|
||||
import { addEntityToRegion, getRegionTiles, removeEntityFromRegion } from './serverRegion';
|
||||
import * as entities from '../common/entities';
|
||||
import { updateTileIndices } from '../client/tileUtils';
|
||||
import { generateRegionCollider } from '../common/region';
|
||||
import { PONY_TYPE, tileWidth, tileHeight } from '../common/constants';
|
||||
import { sayTo, saySystem } from './chat';
|
||||
import { setEntityName, updateEntityVelocity, setEntityAnimation } from './entityUtils';
|
||||
import { updateAccountState } from './accountUtils';
|
||||
import { toInt, includes } from '../common/utils';
|
||||
import { holdItem } from './playerUtils';
|
||||
import { random, sample, clamp } from 'lodash';
|
||||
import { findEntities } from './serverMap';
|
||||
import { randomPosition } from './controllers/collectableController';
|
||||
import { BunnyAnimation } from '../common/entities';
|
||||
|
||||
export const worldForTemplates: any = {
|
||||
featureFlags: {},
|
||||
addEntity(entity: ServerEntity, map: ServerMap) {
|
||||
roundPosition(entity);
|
||||
const region = getRegionGlobal(map, entity.x, entity.y);
|
||||
entity.region = region;
|
||||
addEntityToRegion(region, entity, map);
|
||||
return entity;
|
||||
},
|
||||
removeEntity(entity: ServerEntity, map: ServerMap) {
|
||||
let removed = false;
|
||||
|
||||
if (entity.region) {
|
||||
removed = removeEntityFromRegion(entity.region, entity, map);
|
||||
}
|
||||
|
||||
return removed;
|
||||
},
|
||||
};
|
||||
|
||||
export function addSpawnPointIndicators(world: World, map: ServerMap) {
|
||||
const addSpawn = ({ x, y, w, h }: Rect) => {
|
||||
world.addEntity(entities.spawnPole(x, y), map);
|
||||
|
||||
if (w && h) {
|
||||
world.addEntity(entities.spawnPole(x + w, y), map);
|
||||
world.addEntity(entities.spawnPole(x, y + h), map);
|
||||
world.addEntity(entities.spawnPole(x + w, y + h), map);
|
||||
}
|
||||
};
|
||||
|
||||
addSpawn(map.spawnArea);
|
||||
|
||||
for (const spawn of Array.from(map.spawns.values())) {
|
||||
addSpawn(spawn);
|
||||
}
|
||||
}
|
||||
|
||||
export function generateTileIndicesAndColliders(map: ServerMap) {
|
||||
for (const region of map.regions) {
|
||||
getRegionTiles(region); // initialize encodedTiles
|
||||
|
||||
if (region.tilesDirty) {
|
||||
updateTileIndices(region, map);
|
||||
}
|
||||
}
|
||||
|
||||
for (const region of map.regions) {
|
||||
if (region.colliderDirty) {
|
||||
generateRegionCollider(region, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function removePonies(entities: ServerEntity[]) {
|
||||
for (let i = entities.length - 1; i >= 0; i--) {
|
||||
if (entities[i].type === PONY_TYPE) {
|
||||
entities.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface SignDirection {
|
||||
icon: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface SignConfig {
|
||||
r?: number;
|
||||
w?: (SignDirection | undefined)[];
|
||||
e?: (SignDirection | undefined)[];
|
||||
n?: (SignDirection | undefined)[];
|
||||
s?: (SignDirection | undefined)[];
|
||||
}
|
||||
|
||||
export function createDirectionSign(x: number, y: number, config: SignConfig) {
|
||||
const result: ServerEntity[] = [];
|
||||
const options: SignEntityOptions = { sign: {} };
|
||||
const lines: string[] = [];
|
||||
const { w = [], e = [], s = [], n = [] } = config;
|
||||
const max = clamp(Math.max(w.length, e.length, s.length, n.length), 3, 5);
|
||||
const skip = 5 - max;
|
||||
|
||||
function parse(entries: (SignDirection | undefined)[], arrow: string, plates: CreateEntityMethod[], ox: number) {
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
const e = entries[i];
|
||||
|
||||
if (e) {
|
||||
lines.push(`${arrow} ${e.name}`);
|
||||
const nameplate = plates[i](x + ox / tileWidth, y);
|
||||
setEntityName(nameplate, e.name);
|
||||
result.push(nameplate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.r) {
|
||||
options.sign.r = config.r;
|
||||
}
|
||||
|
||||
const ups = config.r ? entities.directionSignUpsRight : entities.directionSignUpsLeft;
|
||||
const downs = config.r ? entities.directionSignDownsLeft : entities.directionSignDownsRight;
|
||||
|
||||
if (config.n) {
|
||||
options.sign.n = config.n.map(x => x ? x.icon : -1);
|
||||
parse(config.n, '↑', ups.slice(skip), 0);
|
||||
}
|
||||
|
||||
if (config.w) {
|
||||
options.sign.w = config.w.map(x => x ? x.icon : -1);
|
||||
parse(config.w, '←', entities.directionSignLefts.slice(skip), -10);
|
||||
}
|
||||
|
||||
if (config.e) {
|
||||
options.sign.e = config.e.map(x => x ? x.icon : -1);
|
||||
parse(config.e, '→', entities.directionSignRights.slice(skip), 10);
|
||||
}
|
||||
|
||||
if (config.s) {
|
||||
options.sign.s = config.s.map(x => x ? x.icon : -1);
|
||||
parse(config.s, '↓', downs.slice(skip), 0);
|
||||
}
|
||||
|
||||
const text = lines.join('\n');
|
||||
const entity = entities.directionSign(x, y, options) as ServerEntity;
|
||||
entity.interact = (entity, client) => sayTo(client, entity, text, MessageType.System);
|
||||
result.push(entity);
|
||||
return result;
|
||||
}
|
||||
|
||||
const patchTypes = [
|
||||
entities.cloverPatch3, entities.cloverPatch4, entities.cloverPatch5, entities.cloverPatch6, entities.cloverPatch7
|
||||
].map(x => x.type);
|
||||
|
||||
const eggBasketTypes = entities.eggBaskets.map(b => b.type);
|
||||
|
||||
export function pickCandy(client: IClient) {
|
||||
let count = 0;
|
||||
updateAccountState(client.account, state => state.candies = count = toInt(state.candies) + 1);
|
||||
saySystem(client, `${count} 🍬`);
|
||||
}
|
||||
|
||||
export function pickGift(client: IClient) {
|
||||
let count = 0;
|
||||
updateAccountState(client.account, state => state.gifts = count = toInt(state.gifts) + 1);
|
||||
saySystem(client, `${count} 🎁`);
|
||||
holdItem(client.pony, entities.gift2.type);
|
||||
}
|
||||
|
||||
export function pickClover(client: IClient) {
|
||||
let count = 0;
|
||||
updateAccountState(client.account, state => state.clovers = count = toInt(state.clovers) + 1);
|
||||
saySystem(client, `${count} 🍀`);
|
||||
holdItem(client.pony, entities.cloverPick.type);
|
||||
}
|
||||
|
||||
export function pickEgg(client: IClient) {
|
||||
let count = 0;
|
||||
updateAccountState(client.account, state => state.eggs = count = toInt(state.eggs) + 1);
|
||||
saySystem(client, `${count} 🥚`);
|
||||
|
||||
if (Math.random() < 0.05) {
|
||||
const options = client.pony.options as PonyOptions;
|
||||
const basketIndex = eggBasketTypes.indexOf(options.hold || 0);
|
||||
|
||||
if (basketIndex >= 0 && basketIndex < (eggBasketTypes.length - 1)) {
|
||||
holdItem(client.pony, eggBasketTypes[basketIndex + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function pickEntity(client: IClient, entity: ServerEntity) {
|
||||
holdItem(client.pony, entity.type);
|
||||
}
|
||||
|
||||
export function checkLantern(client: IClient) {
|
||||
const options = client.pony.options as PonyOptions;
|
||||
const canPick = options.hold === entities.jackoLanternOn.type || options.hold === entities.jackoLanternOff.type;
|
||||
|
||||
if (!canPick) {
|
||||
saySystem(client, 'Get a lantern to collect candies');
|
||||
}
|
||||
|
||||
return canPick;
|
||||
}
|
||||
|
||||
export function checkBasket(client: IClient) {
|
||||
const options = client.pony.options as PonyOptions;
|
||||
const canPick = includes(eggBasketTypes, options.hold);
|
||||
|
||||
if (!canPick) {
|
||||
saySystem(client, 'Get a basket to collect eggs');
|
||||
}
|
||||
|
||||
return canPick;
|
||||
}
|
||||
|
||||
export function checkNotCollecting(client: IClient) {
|
||||
const options = client.pony.options as PonyOptions;
|
||||
const canPick = includes(eggBasketTypes, options.hold) ||
|
||||
options.hold === entities.jackoLanternOn.type ||
|
||||
options.hold === entities.jackoLanternOff.type;
|
||||
return !canPick;
|
||||
}
|
||||
|
||||
export function positionClover(map: ServerMap) {
|
||||
const patch = sample(findEntities(map, e => includes(patchTypes, e.type)));
|
||||
|
||||
if (patch && patch.bounds) {
|
||||
const bounds = patch.bounds;
|
||||
const position = {
|
||||
x: patch.x + bounds.x / tileWidth + random(0, bounds.w / tileWidth, true),
|
||||
y: patch.y + bounds.y / tileHeight + random(0, bounds.h / tileHeight, true),
|
||||
};
|
||||
return position;
|
||||
} else {
|
||||
return randomPosition(map);
|
||||
}
|
||||
}
|
||||
|
||||
export function createBunny(waypoints: Point[]) {
|
||||
const { x, y } = waypoints[0];
|
||||
const entity = entities.bunny(x, y) as ServerEntity;
|
||||
const bunnySpeed = 2;
|
||||
|
||||
let waypoint = 0;
|
||||
let sleepUntil = 0;
|
||||
|
||||
entity.serverUpdate = (_delta, now) => {
|
||||
if (sleepUntil > now)
|
||||
return;
|
||||
|
||||
const { x, y } = waypoints[waypoint];
|
||||
const reachedX = Math.abs(entity.x - x) < 0.2;
|
||||
const reachedY = Math.abs(entity.y - y) < 0.2;
|
||||
|
||||
if (reachedX && reachedY) {
|
||||
const rand = Math.random();
|
||||
updateEntityVelocity(entity, 0, 0, now);
|
||||
|
||||
if (rand < 0.1) {
|
||||
setEntityAnimation(entity, BunnyAnimation.Clean);
|
||||
sleepUntil = now + 2;
|
||||
} else if (rand < 0.2) {
|
||||
setEntityAnimation(entity, BunnyAnimation.Look);
|
||||
sleepUntil = now + 2;
|
||||
} else if (rand < 0.3) {
|
||||
setEntityAnimation(entity, BunnyAnimation.Blink);
|
||||
sleepUntil = now + 2;
|
||||
} else if (rand < 0.6) {
|
||||
setEntityAnimation(entity, BunnyAnimation.Sit);
|
||||
sleepUntil = now + 2;
|
||||
} else {
|
||||
waypoint = (waypoint + 1) % waypoints.length;
|
||||
setEntityAnimation(entity, BunnyAnimation.Sit);
|
||||
sleepUntil = now + random(0.2, 2, true);
|
||||
}
|
||||
} else {
|
||||
const vx = reachedX ? 0 : (x < entity.x ? -bunnySpeed : bunnySpeed);
|
||||
const vy = reachedY ? 0 : (y < entity.y ? -bunnySpeed : bunnySpeed);
|
||||
|
||||
if (entity.vx !== vx || entity.vy !== vy) {
|
||||
updateEntityVelocity(entity, vx, vy, now);
|
||||
setEntityAnimation(entity, BunnyAnimation.Walk, vx === 0 ? undefined : vx > 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (DEVELOPMENT && false) {
|
||||
return [entity, ...waypoints.map(({ x, y }) => entities.routePole(x, y))];
|
||||
} else {
|
||||
return [entity];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user