二七王服务端:按 design.md 整改结算/算奖/甩牌,roomtype 改位串

结算与算奖(§6.3/§7/§8)
- 扣底倍数改线性:单张×1、主对×2、N连对×2N
- 算子实现常规算子 + 爬坡两套(大光×3、Q=40 / 爬坡分段),X=基础子数×判定倍率
- 常规算奖只计庄家;连对链修复(传实际主花色);移除 ≥10 老主误加奖与设计外的
  「冲关必叫/四王必踢」作废;算奖快照取庄家埋牌后28张(新增 get_seat_cards_award)
- 算奖并入结算改为 X×(2Ni−Nj−Nk);傍王按房间开关、庄闲每王1奖

出牌与甩牌(§5.4)
- 副牌绝对禁甩;甩牌最大性按对手全部手牌逐分量判定(新增 trump_rank/
  decompose_trump/opp_can_beat_flush);甩错惩罚(收回、只打最小一张、下发 shuaicuo)
- 修复 can_followcard 引用未定义 tuolaji_list 的崩溃、can_playcard 14张上限失效

开局/投降/暗牌(§4)
- 投降改为选主阶段(step2)与选主互斥、不埋牌、算奖用庄家36张;埋牌后直进出牌(删废弃step4)
- 70分暗牌摸牌前向所有玩家亮3秒(+ancard3s),非70分不再泄露暗牌给闲家;叫分上限≤70

查牌/亮牌(§8.2/§9)
- 新增亮牌 get_liangpai(庄家埋牌后28张按阈值统计);报无主统计与亮牌按查牌位门控
- 新增 mingpai 明牌 RPC(可查牌+已报无主时查看他家全部主牌)

房间与配置(§10)
- 局数6/12、房主扣卡2/4;新增 class.config.js 以位串解析 roomtype(唯一入口 SSOT)
- 清理 do_choiceflower 死代码

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-04 22:32:53 +08:00
co-authored by Claude Opus 4.8
parent 96372d713c
commit 6120580505
5 changed files with 601 additions and 387 deletions
+206 -113
View File
@@ -3,19 +3,66 @@
///////////////////////////////////////////////////
var cls_youle_erqiwang_arith = cls_youle_erqiwang_arith || {
//根据叫分计算倍数
get_multiple_bycall: function(callgrade){
if (callgrade > 60){
return 1;
}
if (callgrade > 40){
//根据叫分计算基础子数(design §7.1 常规算子 / §7.3.1 爬坡)
//climb: 是否勾选爬坡。70 分打牌基础子数 2;投降(基础1)在结算处特殊处理
get_base_bycall: function(callgrade, climb){
if (callgrade == 70){
return 2;
}
if (callgrade > 0){
return 4;
if (!climb){
//常规算子:65→2 60→3 55→4 50及以下统一6
if (callgrade == 65) return 2;
if (callgrade == 60) return 3;
if (callgrade == 55) return 4;
if (callgrade >= 5 && callgrade <= 50) return 6;
return 0;
}
//爬坡:65→2 起每低5分+1子,直到5分→15
switch (callgrade){
case 65: return 2;
case 60: return 3;
case 55: return 4;
case 50: return 6;
case 45: return 7;
case 40: return 8;
case 35: return 9;
case 30: return 10;
case 25: return 11;
case 20: return 12;
case 15: return 13;
case 10: return 14;
case 5: return 15;
}
return 0;
},
},
//小光/过庄分界与升级级距 Q(design §7.2.0 常规固定40 / §7.3.2 爬坡分段)
get_qvalue: function(callgrade, climb){
if (!climb){
return 40;
}
if (callgrade >= 45){
return 40;
}
if (callgrade == 40 || callgrade == 35){
return 20;
}
if (callgrade == 30 || callgrade == 25){
return 15;
}
if (callgrade == 20 || callgrade == 15){
return 10;
}
if (callgrade == 10 || callgrade == 5){
return 5;
}
return 40;
},
//(兼容)叫分对应的基础子数,供叫分阶段展示,默认按常规算子取值
get_multiple_bycall: function(callgrade){
return cls_youle_erqiwang_arith.get_base_bycall(callgrade, false);
},
//牌id转花色
id_to_flower: function(cardid){
@@ -231,8 +278,104 @@ var cls_youle_erqiwang_arith = cls_youle_erqiwang_arith || {
return tuolaji;
},
//主牌归一化大小(副7 同级取 7000、副2 同级取 2000,其余用牌编码),仅用于甩牌分量比大小
trump_rank: function(mainflower, cardid){
var code = cls_youle_erqiwang_arith.id_to_code(mainflower, cardid);
if (code > 7000 && code < 8000){ //副7
return 7000;
}
if (code > 2000 && code < 3000){ //副2
return 2000;
}
return code;
},
//把一组主牌分解为分量列表(design §5.4.3/§5.4.4)
//返回 [{type:'single'|'pair'|'tractor', len, value, cards:[]}...],value 为该分量最大牌的归一化 rank
decompose_trump: function(mainflower, cards){
var ordered = cls_youle_erqiwang_arith.order_cards(mainflower, cards.concat());
//先分出对子与单张
var pairs = []; //{code, cards:[id,id]}
var singles = []; //{card}
var i = 0;
while (i < ordered.length){
var code_i = cls_youle_erqiwang_arith.id_to_code(mainflower, ordered[i]);
if (i + 1 < ordered.length){
var code_n = cls_youle_erqiwang_arith.id_to_code(mainflower, ordered[i + 1]);
if (code_i == code_n){
pairs.push({code: code_i, cards: [ordered[i], ordered[i + 1]]});
i = i + 2;
continue;
}
}
singles.push(ordered[i]);
i++;
}
//连续对子组成拖拉机,其余为单独对子
var comps = [];
var j = 0;
while (j < pairs.length){
var run = [pairs[j]];
var k = j;
while (k + 1 < pairs.length && cls_youle_erqiwang_arith.is_continuous(pairs[k].code, pairs[k + 1].code)){
run.push(pairs[k + 1]);
k++;
}
if (run.length >= 2){
var tcards = [];
for (var r = 0; r < run.length; r++){
tcards = tcards.concat(run[r].cards);
}
comps.push({type: "tractor", len: run.length, value: cls_youle_erqiwang_arith.trump_rank(mainflower, run[0].cards[0]), cards: tcards});
} else {
comps.push({type: "pair", len: 1, value: cls_youle_erqiwang_arith.trump_rank(mainflower, run[0].cards[0]), cards: run[0].cards});
}
j = k + 1;
}
for (var s = 0; s < singles.length; s++){
comps.push({type: "single", len: 1, value: cls_youle_erqiwang_arith.trump_rank(mainflower, singles[s]), cards: [singles[s]]});
}
return comps;
},
//甩牌最大性判定(design §5.4.2):两名对手是否持有能压过甩牌任一分量的主牌/主对/主拖拉机
//comps:甩牌分量;opp_zhulist:各对手未出的主牌id列表数组。返回 true 表示有人能压(甩错)
opp_can_beat_flush: function(mainflower, comps, opp_zhulist){
for (var o = 0; o < opp_zhulist.length; o++){
var zhu = cls_youle_erqiwang_arith.order_cards(mainflower, opp_zhulist[o].concat());
var pairs = cls_youle_erqiwang_arith.get_pairlist(mainflower, zhu);
for (var c = 0; c < comps.length; c++){
var comp = comps[c];
if (comp.type == "single"){
//对手持有任一 rank 更大的主牌单张即可压
for (var a = 0; a < zhu.length; a++){
if (cls_youle_erqiwang_arith.trump_rank(mainflower, zhu[a]) > comp.value){
return true;
}
}
} else if (comp.type == "pair"){
//对手持有 rank 更大的主对即可压
for (var p = 0; p < pairs.length; p++){
if (cls_youle_erqiwang_arith.trump_rank(mainflower, pairs[p][0]) > comp.value){
return true;
}
}
} else {
//拖拉机:对手持有同长度、顶牌 rank 更大的主拖拉机即可压
var tlist = cls_youle_erqiwang_arith.get_tuolaji_list(mainflower, pairs, 300 + comp.len);
for (var t = 0; t < tlist.length; t++){
if (cls_youle_erqiwang_arith.trump_rank(mainflower, tlist[t][0]) > comp.value){
return true;
}
}
}
}
}
return false;
},
//第一个位置是否可出牌
can_playcard: function(mainflower, cards, selfseat, seatlist){
can_playcard: function(mainflower, cards, selfseat, seatlist, opp_zhulist){
/*
参数:
mainflower: 主牌花色
@@ -273,7 +416,7 @@ var cls_youle_erqiwang_arith = cls_youle_erqiwang_arith || {
//规则外的约定,一次最多只能出14张牌
if (cards.length > 14){
do_returnfalse;
do_returnfalse();
return can;
}
@@ -380,64 +523,33 @@ var cls_youle_erqiwang_arith = cls_youle_erqiwang_arith || {
}
}
/////////// 甩牌处理 ///////////
//其他玩家没有主牌
var other_noflower = function(_flower){
for (var i = 0; i < seatlist.length; i++){
if (i != selfseat){
if (seatlist[i][_flower - 1][0] == 0){
return false;
}
/////////// 甩牌处理(design §5.4)///////////
//把要出的牌分解为分量;>1 个分量即为甩牌
var comps = cls_youle_erqiwang_arith.decompose_trump(mainflower, cards);
if (comps.length > 1){
//副牌绝对禁甩(§5.4.1):甩牌必须全是主牌
var allTrump = true;
for (var ci = 0; ci < cards.length; ci++){
if (cls_youle_erqiwang_arith.id_to_code(mainflower, cards[ci]) < 1000){
allTrump = false;
break;
}
}
return true;
}
//其他玩家没有主对
var other_noflowerpair = function(_flower){
for (var i = 0; i < seatlist.length; i++){
if (i != selfseat){
if (seatlist[i][_flower - 1][1] == 0){
return false;
}
}
}
return true;
}
//不可甩牌判断
if (can.cardtype > 101 && can.cardtype < 200){ //单张甩牌
//其他玩家有主牌则不能甩牌
if (!other_noflower(mainflower)){
if (!allTrump){
//副牌不能甩,属非法出牌(无甩错惩罚,直接拒绝)
do_returnfalse();
return can;
}
//副牌甩牌需要满足其他玩家没有主牌且其他玩家都没有该花色的牌
if (!other_noflower(can.flower)){
//最大性判定(§5.4.2):按全部手牌,两对手都不持有能压过任一分量的主牌
if (cls_youle_erqiwang_arith.opp_can_beat_flush(mainflower, comps, opp_zhulist)){
//甩错(§5.4.5):do_playcard 据此收回甩牌、只强制打出最小一张
do_returnfalse();
can.shuaicuo = true;
can.smallest = cards[cards.length - 1]; //cards 已从大到小排序,末位最小
return can;
}
} else if (can.cardtype > 201 && can.cardtype < 300){ //对子甩牌
if (can.flower == mainflower){ //甩主对
//其他玩家有主牌对子则不能甩牌
if (!other_noflowerpair(mainflower)){
do_returnfalse();
return can;
}
} else { //甩副牌对子
//其他玩家有主牌则不能甩牌
if (!other_noflower(mainflower)){
do_returnfalse();
return can;
}
//副牌甩牌需要其他玩家没有主牌且其他玩家没有该花色的对子
if (!other_noflowerpair(can.flower)){
do_returnfalse();
return can;
}
}
}
return can;
},
@@ -798,7 +910,9 @@ var cls_youle_erqiwang_arith = cls_youle_erqiwang_arith || {
return can;
}
//要是正确的拖拉机牌型
if (tuolaji_list.length == 0){
var _fpairlist = cls_youle_erqiwang_arith.get_pairlist(mainflower, _followcards);
var _ftljlist = cls_youle_erqiwang_arith.get_tuolaji_list(mainflower, _fpairlist, get.cantype);
if (_ftljlist.length == 0){
do_returnfalse();
return can;
}
@@ -922,51 +1036,41 @@ var cls_youle_erqiwang_arith = cls_youle_erqiwang_arith || {
}
},
//闲家抠底倍数
//闲家抠底倍数(design §6.3:单张主 ×1、主对子 ×2、N 连对拖拉机 ×2N)
get_bottom_multiple: function(mainflower, cards){
//拷贝数组
var _cards = cards.concat();
var _cards = cards.concat();
//将牌从大到小排序
_cards = cls_youle_erqiwang_arith.order_cards(mainflower, _cards);
//扣底要求赢下最后一轮的牌全是主牌(首末张都 >=1000 即全为主牌)
var _code = cls_youle_erqiwang_arith.id_to_code(mainflower, _cards[0]);
if (_code < 1000){
return 0;
}
var _code = cls_youle_erqiwang_arith.id_to_code(mainflower, _cards[_cards.length - 1]);
_code = cls_youle_erqiwang_arith.id_to_code(mainflower, _cards[_cards.length - 1]);
if (_code < 1000){
return 0;
}
//单张主牌不翻倍
var _pairlist = cls_youle_erqiwang_arith.get_pairlist(mainflower, _cards);
if (_pairlist.length == 0){
return 2;
return 1;
}
var _tljlist = cls_youle_erqiwang_arith.get_tuolaji_list(mainflower, _pairlist, 302);
if (_tljlist.length == 0){
return 4;
}
var _tljlist = cls_youle_erqiwang_arith.get_tuolaji_list(mainflower, _pairlist, 303);
if (_tljlist.length == 0){
return 8;
//取牌中最长的连对数 N,倍数为 2N(主对子按 N=1,即 2 倍)
var _n = 1;
var _len = 2;
while (true){
var _tljlist = cls_youle_erqiwang_arith.get_tuolaji_list(mainflower, _pairlist, 300 + _len);
if (_tljlist.length == 0){
break;
}
_n = _len;
_len = _len + 1;
}
var _tljlist = cls_youle_erqiwang_arith.get_tuolaji_list(mainflower, _pairlist, 304);
if (_tljlist.length == 0){
return 16;
}
var _tljlist = cls_youle_erqiwang_arith.get_tuolaji_list(mainflower, _pairlist, 305);
if (_tljlist.length == 0){
return 32;
}
var _tljlist = cls_youle_erqiwang_arith.get_tuolaji_list(mainflower, _pairlist, 306);
if (_tljlist.length == 0){
return 64;
}
return 2 * _n;
},
//冲关计算关数
@@ -1042,48 +1146,37 @@ var cls_youle_erqiwang_arith = cls_youle_erqiwang_arith || {
}
}
//六2六7判断
//六2六7判断(design §8.1:6/7/8 个 7 → 1/2/3 奖,6/7/8 个 2 同理)
if (_7list.length >= 6){
re.count = re.count + _7list.length - 5;
do_addlisttocards(_7list);
}
if (_2list.length >= 6){
re.count = re.count + _2list.length - 5;
re.count = re.count + _2list.length - 5;
do_addlisttocards(_2list);
}
//10个老主判断
var _total = _wlist.length + _7list.length + _2list.length;
if (_total >= 10){
re.count = re.count + _total - 9;
do_addlisttocards(_7list);
do_addlisttocards(_2list);
}
//注:固定主牌 ≥10 张只触发亮牌(§8.2)、不算奖,故此处不再加奖
re.cards = cls_youle_erqiwang_arith.order_cards(mainflower, re.cards);
return re;
},
//计算升级级数
get_upgrade: function(call, grade){
//叫分的一半
var _halfcall;
if (call % 2 == 0){
_halfcall = call / 2;
} else {
_halfcall = (call + 5) / 2;
//计算判定的子数倍率(带符号):大光 +3 / 小光 +2 / 过庄 +1 / 升N级 -N(design §7.2.0)
//q: 小光/过庄分界与升级级距(见 get_qvalue:常规40,爬坡分段)
//先判是否达标(升级),再判大光/小光/过庄,顺序不可颠倒
get_upgrade: function(call, grade, q){
if (grade >= call){
//闲家捡分达到叫分:闲赢升级,级数 = 1 + floor((grade-call)/q)
return -1 * (parseInt((grade - call) / q) + 1);
}
if (grade == 0){
return 4;
return 3; //大光
}
if (grade < _halfcall){
return 2;
if (grade < q){
return 2; //小光
}
if (grade < call){
return 1;
}
return -1 * (parseInt((grade - call) / _halfcall) + 1);
return 1; //过庄
}
}
+47
View File
@@ -0,0 +1,47 @@
///////////////////////////////////////////////////
////// cls_youle_erqiwang_config: 房间配置解析 //////
///////////////////////////////////////////////////
//
// roomtype 采用定长数字位串(字符串),每一位对应一个开关,'0'/'1',方便前端逐项勾选:
// 位0 局数: '0'→6局 '1'→12局
// 位1 扣卡方式: '0'→房主扣卡 '1'→AA每人扣卡
// 位2 傍王: '0'→关 '1'→开
// 位3 爬坡: '0'→常规算子 '1'→爬坡
// 位4 查牌: '0'→可查牌 '1'→不查牌
// 示例 "10100" = 12局 / 房主扣卡 / 傍王开 / 常规算子 / 可查牌
// 缺省 "00000" = 6局 / 房主扣卡 / 无傍王 / 常规算子 / 可查牌(对齐 design 缺省)
//
// 本模块是 roomtype 位串格式的唯一解析入口(SSOT);游戏逻辑一律经 parse() 读取,
// 不得在别处按下标硬解析。
//
var cls_youle_erqiwang_config = cls_youle_erqiwang_config || {
//位索引常量
IDX_ASET: 0, //局数
IDX_DEDUCT: 1, //扣卡方式
IDX_BANGWANG:2, //傍王
IDX_CLIMB: 3, //爬坡
IDX_NOCHECK: 4, //查牌
//取第 idx 位是否为 '1';roomtype 缺失/过短一律按 '0'(缺省)处理
bit: function(roomtype, idx){
if (!roomtype || typeof roomtype != "string"){
return false;
}
if (idx < 0 || idx >= roomtype.length){
return false;
}
return roomtype.charAt(idx) == "1";
},
//解析 roomtype 位串为具名配置对象
parse: function(roomtype){
var cfg = {};
cfg.aset12 = cls_youle_erqiwang_config.bit(roomtype, cls_youle_erqiwang_config.IDX_ASET); //true=12局 false=6局
cfg.deductAA = cls_youle_erqiwang_config.bit(roomtype, cls_youle_erqiwang_config.IDX_DEDUCT); //true=AA每人 false=房主
cfg.bangwang = cls_youle_erqiwang_config.bit(roomtype, cls_youle_erqiwang_config.IDX_BANGWANG);//true=开傍王
cfg.climb = cls_youle_erqiwang_config.bit(roomtype, cls_youle_erqiwang_config.IDX_CLIMB); //true=爬坡
cfg.nocheck = cls_youle_erqiwang_config.bit(roomtype, cls_youle_erqiwang_config.IDX_NOCHECK); //true=不查牌
return cfg;
}
}
+38 -101
View File
@@ -7,79 +7,32 @@ var cls_youle_erqiwang_export = cls_youle_erqiwang_export || {
var exp = {};
//解析roomtype获取开房所需房卡
//解析roomtype获取开房所需房卡(design §10.1)
exp.get_needroomcard = function(roomtype){
switch (roomtype[2])
{
case 1: //房主扣卡
switch (roomtype[0])
{
case 1:
return 1;
break;
case 2:
return 2;
break;
default:
return 1;
break;
}
break;
case 2: //每人扣卡
switch (roomtype[0])
{
case 1:
return 1;
break;
case 2:
return 2;
break;
default:
return 1;
break;
}
break;
var cfg = cls_youle_erqiwang_config.parse(roomtype);
if (cfg.deductAA){
//AA每人扣卡:6局每人1张 / 12局每人2张
return cfg.aset12 ? 2 : 1;
}
//房主扣卡:6局2张 / 12局4张
return cfg.aset12 ? 4 : 2;
}
//解析roomtype获取总局数
//解析roomtype获取总局数(design §10.1:6局 / 12局)
exp.get_asetcount = function(roomtype){
switch (roomtype[0])
{
case 1:
return 2;
break;
case 2:
return 4;
break;
default:
return 4;
break;
}
var cfg = cls_youle_erqiwang_config.parse(roomtype);
return cfg.aset12 ? 12 : 6;
}
//加入房间时根据roomtype获取需要的房卡数量
exp.get_needroomcard_joinroom = function(roomtype){
switch (roomtype[2])
{
case 1: //房主扣卡
return 0;
break;
case 2: //每人扣卡
switch (roomtype[0])
{
case 1:
return 1;
break;
case 2:
return 2;
break;
default:
return 1;
break;
}
break;
var cfg = cls_youle_erqiwang_config.parse(roomtype);
if (cfg.deductAA){
//AA每人扣卡:加入者按自己那份扣(6局1张 / 12局2张)
return cfg.aset12 ? 2 : 1;
}
//房主扣卡:加入者不扣
return 0;
}
//开战
@@ -138,11 +91,13 @@ var cls_youle_erqiwang_export = cls_youle_erqiwang_export || {
//庄家叫分倍数
deskinfo.ChooseMain.multiple = cls_youle_erqiwang_arith.get_multiple_bycall(paiju.call);
//选主倒计时
deskinfo.ChooseMain.countdown = o_room.o_desk.method.get_countdown_xuanzhu();
//底牌
deskinfo.ChooseMain.bottomcards = paiju.method.get_bottomcards();
deskinfo.ChooseMain.countdown = o_room.o_desk.method.get_countdown_xuanzhu();
//底牌:暗牌只有庄家可见(70分的3秒亮牌是上庄时的一次性事件,重连不重放)
if (seat == paiju.banker){
deskinfo.ChooseMain.bottomcards = paiju.method.get_bottomcards();
}
//是否可投降
if (paiju.call < 65){
if (paiju.call != 70){
deskinfo.ChooseMain.touxiang = 0;
} else {
deskinfo.ChooseMain.touxiang = 1;
@@ -157,40 +112,14 @@ var cls_youle_erqiwang_export = cls_youle_erqiwang_export || {
//庄家叫分倍数
deskinfo.BuryCards.multiple = cls_youle_erqiwang_arith.get_multiple_bycall(paiju.call);
//埋牌倒计时
deskinfo.BuryCards.countdown = o_room.o_desk.method.get_countdown_maipai();
//底牌
deskinfo.BuryCards.bottomcards = paiju.method.get_bottomcards();
deskinfo.BuryCards.countdown = o_room.o_desk.method.get_countdown_maipai();
//底牌:暗牌只有庄家可见
if (seat == paiju.banker){
deskinfo.BuryCards.bottomcards = paiju.method.get_bottomcards();
}
//主牌花色
deskinfo.BuryCards.flower = paiju.flower;
//是否可投降
if (paiju.call < 65){
deskinfo.BuryCards.touxiang = 0;
} else {
deskinfo.BuryCards.touxiang = 1;
}
break;
case 4: //投降
deskinfo.Surrender = {};
//庄家
deskinfo.Surrender.banker = paiju.banker;
//庄家叫分
deskinfo.Surrender.call = paiju.call;
//庄家叫分倍数
deskinfo.Surrender.multiple = cls_youle_erqiwang_arith.get_multiple_bycall(paiju.call);
//出牌倒计时
deskinfo.Surrender.countdown = o_room.o_desk.method.get_countdown_chupai();
//主牌花色
deskinfo.Surrender.flower = paiju.flower;
if (seat == paiju.banker){
//埋的牌
deskinfo.Surrender.bottomcards = paiju.method.get_burycard();
}
//是否可投降
if (paiju.call < 65){
deskinfo.Surrender.touxiang = 0;
} else {
deskinfo.Surrender.touxiang = 1;
}
//埋牌阶段无投降(投降是选主阶段与选主互斥的选择)
break;
case 5: //出牌
deskinfo.PushCards = {};
@@ -217,8 +146,16 @@ var cls_youle_erqiwang_export = cls_youle_erqiwang_export || {
deskinfo.PushCards.grade = jian_grade.grade;
//当前的出牌情况
deskinfo.PushCards.playproc = paiju.playproc;
//座位列表
deskinfo.PushCards.seatlist = paiju.seatlist;
//座位列表(报副统计)与亮牌:仅可查牌模式下展示(§9/§8.2)
if (!cls_youle_erqiwang_config.parse(o_room.roomtype).nocheck){
deskinfo.PushCards.seatlist = paiju.seatlist;
if (seat != paiju.banker){
var _lp = paiju.method.get_liangpai();
if (_lp){
deskinfo.PushCards.liangpai = _lp;
}
}
}
//出牌历史
deskinfo.PushCards.pushlist = [];
for (var i = 0; i < paiju.cards.length; i++) {
+201 -159
View File
@@ -133,7 +133,7 @@ var cls_youle_erqiwang_paiju = cls_youle_erqiwang_paiju || {
//牌列表
paiju.cards = [];
//当前阶段
paiju.step = -1; //1发完牌叫分 2选主 3埋牌 4投降 5出牌 6结算
paiju.step = -1; //1发完牌叫分 2选主/投降 3埋牌 5出牌 6结算(无独立投降阶段,投降在step2)
//叫分过程
paiju.callproc = [];
//庄家位置
@@ -239,6 +239,11 @@ var cls_youle_erqiwang_paiju = cls_youle_erqiwang_paiju || {
return cls_youle_erqiwang_paiju.get_jian_grade(paiju);
}
//获取庄家亮牌信息(design §8.2)
paiju.method.get_liangpai = function(){
return cls_youle_erqiwang_paiju.get_liangpai(paiju);
}
return paiju;
},
@@ -287,6 +292,25 @@ var cls_youle_erqiwang_paiju = cls_youle_erqiwang_paiju || {
return cls_youle_erqiwang_arith.order_cards(o_paiju.flower, aryCardIDs);
},
//获取算奖用的静态初始手牌快照(design §8)
//庄家:埋牌后保留的28张(发牌+底,排除已埋 playround==0);闲家:发牌后的28张
get_seat_cards_award: function(o_paiju, seat){
var aryCardIDs = [];
for (var i = 0; i < o_paiju.cards.length; i++){
var o_card = o_paiju.cards[i];
if (seat == o_paiju.banker){
if ((o_card.dealowner == seat + 1 || o_card.dealowner == 0) && o_card.playround != 0){
aryCardIDs.push(o_card.id);
}
} else {
if (o_card.dealowner == seat + 1){
aryCardIDs.push(o_card.id);
}
}
}
return cls_youle_erqiwang_arith.order_cards(o_paiju.flower, aryCardIDs);
},
//获取某个位置玩家手上的主牌
get_seat_zhucards: function(o_paiju, seat){
var aryCardIDs = [];
@@ -413,12 +437,7 @@ var cls_youle_erqiwang_paiju = cls_youle_erqiwang_paiju || {
//选主
do_choiceflower: function(o_paiju, flower){
o_paiju.flower = flower;
//修改主牌的牌编码
for (var i = 1; i <= 2; i++){ //两副牌
for (var j = 0; j < 13; j++){
var o_card = o_paiju.cards[(i - 1) * 54 + (flower - 1) * 13 + j];
}
}
//主牌的牌编码在 arith.id_to_code 里按 mainflower 动态计算,选主时只需记录花色
//进入埋牌阶段
o_paiju.step = 3;
},
@@ -450,8 +469,8 @@ var cls_youle_erqiwang_paiju = cls_youle_erqiwang_paiju || {
for (var i = 0; i < cards.length; i++) {
o_paiju.cards[cards[i]].playround = 0;
};
//进入投降阶段
o_paiju.step = 4;
//埋牌后直接进入出牌阶段,由庄家首出(投降已在选主阶段 step2 决定,无独立投降阶段)
o_paiju.step = 5;
cls_youle_erqiwang_paiju.new_playround(o_paiju, 1, o_paiju.banker);
},
@@ -524,13 +543,33 @@ var cls_youle_erqiwang_paiju = cls_youle_erqiwang_paiju || {
var nextseat_2 = cls_youle_erqiwang_paiju.get_nextseat(nextseat_1);
if (o_paiju.playproc.currseat == o_paiju.playproc.start){ //是本轮的第一个出牌
var can = cls_youle_erqiwang_arith.can_playcard(o_paiju.flower, cards, o_paiju.playproc.currseat, o_paiju.seatlist);
if (!can.result){
var re = {};
re.result = false;
return re;
//两名对手未出的主牌,供甩牌最大性判定(§5.4.2)
var opp_zhulist = [];
for (var os = 0; os < 3; os++){
if (os != o_paiju.playproc.currseat){
opp_zhulist.push(cls_youle_erqiwang_paiju.get_seat_zhucards(o_paiju, os));
}
}
//出牌
var can = cls_youle_erqiwang_arith.can_playcard(o_paiju.flower, cards, o_paiju.playproc.currseat, o_paiju.seatlist, opp_zhulist);
var _shuaicuo = false;
if (!can.result){
if (can.shuaicuo){
//甩错惩罚(§5.4.5):收回甩牌,本轮只强制打出最小一张
_shuaicuo = true;
cards = [can.smallest];
can = cls_youle_erqiwang_arith.can_playcard(o_paiju.flower, cards, o_paiju.playproc.currseat, o_paiju.seatlist, opp_zhulist);
if (!can.result){
var reErr = {};
reErr.result = false;
return reErr;
}
} else {
var re = {};
re.result = false;
return re;
}
}
//出牌(cards 在甩错时已被替换为仅最小一张)
doplay(1);
//记录下牌型、花色、牌型最大牌
o_paiju.playproc.startcount = cards.length;
@@ -546,6 +585,8 @@ var cls_youle_erqiwang_paiju = cls_youle_erqiwang_paiju || {
re1.count = cards.length;
re1.flower = can.flower;
re1.cardtype = can.cardtype;
re1.cards = cards; //实际打出的牌(甩错时为单张)
re1.shuaicuo = _shuaicuo;
return re1;
}
@@ -642,6 +683,51 @@ var cls_youle_erqiwang_paiju = cls_youle_erqiwang_paiju || {
return cls_youle_erqiwang_arith.order_cards(o_paiju.flower, aryCardIDs);
},
//获取庄家亮牌信息(design §8.2):基于庄家埋牌后 28 张手牌,达标才亮,只亮数量/结构
//返回 null 表示无需亮牌;否则返回 {zhu,zhupair,zhutuo?, wang?, qi?, er?}
get_liangpai: function(o_paiju){
if (o_paiju.banker < 0){
return null;
}
var cards = cls_youle_erqiwang_paiju.get_seat_cards(o_paiju, o_paiju.banker);
var wang = 0, qi = 0, er = 0;
var zhucards = [];
for (var i = 0; i < cards.length; i++){
var num = cls_youle_erqiwang_arith.id_to_number(cards[i]);
var flw = cls_youle_erqiwang_arith.id_to_flower(cards[i]);
if (num >= 53){ wang = wang + 1; }
if (num == 7){ qi = qi + 1; }
if (num == 2){ er = er + 1; }
//主牌 = 主花色普通牌 或 王 或 任意 2/7
if (flw == o_paiju.flower || flw == 5 || num == 2 || num == 7){
zhucards.push(cards[i]);
}
}
var guding = wang + qi + er; //固定主牌(王 + 全部 2 + 全部 7)
var re = {};
var has = false;
if (guding >= 10){
zhucards = cls_youle_erqiwang_arith.order_cards(o_paiju.flower, zhucards);
var pairs = cls_youle_erqiwang_arith.get_pairlist(o_paiju.flower, zhucards);
var comps = cls_youle_erqiwang_arith.decompose_trump(o_paiju.flower, zhucards);
var tuo = 0;
for (var c = 0; c < comps.length; c++){
if (comps[c].type == "tractor"){ tuo = tuo + 1; }
}
re.zhu = zhucards.length; //主牌总数
re.zhupair = pairs.length; //主对子数
re.zhutuo = tuo; //主拖拉机组数
has = true;
}
if (wang >= 3){ re.wang = wang; has = true; }
if (qi >= 6){ re.qi = qi; has = true; }
if (er >= 6){ re.er = er; has = true; }
if (!has){
return null;
}
return re;
},
//获取抠底包
get_bottom_account: function(o_paiju, msg){
msg.data.bottom = {};
@@ -682,7 +768,7 @@ var cls_youle_erqiwang_paiju = cls_youle_erqiwang_paiju || {
var do_deduct_roomcard = function(){
youle_erqiwang.import.deduct_roomcard(o_paiju.o_desk.o_room);
}
min_ontimeout(do_deduct_roomcard, 1000);
min_ontimeout(do_deduct_roomcard, 1000);
}
if (msg.rpc != "jiesuan"){
@@ -691,165 +777,121 @@ var cls_youle_erqiwang_paiju = cls_youle_erqiwang_paiju || {
if (!msg.data){
msg.data = {};
}
msg.data.aset = {};
msg.data.aset.banker = o_paiju.banker;
msg.data.aset.call = o_paiju.call;
msg.data.aset.multiple = cls_youle_erqiwang_arith.get_multiple_bycall(o_paiju.call);
msg.data.aset.flower = o_paiju.flower;
var jian_grade = cls_youle_erqiwang_paiju.get_jian_grade(o_paiju);
msg.data.aset.grade = jian_grade.grade;
//读取房间可选规则(缺省:常规算子、不傍王;见 class.config.js 位串约定)
var o_room = o_paiju.o_desk.o_room;
var _cfg = cls_youle_erqiwang_config.parse(o_room.roomtype);
var _climb = _cfg.climb; //爬坡
var _bangwang = _cfg.bangwang; //傍王
//闲家捡分(含抠底)
var _call = o_paiju.call;
var _jian = cls_youle_erqiwang_paiju.get_jian_grade(o_paiju);
var _grade = _jian.grade;
if (msg.data.bottom && msg.data.bottom.grade2){
msg.data.aset.grade = msg.data.aset.grade + msg.data.bottom.grade2;
_grade = _grade + msg.data.bottom.grade2;
}
//算子:_base 基础子数、_upgrade 判定倍率(带符号,送客户端)、_X 每对子子数、_win 胜负(1庄赢 -1闲赢 0无)
var _base, _upgrade, _X, _win;
switch (type){
case 0:
msg.data.aset.upgrade = cls_youle_erqiwang_arith.get_upgrade(o_paiju.call, msg.data.aset.grade);
if (msg.data.aset.upgrade > 0){
o_paiju.result = 0;
} else {
o_paiju.result = 1;
}
_base = cls_youle_erqiwang_arith.get_base_bycall(_call, _climb);
var _q = cls_youle_erqiwang_arith.get_qvalue(_call, _climb);
_upgrade = cls_youle_erqiwang_arith.get_upgrade(_call, _grade, _q);
_win = (_upgrade > 0) ? 1 : -1;
_X = ((_upgrade < 0) ? (0 - _upgrade) : _upgrade) * _base;
o_paiju.result = (_upgrade > 0) ? 0 : 1;
break;
case 1:
msg.data.aset.upgrade = -99;
case 1: //投降:70分坐庄,基础子数1,庄家直接输1个子
_base = 1;
_upgrade = -99; //送客户端的投降标识
_win = -1;
_X = 1;
o_paiju.result = 2;
break;
case 2:
msg.data.aset.upgrade = 0;
case 2: //解散:本局不结算子数与算奖
_base = 0;
_upgrade = 0;
_win = 0;
_X = 0;
o_paiju.result = 3;
break;
}
msg.data.aset.seatlist = [];
var _player0 = {};
var _player1 = {};
var _player2 = {};
//获取玩家的牌
var _card0 = cls_youle_erqiwang_paiju.get_seat_cards_owner(o_paiju, 0);
var _card1 = cls_youle_erqiwang_paiju.get_seat_cards_owner(o_paiju, 1);
var _card2 = cls_youle_erqiwang_paiju.get_seat_cards_owner(o_paiju, 2);
//计算冲关或王牌
var _flower = o_paiju.flower;
if (type != 2){
_flower = -1;
}
var _chongguan0 = cls_youle_erqiwang_arith.get_chongguan(_flower, _card0);
var _chongguan1 = cls_youle_erqiwang_arith.get_chongguan(_flower, _card1);
var _chongguan2 = cls_youle_erqiwang_arith.get_chongguan(_flower, _card2);
//冲关的牌或王牌
_player0.cards = _chongguan0.cards;
_player1.cards = _chongguan1.cards;
_player2.cards = _chongguan2.cards;
//关数
_player0.chongguan = _chongguan0.count;
_player1.chongguan = _chongguan1.count;
_player2.chongguan = _chongguan2.count;
//是否作废
_player0.obsolete = 0;
_player1.obsolete = 0;
_player2.obsolete = 0;
//根据叫分判断冲关是否作废
var do_obsolete_with_call = function(player, seat){
var _dealcards = cls_youle_erqiwang_paiju.get_seat_cards_deal(o_paiju, seat);
var _dealchongguan = cls_youle_erqiwang_arith.get_chongguan(-1, _dealcards);
if (_dealchongguan.count == 0){
return;
msg.data.aset = {};
msg.data.aset.banker = o_paiju.banker;
msg.data.aset.call = _call;
msg.data.aset.multiple = _base;
msg.data.aset.flower = o_paiju.flower;
msg.data.aset.grade = _grade;
msg.data.aset.upgrade = _upgrade;
msg.data.aset.bangwang = _bangwang ? 1 : 0;
msg.data.aset.climb = _climb ? 1 : 0;
//算奖:各家奖数 N =(庄家?常规算奖 : 0)+(傍王?王数 : 0)
//静态初始手牌快照:庄家取埋牌后28张、闲家取发牌后28张
var _c0 = cls_youle_erqiwang_paiju.get_seat_cards_award(o_paiju, 0);
var _c1 = cls_youle_erqiwang_paiju.get_seat_cards_award(o_paiju, 1);
var _c2 = cls_youle_erqiwang_paiju.get_seat_cards_award(o_paiju, 2);
var _cglist = [
cls_youle_erqiwang_arith.get_chongguan(o_paiju.flower, _c0),
cls_youle_erqiwang_arith.get_chongguan(o_paiju.flower, _c1),
cls_youle_erqiwang_arith.get_chongguan(o_paiju.flower, _c2)
];
var award_count = function(cgobj, seat){
var n = 0;
if (seat == o_paiju.banker){
n = n + cgobj.count; //常规算奖只计庄家(design §8.1)
}
var _call = null;
for (var i = 0; i < o_paiju.callproc.length; i++){
if (o_paiju.callproc[i].seat == seat){
_call = o_paiju.callproc[i].call;
break;
if (_bangwang){
n = n + cgobj.wang; //傍王勾选时庄闲都算,每张王1奖(design §8.3)
}
return n;
}
var _nlist = [
award_count(_cglist[0], 0),
award_count(_cglist[1], 1),
award_count(_cglist[2], 2)
];
//算奖并入结算(design §8.4):玩家i从另两家各收 X×Ni、各付 X×Nj,净得 X×(2Ni−Nj−Nk)
var _aw = [
_X * (2 * _nlist[0] - _nlist[1] - _nlist[2]),
_X * (2 * _nlist[1] - _nlist[0] - _nlist[2]),
_X * (2 * _nlist[2] - _nlist[0] - _nlist[1])
];
//捡分子数:_win=1庄赢→庄+X×2/闲−X;_win=-1闲赢→庄−X×2/闲+X
var _jf = [0, 0, 0];
if (o_paiju.banker >= 0){
for (var s = 0; s < 3; s++){
if (s == o_paiju.banker){
_jf[s] = _win * _X * 2;
} else {
_jf[s] = _win * _X * -1;
}
}
if (!_call){ //冲关必叫
player.obsolete = 1;
} else if (_dealchongguan.wang == 4 && _call > 60){ //四王必踢
player.obsolete = 1;
}
}
do_obsolete_with_call(_player0, 0);
do_obsolete_with_call(_player1, 1);
do_obsolete_with_call(_player2, 2);
//计算冲关得分
var _cg0 = _player0.chongguan;
var _cg1 = _player1.chongguan;
var _cg2 = _player2.chongguan;
if (_player0.obsolete){
_cg0 = 0;
msg.data.aset.seatlist = [];
for (var i = 0; i < 3; i++){
var _p = {};
_p.cards = _cglist[i].cards; //算奖相关牌(王/冲关牌)
_p.chongguan = _cglist[i].count; //常规算奖奖数(仅庄家计入 N)
_p.wang = _cglist[i].wang; //王数
_p.naward = _nlist[i]; //该家总奖数 N
_p.grade_aw = _aw[i]; //算奖得分 X×(2Ni−Nj−Nk)
_p.grade_jf = _jf[i]; //捡分子数得分
_p.grade = _p.grade_aw + _p.grade_jf; //本局总得分
//大局累积得分
o_paiju.o_desk.seatlist[i][0] = o_paiju.o_desk.seatlist[i][0] + _p.grade;
_p.score = o_paiju.o_desk.seatlist[i][0];
//保存每局得分
o_paiju.o_desk.seatlist[i][1].push(_p.grade);
msg.data.aset.seatlist.push(_p);
}
if (_player1.obsolete){
_cg1 = 0;
}
if (_player2.obsolete){
_cg2 = 0;
}
_player0.grade_cg = _cg0 * 2 - _cg1 - _cg2;
_player1.grade_cg = _cg1 * 2 - _cg2 - _cg0;
_player2.grade_cg = _cg2 * 2 - _cg0 - _cg1;
//计算傍王得分
var _w0 = _chongguan0.wang;
var _w1 = _chongguan1.wang;
var _w2 = _chongguan2.wang;
if (_player0.obsolete){
_w0 = 0;
}
if (_player1.obsolete){
_w1 = 0;
}
if (_player2.obsolete){
_w2 = 0;
}
_player0.grade_w = _w0 * 2 - _w1 - _w2;
_player1.grade_w = _w1 * 2 - _w2 - _w0;
_player2.grade_w = _w2 * 2 - _w0 - _w1;
//计算捡分得分
var _upgrade = msg.data.aset.upgrade;
if (_upgrade == -99){
_upgrade = -2;
}
switch (o_paiju.banker){
case -1:
_player0.grade_jf = 0;
_player1.grade_jf = 0;
_player2.grade_jf = 0;
break;
case 0:
_player0.grade_jf = _upgrade * msg.data.aset.multiple * 2;
_player1.grade_jf = _upgrade * msg.data.aset.multiple * -1;
_player2.grade_jf = _player1.grade_jf;
break;
case 1:
_player0.grade_jf = _upgrade * msg.data.aset.multiple * -1;
_player1.grade_jf = _upgrade * msg.data.aset.multiple * 2;
_player2.grade_jf = _player0.grade_jf;
break;
case 2:
_player0.grade_jf = _upgrade * msg.data.aset.multiple * -1;
_player1.grade_jf = _player0.grade_jf;
_player2.grade_jf = _upgrade * msg.data.aset.multiple * 2;
break;
}
//计算本局总得分
_player0.grade = _player0.grade_cg + _player0.grade_w + _player0.grade_jf;
_player1.grade = _player1.grade_cg + _player1.grade_w + _player1.grade_jf;
_player2.grade = _player2.grade_cg + _player2.grade_w + _player2.grade_jf;
//大局累积得分
o_paiju.o_desk.seatlist[0][0] = o_paiju.o_desk.seatlist[0][0] + _player0.grade;
o_paiju.o_desk.seatlist[1][0] = o_paiju.o_desk.seatlist[1][0] + _player1.grade;
o_paiju.o_desk.seatlist[2][0] = o_paiju.o_desk.seatlist[2][0] + _player2.grade;
_player0.score = o_paiju.o_desk.seatlist[0][0];
_player1.score = o_paiju.o_desk.seatlist[1][0];
_player2.score = o_paiju.o_desk.seatlist[2][0];
//保存每局得分
o_paiju.o_desk.seatlist[0][1].push(_player0.grade);
o_paiju.o_desk.seatlist[1][1].push(_player1.grade);
o_paiju.o_desk.seatlist[2][1].push(_player2.grade);
msg.data.aset.seatlist.push(_player0);
msg.data.aset.seatlist.push(_player1);
msg.data.aset.seatlist.push(_player2);
if (o_paiju.idx >= o_paiju.o_desk.o_room.asetcount || type == 2){
msg = o_paiju.o_desk.method.get_desk_account(msg);
+109 -14
View File
@@ -4,6 +4,8 @@
var youle_erqiwang = youle_erqiwang || cls_mod.new("youle_erqiwang", "erqiwang", youle_app);
//配置解析类(roomtype 位串解析,SSOT)
min_loadJsFile("games/erqiwang/class.config.js", function(){
//牌类
min_loadJsFile("games/erqiwang/class.pai.js", function(){
//牌局类
@@ -23,6 +25,7 @@ min_loadJsFile("games/erqiwang/class.export.js", function(){
});
});
});
});
//对内的输入接口类(需要的外部接口)
youle_erqiwang.import = null;
@@ -60,10 +63,10 @@ youle_erqiwang.jiaofen = function(pack){
if (o_paiju.method.get_callgrade_seat() != seat){
return;
}
//检查当前的叫分分值必须大于0,且是5的整数倍
if (call < 0 || call % 5 != 0){
//检查叫分:0(不叫)或 5~70 且为 5 的整数倍(design §4)
if (call < 0 || call > 70 || call % 5 != 0){
return;
}
}
var curr_call = o_paiju.method.get_callgrade_value();
//第一家不能不叫分
if (curr_call == 0 && call == 0){
@@ -106,21 +109,33 @@ youle_erqiwang.jiaofen = function(pack){
msg.data.banker = o_paiju.banker;
msg.data.grade = o_paiju.call;
msg.data.multiple = cls_youle_erqiwang_arith.get_multiple_bycall(msg.data.grade);
msg.data.bottomcards = o_paiju.method.get_bottomcards();
msg.data.countdown = o_desk.method.get_countdown_xuanzhu();
if (o_paiju.call < 65){
if (o_paiju.call != 70){
msg.data.touxiang = 0;
} else {
msg.data.touxiang = 1;
}
//70分坐庄:庄家摸暗牌前,8张暗牌向所有玩家亮3秒(design §4/§7.1)
if (o_paiju.call == 70){
msg.data.ancard3s = 1;
}
var _bottomcards = o_paiju.method.get_bottomcards();
for (var i = 0; i < o_room.seatlist.length; i++) {
msg.conmode = o_room.seatlist[i].conmode;
msg.fromid = o_room.seatlist[i].fromid;
if (i == o_paiju.banker){
//庄家:手牌(含摸起的暗牌)与暗牌本身都可见
msg.data.cards = o_paiju.method.get_seat_cards(i);
msg.data.bottomcards = _bottomcards;
} else {
delete msg.data.cards;
//闲家:仅70分坐庄时才下发暗牌(供亮3秒),否则暗牌只有庄家可见
if (o_paiju.call == 70){
msg.data.bottomcards = _bottomcards;
} else {
delete msg.data.bottomcards;
}
}
youle_erqiwang.app.SendPack(msg);
}
@@ -227,6 +242,13 @@ youle_erqiwang.maipai = function(pack){
//埋牌成功
o_paiju.method.do_burycard(cards);
//亮牌(design §8.2):可查牌模式下,出牌开始向两个闲家亮出庄家手牌统计
var _cfg = cls_youle_erqiwang_config.parse(o_room.roomtype);
var _liangpai = null;
if (!_cfg.nocheck){
_liangpai = o_paiju.method.get_liangpai();
}
//返回前端
var msg = {};
msg.app = "youle";
@@ -241,9 +263,16 @@ youle_erqiwang.maipai = function(pack){
if (i == o_paiju.banker){
msg.data.cards = o_paiju.method.get_seat_cards(i);
msg.data.bottomcards = cards;
delete msg.data.liangpai;
} else {
delete msg.data.cards;
delete msg.data.bottomcards;
//闲家:可查牌且庄家达标时亮牌
if (_liangpai){
msg.data.liangpai = _liangpai;
} else {
delete msg.data.liangpai;
}
}
youle_erqiwang.app.SendPack(msg);
}
@@ -271,16 +300,16 @@ youle_erqiwang.touxiang = function(pack){
if (!o_paiju){
return;
}
//检查当前的游戏阶段是否是叫分、埋牌、投降阶段
if (o_paiju.step != 2 && o_paiju.step != 3 && o_paiju.step != 4){
//投降是选主阶段(step 2)与选主互斥的选择:点投降直接结算,不选主、不埋牌(design §4)
if (o_paiju.step != 2){
return;
}
//检查庄家位置
if (o_paiju.banker != seat){
return;
}
//检查是否允许投降
if (o_paiju.call < 65){
//仅 70 分坐庄可投降(design §4 / §7.1)
if (o_paiju.call != 70){
return;
}
@@ -319,7 +348,7 @@ youle_erqiwang.chupai = function(pack){
return;
}
//检查当前的游戏阶段是否是出牌阶段
if (o_paiju.step != 4 && o_paiju.step != 5){
if (o_paiju.step != 5){
return;
}
//检查出牌位置
@@ -341,17 +370,26 @@ youle_erqiwang.chupai = function(pack){
return;
}
//查牌模式(design §9):不查牌时不下发任何主牌统计(info/报无主)
var _cfg = cls_youle_erqiwang_config.parse(o_room.roomtype);
//返回前端
var msg = {};
msg.app = "youle";
msg.route = "erqiwang";
msg.data = {};
msg.data.seat = seat;
msg.data.cards = cards;
msg.data.info = o_paiju.seatlist[seat];
msg.data.cards = re.cards ? re.cards : cards; //实际打出的牌(甩错时为单张)
if (!_cfg.nocheck){
msg.data.info = o_paiju.seatlist[seat]; //座位牌况(报副统计),仅可查牌下发
}
msg.data.nextseat = o_paiju.playproc.currseat;
msg.data.countdown = o_desk.method.get_countdown_chupai();
if (o_paiju.method.have_baofu()){
if (re.shuaicuo){
msg.data.shuaicuo = 1; //甩错:本次甩牌被收回,只打出了最小一张(§5.4.5)
}
//报无主:仅可查牌模式下才据此展示他家主牌数量/对子(§9)
if (!_cfg.nocheck && o_paiju.method.have_baofu()){
msg.data.baozhu = 1;
} else {
msg.data.baozhu = 0;
@@ -421,6 +459,63 @@ youle_erqiwang.chupai = function(pack){
}
}
//明牌:查看另外两家手中全部主牌的具体牌面(design §9,仅可查牌模式且已有人报无主)
youle_erqiwang.mingpai = function(pack){
var agentid = pack.data.agentid;
var playerid = parseInt(pack.data.playerid);
var gameid = pack.data.gameid;
var roomcode = parseInt(pack.data.roomcode);
var seat = parseInt(pack.data.seat);
//检查玩家的位置是否正确
var o_room = youle_erqiwang.import.check_player(agentid, gameid, roomcode, seat, playerid, pack.conmode, pack.fromid);
if (!o_room){
return;
}
//牌桌
var o_desk = o_room.o_desk;
if (!o_desk){
return;
}
//牌局
var o_paiju = o_desk.method.curr_paiju();
if (!o_paiju){
return;
}
//只在出牌阶段
if (o_paiju.step != 5){
return;
}
//不查牌模式禁止明牌
var cfg = cls_youle_erqiwang_config.parse(o_room.roomtype);
if (cfg.nocheck){
return;
}
//必须已有玩家报无主才允许明牌
if (!o_paiju.method.have_baofu()){
return;
}
//另外两家未出的全部主牌,只回发给请求者
var msg = {};
msg.app = "youle";
msg.route = "erqiwang";
msg.rpc = "mingpai";
msg.data = {};
msg.data.seat = seat;
msg.data.others = [];
for (var i = 0; i < 3; i++){
if (i != seat){
var one = {};
one.seat = i;
one.zhucards = cls_youle_erqiwang_paiju.get_seat_zhucards(o_paiju, i);
msg.data.others.push(one);
}
}
msg.conmode = pack.conmode;
msg.fromid = pack.fromid;
youle_erqiwang.app.SendPack(msg);
}
//准备
youle_erqiwang.zhunbei = function(pack){
var agentid = pack.data.agentid;