| Scripts/yah_gem_blackjack.js | "use strict";
this.name = "yah_gem_blackjack";
this.author = "spara";
//add interface, if the player has started the game anywhere elsewhere than constore
this.startUpComplete = function() {
	if (!player.ship.dockedStation.hasRole("constore")) {
		this.shipExitedWitchspace();
	}
}
this.shipExitedWitchspace = function() {
	var constores = system.shipsWithRole("constore");
	if (constores.length > 0) {
		for (var i = 0; i < constores.length; i++) {
			constores[i].setInterface("yah_gem-blackjack",{
				title: "Video blackjack",
				category: expandMissionText("yah_gem-gambling-category"),
				summary: expandMissionText("yah_gem-blackjack-summary"),
				callback: this.$intro.bind(this)
			});
		}
	}
}
//init a new deck
this.$virginDeck = function() {
	var deck = new Array();
	var suits = ["triangle", "crescent", "square", "star"];
	for (var i = 0; i < 4; i++) {
		for (var j = 1; j < 14; j++) {
			var card = new Object();
			card.suit = suits[i];
			card.rank = j;
			card.double = 0; 
			card.hide = 0;
			if (j > 10) card.value = 10;
			else if (j === 1) card.value = 11;
			else card.value = card.rank;
			deck.push(card);
		}
	}
	return deck;
}
//calculate the value of a hand
this.$calculateHandValue = function(cards) {
	var finished = false;
	while (!finished) {
		var sum = 0;
		for (var i = 0; i < cards.length; i++) {
			sum += cards[i].value;
		}
		if (sum > 21) {
			//change aces' value from 11 to 1
			for (var i = 0; i < cards.length; i++) {
				if (cards[i].value === 11) {
					cards[i].value = 1;
					break;
				}
			}
			//all aces have been changed, sum stands.
			if (i === cards.length)
				finished = true;
		}
		else finished = true;
	}
	return sum;
}
//intro screen
this.$intro = function() {
	var credits = "\n\nGems: " + player.ship.manifest["gem_stones"] + " g";
	//gambling choices
	var options = {
		"1_EXIT" : "Exit"
	};
	if (player.ship.manifest["gem_stones"] >= 2)
		options["2_10"] = "Bet 1";
	else credits += expandMissionText("yah_gem-no-credit");
	if (player.ship.manifest["gem_stones"] >= 4)
		options["3_50"] = "Bet 5";
	if (player.ship.manifest["gem_stones"] >= 8)
		options["4_100"] = "Bet 10";	
	
	mission.runScreen({
		titleKey: "yah_gem-blackjack-title",
		message: expandMissionText("yah_gem-blackjack-intro-story") + credits,
		model: "yah_gem_casino_blackjack_card_intro",
		background: "yah_gem_table_bg.png",
		choices: options,
		allowInterrupt: true,
		screenID: "yah_gem_blackjack",
		exitScreen: "GUI_SCREEN_INTERFACES"
	},
	function (choice) {
		if (choice === "2_10") this.$playGame(2);
		else if (choice === "3_50") this.$playGame(4);
		else if (choice === "4_100") this.$playGame(8);
	});
}
//first pay, then deal
this.$playGame = function(bet) {
	
	//pay up first
	player.ship.manifest["gem_stones"] -= bet;
	this.$bet = bet;//initial bet
	this.$totalBet = bet;//sum of all bets in round
	
	//init a new deck
	this.$playDeck = this.$virginDeck();
	
	//dealer initial hand
	var dealerHand = new Object();
	dealerHand.cards = [this.$drawCard(), this.$drawCard()];
	dealerHand.cards[1].hide = 1;
	this.$dealerHands = [dealerHand];
	
	//player initial hand
	var playerHand = new Object();
	playerHand.cards = [this.$drawCard(), this.$drawCard()];
	playerHand.bet = bet;
	this.$playerHands = [playerHand];
	//lets play some blackjack
	this.$deal(0);
}
this.$updateHandProps = function(hand, hands) {
	hand.value = this.$calculateHandValue(hand.cards);
	if (hand.value === 21) {
		if (hands.length === 1 && hand.cards.length === 2) {
			hand.status = "blackjack";
		}
		else hand.status = "21";
	}
	else if (hand.value > 21) hand.status = "busted";
	else if (hand.status !== "stand") hand.status = "hit";
}
//Deal
this.$deal = function() {
	
	//rotate till playable hand
	for (var hand = 0; hand < this.$playerHands.length; hand++) {
		var playerHand = this.$playerHands[hand];
		this.$updateHandProps(playerHand, this.$playerHands);
		if (playerHand.value < 21 && playerHand.status !== "stand")
			break;
	}
	
	//dealer's turn?
	if (hand === this.$playerHands.length) {
		this.$resolve();
		return;
	}
	
	//choices
	var options = {};
	if (playerHand.status === "hit") {
		options["1_HIT"] = "Hit";
		options["2_STAND"] = "Stand";
	}
	if (playerHand.cards.length === 2 && playerHand.status === "hit" && player.ship.manifest["gem_stones"] >= this.$bet) {
		options["3_DOUBLE"] = "Double Down (" + this.$bet + " g)";
	}
	if (playerHand.cards.length === 2 && (playerHand.cards[0].value === playerHand.cards[1].value || playerHand.cards[0].rank === playerHand.cards[1].rank) && this.$playerHands.length < 4) {
		options["4_SPLIT"] = "Split (" + this.$bet + " g)";
	}
	if (playerHand.cards.length === 2 && this.$playerHands.length === 1) {
		options["5_SURRENDER"] = "Surrender";
	}
	//status message
	var message = "Player hand: " + playerHand.value + "\n\n";
	message += "Total bet: " + this.$totalBet;
	message += "\nGems: " + player.ship.manifest["gem_stones"] + " g";
	mission.runScreen({
		titleKey: "yah_gem-blackjack-title",
		model: "yah_gem_casino_blackjack_card_base",
		background: "yah_gem_table_bg.png",
		message: message,
		spinModel: false,
		screenID: "yah_gem_blackjack",
		choices: options
	},
	function (choice) {
		if (choice === "1_HIT") {
			playerHand.cards.push(this.$drawCard());
			this.$deal();
			return;
		}
		else if (choice === "2_STAND") {
			playerHand.status = "stand";
			this.$deal();
			return;
		}
		else if (choice === "3_DOUBLE") {
			playerHand.cards.push(this.$drawCard());
			this.$updateHandProps(playerHand, this.$playerHands);
			if (playerHand.value < 21) playerHand.status = "stand";
			player.ship.manifest["gem_stones"] -= this.$bet;
			this.$totalBet += this.$bet;
			playerHand.bet = 2 * playerHand.bet;
			this.$deal();
			return;
		}
		else if (choice === "4_SPLIT") {
			
			//limit to one card after splitting aces!!!!!!!
			if (playerHand.cards[0].rank === 1) {
				playerHand.cards[0].value = 11;
				playerHand.cards[1].value = 11;
			}
			player.ship.manifest["gem_stones"] -= this.$bet;
			this.$totalBet += this.$bet;
			var newHand = new Object();
			newHand.cards = [playerHand.cards.pop(), this.$drawCard()];
			newHand.bet = this.$bet;
			this.$playerHands.push(newHand);
			playerHand.cards.push(this.$drawCard());
			this.$deal();
			return;
		}
		else if (choice === "5_SURRENDER") {
			playerHand.status = "surrender";
			this.$resolve();
			return;
		}
		else {
			this.$intro();
			return;
		}
	}
	);
	
	this.$updateScreen();
	
	//update flasher markers
	//while playing: yellow - current hand, red - busted hand
	for (var i = 0; i < this.$playerHands.length; i++) {
		var status = this.$playerHands[i].status;
		if (i === hand)
			mission.displayModel.flashers[i].color = "yellowColor";
		else if (status === "busted")
			mission.displayModel.flashers[i].color = "redColor";
		else {
			mission.displayModel.flashers[i].position = [0, 0, 50];
		}
	}
	for (var j = i; j < 4; j++)
		mission.displayModel.flashers[j].position = [0, 0, 50];
}
this.$resolve = function() {
	var dealerHand = this.$dealerHands[0];
	this.$updateHandProps(dealerHand, this.$dealerHands);
	dealerHand.cards[1].hide = false;
	//check player for non-busted hands
	var busted = true;
	for (var i = 0; i < this.$playerHands.length; i++) {
		if (this.$playerHands[i].status !== "busted") {
			busted = false;
			break;
		}
	}
	//if all player cards are busted, dealer automatically wins
	if (busted || this.$playerHands[i].status === "surrender") {
		for (var i = 0; i < this.$playerHands.length; i++) {
			this.$playerHands[i].result = "loss";
		}
	}
	else {
		//start drawing cards until we go over 16.
		while (dealerHand.value < 17) {
			dealerHand.cards.push(this.$drawCard());
			this.$updateHandProps(dealerHand, this.$dealerHands);
		}
		//compare player hands to the dealer hand
		for (var i = 0; i < this.$playerHands.length; i++) {
			var playerHand = this.$playerHands[i];
			//if the player has not busted, we'll compare
			if (playerHand.status !== "busted") {
				//blackjack
				if (playerHand.status === "blackjack") {
					if (dealerHand.status === "blackjack")
						playerHand.result = "push";
					else playerHand.result = "win";
				}
				//push
				else if (dealerHand.value === playerHand.value)
					playerHand.result = "push";
				//win
				else if (dealerHand.value > 21 || (21 - playerHand.value < 21 - dealerHand.value))
					playerHand.result = "win";
				//loss
				else playerHand.result = "loss";
			}
			//if the player has busted, it's a loss
			else playerHand.result = "loss";
		}
	}
	//calculate the winnings
	var win = 0;
	for (var i = 0; i < this.$playerHands.length; i++) {
		var playerHand = this.$playerHands[i];
		if (playerHand.result === "win") {
			if (playerHand.status === "blackjack")
				win += 2.5 * playerHand.bet;
			else win += 2 * playerHand.bet;
		}
		else if (playerHand.result === "push")
			win += playerHand.bet;
		else if (playerHand.status === "surrender" && dealerHand.status !== "blackjack")
			win += playerHand.bet / 2;
	}
	player.ship.manifest["gem_stones"] += win;
	
	//status message
	var resultMessage = "";
	
	//player
	for (var i = 0; i < this.$playerHands.length; i++) {
		var playerHand = this.$playerHands[i]
		resultMessage += "Player hand: ";
		if (playerHand.status === "blackjack")
			resultMessage += "Blackjack\n";
		else if (playerHand.status === "busted")
			resultMessage += "Busted\n";
		else if (playerHand.result === "push")
			resultMessage += "Push\n";
		else if (playerHand.status === "surrender")
			resultMessage += "Surrender\n";
		else resultMessage += playerHand.value + "\n";
	}
	
	//dealer
	if (dealerHand.status === "blackjack")
		resultMessage += "Dealer hand: Blackjack\n\n"
	else if (dealerHand.status === "busted")
		resultMessage += "Dealer hand: Busted\n\n"
	else resultMessage += "Dealer hand: " + dealerHand.value + "\n\n";
	//winnings
	var notifySound = new SoundSource;
	if (win - this.$totalBet > 0) {
		resultMessage += "You win " + (win -  this.$totalBet) + " g\n";
		notifySound.sound = "yah_gem_win.ogg";
	}
	else if (win - this.$totalBet < 0) {
		resultMessage += "You lose " + (this.$totalBet - win) + " g\n";
		notifySound.sound = "yah_gem_lose.ogg";
	}
	else {
		resultMessage += "You get even\n";
		notifySound.sound = "yah_gem_win.ogg";
	}
	notifySound.play();
	
	resultMessage += "\nGems: " + player.ship.manifest["gem_stones"] + " g";
	
	var options = {
		"2_REBET" : "Change bet",
		"3_EXIT" : "Exit"
	};
	if (player.ship.manifest["gem_stones"] >= this.$bet)
		options["1_AGAIN"] = "Deal again (" + this.$bet + " g)";
	mission.runScreen({
		titleKey: "yah_gem-blackjack-title",
		model: "yah_gem_casino_blackjack_card_base",
		message: resultMessage,
		spinModel: false,
		background: "yah_gem_table_bg.png",
		choices: options,
		allowInterrupt: true,
		screenID: "yah_gem_blackjack",
		exitScreen: "GUI_SCREEN_INTERFACES"
	},
	function (choice) {
		if (choice === "1_AGAIN") {
			this.$playGame(this.$bet);
			return;
		}
		else if (choice === "2_REBET") {
			this.$intro();
			return;
		}
	});
	
	this.$updateScreen(-1);
	
	//red: lose
	//green: win
	//yellow: push
	for (var i = 0; i < this.$playerHands.length; i++) {
		var result = this.$playerHands[i].result;
		if (result === "win")
			mission.displayModel.flashers[i].color = "greenColor";
		else if (result === "loss")
			mission.displayModel.flashers[i].color = "redColor";
		else mission.displayModel.flashers[i].color = "yellowColor";
	}
	for (var j = i; j < 4; j++)
		mission.displayModel.flashers[j].position = [0, 0, 50];
}
//draws a card from the current deck in play
this.$drawCard = function() {
	return this.$playDeck.splice(Math.floor(this.$playDeck.length * Math.random()),1)[0];
}
//update textures and positions for cards
this.$updateScreen = function() {
	//player cards subents 0-10, 11-21, 22 -32, 33-43
	//dealer cards subents 44-54
	//player cards
	for (var i = 0; i < this.$playerHands.length; i++) {
		//show player hand
		var playerHand = this.$playerHands[i];
		for (var j = 0; j < playerHand.cards.length; j++) {
			var card = playerHand.cards[j];
			var fileName = "yah_gem_card_" + card.suit + "_" + card.rank + ".png";
			var place = i * 11 + j;
			mission.displayModel.subEntities[place].setMaterials({"casino_poker_card_diffuse.png": {diffuse_map: fileName, emission_map: fileName, emission_modulate_color: "darkGrayColor"}});
		}
		//double down
		if (playerHand.bet === 2 * this.$bet) {
			mission.displayModel.subEntities[place].orientation = [0.5, 0.5, 0.5, 0.5];
		}
		//hide non used player subents from view
		for (var k = j; k < 11; k++) this.$hideCard(i * 11 + k);
	}
	//hide non used player subents from view
	for (var k = i * 11; k < 44; k++) this.$hideCard(k);
	
	//dealer cards
	var dealerHand = this.$dealerHands[0];
	for (var j = 0; j < dealerHand.cards.length; j++) {
		var card = dealerHand.cards[j];
		if (card.hide) {
			var fileName = "yah_gem_blackjack_card_diffuse.png";
		}
		else {
			var fileName = "yah_gem_card_" + card.suit + "_" + card.rank + ".png";
		}
		mission.displayModel.subEntities[4 * 11 + j].setMaterials({"casino_poker_card_diffuse.png": {diffuse_map: fileName, emission_map: fileName, emission_modulate_color: "darkGrayColor"}});
	}
	//hide non used dealer subents from view
	for (var k = 4 * 11 + j; k < 54; k++) this.$hideCard(k);
}
//moves the cards to the centerline and turns them out of view
this.$hideCard = function(place) {
	var position = mission.displayModel.subEntities[place].position;
	position[2] = 0;
	mission.displayModel.subEntities[place].position = position;
	var orientation = [0, 0, 0, 1];
	mission.displayModel.subEntities[place].orientation = orientation;
}
 | 
                
                    | Scripts/yah_gem_dice.js | "use strict";
this.name = "yah_gem_dice";
this.author = "spara";
//game track with bet multipliers
this.$track = [0, 0, 0, 4, 0, 8, 0, 17, 0, 35];
//add interface, if the player has started the game anywhere elsewhere than constore
this.startUpComplete = function() {
	if (!player.ship.dockedStation.hasRole("constore")) {
		this.shipExitedWitchspace();
	}
}
this.shipExitedWitchspace = function() {
	var constores = system.shipsWithRole("constore");
	if (constores.length > 0) {
		for (var i = 0; i < constores.length; i++) {
			constores[i].setInterface("yah_gem-dice",{
				title: "Smuggler's run",
				category: expandMissionText("yah_gem-gambling-category"),
				summary: expandMissionText("yah_gem-dice-summary"),
				callback: this.$intro.bind(this)
			});
		}
	}
}
//helper function for tabulating text on screen
this.$tabulate = function(line, width) {
	var hairSpace = String.fromCharCode(31);
	var space = defaultFont.measureString(" ");
	while (defaultFont.measureString(line) < width - space)
		line += " ";
	while (defaultFont.measureString(line) < width)
		line += hairSpace;
	return line;
}
//intro screen
this.$intro = function() {
	var bets = [1, 5, 10];
	//build and format the payoff table for screen
	var payoffMessage = "Bet:";
	for (var i = 0; i < 3; i++) {
		payoffMessage = this.$tabulate(payoffMessage, 5 * (i + 1));
		payoffMessage += bets[i] + " g";
	}
	var payoffMessage2 = "Score";
	for (var i = 0; i < 3; i++) {
		payoffMessage2 = this.$tabulate(payoffMessage2, 5 * (i + 1));
		payoffMessage2 += "Win!";
	}	
	payoffMessage = "\n\n" + payoffMessage + "\n\n" + payoffMessage2 + "\n";
	for (i = this.$track.length - 1; i > 0; i--) {
		if (this.$track[i] !== 0) {
			var line = this.$tabulate("", 0.5) + (i + 1);
			for (var j = 0; j < 3; j++) {
				line = this.$tabulate(line, 5 * (j + 1));
				line += this.$track[i] * bets[j] + " g";
			}
			payoffMessage += line+"\n";
		}
	}
	
	//format player credits for screen
	var credits = expandMissionText("yah_gem-credits")+player.ship.manifest["gem_stones"] + " g";
	
	var options = {
		"1_EXIT" : "Exit"
	};
	if (player.ship.manifest["gem_stones"] >= 1)
		options["2_10"] = "Bet 1";
	else credits += expandMissionText("yah_gem-no-credit");
	if (player.ship.manifest["gem_stones"] >= 5)
		options["3_50"] = "Bet 5";
	if (player.ship.manifest["gem_stones"] >= 10)
		options["4_100"] = "Bet 10";
	mission.runScreen({
		titleKey: "yah_gem-dice-title",
		screenID: "yah_gem_dice",
		message: expandMissionText("yah_gem-dice-intro-story")  + payoffMessage + credits,
		choices: options,
		background: "yah_gem_dice_bg-intro.png",
		exitScreen: "GUI_SCREEN_INTERFACES"
	},
	function (choice) {
		if (choice === "2_10") this.$playGame(1);
		else if (choice === "3_50") this.$playGame(5);
		else if (choice === "4_100") this.$playGame(10);
	}
	);
}
//da game
this.$playGame = function(bet, prevSum, round, track, select) {
	//init the game
	if (typeof round === 'undefined') {
		var round = 0;
		var track = this.$tabulate(" ", 3);
		player.ship.manifest["gem_stones"] -= bet;
	}
	
	//roll the dice
	var die1 = Math.ceil(6 * Math.random());
	var die2 = Math.ceil(6 * Math.random());
	var sum = die1 + die2;
	//check the guess
	var pass = true;
	if (typeof prevSum !== 'undefined') {
		if (select === "high_same") {
			if (sum < prevSum) 
				pass = false;
		}
		else if (select === "high") {
			if (sum <= prevSum) 
				pass = false;
		}
		else if (select === "low_same") {
			if (sum > prevSum) 
				pass = false;
		}
		else if (select === "low") {
			if (sum >= prevSum)
				pass = false;
		}
	}
//debug	
//pass = true; 
	//build the track display
	track += sum;
	//don't add tabs to the final score
	if (round < this.$track.length) {
		track = this.$tabulate(track, 3 + (round + 1) * 2.7);
	}
	var messageTrack = track;
	for (var i = round; i < this.$track.length; i++) {
		if (this.$track[i] !== 0) {
			messageTrack += bet * this.$track[i] + " g";
		}
		else messageTrack += "?";
		if (i < this.$track.length - 1) {
			messageTrack = this.$tabulate(messageTrack, 3 + (i + 2) * 2.7);
		}
	}
	var credits = "Gems: " + player.ship.manifest["gem_stones"] + " g";
	var betText = "Bet: " + bet + "\n";
	//correct guess
	if (pass) {
		var options = {};
		//cash out
		if (round > 0 && this.$track[round-1] !== 0) {
			var cash_out = bet * this.$track[round-1] + " g";
			options["1_CASH"] = "Cash out " + cash_out;
			var message = expandMissionText("yah_gem-dice-track-cash");
			var background = "yah_gem_dice_bg-cash.png";
		}
		else { 
			var message = expandMissionText("yah_gem-dice-track-basic");
			var background = "yah_gem_dice_bg-basic.png";
		}
		
		var background = "yah_gem_dice_bg-" + round + ".png"
		//guess choices
		if (round !== this.$track.length) {
			if (sum >= 7)
				options["2_HIGH_SAME"] = "Higher or same";
			else
				options["3_HIGH"] = "Higher";
			if (sum <= 7)
				options["4_LOW_SAME"] = "Lower or same";
			else
				options["5_LOW"] = "Lower";
		}
		//game finished
		else {
			var message = expandMissionText("yah_gem-dice-track-final");
		}
		mission.runScreen({
			titleKey: "yah_gem-dice-title",
			screenID: "yah_gem_dice",
			overlay: "yah_gem_dice_"+die1+"-"+die2+".png",
			message: "\n" + messageTrack + "\n\n" + message + "\n\n" + credits + "\n" + betText,
			choices: options,
			background: background
		}, 
		function (choice) {
			if (choice === "1_CASH") {
				var win = this.$track[round-1] * bet;
				player.ship.manifest["gem_stones"] += win;
				var notifySound = new SoundSource;
				notifySound.sound = "yah_gem_win.ogg";
				notifySound.play();
				this.$intro();
				return;
			}
			else if (choice === "2_HIGH_SAME") {
				this.$playGame(bet, sum, round + 1, track, "high_same");
				return;
			}
			else if (choice === "3_HIGH") {
				this.$playGame(bet, sum, round + 1, track, "high");
				return;
			}
			else if (choice === "4_LOW_SAME") {
				this.$playGame(bet, sum, round + 1, track, "low_same");
				return;
			}
			else if (choice === "5_LOW") {
				this.$playGame(bet, sum, round + 1, track, "low");
				return;
			}
		}
		);
	}
	else {
		var sound = "yah_gem_lose.ogg";
		var options = {
			"1_EXIT" : "Exit",
			"2_AGAIN" : "Change bet"
		};
		if (player.ship.manifest["gem_stones"] >= bet) options["3_PLAY"] = "Play again";
		mission.runScreen({
			titleKey: "yah_gem-dice-title",
			screenID: "yah_gem_dice",
			overlay: "yah_gem_dice_"+die1+"-"+die2+".png",
			message: "\n" + messageTrack + "\n\n" + expandMissionText("yah_gem-dice-track-fail") + "\n\n" + credits + "\n" + betText,
			choices: options,
			music: sound,
			background: "yah_gem_dice_bg-fail.png",
			exitScreen: "GUI_SCREEN_INTERFACES"
		},
		function (choice) {
			if (choice === "2_AGAIN") {
				this.$intro();
				return;
			}
			else if (choice === "3_PLAY") {
				this.$playGame(bet);
				return;
			}
		}
		);
	}
}
 | 
                
                    | Scripts/yah_gem_holdem.js | "use strict";
this.name = "yah_gem_holdem";
this.author = "spara";
this.$highNames = ["Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King", "Ace"];
this.$handRanks = ["High", "Pair","Two Pair","Three of a Kind","Straight","Flush","Full House","Four of a Kind","Straight Flush","Royal Flush"];
//add interface, if the player has started the game anywhere elsewhere than constore
this.startUpComplete = function() {
	if (!player.ship.dockedStation.hasRole("constore")) {
		this.shipExitedWitchspace();
	}
}
this.shipExitedWitchspace = function() {
	var constores = system.shipsWithRole("constore");
	if (constores.length > 0) {
		for (var i = 0; i < constores.length; i++) {
			constores[i].setInterface("yah_gem-holdem",{
				title: "hOopy hold'em",
				category: expandMissionText("yah_gem-gambling-category"),
				summary: expandMissionText("yah_gem-holdem-summary"),
				callback: this.$intro.bind(this)
			});
		}
	}
}
//init a new deck
this.$virginDeck = function() {
	var deck = new Array();
	var suits = ["triangle", "crescent", "square", "star"];
	for (var i = 0; i < 4; i++) {
		for (var j = 1; j < 14; j++) {
			var card = new Object();
			card.suit = suits[i];
			card.rank = j;
			card.show = false;
			deck.push(card);
		}
	}
	return deck;
}
//draws a card from the current deck in play
this.$drawCard = function() {
	return this.$playDeck.splice(Math.floor(this.$playDeck.length * Math.random()),1)[0];
}
this.$intro = function() {
	var credits = "\n\nGems: " + player.ship.manifest["gem_stones"] + " g";
	var options = {};
	options["1_EXIT"] = "Exit";
	if (player.ship.manifest["gem_stones"] >= 3)
		options["2_10"] = "Bet 1";
	else credits += expandMissionText("yah_gem-no-credit") + " Minimum of 3 g is needed to play.";
	if (player.ship.manifest["gem_stones"] >= 15)
		options["3_50"] = "Bet 5";
	if (player.ship.manifest["gem_stones"] >= 30)
		options["4_100"] = "Bet 10";
	
	mission.runScreen({
		titleKey: "yah_gem-holdem-title",
		message: expandMissionText("yah_gem-holdem-intro-story") + credits,
		model: "yah_gem_casino_holdem_intro",
		background: "yah_gem_table_bg.png",
		choices: options,
		allowInterrupt: true,
		screenID: "yah_gem_holdem",
		exitScreen: "GUI_SCREEN_INTERFACES"
	},
	function (choice) {
		if (choice === "2_10") this.$play(1);
		else if (choice === "3_50") this.$play(5);
		else if (choice === "4_100") this.$play(10);
	}	
	);
}
//first pay, then deal
this.$play = function(bet) {
	player.ship.manifest["gem_stones"] -= bet;
	this.$ante = bet;
	this.$bets = 0;
	this.$playDeck = this.$virginDeck();
	this.$cards = new Array();
	for (var i = 0; i < 9; i++) this.$cards.push(this.$drawCard());
	
	//debug hands
	//var deal = [48, 41, 5, 6, 23, 33, 19, 21, 30];
	//for (var i = 0; i < 9; i++) {
	//	this.$cards.push(this.$playDeck[deal[i]]);
	//}
	
	this.$deal("deal");
}
this.$deal = function(phase) {
	var message = "Ante: " + this.$ante;
	if (this.$bets > 0) message += "\nBets: " + this.$bets;
	message += "\n\nGems: " + player.ship.manifest["gem_stones"] + " g";
	var options = {};
	switch(phase) {
		case "deal" :	this.$cards[7].show = true; 
						this.$cards[8].show = true;
						options["1_FLOP"] = "Play (" + this.$ante * 2 + " g)";
						options["2_FOLD"] = "Fold";
						break;
		case "flop" :	this.$cards[2].show = true; 
						this.$cards[3].show = true;
						this.$cards[4].show = true;
						options["3_CHECK_TURN"] = "Check";
						if (player.ship.manifest["gem_stones"] >= this.$ante)
							options["4_BET_TURN"] = "Bet (" + this.$ante + " g)";
						break;
		case "turn" :	this.$cards[5].show = true; 
						options["5_CHECK_RIVER"] = "Check";
						if (player.ship.manifest["gem_stones"] >= this.$ante)
							options["6_BET_RIVER"] = "Bet (" + this.$ante + " g)";
						break;
	};
	mission.runScreen({
		titleKey: "yah_gem-holdem-title",
		model: "yah_gem_casino_holdem_base",
		message: message,
		background: "yah_gem_table_bg.png",
		spinModel: false,
		screenID: "yah_gem_holdem",
		choices: options
	},
	function(choice) {
		switch(choice) {
			case "1_FLOP" : player.ship.manifest["gem_stones"] -= 2 * this.$ante;
							this.$bets += 2 * this.$ante;
							this.$deal("flop");
							return;
			case "2_FOLD" : this.$showDown(true);
							return;
			case "3_CHECK_TURN" : 	this.$deal("turn");
									return;
			case "4_BET_TURN" : player.ship.manifest["gem_stones"] -= this.$ante;
								this.$bets += this.$ante;
								this.$deal("turn");
								return;
			case "5_CHECK_RIVER" : 	this.$showDown(false);
									return;
			case "6_BET_RIVER" : 	player.ship.manifest["gem_stones"] -= this.$ante;
									this.$bets += this.$ante;
									this.$showDown(false);
									return;
		}
	});
	this.$updateCards();
}
this.$handName = function(value, high) {
	if (value > 0)
		return this.$handRanks[value];
	else
		return this.$highNames[high - 7] + " " + this.$handRanks[0];
}
this.$formatHand = function(hand) {
	var formatted = "(";
	for (var i = 0; i < 5; i++) {
		var value = hand[0][i].value;
		if (value === 11) value = "J";
		else if (value === 12) value = "Q";
		else if (value === 13) value = "K";
		else if (value === 14 || value === 1) value = "A";
		formatted += value;
		if (i < 4) formatted += ", ";
		else formatted += ")";
	}
	return formatted;
}
this.$showDown = function(fold) {
	for (var i = 0; i < 9; i++) this.$cards[i].show = true;
	var playerHand = this.$bestHand(2);
	var dealerHand = this.$bestHand(0);
	var playerValues = "\n" + this.$formatHand(playerHand) + "\n\n";
	var dealerValues = "\n" + this.$formatHand(dealerHand) + "\n\n";
	var message = "Player: " + this.$handName(playerHand[1], playerHand[0][0].value) + playerValues;
	message += "Dealer: " + this.$handName(dealerHand[1], dealerHand[0][0].value) + dealerValues;
	
	if (fold) var result = "fold";
	else {
		var result = "push";
		if (dealerHand[1] > playerHand[1])
			result = "loss";
		else if (dealerHand[1] < playerHand[1]) {
			result = "win";
		}
		else {
			for (var i = 0; i < 5; i++) {
				if (playerHand[0][i].value > dealerHand[0][i].value) {
					result = "win";
					break;
				}
				else if (playerHand[0][i].value < dealerHand[0][i].value) {
					result = "loss";
					break;
				}
			}
		}
	}
	var notifySound = new SoundSource;
	switch (result) {
		case "win" : 	if (playerHand[1] > 3) {
							var win = 2 * (this.$bets + this.$ante);
						}
						else var win = this.$ante + 2 * (this.$bets);
						message += "You win " + (win - this.$bets - this.$ante) + " g";
						player.ship.manifest["gem_stones"] += win;
						notifySound.sound = "yah_gem_win.ogg";
						break;
		case "loss" : 	message += "Dealer wins, you lose " + this.$bets + " g";
						notifySound.sound = "yah_gem_lose.ogg";
						break;
		case "push" : 	message += "It's a push, wagers returned.";
						notifySound.sound = "yah_gem_win.ogg";
						player.ship.manifest["gem_stones"] += this.$bets + this.$ante;
						break;
		case "fold" :	message += "You fold and lose " + this.$ante + " g";
						notifySound.sound = "yah_gem_lose.ogg";
						break;
	}
	notifySound.play();
	message += "\n\nGems: " + player.ship.manifest["gem_stones"] + " g";
	var options = {};
	if (player.ship.manifest["gem_stones"] >= 3 * this.$ante)
		options["7_DEAL"] = "Deal again (" + this.$ante + " g)";
	options["8_BET"] = "Change ante";
	options["9_EXIT"] = "Exit";
	mission.runScreen({
		titleKey: "yah_gem-holdem-title",
		model: "yah_gem_casino_holdem_base",
		message: message,
		background: "yah_gem_table_bg.png",
		spinModel: false,
		choices: options,
		allowInterrupt: true,
		screenID: "yah_gem_holdem",
		exitScreen: "GUI_SCREEN_INTERFACES"
	},
	function(choice) {
		switch(choice) {
			case "7_DEAL" : this.$play(this.$ante);
							return;
			case "8_BET" : this.$intro(1);
							return;
		};
	});
	this.$updateCards();
}
this.$updateCards = function() {
	for (var i = 0; i < 9; i++) {
		var card = this.$cards[i];
		if (card.show) {
			var fileName = "yah_gem_card_" + card.suit + "_" + card.rank + ".png";
		}
		else var fileName = "yah_gem_holdem_card_diffuse.png";
		mission.displayModel.subEntities[i].setMaterials({"casino_poker_card_diffuse.png": {diffuse_map: fileName, emission_map: fileName, emission_modulate_color: "darkGrayColor"}});
	}
}
this.$bestHand = function(start) {
	
	//make a new hand with new objects
	var hand = new Array();
	for (var i = start; i < start + 7; i++) {
		var suits = ["triangle", "crescent", "square", "star"];
		var card = new Object();
		card.value = this.$cards[i].rank;
		card.suit = suits.indexOf(this.$cards[i].suit);
		if (card.value === 1) card.value = 14;
		hand.push(card);
	}
	
	//order cards by suit
	hand.sort(function(a, b) {return a.suit - b.suit});
	//handle flushes first	
	if (hand[0].suit === hand[4].suit || hand[1].suit === hand[5].suit || hand[2].suit === hand[6].suit) {
		//suit of flush
		var suit = hand[2].suit;
		//remove wrong suit cards
		for (var i = 0; i < 7; i++) {
			if (hand[6 - i].suit !== suit)
				hand.splice(6 - i, 1);
		}
		//order cards by value
		hand.sort(function(a, b) {return b.value - a.value})
		//handle possible ace by duplicating to a different value
		if (hand[0].value === 14) {
			card = new Object();
			card.value = 1;
			card.suit = suit;
			hand.push(card);
		}
		//look for a straight
		var straight = -1;
		var length = 0;
		for (var i = 0; i < hand.length - 1; i++) {
			//tracking a straight
			if (hand[i].value - hand[i + 1].value === 1) length++;
			else if (hand[i].value - hand[i + 1].value != 0) length = 0;
			if (length === 4) {
				//highest straight starts from index i - 3
				straight = i - 3;
				break;
			}
		}
		//straight flush found
		if (straight > -1) {
			hand = hand.splice(straight, 5);
			//royal flush
			if (hand[0].value === 14)
				return [hand, 9];
			//straight flush
			else return [hand, 8];
		}
		//a plain flush found
		else {
			//take five most valuable cards
			hand = hand.splice(0, 5);
			return [hand, 5];
		}
	}
	//order cards by value
	hand.sort(function(a, b) {return b.value - a.value});
	
	//handle possible ace by duplicating to a different value
	if (hand[0].value === 14) {
		card = new Object();
		card.value = 1;
		card.suit = hand[0].suit;
		hand.push(card);
	}
	//look for a straight
	var straight = -1;
	var length = 0;
	for (var i = 0; i < hand.length - 1; i++) {
		//tracking a straight
		if (hand[i].value - hand[i + 1].value === 1) length++;
		else if (hand[i].value - hand[i + 1].value != 0) length = 0;
		if (length === 4) {
			//highest straight starts from index i - 3
			straight = i - 3;
			break;
		}
	}
	//straight found
	if (straight > -1) {
		hand = hand.splice(straight, 5);
		return [hand, 4];
	}
	
	//remove possible added ace. this was needed for straight search
	if (hand[0].value === 14)
		hand.pop();
	//make a new array of the cards so that cards with the same value are grouped ot sub arrays
	var grouped = new Array();
	grouped.push([hand[0]]);
	for (var i = 1; i < hand.length; i++) {
		//if there is a group for this card value, then push the card into it.
		if (hand[i].value === grouped[grouped.length - 1][0].value)
			grouped[grouped.length - 1].push(hand[i]);
		//otherwise create a new group
		else grouped.push([hand[i]]);
	}
	//sort grouped cards by group size
	grouped.sort(function(a, b) {return b.length - a.length});
	//four of a kind
	if (grouped[0].length === 4) {
		var newHand = grouped[0];
		var kicker = grouped[1][0];
		for (var i = 2; i < grouped.length; i++) {
			if (grouped[i][0] > kicker) kicker = grouped[i][0];
		}
		newHand.push(kicker);
		return [newHand, 7];
	}
	
	//three of a kind or full house
	if (grouped[0].length === 3) {
		var newHand = grouped[0];
		//full house
		if (grouped[1].length > 1) {
			newHand.push(grouped[1][0]);
			newHand.push(grouped[1][1]);
			return [newHand, 6];
		}
		//three of a kind
		else {
			newHand.push(grouped[1][0]);
			newHand.push(grouped[2][0]);
			return [newHand, 3];
		}
	}
	
	//pair or two pair
	if (grouped[0].length === 2) {
		var newHand = grouped[0];
		//two pair
		if (grouped[1].length > 1) {
			newHand.push(grouped[1][0]);
			newHand.push(grouped[1][1]);
			newHand.push(grouped[2][0]);
			return [newHand, 2];
		}
		//pair
		else {
			newHand.push(grouped[1][0]);
			newHand.push(grouped[2][0]);
			newHand.push(grouped[3][0]);
			return [newHand, 1];
		}
	}
	hand = hand.splice(0, 5);
	return [hand, 0];
}
 | 
                
                    | Scripts/yah_gem_poker.js | "use strict";
this.name = "yah_gem_poker";
this.author = "spara";
this.payoffHands = ["Jacks or Better","Two Pair","Three of a Kind","Straight","Flush","Full House","Four of a Kind","Straight Flush","Royal Flush"];
this.payoffTable = [[1,2,3,4,6,9,25,50,250],[2,4,6,8,12,18,50,100,500],[3,6,9,12,18,27,75,150,750],[4,8,12,16,24,36,100,200,1000],[5,10,15,20,30,45,125,250,4000]];
//add interface, if the player has started the game anywhere elsewhere than constore
this.startUpComplete = function() {
	if (!player.ship.dockedStation.hasRole("constore")) {
		this.shipExitedWitchspace();
	}
}
this.shipExitedWitchspace = function() {
	var constores = system.shipsWithRole("constore");
	if (constores.length > 0) {
		for (var i = 0; i < constores.length; i++) {
			constores[i].setInterface("yah_gem-poker",{
				title: "Video poker",
				category: expandMissionText("yah_gem-gambling-category"),
				summary: expandMissionText("yah_gem-poker-summary"),
				callback: this.$intro.bind(this)
			});
		}
	}
}
//init a new deck
this.$virginDeck = function() {
	var deck = new Array();
	var suits = ["triangle", "crescent", "square", "star"];
	for (var i = 0; i < 4; i++) {
		for (var j = 1; j < 14; j++) {
			var card = new Object();
			card.suit = suits[i];
			card.rank = j;
			card.hold = 0; 
			deck.push(card);
		}
	}
	return deck;
}
//helper function for tabulating text on screen
this.$tabulate = function(line, width) {
	var hairSpace = String.fromCharCode(31);
	var space = defaultFont.measureString(" ");
	while (defaultFont.measureString(line) < width - space)
		line += " ";
	while (defaultFont.measureString(line) < width)
		line += hairSpace;
	return line;
}
//intro screen
this.$intro = function() {	
	//build and format the payoff table for screen
	var payoffMessage = this.$tabulate("Hand", 10);
	for (var i = 0; i < 5; i++) {
		payoffMessage += i + 1 + " g";
		payoffMessage = this.$tabulate(payoffMessage, 10 + 4 * (i + 1));
	}
	payoffMessage = "\n" + payoffMessage + "\n\n";
	for (i = 0; i < this.payoffHands.length; i++) {
		var line = this.payoffHands[this.payoffHands.length - i - 1];
		line = this.$tabulate(line, 10);
		for (var j = 0; j < 5; j++) {
			line = this.$tabulate(line, 10 + 4 * j);
			line += this.payoffTable[j][this.payoffHands.length - i - 1];
		}
		payoffMessage += line+"\n";
	}
	
	//format player credits for screen
	var credits = "Gems: " + player.ship.manifest["gem_stones"] + " g\n";
	
	//gambling choices
	var options = {
		"1_EXIT" : "Exit"
	};
	if (player.ship.manifest["gem_stones"] >= 1) {
		options["2_10"] = "Bet 1";
	}
	else payoffMessage += expandMissionText("yah_gem-no-credit");
	if (player.ship.manifest["gem_stones"] >= 2)
		options["3_20"] = "Bet 2";
	if (player.ship.manifest["gem_stones"] >= 3)
		options["4_30"] = "Bet 3";
	if (player.ship.manifest["gem_stones"] >= 4)
		options["5_40"] = "Bet 4";
	if (player.ship.manifest["gem_stones"] >= 5)
		options["6_50"] = "Bet 5";
	
	
	mission.runScreen({
		titleKey: "yah_gem-poker-title",
		message: this.$tabulate(expandMissionText("yah_gem-poker-intro-story"), 26) + credits + payoffMessage,
		model: "yah_gem_casino_poker_card_spin",
		background: "yah_gem_table_bg.png",
		choices: options,
		allowInterrupt: true,
		screenID: "yah_gem_poker",
		exitScreen: "GUI_SCREEN_INTERFACES"
	},
	function (choice) {
		if (choice === "2_10") this.$play(1);
		else if (choice === "3_20") this.$play(2);
		else if (choice === "4_30") this.$play(3);
		else if (choice === "5_40") this.$play(4);
		else if (choice === "6_50") this.$play(5);
	}
	);
}
//first pay, then deal
this.$play = function(bet) {
	player.ship.manifest["gem_stones"] -= bet;
	//init a new deck and draw a hand (don't show it yet)
	this.$playDeck = this.$virginDeck();
	var hand = new Array();
	for (var i = 0; i < 5; i++) hand.push(this.$drawCard());
	this.$deal(bet, hand);
}
//Deal
this.$deal = function(bet, hand, choice) {
	if (typeof choice === 'undefined') var choice = "0_HOLD";
	var options = {
		"0_HOLD" : "Hold/Cancel 1.",
		"1_HOLD" : "Hold/Cancel 2.",
		"2_HOLD" : "Hold/Cancel 3.",
		"3_HOLD" : "Hold/Cancel 4.",
		"4_HOLD" : "Hold/Cancel 5.",
		"5_DEAL" : "Draw"
	}
	var credits = "Gems: " + player.ship.manifest["gem_stones"] + " g\n";
	var betText = "Bet: " + bet + "\n";
	mission.runScreen({
		titleKey: "yah_gem-poker-title",
		message: this.$tabulate(expandMissionText("yah_gem-poker-deal-story"), 26) + credits + this.$tabulate(" ", 26) + betText,
		model: "yah_gem_casino_poker_card_base",
		background: "yah_gem_table_bg.png",
		spinModel: false,
		choices: options,
		screenID: "yah_gem_poker",
		initialChoicesKey: choice
	},
	function (choice) {
		if (choice === "0_HOLD")
			hand[0].hold = (hand[0].hold + 1) % 2;
		else if (choice === "1_HOLD")
			hand[1].hold = (hand[1].hold + 1) % 2;
		else if (choice === "2_HOLD")
			hand[2].hold = (hand[2].hold + 1) % 2;
		else if (choice === "3_HOLD")
			hand[3].hold = (hand[3].hold + 1) % 2;
		else if (choice === "4_HOLD")
			hand[4].hold = (hand[4].hold + 1) % 2;
		else if (choice === "5_DEAL") {
			this.$outCome(bet, hand);
			return;
		}
		this.$deal(bet, hand, choice);
		return;
	}
	);
	//update the cards on screen
	for (var i = 0; i < 5; i++)
		this.$changeCard(i, hand[i]);
}
//draw && outcome
this.$outCome = function(bet, hand) {
	//draw new cards
	for (var i = 0; i < 5; i++) {
		if (!hand[i].hold)
			hand[i] = this.$drawCard();
		else hand[i].hold = 0;
	}
	//check for wins
	var result = this.winCheck(hand);
	//fail
	if (result === -1) {
		var sound = "yah_gem_lose.ogg";
		var resultText = expandMissionText("yah_gem-poker-fail");
	}
	//win
	else {
		var win = this.payoffTable[(bet - 1)][result];
		var resultText = this.payoffHands[result] + ", you win " + win + " g of Gems.";
		player.ship.manifest["gem_stones"] += win;
		var sound = "yah_gem_win.ogg";
	}
	//format player credits for screen
	var credits = "Gems: " + player.ship.manifest["gem_stones"] + " g\n";
	var betText = "Bet: " + bet;
	var options = {
		"1_EXIT" : "Exit",
		"2_AGAIN" : "Change bet",
	};
	if (player.ship.manifest["gem_stones"] >= bet) options["3_DEAL"] = "Deal again";
	mission.runScreen({
		titleKey: "yah_gem-poker-title",
		message: this.$tabulate(resultText, 26) + credits + this.$tabulate(" ", 26) + betText,
		model: "yah_gem_casino_poker_card_base",
		background: "yah_gem_table_bg.png",
		spinModel: false,
		choices: options,
		music: sound,
		allowInterrupt: true,
		screenID: "yah_gem_poker",
		exitScreen: "GUI_SCREEN_INTERFACES"
	},
		function (choice) {
			if (choice === "2_AGAIN") {
				this.$intro();
				return;
			}
			else if (choice === "3_DEAL") {
				this.$play(bet);
				return;
			}
				
		}
	)
	//update the cards on screen
	for (var i = 0; i < 5; i++)
		this.$changeCard(i, hand[i]);
}
//draws a card from the current deck in play
this.$drawCard = function() {
	return this.$playDeck.splice(Math.floor(this.$playDeck.length * Math.random()),1)[0];
}
//update the texture and position for a card
this.$changeCard = function(place, card) {
	var fileName = "yah_gem_card_" + card.suit + "_" + card.rank + ".png";
	mission.displayModel.subEntities[place].setMaterials({"casino_poker_card_diffuse.png": {diffuse_map: fileName, emission_map: fileName, emission_modulate_color: "darkGrayColor"}});
	if (card.hold) {
		var position = mission.displayModel.subEntities[place].position;
		position[2] = 3;
		mission.displayModel.subEntities[place].position = position;
	}
}
//rules for a winning hand
this.winCheck = function(hand) {
	//work with a hand that has been ordered by rank
	var orderedHand = hand.concat();
	orderedHand.sort(function(a, b) {return a.rank - b.rank});
	
	//check for flush
	var suit = orderedHand[0].suit;
	var i = 0;
	var flush = false;
	for (i = 1; i < 5; i++) {
		if (orderedHand[i].suit !== suit) {
			i = -1; 
			break;
		}
	}
	//flush found
	if (i !== -1) flush = true;
	
	//check for straight
	var prevRank = orderedHand[0].rank;
	var straight = false
	for (i = 1; i < 5; i++) {
		if (orderedHand[i].rank - prevRank !== 1 && (i !== 1 || orderedHand[i].rank !== 10 || prevRank !== 1)) {
			i = -1; 
			break;
		}
		prevRank = orderedHand[i].rank;
	}
	//straight found
	if (i !== -1) straight = true;
	
	//straight flush
	if (flush && straight) {
		if (orderedHand[0].rank === 1 && orderedHand[4].rank === 13)
			return 8;//royal_flush
		else return 7;//straight_flush
	}
	
	//flush 
	if (flush) return 4;//flush"
	
	//straight
	if (straight) return 3;//straight
	
	//in the ordered list, for every adjacent two cards, check if they form a rank pair.
	prevRank = orderedHand[0].rank;
	var pairs = new Array();
	for (i = 1; i < 5; i++) {
		if (orderedHand[i].rank === prevRank) pairs.push(i);
		prevRank = orderedHand[i].rank;
	}
	//four of a kind (3 adjacent pairs)
	//full house (3 adjacent pairs)
	if (pairs.length === 3) {
		if (orderedHand[1].rank === orderedHand[2].rank && orderedHand[2].rank === orderedHand[3].rank)
			return 6;//four_of_a_kind
		else return 5;//full_house
	}
	//three of a kind (2 adjacent pairs)
	//two pair (2 adjacent pairs)
	if (pairs.length === 2) {
		if (pairs[1] - pairs[0] === 1)
			return 2;//three_of_a_kind
		else return 1;//two pair
	}
	
	//pair (jacks or better)
	if (pairs.length === 1) {
		if (orderedHand[pairs[0]].rank > 10 || orderedHand[pairs[0]].rank === 1)
			return 0;
	}
	
	return -1;
}
 |