overte/unpublishedScripts/marketplace/gameTable/games/deckOfCards/deckOfCards.js
2017-04-17 13:16:10 +02:00

576 lines
No EOL
18 KiB
JavaScript

//
// Created by Thijs Wenker on 3/31/2017
// Copyright 2017 High Fidelity, Inc.
//
// Revision of James B. Pollack's work on GamesTable in 2016
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
// TODO: This game needs some work to get running
(function() {
var _this;
var MAPPING_NAME = "hifi-gametable-cards-dev-" + Math.random();
var PLAYING_CARD_SCRIPT_URL = Script.resolvePath('playingCard.js');
var PLAYING_CARD_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/thoys/production/gameTable/assets/deckOfCards/playing_card.fbx';
var PLAYING_CARD_BACK_IMAGE_URL = "http://hifi-content.s3.amazonaws.com/thoys/production/gameTable/assets/deckOfCards/back.jpg";
var PLAYING_CARD_DIMENSIONS = {
x: 0.2621,
y: 0.1,
z: 0.4533
};
var COLORS_CAN_PLACE = {
red: 0,
green: 255,
blue: 0
};
var COLORS_CANNOT_PLACE = {
red: 255,
green: 0,
blue: 0
};
var NEARBY_CARDS_RANGE = 5;
function DeckOfCards() {
_this = this;
}
DeckOfCards.prototype = {
rightOverlayLine: null,
leftOverlayLine: null,
targetOverlay: null,
currentHand: null,
offHand: null,
updateConnected: null,
preload: function(entityID) {
print('jbp preload deck of cards');
_this.entityID = entityID;
},
createMapping: function() {
var mapping = Controller.newMapping(MAPPING_NAME);
mapping.from([Controller.Standard.RTClick]).peek().to(function(val) {
_this.handleTrigger(val, 'right');
});
mapping.from([Controller.Standard.LTClick]).peek().to(function(val) {
_this.handleTrigger(val, 'left');
});
Controller.enableMapping(MAPPING_NAME);
},
destroyMapping: function() {
Controller.disableMapping(MAPPING_NAME);
},
handleTrigger: function(val, hand) {
if (val !== 1) {
return;
}
print('jbp trigger pulled at val:' + val + ":" + hand);
print('jbp at time hand was:' + _this.currentHand);
if (_this.currentHand === hand) {
print('jbp should ignore its the same hand');
} else {
print('jbp should make a new thing its the off hand');
_this.createPlayingCard();
}
},
checkIfAlreadyHasCards: function() {
print('jbp checking if already has cards');
var cards = _this.getCardsFromUserData();
if (cards === false) {
print('jbp should make new deck');
// should make a deck the first time
_this.makeNewDeck();
} else {
print('jbp already has deck' + cards);
// someone already started a game with this deck
_this.makeNewDeck();
_this.currentStack._import(cards);
}
},
resetDeck: function() {
print('jbp resetting deck');
// finds and delete any nearby cards
var position = Entities.getEntityProperties(_this.entityID, 'position');
var results = Entities.findEntities(position, NEARBY_CARDS_RANGE);
results.forEach(function(item) {
var itemProps = Entities.getEntityProperties(item, 'userData');
if (itemProps.userData.hasOwnProperty('playingCards') &&
itemProps.userData.playingCards.hasOwnProperty('card')) {
Entities.deleteEntity(item);
}
});
// resets this deck to a new deck
_this.makeNewDeck();
},
makeNewDeck: function() {
print('jbp make new deck');
// make a stack and shuffle it up.
var stack = new Stack();
stack.makeDeck(1);
stack.shuffle(100);
_this.currentStack = stack;
},
collisionWithEntity: function(me, other, collision) {
// on the start of a collision with the deck, if its a card, add it back to the deck
if (collision.type !== 0) {
// its not the start, so exit early.
return;
}
var otherProps = Entities.getEntityProperties(other, 'userData');
var userData = {};
try {
userData = JSON.parse(otherProps.userData);
} catch (e) {
return;
}
if (userData.hasOwnProperty('playingCards') && userData.playingCards.hasOwnProperty('card')) {
print('collided with a playing card!!!');
_this.currentStack.addCard(userData.playingCards.card);
Entities.deleteEntity(other);
}
},
startNearGrab: function(id, paramsArray) {
print('jbp deck started near grab');
_this.checkIfAlreadyHasCards();
_this.enterDealerMode(paramsArray[0]);
},
startEquip: function(id, params) {
this.startNearGrab(id, params);
},
releaseGrab: function() {
print('jbp release grab');
_this.exitDealerMode();
},
enterDealerMode: function(hand) {
_this.createMapping();
print('jbp enter dealer mode:' + hand);
var offHand;
if (hand === "left") {
offHand = "right";
}
if (hand === "right") {
offHand = "left";
}
_this.currentHand = hand;
_this.offHand = offHand;
Messages.sendLocalMessage('Hifi-Hand-Disabler', _this.offHand);
Script.update.connect(_this.updateRays);
_this.updateConnected = true;
},
updateRays: function() {
if (_this.currentHand === 'left') {
_this.rightRay();
}
if (_this.currentHand === 'right') {
_this.leftRay();
}
},
exitDealerMode: function() {
_this.destroyMapping();
// turn grab on
// save the cards
// delete the overlay beam
if (_this.updateConnected === true) {
Script.update.disconnect(_this.updateRays);
}
Messages.sendLocalMessage('Hifi-Hand-Disabler', 'none');
_this.deleteCardTargetOverlay();
_this.turnOffOverlayBeams();
_this.storeCards();
},
storeCards: function() {
var cards = _this.currentStack._export();
print('deck of cards: ' + cards);
Entities.editEntity(_this.entityID, {
userData: JSON.stringify({
cards: cards
})
});
},
restoreCards: function() {
_this.currentStack = _this.getCardsFromUserData();
},
getCardsFromUserData: function() {
var props = Entities.getEntityProperties(_this.entityID, 'userData');
var data;
try {
data = JSON.parse(props.userData);
print('jbp has cards in userdata' + props.userData);
} catch (e) {
print('jbp error parsing userdata');
return false;
}
if (data.hasOwnProperty('cards')) {
print('jbp returning data.cards');
return data.cards;
}
return false;
},
rightRay: function() {
var pose = Controller.getPoseValue(Controller.Standard.RightHand);
var rightPosition = pose.valid ?
Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position) :
MyAvatar.getHeadPosition();
var rightRotation = pose.valid ? Quat.multiply(MyAvatar.orientation, pose.rotation) :
Quat.multiply(MyAvatar.headOrientation, Quat.angleAxis(-90, {
x: 1,
y: 0,
z: 0
}));
var rightPickRay = {
origin: rightPosition,
direction: Quat.getUp(rightRotation)
};
this.rightPickRay = rightPickRay;
var location = Vec3.sum(rightPickRay.origin, Vec3.multiply(rightPickRay.direction, 50));
var rightIntersection = Entities.findRayIntersection(rightPickRay, true, [], [this.targetEntity]);
if (rightIntersection.intersects) {
this.rightLineOn(rightPickRay.origin, rightIntersection.intersection, COLORS_CAN_PLACE);
if (this.targetOverlay !== null) {
this.updateTargetOverlay(rightIntersection);
} else {
this.createTargetOverlay();
}
} else {
this.rightLineOn(rightPickRay.origin, location, COLORS_CANNOT_PLACE);
}
},
leftRay: function() {
var pose = Controller.getPoseValue(Controller.Standard.LeftHand);
var leftPosition = pose.valid ? Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position) : MyAvatar.getHeadPosition();
var leftRotation = pose.valid ? Quat.multiply(MyAvatar.orientation, pose.rotation) :
Quat.multiply(MyAvatar.headOrientation, Quat.angleAxis(-90, {
x: 1,
y: 0,
z: 0
}));
var leftPickRay = {
origin: leftPosition,
direction: Quat.getUp(leftRotation)
};
this.leftPickRay = leftPickRay;
var location = Vec3.sum(MyAvatar.position, Vec3.multiply(leftPickRay.direction, 50));
var leftIntersection = Entities.findRayIntersection(leftPickRay, true, [], [this.targetEntity]);
if (leftIntersection.intersects) {
this.leftLineOn(leftPickRay.origin, leftIntersection.intersection, COLORS_CAN_PLACE);
if (this.targetOverlay !== null) {
this.updateTargetOverlay(leftIntersection);
} else {
this.createTargetOverlay();
}
} else {
this.leftLineOn(leftPickRay.origin, location, COLORS_CANNOT_PLACE);
}
},
rightLineOn: function(closePoint, farPoint, color) {
if (this.rightOverlayLine === null) {
var lineProperties = {
start: closePoint,
end: farPoint,
color: color,
ignoreRayIntersection: true,
visible: true,
alpha: 1,
solid: true,
drawInFront: true,
glow: 1.0
};
this.rightOverlayLine = Overlays.addOverlay("line3d", lineProperties);
} else {
Overlays.editOverlay(this.rightOverlayLine, {
start: closePoint,
end: farPoint,
color: color
});
}
},
leftLineOn: function(closePoint, farPoint, color) {
if (this.leftOverlayLine === null) {
var lineProperties = {
ignoreRayIntersection: true,
start: closePoint,
end: farPoint,
color: color,
visible: true,
alpha: 1,
solid: true,
glow: 1.0,
drawInFront: true
};
this.leftOverlayLine = Overlays.addOverlay("line3d", lineProperties);
} else {
Overlays.editOverlay(this.leftOverlayLine, {
start: closePoint,
end: farPoint,
color: color
});
}
},
rightOverlayOff: function() {
if (this.rightOverlayLine !== null) {
print('jbp inside right off');
Overlays.deleteOverlay(this.rightOverlayLine);
this.rightOverlayLine = null;
}
},
leftOverlayOff: function() {
if (this.leftOverlayLine !== null) {
print('jbp inside left off');
Overlays.deleteOverlay(this.leftOverlayLine);
this.leftOverlayLine = null;
}
},
turnOffOverlayBeams: function() {
this.rightOverlayOff();
this.leftOverlayOff();
},
createTargetOverlay: function() {
print('jbp should create target overlay');
if (_this.targetOverlay !== null) {
return;
}
var targetOverlayProps = {
url: PLAYING_CARD_MODEL_URL,
dimensions: PLAYING_CARD_DIMENSIONS,
position: MyAvatar.position,
visible: true
};
_this.targetOverlay = Overlays.addOverlay("model", targetOverlayProps);
print('jbp created target overlay: ' + _this.targetOverlay);
},
updateTargetOverlay: function(intersection) {
// print('jbp should update target overlay: ' + _this.targetOverlay)
_this.intersection = intersection;
var rotation = Quat.lookAt(intersection.intersection, MyAvatar.position, Vec3.UP);
var euler = Quat.safeEulerAngles(rotation);
var position = {
x: intersection.intersection.x,
y: intersection.intersection.y + PLAYING_CARD_DIMENSIONS.y / 2,
z: intersection.intersection.z
};
_this.shiftedIntersectionPosition = position;
var towardUs = Quat.fromPitchYawRollDegrees(0, euler.y, 0);
// print('jbp should update target overlay to ' + JSON.stringify(position))
Overlays.editOverlay(_this.targetOverlay, {
position: position,
rotation: towardUs
});
},
deleteCardTargetOverlay: function() {
Overlays.deleteOverlay(_this.targetOverlay);
_this.targetOverlay = null;
},
handleEndOfDeck: function() {
print('jbp at the end of the deck, no more.');
},
createPlayingCard: function() {
print('jbp should create playing card');
if (_this.currentStack.cards.length > 0) {
var card = _this.currentStack.draw(1);
} else {
_this.handleEndOfDeck();
return;
}
print('jbp drew card: ' + card);
var properties = {
type: 'Model',
description: 'hifi:gameTable:game:playingCards',
dimensions: PLAYING_CARD_DIMENSIONS,
modelURL: PLAYING_CARD_MODEL_URL,
script: PLAYING_CARD_SCRIPT_URL,
position: _this.shiftedIntersectionPosition,
shapeType: "box",
dynamic: true,
gravity: {
x: 0,
y: -9.8,
z: 0
},
textures: JSON.stringify({
file1: PLAYING_CARD_BACK_IMAGE_URL,
file2: PLAYING_CARD_BACK_IMAGE_URL
}),
userData: JSON.stringify({
grabbableKey: {
grabbable: true
},
playingCards: {
card: card
}
})
};
Entities.addEntity(properties);
}
};
function Card(rank, suit) {
this.rank = rank;
this.suit = suit;
}
function stackImportCards(exportedCards) {
print('jbp importing ' + exportedCards);
var cards = JSON.parse(exportedCards);
this.cards = [];
var cardArray = this.cards;
cards.forEach(function(card) {
var newCard = new Card(card.substr(1, card.length), card[0]);
cardArray.push(newCard);
});
}
function stackExportCards() {
var _export = [];
this.cards.forEach(function(item) {
_export.push(item.suit + item.rank);
});
return JSON.stringify(_export);
}
function stackAddCard(card) {
this.cards.push(card);
}
function stackMakeDeck(n) {
var ranks = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"];
var suits = ["C", "D", "H", "S"];
var i, j, k;
var m;
m = ranks.length * suits.length;
// Set array of cards.
this.cards = [];
// Fill the array with 'n' packs of cards.
for (i = 0; i < n; i++) {
for (j = 0; j < suits.length; j++) {
for (k = 0; k < ranks.length; k++) {
this.cards[i * m + j * ranks.length + k] = new Card(ranks[k], suits[j]);
}
}
}
}
function stackShuffle(n) {
var i, j, k;
var temp;
// Shuffle the stack 'n' times.
for (i = 0; i < n; i++) {
for (j = 0; j < this.cards.length; j++) {
k = Math.floor(Math.random() * this.cards.length);
temp = this.cards[j];
this.cards[j] = this.cards[k];
this.cards[k] = temp;
}
}
}
function stackDeal() {
if (this.cards.length > 0) {
return this.cards.shift();
}
return null;
}
function stackDraw(n) {
var card;
if (n >= 0 && n < this.cards.length) {
card = this.cards[n];
this.cards.splice(n, 1);
} else {
card = null;
}
return card;
}
function stackCardCount() {
return this.cards.length;
}
function stackCombine(stack) {
this.cards = this.cards.concat(stack.cards);
stack.cards = [];
}
function Stack() {
// Create an empty array of cards.
this.cards = [];
this.makeDeck = stackMakeDeck;
this.shuffle = stackShuffle;
this.deal = stackDeal;
this.draw = stackDraw;
this.addCard = stackAddCard;
this.combine = stackCombine;
this.cardCount = stackCardCount;
this._export = stackExportCards;
this._import = stackImportCards;
}
return new DeckOfCards();
});