content/hifi-content/davidback/oldstuff/zombiework/zombieSurvivorScript.js
2022-02-13 22:49:05 +01:00

375 lines
No EOL
14 KiB
JavaScript

//
// zombieSurvivorScript.js
//
// Created by David Back on 2/8/18.
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
var CHANNEL_NAME = "ZOMBIE_BITE";
var DEAD_ZONE_POS = { x:-1.887, y:4.39989, z:-53.2878 };
var MINIMUM_STRIDE_MOVEMENT = 0.015;
var MINIMUM_FORWARD_STRIDES = 20;
var MINIMUM_BACKWARD_STRIDES = 20;
var MAX_VELOCITY = 10;
var VELOCITY_INCREASE_FACTOR = 60;
var VELOCITY_DECREASE = 0.2;
var VELOCITY_DECREASE_RUNNING = 0.05;
var RUN_CONTROLS = [Controller.Standard.LeftGrip, Controller.Standard.RightGrip];
var RUN_CONTROLS_THRESHOLD = 0.9;
var ADDITIONAL_BODY_OFFSET = {x:-0.097595, y:-0.018677, z:-0.088746};
var BITE_ANIMATION = "atp:/biteReaction.fbx";
var BITE_ANIMATION_START_FRAME = 0;
var BITE_ANIMATION_BLOOD_KEYFRAME = 10;
var BITE_ANIMATION_END_FRAME = 138;
var BITE_ANIMATION_FPS = 60;
var BLOOD_HAZE = "https://hifi-content.s3.amazonaws.com/davidback/development/zombies/BloodSphere2.fbx";
var MSEC_PER_SEC = 1000;
var BITES_REQUIRED = 3;
var BITES_SETTING_NAME = "ZombieBiteCount";
var HEALTH_VERTICAL_OFFSET_OVERHEAD = 1;
var HEALTH_VERTICAL_OFFSET_OVERLAY = -0.25;
var HEALTH_HORIZONTAL_OFFSET_OVERHEAD = 0.1;
var HEALTH_HORIZONTAL_OFFSET_OVERLAY = 0.1;
var HEALTH_OFFSET_WRIST = { x:0, y:0.03, z:0 };
var FORWARD_OFFSET = 0.2;
var HEART_MODEL_URL = "http://hifi-content.s3-us-west-1.amazonaws.com/rebecca/zombies/models/1410%20Heart.obj";
var DEBUG_BITE_KEY = "f";
var DEBUG_PRINT = true;
var FORCE_TEST_RUN = false;
var currentVelocity = 0;
var previousLeftDotProduct = 0;
var previousRightDotProduct = 0;
var bodyOffset;
var additionalBodyOffset;
var minLeftStride;
var maxLeftStride;
var minRightStride;
var maxRightStride;
var leftStrideForwardCount = 0;
var previousLeftStrideForwardCount = 0;
var leftStrideBackwardCount = 0;
var rightStrideForwardCount = 0;
var previousRightStrideForwardCount = 0;
var rightStrideBackwardCount = 0;
var biteAnimationPlaying = false;
var bloodHaze = undefined;
var healthOverhead = [];
var healthWrist = [];
var localPositionOverhead;
var localPositionOverlay;
var localPositionWrist;
function onMessageReceived(channel, message, senderID) {
var messageData = JSON.parse(message);
var type = messageData['type'];
var biterID = messageData['biterID'];
var victimID = messageData['victimID'];
if (type == "receiveBite") {
if (DEBUG_PRINT) {
print("receiveBite message received from biter " + biterID + " biting " + victimID);
}
if (victimID == MyAvatar.sessionUUID) {
if (DEBUG_PRINT) {
print("Bitten by zombie " + biterID);
}
biteReceived();
}
}
}
function keyPressEvent(event) {
if (DEBUG_BITE_KEY == event.text) {
if (DEBUG_PRINT) {
print("biteReceived called from debug key press");
}
biteReceived();
}
}
function biteReceived() {
var oldBites = Settings.getValue(BITES_SETTING_NAME, 0);
var newBites = oldBites;
newBites++;
Settings.setValue(BITES_SETTING_NAME, newBites);
if (DEBUG_PRINT) {
print(BITES_SETTING_NAME + " setting changed from " + oldBites + " to " + newBites);
}
var frameCount = BITE_ANIMATION_END_FRAME - BITE_ANIMATION_START_FRAME;
MyAvatar.overrideAnimation(BITE_ANIMATION, BITE_ANIMATION_FPS, false,
BITE_ANIMATION_START_FRAME, BITE_ANIMATION_END_FRAME);
biteAnimationPlaying = true;
var timeOut = MSEC_PER_SEC * frameCount / BITE_ANIMATION_FPS;
Script.setTimeout(function () {
biteAnimationPlaying = false;
MyAvatar.restoreAnimation();
Overlays.deleteOverlay(bloodHaze);
bloodHaze = undefined;
if (newBites >= BITES_REQUIRED) {
//MyAvatar.goToLocation(DEAD_ZONE_POS, true, MyAvatar.orientation);
Settings.setValue(BITES_SETTING_NAME, 0);
initHealth();
if (DEBUG_PRINT) {
print("DEAD - teleport to dead zone - " + BITES_SETTING_NAME + " reset back to 0");
}
}
}, timeOut);
var bloodTimeOut = MSEC_PER_SEC * BITE_ANIMATION_BLOOD_KEYFRAME / BITE_ANIMATION_FPS;
Script.setTimeout(function () {
var localPositionBlood = Vec3.subtract(MyAvatar.getJointPosition("Head"), MyAvatar.position);
var localRotationBlood = Quat.fromPitchYawRollDegrees(0, 0, 0);
bloodHaze = Overlays.addOverlay("model", {
localPosition: localPositionBlood,
localRotation: Quat.fromPitchYawRollDegrees(0, 0, 0),
parentID: MyAvatar.sessionUUID,
dimensions: {
x: 1,
y: 1,
z: 1
},
url: BLOOD_HAZE
});
}, bloodTimeOut);
loseHealth();
}
function update() {
var runControlsHeld = true;
for (var i = 0; i < RUN_CONTROLS.length; i++) {
var controlValue = Controller.getValue(RUN_CONTROLS[i]);
if (controlValue < RUN_CONTROLS_THRESHOLD) {
runControlsHeld = false;
}
}
if (runControlsHeld && !biteAnimationPlaying) {
if (Vec3.equal(bodyOffset, Vec3.ZERO)) {
bodyOffset = Vec3.subtract(MyAvatar.getJointPosition("Body"), MyAvatar.position);
additionalBodyOffset = Vec3.sum(bodyOffset, ADDITIONAL_BODY_OFFSET);
}
var leftHandPosition = Vec3.sum(MyAvatar.position, MyAvatar.getLeftHandPosition());
var rightHandPosition = Vec3.sum(MyAvatar.position, MyAvatar.getRightHandPosition());
var leftPlaneNormal = Vec3.cross(bodyOffset, additionalBodyOffset);
var rightPlaneNormal = leftPlaneNormal;
var toLeftHand = Vec3.subtract(leftHandPosition, MyAvatar.position);
var leftDotProduct = Vec3.dot(leftPlaneNormal, toLeftHand);
var toRightHand = Vec3.subtract(rightHandPosition, MyAvatar.position);
var rightDotProduct = Vec3.dot(rightPlaneNormal, toRightHand);
var leftHandDifference = leftDotProduct - previousLeftDotProduct;
var leftHandDirection = leftHandDifference > 0 ? 1 : -1;
if (leftHandDirection === 1) {
leftStrideForwardCount++;
} else {
leftStrideBackwardCount++;
}
var rightHandDifference = rightDotProduct - previousRightDotProduct;
var rightHandDirection = rightHandDifference > 0 ? 1 : -1;
if (rightHandDirection === 1) {
rightStrideForwardCount++;
} else {
rightStrideBackwardCount++;
}
if (minLeftStride == undefined || leftDotProduct < minLeftStride) {
minLeftStride = leftDotProduct;
}
if (maxLeftStride == undefined || leftDotProduct > maxLeftStride) {
maxLeftStride = leftDotProduct;
}
if (minRightStride == undefined || rightDotProduct < minRightStride) {
minRightStride = rightDotProduct;
}
if (maxRightStride == undefined || rightDotProduct > maxRightStride) {
maxRightStride = rightDotProduct;
}
if (minLeftStride != undefined && maxLeftStride != undefined && maxLeftStride - minLeftStride > MINIMUM_STRIDE_MOVEMENT && leftStrideForwardCount >= MINIMUM_FORWARD_STRIDES && leftStrideBackwardCount >= MINIMUM_BACKWARD_STRIDES) {
var maxLeftStrideDifference = Math.abs(leftDotProduct - maxLeftStride);
if (maxLeftStrideDifference > 0 && maxLeftStrideDifference < 0.01) {
var strideLength = maxLeftStride - minLeftStride;
var velocityIncrease = strideLength * VELOCITY_INCREASE_FACTOR;
currentVelocity += velocityIncrease;
if (currentVelocity > MAX_VELOCITY) {
currentVelocity = MAX_VELOCITY;
}
maxLeftStride = undefined;
minLeftStride = undefined;
leftStrideForwardCount = 0;
leftStrideBackwardCount = 0;
}
}
if (minRightStride != undefined && maxRightStride != undefined && maxRightStride - minRightStride > MINIMUM_STRIDE_MOVEMENT && rightStrideForwardCount >= MINIMUM_FORWARD_STRIDES && rightStrideBackwardCount >= MINIMUM_BACKWARD_STRIDES) {
var maxRightStrideDifference = Math.abs(rightDotProduct - maxRightStride);
if (maxRightStrideDifference > 0 && maxRightStrideDifference < 0.01) {
var strideLength = maxRightStride - minRightStride;
var velocityIncrease = strideLength * VELOCITY_INCREASE_FACTOR;
currentVelocity += velocityIncrease;
if (currentVelocity > MAX_VELOCITY) {
currentVelocity = MAX_VELOCITY;
}
maxRightStride = undefined;
minRightStride = undefined;
rightStrideForwardCount = 0;
rightStrideBackwardCount = 0;
}
}
} else {
maxLeftStride = undefined;
minLeftStride = undefined;
maxRightStride = undefined;
minRightStride = undefined;
leftStrideForwardCount = 0;
leftStrideBackwardCount = 0;
rightStrideForwardCount = 0;
rightStrideBackwardCount = 0;
}
if (FORCE_TEST_RUN && !biteAnimationPlaying) {
currentVelocity = MAX_VELOCITY;
}
var velocityDecrease = runControlsHeld ? VELOCITY_DECREASE_RUNNING : VELOCITY_DECREASE;
if (currentVelocity > 0) {
currentVelocity -= velocityDecrease;
}
if (currentVelocity < 0) {
currentVelocity = 0;
}
var velocityForward = { x:0, y:0, z:1 };
var newVelocity = currentVelocity;
if (newVelocity < 0) {
newVelocity = 0;
}
var newVelocityVector = Vec3.multiply(velocityForward, newVelocity);
if (Vec3.length(newVelocityVector) > MAX_VELOCITY) {
newVelocityVector = Vec3.normalize(newVelocityVector);
newVelocityVector = Vec3.multiply(newVelocityVector, MAX_VELOCITY);
}
MyAvatar.motorVelocity = newVelocityVector;
previousLeftDotProduct = leftDotProduct;
previousRightDotProduct = rightDotProduct;
if (bloodHaze !== undefined) {
var localRotationBlood = Quat.multiply(Quat.inverse(MyAvatar.orientation), Quat.multiply(Camera.orientation, Quat.fromPitchYawRollDegrees(0, 0, 0)));
Overlays.editOverlay(bloodHaze, { localRotation: localRotationBlood });
}
}
function addHealth() {
var heart = Entities.addEntity({
"clientOnly": 1,
"dimensions": {
"x": 0.075,
"y": 0.075,
"z": 0.075
},
"localPosition": localPositionOverhead,
"modelURL": HEART_MODEL_URL,
"name": "Heart CC-BY Poly by Google",
"parentID": MyAvatar.sessionUUID,
"parentJointName": "Hips",
"owningAvatarID": MyAvatar.sessionUUID,
"type": "Model",
"userData": "{\"grabbableKey\":{\"grabbable\":false}}"
});
healthOverhead.push(heart);
//spawnOverlayReplica(heart);
spawnWristOverlay();
}
function loseHealth() {
if (healthOverhead[0]) {
Entities.deleteEntity(healthOverhead[0]);
healthOverhead.shift();
}
if (healthWrist[0]) {
Overlays.deleteOverlay(healthWrist[0]);
healthWrist.shift();
}
}
function spawnOverlayReplica(entity) {
var overlayProperties = {
url: HEART_MODEL_URL,
alpha: 0.9,
parentID: entity,
localPosition: {x: 0, y: HEALTH_VERTICAL_OFFSET_OVERLAY, z: 0.5},
dimensions: {
x: 0.04,
y: 0.04,
z: 0.04
}
};
Overlays.addOverlay("model", overlayProperties);
}
function spawnWristOverlay() {
// maybe change this to an image overlay
var overlayProperties = {
url: HEART_MODEL_URL,
alpha: 0.9,
parentID: MyAvatar.sessionUUID,
parentJointIndex: MyAvatar.getJointIndex("RightForeArm"),
localPosition: localPositionWrist,
dimensions: {
x: 0.02,
y: 0.02,
z: 0.02
}
};
healthWrist.push(Overlays.addOverlay("model", overlayProperties));
}
function initHealth() {
localPositionOverhead = {x:-HEALTH_HORIZONTAL_OFFSET_OVERHEAD, y:HEALTH_VERTICAL_OFFSET_OVERHEAD, z:0};
localPositionWrist = {x:0.06, y:0.15, z:0};
addHealth();
for (var i = 1; i < BITES_REQUIRED; i++) {
localPositionOverhead.x += HEALTH_HORIZONTAL_OFFSET_OVERHEAD;
localPositionWrist = Vec3.sum(localPositionWrist, HEALTH_OFFSET_WRIST);
addHealth();
}
}
function shutdown() {
Messages.unsubscribe(CHANNEL_NAME);
Messages.messageReceived.disconnect(onMessageReceived);
Controller.keyPressEvent.disconnect(keyPressEvent);
MyAvatar.motorVelocity = { x:0, y:0, z:0 };
MyAvatar.motorMode = "simple";
for (var i = 0; i < BITES_REQUIRED; i++) {
loseHealth();
}
}
function init() {
Script.scriptEnding.connect(shutdown);
Messages.subscribe(CHANNEL_NAME);
Messages.messageReceived.connect(onMessageReceived);
Controller.keyPressEvent.connect(keyPressEvent);
MyAvatar.motorMode = "dynamic";
MyAvatar.motorReferenceFrame = "camera";
Script.update.connect(update);
Script.setTimeout(function () {
initHealth();
}, 500);
}
init();