feat: integrate erqiwang rooms and use spec-compliant Web compilation
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.2.0",
|
||||
"importer": "directory",
|
||||
"imported": true,
|
||||
"uuid": "66d74934-1469-4fe1-ad7d-92b5cd70e688",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "c1608cf0-5b48-4714-8a06-9363c854ab71",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "ErqiwangCreateRoom"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import {_decorator,Button,Label,Toggle,ToggleContainer} from 'cc';
|
||||
import {CreateRoomPage} from '../../scripts/platform-login/CreateRoomPage.ts';
|
||||
import type {CreateRoomPageContext} from '../../framework/sdk/contracts/create-room-page.ts';
|
||||
import {ErqiwangRoomRules} from './erqiwang-room-rules.ts';
|
||||
const {ccclass,property}=_decorator;
|
||||
@ccclass('ErqiwangCreateRoomView')
|
||||
export class ErqiwangCreateRoomView extends CreateRoomPage {
|
||||
@property([ToggleContainer]) groups:ToggleContainer[]=[];
|
||||
@property([Toggle]) options:Toggle[]=[];
|
||||
@property([Label]) optionLabels:Label[]=[];
|
||||
@property(Button) submitButton:Button|null=null;
|
||||
@property([Button]) cancelButtons:Button[]=[];
|
||||
@property(Label) feeLabel:Label|null=null;
|
||||
private readonly rules=new ErqiwangRoomRules();
|
||||
private context:CreateRoomPageContext|null=null;
|
||||
private busy=false;
|
||||
private releases:Array<()=>void>=[];
|
||||
open(context:CreateRoomPageContext):void{
|
||||
this.close();
|
||||
if(this.groups.length!==3||this.options.length!==8||this.optionLabels.length!==8||!this.feeLabel||!this.submitButton||this.cancelButtons.length!==2)throw Error('ErqiwangCreateRoomView requires serialized controls');
|
||||
this.rules.open(context.previousRoomtype);this.context=context;
|
||||
// Permit all toggles to reset before restoring each mandatory group.
|
||||
this.groups.forEach(group=>group.allowSwitchOff=true);
|
||||
this.optionLabels.forEach((label,i)=>label.string=['6局','12局','房主扣卡','AA每人扣卡','可查牌','不查牌','傍王','爬坡'][i]);
|
||||
this.options.forEach((toggle,i)=>{
|
||||
toggle.isChecked=i<6?this.rules.selection[Math.floor(i/2)]===i%2:this.rules.selection[i-3]===1;
|
||||
const changed=()=>{if(this.busy||!this.context)return;if(i<6&&!toggle.isChecked)return;this.rules.select(i<6?Math.floor(i/2):i-3,i<6?i%2:Number(toggle.isChecked));this.renderFee();};
|
||||
toggle.node.on(Toggle.EventType.TOGGLE,changed);this.releases.push(()=>toggle.node.off(Toggle.EventType.TOGGLE,changed));
|
||||
});
|
||||
this.groups.forEach(group=>group.allowSwitchOff=false);
|
||||
const bind=(button:Button,action:()=>void)=>{const fn=()=>{if(!this.busy&&this.context)try{action();}catch(error){context.reportError(error instanceof Error?error.message:String(error));}};
|
||||
button.node.on(Button.EventType.CLICK,fn);this.releases.push(()=>button.node.off(Button.EventType.CLICK,fn));};
|
||||
bind(this.submitButton,()=>context.submit(this.rules.build()));
|
||||
this.cancelButtons.forEach(button=>{const cancel=()=>{if(this.context===context)context.cancel();};button.node.on(Button.EventType.CLICK,cancel);this.releases.push(()=>button.node.off(Button.EventType.CLICK,cancel));});this.setBusy(false);this.renderFee();
|
||||
}
|
||||
private renderFee():void{if(this.feeLabel)this.feeLabel.string=`${this.rules.selection[1]===1?'每人':'房主'}消耗 ${this.rules.roomCards} 张房卡`; }
|
||||
setBusy(busy:boolean):void{this.busy=busy;this.options.forEach(toggle=>toggle.interactable=!busy);if(this.submitButton)this.submitButton.interactable=!busy;}
|
||||
close():void{for(const release of this.releases.splice(0))release();this.context=null;}
|
||||
onDestroy():void{this.close();}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "987021eb-b5b3-4b73-bba9-39f3ea97c6b9",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"ver": "1.1.50",
|
||||
"importer": "prefab",
|
||||
"imported": true,
|
||||
"uuid": "28fcf5a7-d779-4400-9c71-300cf492bcc7",
|
||||
"files": [
|
||||
".json"
|
||||
],
|
||||
"subMetas": {},
|
||||
"userData": {
|
||||
"syncNodeName": "ErqiwangRoom"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import {_decorator} from 'cc';
|
||||
import {TemplateRoomView} from '../template/TemplateRoomView.ts';
|
||||
import type {TemplateRoomActions} from '../template/template-game.ts';
|
||||
import type {PlatformGameSnapshot} from '../../framework/sdk/contracts/index.ts';
|
||||
const {ccclass}=_decorator;
|
||||
/** Temporary room receipt surface for the create-room integration stage. */
|
||||
@ccclass('ErqiwangRoomView')
|
||||
export class ErqiwangRoomView extends TemplateRoomView {
|
||||
render(snapshot:PlatformGameSnapshot,actions:TemplateRoomActions):void{
|
||||
super.render(snapshot,actions);
|
||||
if(this.roomLabel)this.roomLabel.string='二七王 房间号:'+snapshot.room.roomcode+'\n玩法尚未接入';
|
||||
if(this.prepareButton)this.prepareButton.node.active=false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "aeb4bcf6-864b-4d21-bfce-19b69f5c526c",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import type {GameEntry,GameHost,GameModule,PlatformGameSnapshot} from '../../framework/sdk/contracts/index.ts';
|
||||
import {ErqiwangRoomRules} from './erqiwang-room-rules.ts';
|
||||
export interface ErqiwangRoomActions {prepare():void;exit():void;}
|
||||
export interface ErqiwangRoomPresentation {render(snapshot:PlatformGameSnapshot,actions:ErqiwangRoomActions):void;close():void;}
|
||||
/** Creation-stage room handoff. Gameplay and deskinfo rendering are not migrated yet. */
|
||||
export function createErqiwangGame(gameId:string|number){
|
||||
let active:ErqiwangModule|null=null;
|
||||
class ErqiwangModule implements GameModule {
|
||||
private host:GameHost|null=null;
|
||||
private unsubscribe:(()=>void)|null=null;
|
||||
private view:ErqiwangRoomPresentation|null=null;
|
||||
restored:unknown=null;
|
||||
attach(host:GameHost):void{
|
||||
if(this.host||active)throw Error('Erqiwang module already attached');
|
||||
this.host=host;active=this;this.unsubscribe=host.subscribe(()=>this.render());
|
||||
}
|
||||
mount(view:ErqiwangRoomPresentation):void{this.view?.close();this.view=view;this.render();}
|
||||
private requireHost():GameHost{if(!this.host)throw Error('Erqiwang room session disposed');return this.host;}
|
||||
private render():void{this.view?.render(this.requireHost().getSnapshot(),{prepare:()=>this.requireHost().execute({type:'room.prepare'}),exit:()=>this.requireHost().execute({type:'room.exit'})});}
|
||||
handlePlatformEvent():void{this.render();}
|
||||
handleGameMessage():void{throw Error('二七王玩法消息处理尚未接入');}
|
||||
restore(deskinfo:unknown):void{this.requireHost();this.restored=deskinfo;}
|
||||
dispose():void{this.unsubscribe?.();this.unsubscribe=null;this.view?.close();this.view=null;this.host=null;this.restored=null;if(active===this)active=null;}
|
||||
}
|
||||
const rules=new ErqiwangRoomRules();
|
||||
const entry:GameEntry={key:'erqiwang',gameId,route:'erqiwang',resolveSeatCount:roomtype=>rules.seatCount(roomtype),createModule:()=>new ErqiwangModule()};
|
||||
return {entry,mount(view:ErqiwangRoomPresentation){if(!active)throw Error('Erqiwang room not attached');active.mount(view);},
|
||||
get restoredSnapshot():unknown{return active?.restored;}};
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "9ed79bcf-75f3-44b9-b171-b0f465b7b2fc",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import type {Roomtype} from '../../framework/sdk/contracts/roomtype.ts';
|
||||
/** UI order differs from server class.config.js: aset, deduct, bangwang, climb, nocheck. */
|
||||
const WIRE_INDEX = [0,1,4,2,3] as const;
|
||||
export class ErqiwangRoomRules {
|
||||
private selected=[0,0,0,0,0];
|
||||
get selection():readonly number[]{return [...this.selected];}
|
||||
get roomCards():number{return (this.selected[0]===1?2:1)*(this.selected[1]===1?1:2);}
|
||||
open(previous:unknown):void{
|
||||
if(previous===null){this.selected=[0,0,0,0,0];return;}
|
||||
this.validate(previous);
|
||||
this.selected=WIRE_INDEX.map(index=>Number((previous as string)[index]));
|
||||
}
|
||||
select(group:number,value:number):void{
|
||||
if(!Number.isInteger(group)||group<0||group>=5||(value!==0&&value!==1))throw Error('Invalid erqiwang option');
|
||||
this.selected[group]=value;
|
||||
}
|
||||
build():string{
|
||||
const bits=Array<string>(11).fill('0');
|
||||
WIRE_INDEX.forEach((wire,group)=>bits[wire]=String(this.selected[group]));
|
||||
return bits.join('');
|
||||
}
|
||||
seatCount(roomtype:Roomtype):number{this.validate(roomtype);return 3;}
|
||||
private validate(value:unknown):void{
|
||||
if(typeof value!=='string'||!/^[01]{5}0{6}$/.test(value))throw Error('二七王房间配置必须为 11 位字符串,后 6 位为 0');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "4.0.24",
|
||||
"importer": "typescript",
|
||||
"imported": true,
|
||||
"uuid": "574b385e-9068-4418-8a63-110ad96d0915",
|
||||
"files": [],
|
||||
"subMetas": {},
|
||||
"userData": {}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import type {Roomtype} from '../../framework/sdk/contracts/roomtype.ts';
|
||||
/** Source: 01_SubGame_modify.js. Options are presentation state, not a rule-array encoder. */
|
||||
export class TemplateRoomRules {
|
||||
readonly labels=['10局(房卡X1)','20局(房卡X2)','房主扣卡','每人扣卡'] as const;
|
||||
@@ -13,7 +14,7 @@ export class TemplateRoomRules {
|
||||
this.selected[group]=index;
|
||||
}
|
||||
build():unknown[]{return [1,4,1,2,2,[1,1,[1,2000,10],null,null,1],[1,0,5]];}
|
||||
seatCount(roomtype:readonly unknown[]):number{
|
||||
seatCount(roomtype: Roomtype):number{
|
||||
if(!Array.isArray(roomtype))throw Error('Template roomtype must be an array');
|
||||
// Desk.Create uses Game_Config.Max.PlayerCnt because the template defines no getMaxPlayerCount hook.
|
||||
return 10;
|
||||
|
||||
Reference in New Issue
Block a user