OpenWorldVGDL/javascript/core/ontology/effect.js

566 lines
19 KiB
JavaScript
Raw Normal View History

2025-01-17 13:42:05 +00:00
import { colorDict, DOWN } from "./constants.js";
import { OrientedSprite } from "./vgdl-sprite.js";
import * as tools from "../tools.js";
import { oncePerStep, unitVector, vectNorm } from "../tools.js";
import { Resource } from "./resource.js";
import { ContinuousPhysics } from "./physics.js";
export function getColor(sprite) {
try {
let color = sprite.color;
try {
return colorDict[color];
} catch (e) {
console.log(e);
return color;
}
} catch (e) {
console.log(e);
return null;
}
}
export function scoreChange(sprite, partner, game, kwargs) {
// console.log(`Before Score Change: ${kwargs.score}/${game.score}`)
game.score += kwargs.score ?? kwargs.value;
// console.log(`Score Change: ${kwargs.score}/${game.score}`)
return ["scoreChange", sprite.ID || sprite, partner.ID || partner];
}
export let changeScore = scoreChange;
export function nothing(sprite, partner, game, kwargs) {
return ["nothing", sprite.ID || sprite, partner.ID || partner];
}
export function killSprite(sprite, partner, game, kwargs) {
game.kill_list.push(sprite);
// console.log("kill sprite", sprite.name, partner.name, game.collision_set)
return [
"killSprite",
sprite.ID || sprite,
partner ? partner.ID || partner : null,
];
}
//正好与killsprite效果相反专门为大预言模型设计
export function removeSprite(sprite, partner, game, kwargs) {
game.kill_list.push(partner);
return [
"removeSprite",
sprite.ID || sprite,
partner ? partner.ID || partner : null,
];
}
export function cloneSprite(sprite, partner, game, kwargs) {
game._createSprite([sprite.name], [sprite.location.x, sprite.location.y]);
return ["cloneSprite", sprite.ID || sprite, partner.ID || partner];
}
export function transformTo(sprite, partner, game, kwargs) {
// let hasID = partner.ID in sprite.transformedBy;
// let validTime;
// if (hasID) {
// if (game.time > sprite.transformedBy[partner.ID] + 3) {
// validTime = true;
// } else {
// validTime = false;
// }
// }
// if (!(hasID) || validTime) {
//(sprite.transformedBy.has(partner.ID)) {
//sprite.transformedBy.add(partner.ID);
sprite.transformedBy[partner.ID] = game.time;
let stype = kwargs.stype;
const forceOrientation = kwargs.forceOrientation;
let newones = game._createSprite(
[stype],
[sprite.location.x, sprite.location.y],
);
if (newones.length > 0) {
if (
forceOrientation ||
(sprite instanceof OrientedSprite &&
newones[0] instanceof OrientedSprite &&
vectNorm(newones[0].orientation) === 0)
)
newones[0].orientation = sprite.orientation;
newones[0].transformedBy = sprite.transformedBy;
newones[0].lastlocation = { ...sprite.lastlocation };
killSprite(sprite, partner, game, kwargs);
}
// if(kwargs['killSecond'] && kwargs['killSecond'] === true){
// game.kill_list.push(partner)
// }
return ["transformTo", sprite.ID || sprite, partner.ID || partner];
// } else {
// return;
// }
}
export function transformToAll(sprite, partner, game, kwargs) {
//(sprite.transformedBy.has(partner.ID)) {
//sprite.transformedBy.add(partner.ID);
sprite.transformedBy[partner.ID] = game.time;
let stype = kwargs.stype;
const sprites = game.getSprites(stype);
sprites.forEach((s) => {
transformTo(s, partner, game, { stype: kwargs.stypeTo });
});
return ["transforrmToAll", sprite.ID || sprite, partner.ID || partner];
}
export function stepBack(sprite, partner, game, kwargs) {
// console.log(`[Step Back] ${sprite.name} last location: ${JSON.stringify(sprite.lastlocation)}`)
sprite.location = { x: sprite.lastlocation.x, y: sprite.lastlocation.y };
return ["stepBack", sprite.ID || sprite, partner.ID || partner];
}
export function bounceForward(sprite, partner, game, kwargs) {
// console.log("bounce forward", sprite.name, partner.name, JSON.stringify(partner.lastdirection()))
// detect if the partner is moving toward the sprite
if(game.use_frame){
const partner2spriteVector = [sprite.location.x - partner.location.x, sprite.location.y - partner.location.y]
const dotResult = tools.dot(partner2spriteVector, partner.orientation)
if(dotResult <= 0.2) {return;}
}
sprite.physics.activeMovement(
sprite,
tools.unitVector(partner.lastdirection()),
partner.speed,
);
game._updateCollisionDict(sprite);
return ["bounceForward", sprite.ID || sprite, partner.ID || partner];
}
export function conveySprite(sprite, partner, game, kwargs) {
let sprite_lastlocation = { ...sprite.lastlocation };
let vect = tools.unitVector(partner.orientation);
sprite.physics.activeMovement(sprite, vect, partner.strength);
sprite.lastlocation = sprite_lastlocation;
game._updateCollisionDict(sprite);
return ["conveySprite", sprite.ID || sprite, partner.ID || partner];
}
export function windGust(sprite, partner, game, kwargs) {
let s = partner.strength - [0, 1, -1].randomElement();
if (s !== 0) {
let sprite_lastlocation = { ...sprite.lastlocation };
let vect = tools.unitVector(partner.orientation);
sprite.physics.activeMovement(sprite, vect, s);
sprite.lastlocation = sprite_lastlocation;
game._updateCollisionDict(sprite);
}
return ["windGust", sprite.ID || sprite, partner.ID || partner];
}
export function slipForward(sprite, partner, game, kwargs) {
if (kwargs.prob > Math.random()) {
let sprite_lastlocation = { ...sprite.lastlocation };
let vect = tools.unitVector(partner.orientation);
sprite.physics.activeMovement(sprite, vect, 1);
sprite.lastlocation = sprite_lastlocation;
game._updateCollisionDict(sprite);
}
return ["slipForward", sprite.ID || sprite, partner.ID || partner];
}
export function undoAll(sprite, partner, game, kwargs) {
const notStypeStr = kwargs["nontStype"] ?? "";
const notStype = notStypeStr.split(",").map((s) => s.trim());
game._iterAllExcept(notStype).forEach((s) => {
s.location = { ...s.lastlocation };
});
return ["undoAll", sprite.ID || sprite, partner.ID || partner];
}
export function attractGaze(sprite, partner, game, kwargs) {
if (kwargs.prob > Math.random()) {
sprite.orientation = partner.orientation;
}
return ["attractGaze", sprite.ID || sprite, partner.ID || partner];
}
export function turnAround(sprite, partner, game, kwargs) {
sprite.location = sprite.lastlocation;
sprite.lastmove = sprite.cooldown;
sprite.physics.activeMovement(sprite, DOWN);
sprite.lastmove = sprite.cooldown;
sprite.physics.activeMovement(sprite, DOWN);
reverseDirection(sprite, partner, game, kwargs);
game._updateCollisionDict(sprite);
return ["turnAround", sprite.ID || sprite, partner.ID || partner];
}
export function reverseDirection(sprite, partner, game, kwargs) {
sprite.orientation = [-sprite.orientation[0], -sprite.orientation[1]];
return ["reverseDirection", sprite.ID || sprite, partner.ID || partner];
}
export function bounceDirection(sprite, partner, game, kwargs) {
let friction = kwargs.friction || 0;
stepBack(sprite, partner, game);
let inc = sprite.orientation;
let snorm = unitVector([
-sprite.location.x + partner.location.y,
-sprite.location.y + partner.location.x,
]);
let dp = snorm[0] * inc[0] + snorm[1] * inc[1];
sprite.orientation = [
-2 * dp * snorm[0] + inc[0],
-2 * dp * snorm[1] + inc[1],
];
sprite.speed *= 1 - friction;
return ["bounceDirection", sprite.ID || sprite, partner.ID || partner];
}
export function wallBounce(sprite, partner, game, kwargs) {
let friction = kwargs.friction || 0;
if (!oncePerStep(sprite, game, "lastbounce")) return;
sprite.speed *= 1 - friction;
stepBack(sprite, partner, game);
if (
Math.abs(sprite.location.x - partner.location.x) >
Math.abs(sprite.location.y - partner.location.y)
)
sprite.orientation = (-sprite.orientation[0], sprite.orientation[1]);
else sprite.orientation = (sprite.orientation[0], -sprite.orientation[1]);
// return ('wallBounce', colorDict[str(partner.color)], colorDict[str(sprite.color)])
// TODO: Not printing for now
// return ('wallBounce', sprite, partner)
return ["wallBounce", sprite.ID || sprite, partner.ID || partner];
}
export function wallStop(sprite, partner, game, kwargs) {
if (!tools.oncePerStep(sprite, game, "laststop")) return;
stepBack(sprite, partner, game, kwargs);
let x_dist = Math.abs(sprite.location.x - partner.location.x);
let y_dist = Math.abs(sprite.location.y - partner.location.y);
let y_orient = sprite.orientation[1] * (1 - kwargs.friction);
let x_orient = sprite.orientation[0] * (1 - kwargs.friction);
if (x_dist > y_dist) sprite.orientation = [0, y_orient];
else sprite.orientation = [x_orient, 0];
sprite.speed = tools.vectNorm(sprite.orientation) * sprite.speed;
sprite.orientation = tools.unitVector(sprite.orientation);
return ["wallStop", sprite.ID || sprite, partner.ID || partner];
}
export function killIfSlow(sprite, partner, game, kwargs) {
let limitspeed = kwargs.limitspeed ?? 1000;
let relspeed = 0;
if (sprite.is_static) relspeed = partner.speed;
else if (partner.is_static) relspeed = sprite.speed;
else
relspeed = tools.vectNorm([
sprite._velocity()[0] - partner._velocity()[0],
sprite._velocity()[1] - partner._velocity()[1],
]);
if (relspeed < limitspeed) {
killSprite(sprite, partner, game);
return ["killIfSlow", sprite.ID || sprite, partner.ID || partner];
}
}
export function killIfFromAbove(sprite, partner, game, kwargs) {
if (
sprite.lastlocation.y > partner.lastlocation.y &&
partner.location.y > partner.lastlocation.y
) {
killSprite(sprite, partner, game);
return ["killIfFromAbove", sprite.ID || sprite, partner.ID || partner];
}
}
export function killIfAlive(sprite, partner, game, kwargs) {
if (!game.kill_list.contains(partner)) {
killSprite(sprite, partner, game);
return ["killIfAlive", sprite.ID || sprite, partner.ID || partner];
}
}
export function killBoth(sprite, partner, game, kwargs) {
if (!game.kill_list.contains(partner)) {
killSprite(sprite, partner, game);
killSprite(partner, sprite, game);
return ["killBoth", sprite.ID || sprite, partner.ID || partner];
}
}
export function killAll(sprite, partner, game, kwargs) {
const stype = kwargs.stype;
const sprites = game.getSprites(stype);
sprites.forEach((s) => {
killSprite(s, partner, game, kwargs);
});
}
export function collectResource(sprite, partner, game, kwargs) {
// console.assert(sprite instanceof Resource);
let resource_type = sprite.name;
partner.resources[resource_type] = Math.max(
-1,
Math.min(
partner.resources.get(resource_type) + sprite.value,
game.resources_limits.get(resource_type),
),
);
killSprite(sprite, partner, game, kwargs);
return ["collectResource", sprite.ID || sprite, partner.ID || partner];
}
export function changeResource(sprite, partner, game, kwargs) {
let resource = kwargs.resource;
let value = kwargs.value || 1;
let sprite_resource = sprite.resources[resource] || 0;
let resource_limit = game.resources_limits[resource] || Infinity;
sprite.resources[resource] = Math.max(
-1,
Math.min(sprite_resource + value, resource_limit),
);
if (kwargs.killResource) {
killSprite(partner, undefined, game, {});
}
return ["changeResource", sprite.ID || sprite, partner.ID || partner];
}
export function spawnIfHasMore(sprite, partner, game, kwargs) {
const resource = kwargs.resource;
const stype = kwargs.stype;
let limit = kwargs.limit || 1;
if (sprite.resources[resource] >= limit) {
game._createSprite([stype], [sprite.location.x, sprite.location.y]);
return ["spawnIfHasMore", sprite.ID || sprite, partner.ID || partner];
}
}
export function spawnIfHasLess(sprite, partner, game, kwargs) {
const resource = kwargs.resource;
const stype = kwargs.stype;
let limit = kwargs.limit || 1;
if (sprite.resources[resource] < limit) {
game._createSprite([stype], [sprite.location.x, sprite.location.y]);
return ["spawnIfHasLess", sprite.ID || sprite, partner.ID || partner];
}
}
export function killIfHasMore(sprite, partner, game, kwargs) {
let limit = kwargs.limit;
let resource = kwargs.resource;
if (sprite.resources[resource] === undefined) sprite.resources[resource] = 0;
if (sprite.resources[resource] >= limit) {
killSprite(sprite, partner, game, kwargs);
return ["killIfHasMore", sprite.ID || sprite, partner.ID || partner];
}
}
export function killIfHasLess(sprite, partner, game, kwargs) {
let resource = kwargs.resource;
let limit = kwargs.limit;
if (sprite.resources[resource] === undefined) sprite.resources[resource] = 0;
if (sprite.resources[resource] <= limit) {
killSprite(sprite, partner, game, kwargs);
return ["killIfHasLess", sprite.ID || sprite, partner.ID || partner];
}
}
export function killIfOtherHasMore(sprite, partner, game, kwargs) {
let resource = kwargs.resource;
let limit = kwargs.limit;
if (sprite.resources[resource] === undefined) {
sprite.resources[resource] = 0;
}
if (partner.resources[resource] >= limit) {
killSprite(sprite, partner, game, kwargs);
return ["killIfOtherHasMore", sprite.ID || sprite, partner.ID || partner];
}
}
export function wrapAround(sprite, partner, game, kwargs) {
let offset = kwargs.offset || 0;
if (sprite.orientation[0] > 0) sprite.location.x = offset * 1;
else if (sprite.orientation[0] < 0)
sprite.location.x = game.screensize[0] - 1 * (1 + offset);
if (sprite.orientation[1] > 0) sprite.location.y = offset * 1;
else if (sprite.orientation[1] < 0)
sprite.location.y = game.screensize[1] - 1 * (1 + offset);
sprite.lastmove = 0;
return ["wrapAround", sprite.ID || sprite, partner.ID || partner];
}
export function pullWithIt(sprite, partner, game, kwargs) {
if (!tools.oncePerStep(sprite, game, "lastpull")){
// console.log("once per step o!", sprite.name, sprite["_lastpull"], game.time)
return;
}
let tmp = { ...sprite.lastlocation };
let v = tools.unitVector(partner.lastdirection());
// console.log("Pull with it!", sprite.name, sprite["_lastpull"], game.time, sprite.physics.gridsize[0], partner.speed);
sprite._updatePos(v, partner.speed * sprite.physics.gridsize[0]);
if (sprite.physics instanceof ContinuousPhysics) {
sprite.speed = partner.speed;
sprite.orientation = partner.lastdirection;
}
sprite.lastlocation = { ...tmp };
}
export function teleportToExit(sprite, partner, game, kwargs) {
let rand_sprite;
try {
rand_sprite = game.sprite_groups[partner.stype].randomElement();
} catch (error) {
rand_sprite = game.sprite_groups["goal"].randomElement();
}
sprite.location = { ...rand_sprite.location };
sprite.lastmove = 0;
return ["teleportToExit", sprite.ID || sprite, partner.ID || partner];
}
export const stochastic_effects = [
teleportToExit,
windGust,
slipForward,
attractGaze,
];
export const kill_effects = [
killSprite,
killIfSlow,
transformTo,
transformToAll,
killIfOtherHasMore,
killIfHasMore,
killIfHasLess,
killIfFromAbove,
killIfAlive,
];
export function spawn(sprite, partner, game, kwargs) {
const stype = kwargs["stype"];
game._createSprite([stype], [sprite.location.x, sprite.location.y]);
}
export function setSpeedForAll(sprite, partner, game, kwargs) {
const value = kwargs["value"] ?? 1.0;
const stype = kwargs["stype"];
const sprites = game.getSprites(stype);
sprites.forEach((s) => (s.speed = value));
return ["setSpeedForAll", sprite.ID || sprite, partner.ID || partner];
}
export function align(sprite, partner, game, kwargs) {
const orient = kwargs["orient"];
if (orient) sprite.orient = Object.copy(orient);
sprite.location = Object.copy(partner.location);
return ["align", sprite.ID || sprite, partner.ID || partner];
}
export function addHealthPoints(sprite, partner, game, kwargs) {
const value = kwargs.value;
if (sprite.healthPoints + value < sprite.limitHealthPoints) {
sprite.healthPoints += value;
sprite.healthPoints = Math.min(sprite.healthPoints, sprite.maxHealthPoints);
}
return ["addHealthPoints", sprite.ID || sprite, partner.ID || partner];
}
export function addHealthPointsToMax(sprite, partner, game, kwargs) {
const value = kwargs.value;
if (sprite.healthPoints + value < sprite.limitHealthPoints) {
sprite.healthPoints += value;
} else {
sprite.healthPoints = sprite.limitHealthPoints;
}
if (sprite.healthPoints > sprite.maxHealthPoints)
sprite.maxHealthPoints = sprite.healthPoints;
return ["addHealthPointsToMax", sprite.ID || sprite, partner.ID || partner];
}
export function subtractHealthPoints(sprite, partner, game, kwargs) {
const value = kwargs.value || 0;
const stype = kwargs.stype;
const limit = kwargs.limit || 0;
if (stype) {
const sprites = game.getSprites(stype);
sprites.forEach((s) => {
s.healthPoints -= value;
if (s.healthPoints <= limit) {
killSprite(s, partner, game, kwargs);
}
});
} else {
sprite.healthPoints -= value;
if (sprite.healthPoints <= limit) {
killSprite(sprite, partner, game, kwargs);
}
}
return ["subtractHealthPoints", sprite.ID || sprite, partner.ID || partner];
}
export function transformToRandomChild(sprite, partner, game, kwargs) {
const stype = kwargs.stype;
if (stype) {
console.log();
const types = Object.keys(game.getSubTypes(stype));
transformTo(sprite, partner, game, { stype: types.randomElement() });
}
return ["transformToRandomChild", sprite.ID || sprite, partner.ID || partner];
}
export function shieldFrom(sprite, partner, game, kwargs) {
const stype = kwargs.stype;
const ftype = kwargs.ftype;
game.addShield(sprite.stypes, stype, ftype);
return ["shieldFrom", sprite.ID || sprite, partner.ID || partner];
}
export function killIfFrontal(sprite, partner, game, kwargs) {
const direction1 = unitVector(sprite.lastdirection());
const direction2 = unitVector(partner.lastdirection());
// console.log("kill if frontal")
const dirsum = [direction1[0] + direction2[0], direction1[1] + direction2[1]];
if (vectNorm(dirsum) === 0 || vectNorm(direction1) === 0) {
killSprite(sprite, partner, game, kwargs);
}
}
export function killIfNotFrontal(sprite, partner, game, kwargs) {
const direction1 = unitVector(sprite.lastdirection());
const direction2 = unitVector(partner.lastdirection());
const dirsum = [direction1[0] + direction2[0], direction1[1] + direction2[1]];
// console.log("kill not frontal", dirsum, direction1)
if (vectNorm(dirsum) !== 0 || vectNorm(direction1) === 0) {
killSprite(sprite, partner, game, kwargs);
}
}
export function increaseSpeedToAll(sprite, partner, game, kwargs) {
const value = kwargs.value || 0.1;
const stype = kwargs.stype;
if(!stype) return;
const sprites = game.getSprites(stype);
sprites.forEach((s) => (s.speed += value));
return ["increaseSpeedToAll", sprite.ID || sprite, partner.ID || partner];
}