二七王服务端:按 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:
@@ -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; //过庄
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user