diff --git a/imports/api/HandScoreCalculator.js b/imports/api/HandScoreCalculator.js new file mode 100644 index 0000000..0767214 --- /dev/null +++ b/imports/api/HandScoreCalculator.js @@ -0,0 +1,142 @@ +import Constants from './Constants'; +import { GameRecordUtils } from './utils/GameRecordUtils'; + +export var HandScoreCalculator = { + jpn: { + dealinDelta: jpnDealinDelta, + selfDrawDelta: jpnSelfDrawDelta, + mistakeDelta: jpnMistakeDelta + } +}; + +/** + * Calculates the change in points as a result of a deal-in hand + * Uses the formula from: + * https://en.wikipedia.org/wiki/Japanese_Mahjong_scoring_rules + * + * @param {Number} points - the total number of points in hand + * @param {Number} fu - the fu value of the hand + * @param {Number} bonus - the current round bonus + * @param {string} dealerWind - the true wind of the current dealer + * @param {string} winnerWind - the winning seat true wind + * @param {string} loserWind - the losing seat true wind + * @param {Number} riichiSticks - the number of riichi sticks won + * @return {Object} containing the point difference for each seat + */ +function jpnDealinDelta(points, fu, bonus, dealerWind, winnerWind, loserWind, riichiSticks) { + let winds = {}; + Constants.WINDS.forEach(w => winds[w] = 0); + + let handValue; + let bonusPoints = bonus * Constants.JPN_BONUS_POINTS; + + // The multiplier is for whether or not it's a dealer victory + let multiplier = (winnerWind != dealerWind) ? 4 : 6; + + // Check to see if you have to count basic points + if (points < 5) { + if (fu === 20 || (points === 1 && fu === 25)) { + throw RangeError("Invalid points/fu combination"); + } else { + // Calculate hand value, if it's above a mangan, cap it there + let manganPayout = Constants.JPN_MANGAN_BASE_POINTS * multiplier; + handValue = Math.ceil((fu * Math.pow(2, 2 + points)) * multiplier / 100) * 100; + handValue = (handValue > manganPayout) ? manganPayout : handValue; + } + } else { + handValue = manganValue(points) * multiplier; + } + + // Add everything together to finalize total + winds[winnerWind] = handValue + bonusPoints + (riichiSticks * Constants.JPN_RIICHI_POINTS); + winds[loserWind] = -(handValue + bonusPoints); + + return winds; +}; + +/** + * Calculates the change in points as a result of a self-drawn hand + * Uses the formula from https://en.wikipedia.org/wiki/Japanese_Mahjong_scoring_rules + * + * @param {Number} points - the total number of han + dora + * @param {Number} fu - the fu value of the hand + * @param {Number} bonus - the current round bonus + * @param {string} dealerWind - the true wind of the current dealer + * @param {string} winnerWind - the winning seat true wind + * @param {Number} riichiSticks - the total number of thrown riichi sticks + * @return {Object} containing the point difference for each seat + */ +function jpnSelfDrawDelta(points, fu, bonus, dealerWind, winnerWind, riichiSticks) { + let winds = {}; + Constants.WINDS.forEach(w => winds[w] = 0); + let basicPoints, nonDealerPays, dealerPays; + let individualBonusPayout = Constants.JPN_BONUS_POINTS / 3; + + // Check to see if you have to count basic points + if (points < 5) { + if ((points === 1 && (fu === 20 || fu === 25)) || (points === 2 && fu === 25)) { + throw RangeError("Invalid points/fu combination"); + } else { + // Calculate hand value, if it's above a mangan, cap it there + basicPoints = fu * Math.pow(2, 2 + points); + basicPoints = basicPoints < Constants.JPN_MANGAN_BASE_POINTS ? basicPoints : Constants.JPN_MANGAN_BASE_POINTS; + } + } else { + basicPoints = manganValue(points); + } + nonDealerPays = Math.ceil(basicPoints / 100 * (dealerWind == winnerWind ? 2 : 1)) * 100; + dealerPays = Math.ceil(basicPoints / 100 * 2) * 100; + + // Everyone loses except the winner + Object.keys(winds).forEach(v => winds[v] = -nonDealerPays); + + if (winnerWind == dealerWind) { + winds[dealerWind] = (nonDealerPays * 3) + + (bonus * Constants.JPN_BONUS_POINTS) + + (riichiSticks * Constants.JPN_RIICHI_POINTS); + } else { + winds[dealerWind] = -(dealerPays + bonus * individualBonusPayout) + winds[winnerWind] = dealerPays + + (nonDealerPays * 2) + + (bonus * Constants.JPN_BONUS_POINTS) + + (riichiSticks * Constants.JPN_RIICHI_POINTS); + } + + return winds; +}; + +/** + * Calculates the point difference as the result of a mistaken hand + * @param {string} loser - the losing seat true wind + * @return {Object} containing the point difference for each seat + */ +function jpnMistakeDelta(loser) { + let winds = {}; + Constants.WINDS.forEach(w => winds[w] = Constants.JPN_MISTAKE_POINTS / 3); + + winds[loser] = -Constants.JPN_MISTAKE_POINTS; + return winds; +}; + +/** + * Calculates the total base points for high value hands + * @param {Number} points - total points in hand + * @returns {Number} representing number of base points as the result of a certain point threshold, + * must be greater than mangan minimum points + */ +function manganValue(points) { + let multiplier; + switch (true) { + case (points === 5): multiplier = 1; break; + case (points <= 7): multiplier = 1.5; break; + case (points <= 10): multiplier = 2; break; + case (points <= 12): multiplier = 3; break; + // After 13 points is hit, we only see multiples of 13 + case (points === 13): multiplier = 4; break; + case (points === 26): multiplier = 4 * 2; break; + case (points === 39): multiplier = 4 * 3; break; + case (points === 52): multiplier = 4 * 4; break; + case (points === 65): multiplier = 4 * 5; break; + } + return Constants.JPN_MANGAN_BASE_POINTS * multiplier; +}; diff --git a/imports/ui/record-game/RecordJapaneseGame.js b/imports/ui/record-game/RecordJapaneseGame.js index 7731ce8..879108a 100644 --- a/imports/ui/record-game/RecordJapaneseGame.js +++ b/imports/ui/record-game/RecordJapaneseGame.js @@ -5,6 +5,7 @@ import { JapaneseHands } from '../../api/GameDatabases'; import Constants from '../../api/Constants'; import EloCalculator from '../../api/EloCalculator'; import GameRecordUtils from '../../api/utils/GameRecordUtils'; +import { HandScoreCalculator } from '../../api/HandScoreCalculator'; import './RecordJapaneseGame.html'; @@ -227,7 +228,7 @@ Template.jpn_render_hand.helpers({ }) // Helper for point selection dropdown--All allowable points -// Assume that 13, 26, 39, and 52 are single->quadruple yakuman +// Assume that 13, 26, 39, and 52, 65 are single->quintuple yakuman Template.jpn_points.helpers({ possible_points: [ { point: 1 }, @@ -769,12 +770,14 @@ function push_dealin_hand(template) { var points = Number(Session.get("current_points")); var fu = Number(Session.get("current_fu")); var dora = Number(Session.get("current_dora")); + let dealerWind = GameRecordUtils.roundToDealerDirection(Number(Session.get("current_round"))); var winnerWind = GameRecordUtils.playerToDirection(Session.get("round_winner")); var loserWind = GameRecordUtils.playerToDirection(Session.get("round_loser")); var riichiSum = Session.get("free_riichi_sticks"); - var eastDelta = 0, southDelta = 0, westDelta = 0, northDelta = 0; + let seatDeltas = {}; + Constants.WINDS.forEach(w => seatDeltas[w] = 0); - if (winnerWind == Constants.EAST) { + if (winnerWind == Constants.EAST) { Session.set("eastPlayerWins", Number(Session.get("eastPlayerWins")) + 1); Session.set("eastPlayerPointsWon", Number(Session.get("eastPlayerPointsWon")) + points); Session.set("eastPlayerDoraSum", Number(Session.get("eastPlayerDoraSum")) + dora); @@ -803,7 +806,7 @@ function push_dealin_hand(template) { Session.set("northPlayerRiichisWon", Number(Session.get("northPlayerRiichisWon")) + 1); } - if (loserWind == Constants.EAST) + if (loserWind == Constants.EAST) Session.set("eastPlayerLosses", Number(Session.get("eastPlayerLosses")) + 1); else if (loserWind == Constants.SOUTH) Session.set("southPlayerLosses", Number(Session.get("southPlayerLosses")) + 1); @@ -812,41 +815,52 @@ function push_dealin_hand(template) { else if (loserWind == Constants.NORTH) Session.set("northPlayerLosses", Number(Session.get("northPlayerLosses")) + 1); + // Find riichis and save them to allocate them if (Session.get("east_riichi") == true) { - eastDelta -= Constants.JPN_RIICHI_POINTS; + seatDeltas[Constants.EAST] -= Constants.JPN_RIICHI_POINTS; riichiSum++; Session.set("east_riichi_sum", Number(Session.get("east_riichi_sum")) + 1); } if (Session.get("south_riichi") == true) { - southDelta -= Constants.JPN_RIICHI_POINTS; + seatDeltas[Constants.SOUTH] -= Constants.JPN_RIICHI_POINTS; riichiSum++; Session.set("south_riichi_sum", Number(Session.get("south_riichi_sum")) + 1); } if (Session.get("west_riichi") == true) { - westDelta -= Constants.JPN_RIICHI_POINTS; + seatDeltas[Constants.WEST] -= Constants.JPN_RIICHI_POINTS; riichiSum++; Session.set("west_riichi_sum", Number(Session.get("west_riichi_sum")) + 1); } if (Session.get("north_riichi") == true) { - northDelta -= Constants.JPN_RIICHI_POINTS; + seatDeltas[Constants.NORTH] -= Constants.JPN_RIICHI_POINTS; riichiSum++; Session.set("north_riichi_sum", Number(Session.get("north_riichi_sum")) + 1); } - eastDelta += dealin_delta(points, fu, Constants.EAST, winnerWind, loserWind) + - rewardRiichiSticks(riichiSum, Constants.EAST, winnerWind); - southDelta += dealin_delta(points, fu, Constants.SOUTH, winnerWind, loserWind) + - rewardRiichiSticks(riichiSum, Constants.SOUTH, winnerWind); - westDelta += dealin_delta(points, fu, Constants.WEST, winnerWind, loserWind) + - rewardRiichiSticks(riichiSum, Constants.WEST, winnerWind); - northDelta += dealin_delta(points, fu, Constants.NORTH, winnerWind, loserWind) + - rewardRiichiSticks(riichiSum, Constants.NORTH, winnerWind); + let handDeltas = HandScoreCalculator.jpn.dealinDelta(points, + fu, + Number(Session.get("current_bonus")), + dealerWind, + winnerWind, + loserWind, + riichiSum); + Session.set("free_riichi_sticks", 0); + + // Accumulate hand deltas for this round + for (const seat of Constants.WINDS) { + seatDeltas[seat] += handDeltas[seat]; + } - pushHand(template, Constants.DEAL_IN, eastDelta, southDelta, westDelta, northDelta); + pushHand(template, + Constants.DEAL_IN, + seatDeltas[Constants.EAST], + seatDeltas[Constants.SOUTH], + seatDeltas[Constants.WEST], + seatDeltas[Constants.NORTH]); - if (winnerWind == GameRecordUtils.roundToDealerDirection(Session.get("current_round"))) + if (winnerWind == dealerWind) { Session.set("current_bonus", Number(Session.get("current_bonus")) + 1); - else { + } else { Session.set("current_bonus", 0); Session.set("current_round", Number(Session.get("current_round")) + 1) } @@ -861,11 +875,13 @@ function push_selfdraw_hand(template) { var points = Number(Session.get("current_points")); var fu = Number(Session.get("current_fu")); var dora = Number(Session.get("current_dora")); + let dealerWind = GameRecordUtils.roundToDealerDirection(Number(Session.get("current_round"))); var winnerWind = GameRecordUtils.playerToDirection(Session.get("round_winner")); var riichiSum = Session.get("free_riichi_sticks"); - var eastDelta = 0, southDelta = 0, westDelta = 0, northDelta = 0; + let seatDeltas = {}; + Constants.WINDS.forEach(w => seatDeltas[w] = 0); - if (winnerWind == Constants.EAST) { + if (winnerWind == Constants.EAST) { Session.set("eastPlayerWins", Number(Session.get("eastPlayerWins")) + 1); Session.set("eastPlayerPointsWon", Number(Session.get("eastPlayerPointsWon")) + points); Session.set("eastPlayerDoraSum", Number(Session.get("eastPlayerDoraSum")) + dora); @@ -896,38 +912,47 @@ function push_selfdraw_hand(template) { } if (Session.get("east_riichi") == true) { - eastDelta -= Constants.JPN_RIICHI_POINTS; + seatDeltas[Constants.EAST] -= Constants.JPN_RIICHI_POINTS; riichiSum++; Session.set("east_riichi_sum", Number(Session.get("east_riichi_sum")) + 1); } if (Session.get("south_riichi") == true) { - southDelta -= Constants.JPN_RIICHI_POINTS; + seatDeltas[Constants.SOUTH] -= Constants.JPN_RIICHI_POINTS; riichiSum++; Session.set("south_riichi_sum", Number(Session.get("south_riichi_sum")) + 1); } if (Session.get("west_riichi") == true) { - westDelta -= Constants.JPN_RIICHI_POINTS; + seatDeltas[Constants.WEST] -= Constants.JPN_RIICHI_POINTS; riichiSum++; Session.set("west_riichi_sum", Number(Session.get("west_riichi_sum")) + 1); } if (Session.get("north_riichi") == true) { - northDelta -= Constants.JPN_RIICHI_POINTS; + seatDeltas[Constants.NORTH] -= Constants.JPN_RIICHI_POINTS; riichiSum++; Session.set("north_riichi_sum", Number(Session.get("north_riichi_sum")) + 1); } - eastDelta += selfdraw_delta(points, fu, Constants.EAST, winnerWind) + - rewardRiichiSticks(riichiSum, Constants.EAST, winnerWind); - southDelta += selfdraw_delta(points, fu, Constants.SOUTH, winnerWind) + - rewardRiichiSticks(riichiSum, Constants.SOUTH, winnerWind); - westDelta += selfdraw_delta(points, fu, Constants.WEST, winnerWind) + - rewardRiichiSticks(riichiSum, Constants.WEST, winnerWind); - northDelta += selfdraw_delta(points, fu, Constants.NORTH, winnerWind) + - rewardRiichiSticks(riichiSum, Constants.NORTH, winnerWind); + let handDeltas = HandScoreCalculator.jpn.selfDrawDelta(points, + fu, + Number(Session.get("current_bonus")), + dealerWind, + winnerWind, + riichiSum); + Session.set("free_riichi_sticks", 0); - pushHand(template, Constants.SELF_DRAW, eastDelta, southDelta, westDelta, northDelta); + // Accumulate hand deltas for this round + for (const seat of Constants.WINDS) { + seatDeltas[seat] += handDeltas[seat]; + } + + pushHand(template, + Constants.SELF_DRAW, + seatDeltas[Constants.EAST], + seatDeltas[Constants.SOUTH], + seatDeltas[Constants.WEST], + seatDeltas[Constants.NORTH]); - if (winnerWind == GameRecordUtils.roundToDealerDirection(Session.get("current_round"))) + if (winnerWind == dealerWind) Session.set("current_bonus", Number(Session.get("current_bonus")) + 1); else { Session.set("current_bonus", 0); @@ -1034,18 +1059,25 @@ function push_restart_hand(template) { }; function push_mistake_hand(template) { - var loserWind = GameRecordUtils.playerToDirection(Session.get("round_loser")); - var eastDelta = mistake_delta(Constants.EAST, loserWind); - var southDelta = mistake_delta(Constants.SOUTH, loserWind); - var westDelta = mistake_delta(Constants.WEST, loserWind); - var northDelta = mistake_delta(Constants.NORTH, loserWind); - - if (loserWind == Constants.EAST) Session.set("eastMistakeTotal", Number(Session.get("eastMistakeTotal")) + 1); - else if (loserWind == Constants.SOUTH) Session.set("southMistakeTotal", Number(Session.get("southMistakeTotal")) + 1); - else if (loserWind == Constants.WEST) Session.set("westMistakeTotal", Number(Session.get("westMistakeTotal")) + 1); - else if (loserWind == Constants.NORTH) Session.set("northMistakeTotal", Number(Session.get("northMistakeTotal")) + 1); + let loserWind = GameRecordUtils.playerToDirection(Session.get("round_loser")); + let handDeltas = HandScoreCalculator.jpn.mistakeDelta(loserWind); + + if (loserWind == Constants.EAST) { + Session.set("eastMistakeTotal", Number(Session.get("eastMistakeTotal")) + 1); + } else if (loserWind == Constants.SOUTH) { + Session.set("southMistakeTotal", Number(Session.get("southMistakeTotal")) + 1); + } else if (loserWind == Constants.WEST) { + Session.set("westMistakeTotal", Number(Session.get("westMistakeTotal")) + 1); + } else if (loserWind == Constants.NORTH) { + Session.set("northMistakeTotal", Number(Session.get("northMistakeTotal")) + 1); + } - pushHand(template, Constants.MISTAKE, eastDelta, southDelta, westDelta, northDelta); + pushHand(template, + Constants.MISTAKE, + handDeltas[Constants.EAST], + handDeltas[Constants.SOUTH], + handDeltas[Constants.WEST], + handDeltas[Constants.NORTH]); template.riichi_round_history.push({east: false, south: false, @@ -1057,13 +1089,15 @@ function push_split_pao_hand(template) { var points = Number(Session.get("current_points")); var fu = Number(Session.get("current_fu")); var dora = Number(Session.get("current_dora")); + let dealerWind = GameRecordUtils.roundToDealerDirection(Number(Session.get("current_round"))); var winnerWind = GameRecordUtils.playerToDirection(Session.get("round_winner")); var loserWind = GameRecordUtils.playerToDirection(Session.get("round_loser")); var paoWind = GameRecordUtils.playerToDirection(Session.get("round_pao_player")); var riichiSum = Session.get("free_riichi_sticks"); - var eastDelta = 0, southDelta = 0, westDelta = 0, northDelta = 0; + let seatDeltas = {}; + Constants.WINDS.forEach(w => seatDeltas[w] = 0); - if (winnerWind == Constants.EAST) { + if (winnerWind == Constants.EAST) { Session.set("eastPlayerWins", Number(Session.get("eastPlayerWins")) + 1); Session.set("eastPlayerPointsWon", Number(Session.get("eastPlayerPointsWon")) + points); Session.set("eastPlayerDoraSum", Number(Session.get("eastPlayerDoraSum")) + dora); @@ -1092,7 +1126,7 @@ function push_split_pao_hand(template) { Session.set("northPlayerRiichisWon", Number(Session.get("northPlayerRiichisWon")) + 1); } - if (loserWind == Constants.EAST || paoWind == Constants.EAST) + if (loserWind == Constants.EAST || paoWind == Constants.EAST) Session.set("eastPlayerLosses", Number(Session.get("eastPlayerLosses")) + 1); else if (loserWind == Constants.SOUTH || paoWind == Constants.SOUTH) Session.set("southPlayerLosses", Number(Session.get("southPlayerLosses")) + 1); @@ -1102,60 +1136,56 @@ function push_split_pao_hand(template) { Session.set("northPlayerLosses", Number(Session.get("northPlayerLosses")) + 1); if (Session.get("east_riichi") == true) { - eastDelta -= Constants.JPN_RIICHI_POINTS; + seatDeltas[Constants.EAST] -= Constants.JPN_RIICHI_POINTS; riichiSum++; Session.set("east_riichi_sum", Number(Session.get("east_riichi_sum")) + 1); } if (Session.get("south_riichi") == true) { - southDelta -= Constants.JPN_RIICHI_POINTS; + seatDeltas[Constants.SOUTH] -= Constants.JPN_RIICHI_POINTS; riichiSum++; Session.set("south_riichi_sum", Number(Session.get("south_riichi_sum")) + 1); } if (Session.get("west_riichi") == true) { - westDelta -= Constants.JPN_RIICHI_POINTS; + seatDeltas[Constants.WEST] -= Constants.JPN_RIICHI_POINTS; riichiSum++; Session.set("west_riichi_sum", Number(Session.get("west_riichi_sum")) + 1); } if (Session.get("north_riichi") == true) { - northDelta -= Constants.JPN_RIICHI_POINTS; + seatDeltas[Constants.NORTH] -= Constants.JPN_RIICHI_POINTS; riichiSum++; Session.set("north_riichi_sum", Number(Session.get("north_riichi_sum")) + 1); } - var value = dealin_delta(points, fu, winnerWind, winnerWind); + var value = HandScoreCalculator.jpn.dealinDelta(points, + fu, + Number(Session.get("current_bonus")), + dealerWind, + winnerWind, + loserWind, + 0)[winnerWind]; - if (((value / 2 ) % 100) == 50) + if (((value / 2 ) % 100) == 50) { value += 100; - - switch (winnerWind) { - case Constants.EAST: - eastDelta += value; - eastDelta += (riichiSum * Constants.JPN_RIICHI_POINTS); - break; - case Constants.SOUTH: - southDelta += value; - southDelta += (riichiSum * Constants.JPN_RIICHI_POINTS); - break; - case Constants.WEST: - westDelta += value; - westDelta += (riichiSum * Constants.JPN_RIICHI_POINTS); - break; - case Constants.NORTH: - northDelta += value; - northDelta += (riichiSum * Constants.JPN_RIICHI_POINTS); - break; } + // Accumulate hand deltas for this round + for (const wind of Constants.WINDS) { + if (wind === winnerWind) { + seatDeltas[wind] += value + riichiSum * Constants.JPN_RIICHI_POINTS; + } else if (wind === loserWind || wind === paoWind) { + seatDeltas[wind] -= value / 2; + } + } Session.set("free_riichi_sticks", 0); - if (loserWind == Constants.EAST || paoWind == Constants.EAST) eastDelta -= value / 2; - if (loserWind == Constants.SOUTH || paoWind == Constants.SOUTH) southDelta -= value / 2; - if (loserWind == Constants.WEST || paoWind == Constants.WEST) westDelta -= value / 2; - if (loserWind == Constants.NORTH || paoWind == Constants.NORTH) northDelta -= value / 2; - - pushHand(template, Constants.DEAL_IN, eastDelta, southDelta, westDelta, northDelta); + pushHand(template, + Constants.DEAL_IN, + seatDeltas[Constants.EAST], + seatDeltas[Constants.SOUTH], + seatDeltas[Constants.WEST], + seatDeltas[Constants.NORTH]); - if (winnerWind == GameRecordUtils.roundToDealerDirection(Session.get("current_round"))) + if (winnerWind == dealerWind) Session.set("current_bonus", Number(Session.get("current_bonus")) + 1); else { Session.set("current_bonus", 0); @@ -1189,440 +1219,6 @@ function pushHand(template, handType, eastDelta, southDelta, westDelta, northDel Session.set("north_score", Number(Session.get("north_score")) + northDelta); }; -function dealin_delta(points, fu, playerWind, winnerWind, loserWind) { - var retval; - - if (playerWind != winnerWind && playerWind != loserWind) - return 0; - - if (winnerWind != GameRecordUtils.roundToDealerDirection(Number(Session.get("current_round")))) { - switch (points) { - case 1: - switch (fu) { - //Issue protection against 20 and 25 other ways but return 0 - case 20: - case 25: retval = 0; break; - case 30: retval = -1000; break; - case 40: retval = -1300; break; - case 50: retval = -1600; break; - case 60: retval = -2000; break; - case 70: retval = -2300; break; - case 80: retval = -2600; break; - case 90: retval = -2900; break; - case 100: retval = -3200; break; - case 110: retval = -3600; break; - } - break; - case 2: - switch (fu) { - case 20: retval = -1300; break; - case 25: retval = -1600; break; - case 30: retval = -2000; break; - case 40: retval = -2600; break; - case 50: retval = -3200; break; - case 60: retval = -3900; break; - case 70: retval = -4500; break; - case 80: retval = -5200; break; - case 90: retval = -5800; break; - case 100: retval = -6400; break; - case 110: retval = -7100; break; - } - break; - case 3: - switch (fu) { - case 20: retval = -2600; break; - case 25: retval = -3200; break; - case 30: retval = -3900; break; - case 40: retval = -5200; break; - case 50: retval = -6400; break; - case 60: retval = -7700; break; - default: retval = -8000; break; - } - break; - case 4: - switch (fu) { - case 20: retval = -5200; break; - case 25: retval = -6400; break; - case 30: retval = -7700; break; - default: retval = -8000; break; - } - break; - case 5: retval = -8000; break; - case 6: - case 7: retval = -12000; break; - case 8: - case 9: - case 10: retval = -16000; break; - case 11: - case 12: retval = -24000; break; - case 13: retval = -32000; break; - case 26: retval = -64000; break; - case 39: retval = -96000; break; - case 52: retval = -128000; break; - case 65: retval = -160000; break; - } - } else { - switch (points) { - case 1: - switch (fu) { - //Issue protection against 20 and 25 other ways - case 20: - case 25: retval = 0; break; - case 30: retval = -1500; break; - case 40: retval = -2000; break; - case 50: retval = -2400; break; - case 60: retval = -2900; break; - case 70: retval = -3400; break; - case 80: retval = -3900; break; - case 90: retval = -4400; break; - case 100: retval = -4800; break; - case 110: retval = -5300; break; - } - break; - case 2: - switch (fu) { - case 20: retval = -2000; break; - case 25: retval = -2400; break; - case 30: retval = -2900; break; - case 40: retval = -3900; break; - case 50: retval = -4800; break; - case 60: retval = -5800; break; - case 70: retval = -6800; break; - case 80: retval = -7700; break; - case 90: retval = -8700; break; - case 100: retval = -9600; break; - case 110: retval = -10600; break; - } - break; - case 3: - switch (fu) { - case 20: retval = -3900; break; - case 25: retval = -4800; break; - case 30: retval = -5800; break; - case 40: retval = -7700; break; - case 50: retval = -9600; break; - case 60: retval = -11600; break; - default: retval = -12000; break; - } - break; - case 4: - switch (fu) { - case 20: retval = -7700; break; - case 25: retval = -9600; break; - case 30: retval = -11600; break; - default: retval = -12000; break; - } - break; - case 5: retval = -12000; break; - case 6: - case 7: retval = -18000; break; - case 8: - case 9: - case 10: retval = -24000; break; - case 11: - case 12: retval = -36000; break; - case 13: retval = -48000; break; - case 26: retval = -96000; break; - case 39: retval = -144000; break; - case 52: retval = -192000; break; - case 65: retval = -240000; break; - } - } - - if ( playerWind == winnerWind ) - retval = -1 * retval + Constants.JPN_BONUS_POINTS * Number(Session.get("current_bonus")); - else - retval = retval - Constants.JPN_BONUS_POINTS * Number(Session.get("current_bonus")); - - return retval; -}; - -function selfdraw_delta(points, fu, playerWind, winnerWind) { - var retval; - var dealerWind = GameRecordUtils.roundToDealerDirection(Number(Session.get("current_round"))); - - if (winnerWind != dealerWind) { - switch (points) { - case 1: - switch (fu) { - // Issue protection against 20 and 25 other ways - case 20: - case 25: - retval = 0; - break; - case 30: - retval = (playerWind == dealerWind ? -500 : -300); - retval = (playerWind == winnerWind ? 1100 : retval); - break; - case 40: - retval = (playerWind == dealerWind ? -700 : -400); - retval = (playerWind == winnerWind ? 1500 : retval); - break; - case 50: - retval = (playerWind == dealerWind ? -800 : -400); - retval = (playerWind == winnerWind ? 1600 : retval); - break; - case 60: - retval = (playerWind == dealerWind ? -100 : -500); - retval = (playerWind == winnerWind ? 2000 : retval); - break; - case 70: - retval = (playerWind == dealerWind ? -1200 : -600); - retval = (playerWind == winnerWind ? 2400 : retval); - break; - case 80: - retval = (playerWind == dealerWind ? -1300 : -700); - retval = (playerWind == winnerWind ? 2700 : retval); - break; - case 90: - retval = (playerWind == dealerWind ? -1500 : -800); - retval = (playerWind == winnerWind ? 3100 : retval); - break; - case 100: - retval = (playerWind == dealerWind ? -1600 : -800); - retval = (playerWind == winnerWind ? 3200 : retval); - break; - case 110: - retval = (playerWind == dealerWind ? -1800 : -900); - retval = (playerWind == winnerWind ? 3600 : retval); - break; - }; - break; - case 2: - switch (fu) { - case 20: - retval = (playerWind == dealerWind ? -700 : -400); - retval = (playerWind == winnerWind ? 1500 : retval); - break; - //Issue protection against selfdraw 2p25f other ways - case 25: - retval = 0; - break; - case 30: - retval = (playerWind == dealerWind ? -1000 : -500); - retval = (playerWind == winnerWind ? 2000 : retval); - break; - case 40: - retval = (playerWind == dealerWind ? -1300 : -700); - retval = (playerWind == winnerWind ? 2700 : retval); - break; - case 50: - retval = (playerWind == dealerWind ? -1600 : -800); - retval = (playerWind == winnerWind ? 3200 : retval); - break; - case 60: - retval = (playerWind == dealerWind ? -2000 : -1000); - retval = (playerWind == winnerWind ? 4000 : retval); - break; - case 70: - retval = (playerWind == dealerWind ? -2300 : -1200); - retval = (playerWind == winnerWind ? 4700 : retval); - break; - case 80: - retval = (playerWind == dealerWind ? -2600 : -1300); - retval = (playerWind == winnerWind ? 5200 : retval); - break; - case 90: - retval = (playerWind == dealerWind ? -2900 : -1500); - retval = (playerWind == winnerWind ? 5900 : retval); - break; - case 100: - retval = (playerWind == dealerWind ? -3200 : -1600); - retval = (playerWind == winnerWind ? 6400 : retval); - break; - case 110: - retval = (playerWind == dealerWind ? -3600 : -1800); - retval = (playerWind == winnerWind ? 7200 : retval); - break; - }; - break; - case 3: - switch (fu) { - case 20: - retval = (playerWind == dealerWind ? -1300 : -700); - retval = (playerWind == winnerWind ? 2700 : retval); - break; - case 25: - retval = (playerWind == dealerWind ? -1600 : -800); - retval = (playerWind == winnerWind ? 3200 : retval); - break; - case 30: - retval = (playerWind == dealerWind ? -2000 : -1000); - retval = (playerWind == winnerWind ? 4000 : retval); - break; - case 40: - retval = (playerWind == dealerWind ? -2600 : -1300); - retval = (playerWind == winnerWind ? 5200 : retval); - break; - case 50: - retval = (playerWind == dealerWind ? -3200 : -1600); - retval = (playerWind == winnerWind ? 6400 : retval); - break; - case 60: - retval = (playerWind == dealerWind ? -3900 : -2000); - retval = (playerWind == winnerWind ? 7900 : retval); - break; - default: - retval = (playerWind == dealerWind ? -4000 : -2000); - retval = (playerWind == winnerWind ? 8000 : retval); - break; - }; - break; - case 4: - switch (fu) { - case 20: - retval = (playerWind == dealerWind ? -2600 : -1300); - retval = (playerWind == winnerWind ? 5200 : retval); - break; - case 25: - retval = (playerWind == dealerWind ? -3200 : -1600); - retval = (playerWind == winnerWind ? 6400 : retval); - break; - case 30: - retval = (playerWind == dealerWind ? -3900 : -2000); - retval = (playerWind == winnerWind ? 7900 : retval); - break; - default: - retval = (playerWind == dealerWind ? -4000 : -2000); - retval = (playerWind == winnerWind ? 8000 : retval); - break; - }; - break; - case 5: - retval = (playerWind == dealerWind ? -4000 : -2000); - retval = (playerWind == winnerWind ? 8000 : retval); - break; - case 6: - case 7: - retval = (playerWind == dealerWind ? -6000 : -3000); - retval = (playerWind == winnerWind ? 12000 : retval); - break; - case 8: - case 9: - case 10: - retval = (playerWind == dealerWind ? -8000 : -4000); - retval = (playerWind == winnerWind ? 16000 : retval); - break; - case 11: - case 12: - retval = (playerWind == dealerWind ? -12000 : -6000); - retval = (playerWind == winnerWind ? 24000 : retval); - break; - case 13: - retval = (playerWind == dealerWind ? -16000 : -8000); - retval = (playerWind == winnerWind ? 32000 : retval); - break; - case 26: - retval = (playerWind == dealerWind ? -32000 : -16000); - retval = (playerWind == winnerWind ? 64000 : retval); - break; - case 39: - retval = (playerWind == dealerWind ? -48000 : -24000); - retval = (playerWind == winnerWind ? 96000 : retval); - break; - case 52: - retval = (playerWind == dealerWind ? -64000 : -32000); - retval = (playerWind == winnerWind ? 128000 : retval); - break; - case 65: - retval = (playerWind == dealerWind ? -80000 : -40000); - retval = (playerWind == winnerWind ? 160000 : retval); - break; - }; - } else { - switch (points) { - case 1: - switch (fu) { - //Issue protection against 20 and 25 fu other ways but return 0 - case 20: - case 25: retval = 0; break; - case 30: retval = -500; break; - case 40: retval = -700; break; - case 50: retval = -800; break; - case 60: retval = -1000; break; - case 70: retval = -1200; break; - case 80: retval = -1300; break; - case 90: retval = -1500; break; - case 100: retval = -1600; break; - case 110: retval = -1800; break; - }; - break; - case 2: - switch (fu) { - case 20: retval = -700; break; - //Issue protection against 2p25 selfdraw other ways but return 0 - case 25: retval = 0; break; - case 30: retval = -1000; break; - case 40: retval = -1300; break; - case 50: retval = -1600; break; - case 60: retval = -2000; break; - case 70: retval = -1300; break; - case 80: retval = -2600; break; - case 90: retval = -2900; break; - case 100: retval = -3200; break; - case 110: retval = -3600; break; - }; - break; - case 3: - switch (fu) { - case 20: retval = -1300; break; - case 25: retval = -1600; break; - case 30: retval = -2000; break; - case 40: retval = -2600; break; - case 50: retval = -3200; break; - case 60: retval = -3900; break; - default: retval = -4000; break; - }; - break; - case 4: - switch (fu) { - case 20: retval = -2600; break; - case 25: retval = -3200; break; - case 30: retval = -3900; break; - default: retval = -4000; break; - } - break; - case 5: retval = -4000; break; - case 6: - case 7: retval = -6000; break; - case 8: - case 9: - case 10: retval = -8000; break; - case 11: - case 12: retval = -12000; break; - case 13: retval = -16000; break; - case 26: retval = -32000; break; - case 39: retval = -48000; break; - case 52: retval = -64000; break; - case 65: retval = -80000; break; - } - retval *= (playerWind == winnerWind ? -3 : 1) - } - - if ( playerWind == winnerWind ) - retval = retval + Constants.JPN_BONUS_POINTS * Number(Session.get("current_bonus")); - else - retval = retval - Constants.JPN_BONUS_POINTS * Number(Session.get("current_bonus") / 3); - - return retval; - -}; - -function mistake_delta(player, loser) { - if (player == loser) - return -Constants.JPN_MISTAKE_POINTS; - else - return Constants.JPN_MISTAKE_POINTS / 3; -}; - -function rewardRiichiSticks(riichiSticks, playerWind, winnerWind) { - if (playerWind == winnerWind){ - Session.set("free_riichi_sticks", 0); - return (riichiSticks * Constants.JPN_RIICHI_POINTS); - } - return 0; -}; - function setAllGUIRiichisFalse() { Session.set("east_riichi", false); Session.set("south_riichi", false);