extends NpcScript # Behaviour const ThresholdHandValue : int = 17 # Card utilities static var RANKS : PackedStringArray = ["王牌", "2", "3", "4", "5", "6", "7", "8", "9", "10", "侍从", "王后", "国王"] static var SUITS : PackedStringArray = [ "黑桃", "红心", "方片", "梅花" ] # Game state var deck : Array = [] var playerHand : Array = [] var dealerHand : Array = [] # Helper static func _CardName(card : int) -> String: return "%s%s" % [SUITS[floori(card / 13.0)], RANKS[card % 13]] static func _CardValue(card : int) -> int: var rank : int = card % 13 if rank == 0: return 11 if rank >= 10: return 10 return rank + 1 static func _HandValue(hand : Array) -> int: var value : int = 0 var aces : int = 0 for card : int in hand: value += _CardValue(card) if card % 13 == 0: aces += 1 while value > 21 and aces > 0: value -= 10 aces -= 1 return value static func _HandStr(hand : Array) -> String: var parts : PackedStringArray = [] for card : int in hand: parts.append(_CardName(card)) return ", ".join(parts) + " (%d)" % _HandValue(hand) static func _NewDeck() -> Array: var d : Array = [] d.resize(52) for i : int in range(52): d[i] = i d.shuffle() return d # General flow func OnStart(): Mes("欢迎,欢迎!你是来找人,还是来找一局好牌?") Mes("听过 21 点 吗?别被名字吓到,规矩简单,胆量和分寸才是关键。") Mes("坐下吧。图利姆沙 的风会吹乱很多东西,但吹不乱一副洗好的牌。") DisplayChoices() func DisplayChoices(): Choice("挑战 海兰德", StartDealer) Choice("帮我找个对手", StartPvP) Choice("讲讲规则", ShowRules) Choice("今天先不玩", Decline) func ShowRules(): Mes("规则很简单:尽量接近 21 点,但不能超过。") Mes("数字牌按牌面算,花牌都算 10。王牌可以算 1,也可以算 11,看哪种对你更有利。") Mes("比我点数高且不爆牌,你就赢。超过 21,就是爆牌。") Mes("这游戏最难的不是加法,是知道什么时候该停手。许多商人一辈子都没学会。") DisplayChoices() func Decline(): Chat("想玩牌的时候来找我。好牌不会等人太久。") func OnQuit(): if npc and npc.ownScript: npc.ownScript.call("LeavePvP", own) super.OnQuit() # Player vs Dealer Mode func StartDealer(): deck = _NewDeck() playerHand = [deck.pop_back(), deck.pop_back()] dealerHand = [deck.pop_back(), deck.pop_back()] _DealerTurn() func _DealerTurn(): if _HandValue(playerHand) == 21: _DealerReveal() else: Mes("你的手牌:%s" % _HandStr(playerHand)) Mes("我明面上的牌:%s。" % _CardName(dealerHand[0])) Choice("要牌", _DealerHit) Choice("停牌", _DealerReveal) func _DealerHit(): playerHand.append(deck.pop_back()) var value : int = _HandValue(playerHand) if value > 21: Mes("你的手牌:%s" % _HandStr(playerHand)) Mes("哎呀,爆牌了!贪心常常只差一张牌,我见过太多次。") Choice("再来一局", StartDealer) Choice("离开", Decline) elif value == 21: _DealerReveal() else: _DealerTurn() func _DealerReveal(): while _HandValue(dealerHand) < ThresholdHandValue: dealerHand.append(deck.pop_back()) var pv : int = _HandValue(playerHand) var dv : int = _HandValue(dealerHand) Mes("你的手牌:%s" % _HandStr(playerHand)) Mes("我的手牌:%s" % _HandStr(dealerHand)) if dv > 21: Mes("哈!老手也有伸手太长的时候。你赢得漂亮。") elif pv > dv: Mes("嗯,不错。你知道什么时候该停。") elif dv > pv: Mes("经验又赢了一次。别难过,多数人第一次都输给我。") else: Mes("%d 点平局!胆子不错,我承认这一点。" % pv) Choice("再来一局", StartDealer) Choice("离开", Decline) # Player vs Player Mode func StartPvP(): var result : int = npc.ownScript.call("JoinPvP", own) if result == 0: Mes("好,让我们看看还有谁有胆量坐上这张桌子。稍等。") Choice("查看", _PvPCheck) Choice("取消", _PvPCancel) else: _PvPBegin() func _PvPCheck(): var game : Dictionary = npc.ownScript.call("GetGame", own) if game.is_empty(): Mes("耐心点。好牌手要先学会等待。") Choice("查看", _PvPCheck) Choice("取消", _PvPCancel) elif game.has("result"): _PvPShowResult(game) else: _PvPBegin() func _PvPCancel(): npc.ownScript.call("LeavePvP", own) Chat("没有牌局?可惜。也许风向一变,你又想玩了。") func _PvPBegin(): playerHand = npc.ownScript.call("GetHand", own) Mes("哈!对手来了。让我看看你们谁更懂停手。") _PvPTurn() func _PvPTurn(): Mes("你的手牌:%s" % _HandStr(playerHand)) if _HandValue(playerHand) == 21: Mes("21 点!") _PvPStand() else: Choice("要牌", _PvPHit) Choice("停牌", _PvPStand) func _PvPHit(): var card : int = npc.ownScript.call("DrawCard", own) if card < 0: _PvPStand() return playerHand.append(card) var value : int = _HandValue(playerHand) if value > 21: Mes("你的手牌:%s" % _HandStr(playerHand)) Mes("爆牌!刚才心里那点犹豫,其实已经给过你提醒了。") npc.ownScript.call("FinishHand", own, value, true) _PvPWait() elif value == 21: Mes("你的手牌:%s" % _HandStr(playerHand)) _PvPStand() else: _PvPTurn() func _PvPStand(): npc.ownScript.call("FinishHand", own, _HandValue(playerHand), false) _PvPWait() func _PvPWait(): var game : Dictionary = npc.ownScript.call("GetGame", own) if game.has("result"): _PvPShowResult(game) else: Mes("你这边结束了。现在等对手做决定。") Choice("查看", _PvPWaitCheck) Choice("认输", _PvPForfeit) func _PvPWaitCheck(): var game : Dictionary = npc.ownScript.call("GetGame", own) if game.has("result"): _PvPShowResult(game) else: Mes("还在思考。谨慎的人值得尊重,除非他只是忘了轮到自己。") Choice("查看", _PvPWaitCheck) Choice("认输", _PvPForfeit) func _PvPShowResult(game : Dictionary): var isP1 : bool = game.get("p1") == own var myVal : int = game.get("p1Value") if isP1 else game.get("p2Value") var oppBust : bool = game.get("p2Busted") if isP1 else game.get("p1Busted") var oppHand : Array = game.get("p2Hand") if isP1 else game.get("p1Hand") var myBust : bool = game.get("p1Busted") if isP1 else game.get("p2Busted") Mes("你的点数:%d%s" % [myVal, "(爆牌)" if myBust else ""]) Mes("对手手牌:%s%s" % [_HandStr(oppHand), "(爆牌)" if oppBust else ""]) var result : String = game.get("result", "") if result == "draw": Mes("平局!势均力敌,这在我的桌上不常见。") elif (result == "p1" and isP1) or (result == "p2" and not isP1): Mes("胜利归你!今天牌也站在你这边。") else: Mes("可惜。牌有自己的脾气,但它总会再绕回来。") npc.ownScript.call("CleanupGame", own) Choice("再来一局", StartPvP) Choice("离开", Decline) func _PvPForfeit(): npc.ownScript.call("ForfeitPvP", own) Mes("中途离桌?放在我年轻时,这至少要请全桌喝一轮。") Choice("再来一局", StartPvP) Choice("离开", Decline)