[add] 進機台
This commit is contained in:
		| @@ -17,7 +17,7 @@ | ||||
|  | ||||
| <body oncontextmenu="return false"> | ||||
| 	<noscript>You need to enable JavaScript to run this app.</noscript> | ||||
| 	<div id="root"></div> | ||||
| 	<div id="root" style="height: 100vh;"></div> | ||||
| 	<script type="module" src="/src/index.tsx"></script> | ||||
| </body> | ||||
|  | ||||
|   | ||||
| @@ -1,23 +1,9 @@ | ||||
| import { CoroutineV2 } from "@/Engine/CatanEngine/CoroutineV2/CoroutineV2"; | ||||
| import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; | ||||
| import CSSettingsV3 from "@/FormTable/CSSettingsV3"; | ||||
| import { confirmModalObj } from "@/UI/MessageBox/ConfirmModalContext"; | ||||
| import { modalObj } from "@/UIControl/ModalContext"; | ||||
| import { Cocos } from "@/assets/VueScript/Cocos"; | ||||
| import { CommonEventCallBack, JackpotPoolCallBack } from "@/assets/VueScript/CocosVueScript"; | ||||
| import GameData_Cocos from "@/assets/VueScript/share/GameData_Cocos"; | ||||
| import { chatLog, chatMessage, setChatBanTime } from "@/components/ModalContent/ChatRoomModal/chatUtils"; | ||||
| import Config from "@/define/Config"; | ||||
| import Player from "@/modules/player"; | ||||
| import UserData from "@/modules/player/UserData"; | ||||
| import { State } from "@/modules/player/define/data"; | ||||
| import { ILineShareData, ModalContentType } from "@/types"; | ||||
| import { CommonEventType } from "@/utils"; | ||||
| import { NumberEx } from "@/utils/Number/NumberEx"; | ||||
| import { activityComSync, backpackInfo, friendAllowList, friendDenyList, profileInfo, txnCenter, txnNew, txnTrade, txnUserAdd, vipInfo } from "@/utils/setRPCData"; | ||||
| import { gameSync } from "@/utils/setRPCData"; | ||||
| import MainControl from "../MainControl/MainControl"; | ||||
| import CSMessage from "../Message/CSMessage"; | ||||
| import CSResource from "../ResourceItem/CSResource"; | ||||
| import IResourceItem from "../ResourceItem/IResourceItem"; | ||||
|  | ||||
| export default class MainControlData { | ||||
|  | ||||
| @@ -46,7 +32,7 @@ export default class MainControlData { | ||||
| 	private _disconnectErrorType: number = null; | ||||
|  | ||||
| 	constructor() { | ||||
| 		Player.DataReceivedEvent.AddCallback(this._dataReceivedEvent, this); | ||||
| 		MainControl.DataReceivedEvent.AddCallback(this._dataReceivedEvent, this); | ||||
| 	} | ||||
| 	private _dataReceivedEvent(param: any[] = null): void { | ||||
| 		let type: MainControl.DataType = param[0]; | ||||
| @@ -67,139 +53,8 @@ export default class MainControlData { | ||||
| 	private _serverData(resp: INetResponse<any>): void { | ||||
| 		if (resp.IsValid) { | ||||
| 			switch (resp.Method) { | ||||
| 				case "activity_com.sync": { | ||||
| 					activityComSync(resp.Data); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "backpack.info": { | ||||
| 					backpackInfo(resp.Data); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "chat.ban": { | ||||
| 					setChatBanTime(resp.Data); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "chat.message": { | ||||
| 					chatMessage(resp.Data); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "chat.log": { | ||||
| 					chatLog(resp.Data); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "friend.allow_list": { | ||||
| 					friendAllowList(resp.Data); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "friend.deny_list": { | ||||
| 					friendDenyList(resp.Data); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "game.share": { | ||||
| 					const { openLineShareGame } = confirmModalObj; | ||||
| 					const data: ILineShareData = { | ||||
| 						slotID: resp.Data[0], | ||||
| 						winMilt: resp.Data[1] | ||||
| 					}; | ||||
| 					openLineShareGame(data); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "game.sync": { | ||||
| 					Cocos.VicKing_Bridge.InGameGetUUID = true; | ||||
| 					break; | ||||
| 				} | ||||
| 				case "jackpot.get": { | ||||
| 					const { handleOpen, setModalType } = modalObj; | ||||
| 					const playerData: State = Player.data.getState(); | ||||
| 					playerData.account.jackpotGet.push(...resp.Data); | ||||
| 					Player.data.setState(playerData); | ||||
| 					setModalType(ModalContentType.jackpot); | ||||
| 					handleOpen(); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "jackpot.pool": { | ||||
| 					const playerData: State = Player.data.getState(); | ||||
| 					if (!Config.IsVite || MainControl.Instance.IsInGame) { | ||||
| 						for (let i = 0; i < playerData.game.jackpotPool.length; i++) { | ||||
| 							const oldJpData: [gameId: number, maxJPId: number, jp: number] = playerData.game.jackpotPool[i]; | ||||
| 							let newJpData: [gameId: number, maxJPId: number, jp: number] = null; | ||||
| 							for (let j = 0; j < resp.Data.length; j++) { | ||||
| 								const [gameId, maxJPId, jp] = resp.Data[j]; | ||||
| 								if (gameId === oldJpData[0]) { | ||||
| 									newJpData = resp.Data[j]; | ||||
| 									break; | ||||
| 								} | ||||
| 							} | ||||
| 							if (!newJpData) { | ||||
| 								JackpotPoolCallBack.DispatchCallback(oldJpData[0], 0); | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 					playerData.game.jackpotPool = resp.Data; | ||||
| 					Player.data.setState(playerData); | ||||
| 					if (!Config.IsVite || MainControl.Instance.IsInGame) { | ||||
| 						for (let i = 0; i < playerData.game.jackpotPool.length; i++) { | ||||
| 							const jpData: [gameId: number, maxJPId: number, jp: number] = playerData.game.jackpotPool[i]; | ||||
| 							JackpotPoolCallBack.DispatchCallback(jpData[0], jpData[2]); | ||||
| 						} | ||||
| 					} else { | ||||
| 						Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.UpdateJPPool, null); | ||||
| 					} | ||||
| 					break; | ||||
| 				} | ||||
| 				case "maintain.info": { | ||||
| 					const playerData: State = Player.data.getState(); | ||||
| 					if (resp.Data) { | ||||
| 						resp.Data[3] = NumberEx.plus(MainControl.Instance.NowTime, resp.Data[3]); | ||||
| 						playerData.maintain = resp.Data; | ||||
| 						CommonEventCallBack.DispatchCallback(CommonEventType.Maintenance, null); | ||||
| 					} else { | ||||
| 						playerData.maintain = undefined; | ||||
| 					} | ||||
| 					Player.data.setState(playerData); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "profile.info": { | ||||
| 					profileInfo(resp.Data); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "resource.update": { | ||||
| 					const resourceItems: IResourceItem[] = CSResource.GetResourceItemsFromServer(resp.Data); | ||||
| 					UserData.DoResUpdate(resourceItems); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "resource.bankruptcy": { | ||||
| 					Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.Bankruptcy, null); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "system.disconnect": { | ||||
| 					this._disconnectErrorType = +resp.Data["c"]; | ||||
| 					break; | ||||
| 				} | ||||
| 				case "txn.new": { | ||||
| 					txnNew(resp.Data); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "txn.center": { | ||||
| 					txnCenter(resp.Data); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "txn.trade": { | ||||
| 					txnTrade(resp.Data); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "txn.user_add": { | ||||
| 					txnUserAdd(resp.Data); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "vip.info": { | ||||
| 					vipInfo(resp.Data); | ||||
| 					break; | ||||
| 				} | ||||
| 				case "vip.level": { | ||||
| 					const playerData: State = Player.data.getState(); | ||||
| 					playerData.vip.level = resp.Data; | ||||
| 					Player.data.setState(playerData); | ||||
| 					CoroutineV2.Single(gameSync()).Start(); | ||||
| 					break; | ||||
| 				} | ||||
| 				default: | ||||
| @@ -207,10 +62,9 @@ export default class MainControlData { | ||||
| 			} | ||||
| 		} else { | ||||
| 			switch (resp.Method) { | ||||
| 				case "chat.log": { | ||||
| 					chatLog([null, null]); | ||||
| 					break; | ||||
| 				} | ||||
| 				// case "": { | ||||
| 				// 	break; | ||||
| 				// } | ||||
| 				default: | ||||
| 					break; | ||||
| 			} | ||||
|   | ||||
| @@ -1,8 +1,4 @@ | ||||
| import CSSettingsV3 from "@/FormTable/CSSettingsV3"; | ||||
| import { IConfirmMessageData } from "@/UI/MessageBox/ConfirmMessage"; | ||||
| import { confirmModalObj } from "@/UI/MessageBox/ConfirmModalContext"; | ||||
| import { StringFormKey } from "@/define/formkey"; | ||||
|  | ||||
| import { IConfirmMessageData, modalObj } from "@/UIControl/ModalContext"; | ||||
|  | ||||
| /** 訊息框相關 */ | ||||
| export default class CSMessage { | ||||
| @@ -10,7 +6,7 @@ export default class CSMessage { | ||||
|  | ||||
| 	/** 一個按鈕的訊息框 */ | ||||
| 	public static CreateYesMsg(content: string, yesCallback: () => void = null, enterStr: string = null, title: string = null, textAlign: "center" | "left" | "right" = null) { | ||||
| 		enterStr = enterStr ? enterStr : CSSettingsV3.prototype.CommonString(StringFormKey.String.Confirm); | ||||
| 		enterStr = enterStr ? enterStr : "確認"; | ||||
| 		let data: IConfirmMessageData = { | ||||
| 			title: title, | ||||
| 			content: content, | ||||
| @@ -19,14 +15,14 @@ export default class CSMessage { | ||||
| 			enterStr: enterStr, | ||||
| 			textAlign: textAlign | ||||
| 		}; | ||||
| 		const { openOtherConfirm } = confirmModalObj; | ||||
| 		openOtherConfirm(data); | ||||
| 		const { handleOpen } = modalObj; | ||||
| 		handleOpen(data); | ||||
| 	} | ||||
|  | ||||
| 	/** 兩個按鈕的訊息框 */ | ||||
| 	public static CreateYesNoMsg(content: string, yesCallback: () => void = null, noCallback: () => void = null, enterStr: string = null, title: string = null, cancelStr: string = null, textAlign: "center" | "left" | "right" = null) { | ||||
| 		enterStr = enterStr ? enterStr : CSSettingsV3.prototype.CommonString(StringFormKey.String.Confirm); | ||||
| 		cancelStr = cancelStr ? cancelStr : CSSettingsV3.prototype.CommonString(StringFormKey.String.Cancel); | ||||
| 		enterStr = enterStr ? enterStr : "確認"; | ||||
| 		cancelStr = cancelStr ? cancelStr : "取消"; | ||||
| 		let data: IConfirmMessageData = { | ||||
| 			title: title, | ||||
| 			content: content, | ||||
| @@ -37,8 +33,8 @@ export default class CSMessage { | ||||
| 			cancelStr: cancelStr, | ||||
| 			textAlign: textAlign | ||||
| 		}; | ||||
| 		const { openOtherConfirm } = confirmModalObj; | ||||
| 		openOtherConfirm(data); | ||||
| 		const { handleOpen } = modalObj; | ||||
| 		handleOpen(data); | ||||
| 	} | ||||
|  | ||||
| 	/** 網路錯誤訊息 */ | ||||
|   | ||||
| @@ -82,9 +82,9 @@ export class NetConnector { | ||||
| 		// if (CC_DEBUG && NetConfig.ShowServerLog) { | ||||
| 		if (NetConfig.ShowServerLog) { | ||||
| 			if (req.Data != null && req.Data != undefined && !Number.isNaN(req.Data)) { | ||||
| 				console.debug(`[RPC] 傳送server資料: ${req.Method}(${JSON.stringify(req.Data)})`); | ||||
| 				console.log(`[RPC] 傳送server資料: ${req.Method}(${JSON.stringify(req.Data)})`); | ||||
| 			} else { | ||||
| 				console.debug(`[RPC] 傳送server資料: ${req.Method}()`); | ||||
| 				console.log(`[RPC] 傳送server資料: ${req.Method}()`); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @@ -185,9 +185,9 @@ export class NetConnector { | ||||
| 				// if (CC_DEBUG && NetConfig.ShowServerLog) { | ||||
| 				if (NetConfig.ShowServerLog) { | ||||
| 					if (data) { | ||||
| 						console.debug(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}(${JSON.stringify(resp.Data)})`); | ||||
| 						console.log(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}(${JSON.stringify(resp.Data)})`); | ||||
| 					} else { | ||||
| 						console.debug(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}()`); | ||||
| 						console.log(`[RPC] 收到server呼叫:(${resp.Status}): ${resp.Method}()`); | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
|   | ||||
							
								
								
									
										54
									
								
								src/Engine/CatanEngine/NetManagerV2/NetManagerSD.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								src/Engine/CatanEngine/NetManagerV2/NetManagerSD.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| import { INetRequest } from "./Core/INetRequest"; | ||||
| import { NetConnector } from "./NetConnector"; | ||||
|  | ||||
| export class NetManagerSD { | ||||
| 	static get IsConnected() { | ||||
| 		return this._connector && this._connector.IsConnected; | ||||
| 	} | ||||
|  | ||||
| 	static get HasInit() { | ||||
| 		return this._connector != null; | ||||
| 	} | ||||
|  | ||||
| 	private static _connector: NetConnector; | ||||
|  | ||||
| 	static Initialize(connector: NetConnector) { | ||||
| 		this._connector = connector; | ||||
| 	} | ||||
|  | ||||
| 	static ConnectAsync() { | ||||
| 		this.CheckConnector(); | ||||
| 		return this._connector.ConnectAsync(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * 斷線 | ||||
| 	 */ | ||||
| 	static Disconnect() { | ||||
| 		this.CheckConnector(); | ||||
| 		this._connector.Disconnect(); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * 傳送資料給Server, 不等待回應 | ||||
| 	 * @param req | ||||
| 	 */ | ||||
| 	static Send(req: INetRequest<any, any>) { | ||||
| 		this.CheckConnector(); | ||||
| 		this._connector.Send(req); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * 傳送資料給Server, 並等待回應 | ||||
| 	 * @param req | ||||
| 	 */ | ||||
| 	static SendAsync(req: INetRequest<any, any>, mask: boolean) { | ||||
| 		this.CheckConnector(); | ||||
| 		return this._connector.SendAsync(req, mask); | ||||
| 	} | ||||
|  | ||||
| 	private static CheckConnector() { | ||||
| 		if (!this._connector) throw new Error("請先呼叫CasinoNetManager.Initialize()初始化connector"); | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| import { VueNetConnector } from "@/assets/VueScript/Net/VueNetConnector"; | ||||
| import { INetRequest } from "./Core/INetRequest"; | ||||
| import { NetManager } from "./NetManager"; | ||||
|  | ||||
| export abstract class NetRequest<TResquest, TResponse> implements INetRequest<TResquest, TResponse> { | ||||
| 	abstract get Method(): string; | ||||
| @@ -11,18 +11,11 @@ export abstract class NetRequest<TResquest, TResponse> implements INetRequest<TR | ||||
| 	Data: TResquest; | ||||
| 	Result: import("./Core/INetResponse").INetResponse<TResponse>; | ||||
|  | ||||
| 	/** | ||||
| 	 * 在大廳呼叫Cocos會收到SERVER主動通知 | ||||
| 	 * 在大廳呼叫Cocos會收到SERVER主動通知 | ||||
| 	 * 在大廳呼叫Cocos會收到SERVER主動通知 | ||||
| 	 */ | ||||
| 	SendAsync(mask: boolean = false): Iterator<any> { | ||||
| 		// return NetManager.SendAsync(this, mask); | ||||
| 		return VueNetConnector.SendAsync(this, mask); | ||||
| 		return NetManager.SendAsync(this, mask); | ||||
| 	} | ||||
|  | ||||
| 	Send() { | ||||
| 		// NetManager.Send(this); | ||||
| 		VueNetConnector.Send(this); | ||||
| 		NetManager.Send(this); | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										21
									
								
								src/Engine/CatanEngine/NetManagerV2/NetRequestSD.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/Engine/CatanEngine/NetManagerV2/NetRequestSD.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| import { INetRequest } from "./Core/INetRequest"; | ||||
| import { NetManagerSD } from "./NetManagerSD"; | ||||
|  | ||||
| export abstract class NetRequestSD<TResquest, TResponse> implements INetRequest<TResquest, TResponse> { | ||||
| 	abstract get Method(): string; | ||||
|  | ||||
| 	get MethodBack(): string { | ||||
| 		return this.Method; | ||||
| 	} | ||||
|  | ||||
| 	Data: TResquest; | ||||
| 	Result: import("./Core/INetResponse").INetResponse<TResponse>; | ||||
|  | ||||
| 	SendAsync(mask: boolean = false): Iterator<any> { | ||||
| 		return NetManagerSD.SendAsync(this, mask); | ||||
| 	} | ||||
|  | ||||
| 	Send() { | ||||
| 		NetManagerSD.Send(this); | ||||
| 	} | ||||
| } | ||||
| @@ -1,11 +1,9 @@ | ||||
| import MainControl from "@/Common/MainControl/MainControl"; | ||||
| import CSMessage from "@/Common/Message/CSMessage"; | ||||
| import { CoroutineV2 } from "@/Engine/CatanEngine/CoroutineV2/CoroutineV2"; | ||||
| import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; | ||||
| import { useGameItems } from "@/context/GameItemsContext"; | ||||
| import { CommonAccountResponse, LineLoginRequest } from "@/define/Request/RegisterRequest"; | ||||
| import { Layout } from "antd"; | ||||
| import { useEffect } from "react"; | ||||
| import { useNavigate } from "react-router-dom"; | ||||
| import Player from "./Lobby/Player"; | ||||
| import SlotList from "./Lobby/SlotList"; | ||||
|  | ||||
| const Lobby = () => { | ||||
| 	const { player, setPlayer } = useGameItems(); | ||||
| @@ -17,30 +15,6 @@ const Lobby = () => { | ||||
| 			navigate(`/`); | ||||
| 			return; | ||||
| 		} | ||||
| 		CoroutineV2.Single(onStart()).Start(); | ||||
| 	} | ||||
|  | ||||
| 	function* onStart() { | ||||
| 		yield* MainControl.Instance.ConnectAsync(); | ||||
|  | ||||
| 	} | ||||
| 	function* registerLineLogin() { | ||||
| 		let req: LineLoginRequest = new LineLoginRequest(token); | ||||
| 		yield req.SendAsync(true); | ||||
| 		let resp: INetResponse<CommonAccountResponse> = req.Result; | ||||
| 		if (!resp.IsValid) { | ||||
| 			//取得帳號失敗直接斷開SOCKET | ||||
| 			if (resp.Status != 12) { | ||||
| 				const msg: string = "Line Info Error. Error Code:" + req.Result.Status; | ||||
| 				CSMessage.CreateYesMsg(msg); | ||||
| 				return; | ||||
| 			} | ||||
| 			console.warn("LINE帳號無綁定"); | ||||
| 			return; | ||||
| 		} | ||||
| 		// yield* this.ServerAccountLogin(resp.Data.id, resp.Data.pw); | ||||
|  | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	useEffect(() => { | ||||
| @@ -48,7 +22,10 @@ const Lobby = () => { | ||||
| 	}, []); | ||||
|  | ||||
| 	return ( | ||||
| 		<>Lobby</> | ||||
| 		<Layout hasSider style={{ height: "100%", position: "relative" }}> | ||||
| 			<Player /> | ||||
| 			{<SlotList />} | ||||
| 		</Layout> | ||||
| 	); | ||||
| }; | ||||
|  | ||||
|   | ||||
							
								
								
									
										35
									
								
								src/UI/Lobby/Player.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/UI/Lobby/Player.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| import { CurrencyManager } from "@/FormTableExt/Manage/Currency/CurrencyManager"; | ||||
| import { useGameItems } from "@/context/GameItemsContext"; | ||||
| import { useEffect } from "react"; | ||||
|  | ||||
| const Player = () => { | ||||
| 	const { player } = useGameItems(); | ||||
| 	const { aId, name, m } = player; | ||||
|  | ||||
| 	function onLoad() { | ||||
| 	} | ||||
|  | ||||
| 	useEffect(() => { | ||||
| 		onLoad(); | ||||
| 	}, []); | ||||
|  | ||||
| 	return ( | ||||
| 		<div style={siderStyle}> | ||||
| 			<p>aId: {aId}</p> | ||||
| 			<p>暱稱: {name}</p> | ||||
| 			<p>金幣: {CurrencyManager.GetNumberWithComma(m)}</p> | ||||
| 		</div> | ||||
| 	); | ||||
| }; | ||||
|  | ||||
| export default Player; | ||||
|  | ||||
| const siderStyle: React.CSSProperties = { | ||||
| 	fontSize: "1rem", | ||||
| 	color: "#000000", | ||||
| 	display: "flex", | ||||
| 	textAlign: "left", | ||||
| 	flexDirection: "column", | ||||
| 	justifyContent: "center", | ||||
| 	width: "20%" | ||||
| }; | ||||
							
								
								
									
										145
									
								
								src/UI/Lobby/SDGame.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								src/UI/Lobby/SDGame.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,145 @@ | ||||
| import CSMessage from "@/Common/Message/CSMessage"; | ||||
| import { CoroutineV2 } from "@/Engine/CatanEngine/CoroutineV2/CoroutineV2"; | ||||
| import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; | ||||
| import { NetConnector } from "@/Engine/CatanEngine/NetManagerV2/NetConnector"; | ||||
| import { NetManagerSD } from "@/Engine/CatanEngine/NetManagerV2/NetManagerSD"; | ||||
| import { useGameItems } from "@/context/GameItemsContext"; | ||||
| import SlotBase from "@/define/Game/Base/SlotBase"; | ||||
| import { SDAccountLoginRequest } from "@/define/Request/AccountRequest"; | ||||
| import { SlotInRequest } from "@/define/Request/SlotRequest"; | ||||
| import { Button, Flex } from "antd"; | ||||
| import { useEffect, useState } from "react"; | ||||
|  | ||||
| const SDGame = (props: ISDGame) => { | ||||
| 	const { gameUrl, onClickSlotOut } = props; | ||||
| 	const { player, setPlayer } = useGameItems(); | ||||
| 	const { gameData } = useGameItems(); | ||||
| 	const { nowSlotId } = gameData; | ||||
| 	const [slotId, setSlotId] = useState<number>(undefined); | ||||
| 	const [slotData, setSlotData] = useState<Object>(undefined); | ||||
| 	let conn: NetConnector = undefined; | ||||
|  | ||||
| 	function* onLoad(): IterableIterator<any> { | ||||
| 		const url: URL = new URL(gameUrl); | ||||
| 		const queryParameters: URLSearchParams = new URLSearchParams(url.search); | ||||
| 		const token: string = queryParameters.get("token"); | ||||
| 		const slotid: number = +queryParameters.get("slotid"); | ||||
| 		const host: string = queryParameters.get("host"); | ||||
| 		const port: number = 9005; | ||||
|  | ||||
| 		setSlotId(slotid); | ||||
| 		conn = new NetConnector("https://" + host, port); | ||||
| 		conn.OnDataReceived.AddCallback(onNetDataReceived); | ||||
| 		conn.OnDisconnected.AddCallback(onNetDisconnected); | ||||
| 		NetManagerSD.Initialize(conn); | ||||
| 		console.log("[SDsocket] connecting..."); | ||||
| 		yield NetManagerSD.ConnectAsync(); | ||||
| 		yield* login(token); | ||||
| 		yield* slotIn(slotid); | ||||
| 	} | ||||
|  | ||||
| 	function* login(token: string): IterableIterator<any> { | ||||
| 		const req = new SDAccountLoginRequest(token); | ||||
| 		yield req.SendAsync(true); | ||||
| 		const resp = req.Result; | ||||
| 		if (!resp.IsValid) { | ||||
| 			CSMessage.NetError(resp.Method, resp.Status, "SD Account Login Fail"); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	function* slotIn(slotid: number): IterableIterator<any> { | ||||
| 		let req: SlotInRequest = new SlotInRequest(slotid); | ||||
| 		yield req.SendAsync(true); | ||||
| 		let resp: INetResponse<JSON> = req.Result; | ||||
| 		if (resp.IsValid) { | ||||
| 			setSlotData(resp.Data); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	async function OnclickSpin() { | ||||
| 		let slot: any; | ||||
| 		const slotGroup: typeof import("../../define/Game/Base/Slot") = await import(/* @vite-ignore */`../../define/Game/Base/Slot`); | ||||
| 		try { | ||||
| 			slot = slotGroup[`Slot${slotId}`]; | ||||
| 		} catch (error) { | ||||
| 			// | ||||
| 		} | ||||
| 		if (!slot) { | ||||
| 			slot = slotGroup.SlotBase; | ||||
| 		} | ||||
| 		const slotClass: SlotBase = new slot(slotId); | ||||
| 		// this.IsSpin.value = true; | ||||
| 		CoroutineV2.Single(spin(slotClass)).Start(); | ||||
| 	} | ||||
|  | ||||
| 	function* spin(slotClass: SlotBase): IterableIterator<any> { | ||||
| 		yield* slotClass.Spin(20); | ||||
| 		// await Tools.Sleep(this.SpinDelay.value * 1000); | ||||
| 		// if (this.IsSpin.value && this._bj_Casino_Bot.LobbyScript.IsSlotIn.value) { | ||||
| 		//     this.Spin(); | ||||
| 		// } else { | ||||
| 		//     this.IsRun = false; | ||||
| 		// } | ||||
| 	} | ||||
|  | ||||
| 	/**RPC回傳.若協定錯誤斷線.原因也會在這裡收到 */ | ||||
| 	function onNetDataReceived(resp: INetResponse<any>) { | ||||
| 		// MainControl.DataReceivedEvent.DispatchCallback([MainControl.DataType.ServerData, resp]); | ||||
| 	} | ||||
|  | ||||
| 	/**只要連線中斷不管主被動都會走到這裡 */ | ||||
| 	function onNetDisconnected() { | ||||
| 		console.warn("[socket] Disconnected"); | ||||
| 		conn.OnDataReceived.RemoveAllCallbacks(); | ||||
| 		// MainControl.DataReceivedEvent.DispatchCallback([MainControl.DataType.NetDisconnected]); | ||||
| 	} | ||||
|  | ||||
| 	useEffect(() => { | ||||
| 		CoroutineV2.Single(onLoad()).Start(); | ||||
| 	}, []); | ||||
|  | ||||
| 	return (<> | ||||
| 		<div style={siderStyle}> | ||||
| 			<Flex gap="small" wrap="wrap"> | ||||
| 				<div style={controlStyle}> | ||||
| 					Bet: 20 | ||||
| 					<p> | ||||
| 						<Button type="primary" onClick={OnclickSpin} style={{ width: "20%" }}>Spin</Button> | ||||
| 						<Button type="primary" danger onClick={onClickSlotOut} style={{ width: "20%" }}>離開機台</Button> | ||||
| 					</p> | ||||
| 				</div> | ||||
| 				<div> | ||||
| 					Log | ||||
| 				</div> | ||||
| 			</Flex> | ||||
| 		</div> | ||||
| 	</>); | ||||
| }; | ||||
|  | ||||
| export default SDGame; | ||||
|  | ||||
| interface ISDGame { | ||||
| 	gameUrl: string; | ||||
| 	onClickSlotOut: () => void; | ||||
| } | ||||
|  | ||||
| const siderStyle: React.CSSProperties = { | ||||
| 	fontSize: "1rem", | ||||
| 	color: "#000000", | ||||
| 	display: "flex", | ||||
| 	textAlign: "left", | ||||
| 	flexDirection: "column", | ||||
| 	justifyContent: "center", | ||||
| 	width: "100%" | ||||
| }; | ||||
|  | ||||
| const controlStyle: React.CSSProperties = { | ||||
| 	fontSize: "1rem", | ||||
| 	display: "flex", | ||||
| 	textAlign: "left", | ||||
| 	flexDirection: "column", | ||||
| 	justifyContent: "center", | ||||
| 	lineHeight: "30px", | ||||
| 	width: "30%" | ||||
| }; | ||||
							
								
								
									
										93
									
								
								src/UI/Lobby/SlotList.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								src/UI/Lobby/SlotList.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,93 @@ | ||||
| import CSMessage from "@/Common/Message/CSMessage"; | ||||
| import { CoroutineV2 } from "@/Engine/CatanEngine/CoroutineV2/CoroutineV2"; | ||||
| import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; | ||||
| import CSSettingsV3 from "@/FormTable/CSSettingsV3"; | ||||
| import BusinessTypeSetting from "@/_BusinessTypeSetting/BusinessTypeSetting"; | ||||
| import Image from "@/components/Image/Image"; | ||||
| import { useGameItems } from "@/context/GameItemsContext"; | ||||
| import { GameLaunchRequest, GameLeaveRequest, RpcGameLaunchResponse } from "@/define/Request/GameRequest"; | ||||
| import { SlotData } from "@/define/gameData"; | ||||
| import { Button, Flex } from "antd"; | ||||
| import { useEffect, useState } from "react"; | ||||
| import SDGame from "./SDGame"; | ||||
|  | ||||
| const SlotList = () => { | ||||
| 	const { gameData, setGameData } = useGameItems(); | ||||
| 	const { slotData, slotList, nowSlotId } = gameData; | ||||
| 	const [isGameIn, setIsGameIn] = useState<boolean>(false); | ||||
| 	const [gameUrl, setGameUrl] = useState<string>(""); | ||||
|  | ||||
| 	function onLoad() { | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	function* onClickSlotIn(slotId: number): IterableIterator<any> { | ||||
| 		const data: SlotData = slotData[slotId]; | ||||
| 		const [componyID] = data; | ||||
| 		const req: GameLaunchRequest = new GameLaunchRequest(componyID, slotId); | ||||
| 		yield req.SendAsync(); | ||||
| 		const resp: INetResponse<RpcGameLaunchResponse> = req.Result; | ||||
| 		if (!resp.IsValid) { | ||||
| 			if (resp.Status === 18) { | ||||
| 				CSMessage.CreateYesMsg(CSSettingsV3.prototype.CommonString(16)); | ||||
| 			} | ||||
| 			return; | ||||
| 		} | ||||
| 		setIsGameIn(true); | ||||
| 		const url: string = resp.Data; | ||||
| 		setGameData({ | ||||
| 			...gameData, | ||||
| 			nowSlotId: slotId | ||||
| 		}); | ||||
| 		if (componyID === 2) { | ||||
| 			setGameUrl(url); | ||||
| 		} | ||||
| 		else { | ||||
| 			window.open(url, "_blank"); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	function onClickSlotOut() { | ||||
| 		const gameLeaveReq: GameLeaveRequest = new GameLeaveRequest(nowSlotId); | ||||
| 		gameLeaveReq.Send(); | ||||
| 		setGameUrl(""); | ||||
| 		setIsGameIn(false); | ||||
| 	} | ||||
|  | ||||
| 	useEffect(() => { | ||||
| 		onLoad(); | ||||
| 	}, []); | ||||
|  | ||||
| 	return (<> | ||||
| 		{isGameIn | ||||
| 			? <>{gameUrl | ||||
| 				? <SDGame gameUrl={gameUrl} onClickSlotOut={onClickSlotOut} /> | ||||
| 				: <Flex gap="small" wrap="wrap"> | ||||
| 					<Button type="primary" onClick={onClickSlotOut}>離開機台</Button> | ||||
| 				</Flex>}</> | ||||
|  | ||||
| 			: <div style={contentStyle}> | ||||
| 				<Flex gap="small" wrap="wrap"> | ||||
| 					{slotList.map((slotId: number, index: number) => | ||||
| 						<Image key={index} width={80} height={80} src={`${BusinessTypeSetting.UseDownloadUrl}game/${slotId}/s`} | ||||
| 							onClick={() => { CoroutineV2.Single(onClickSlotIn(slotId)).Start(); }} style={{ cursor: "pointer" }} /> | ||||
| 					)} | ||||
| 				</Flex> | ||||
| 			</div> | ||||
| 		} | ||||
| 	</>); | ||||
| }; | ||||
|  | ||||
| export default SlotList; | ||||
|  | ||||
| const contentStyle: React.CSSProperties = { | ||||
| 	fontSize: "1rem", | ||||
| 	minHeight: 120, | ||||
| 	lineHeight: "120px", | ||||
| 	color: "#000000", | ||||
| 	display: "flex", | ||||
| 	textAlign: "center", | ||||
| 	flexDirection: "column", | ||||
| 	justifyContent: "center", | ||||
| 	width: "100%" | ||||
| }; | ||||
| @@ -1,5 +1,11 @@ | ||||
| import MainControl from "@/Common/MainControl/MainControl"; | ||||
| import CSMessage from "@/Common/Message/CSMessage"; | ||||
| import { CoroutineV2 } from "@/Engine/CatanEngine/CoroutineV2/CoroutineV2"; | ||||
| import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; | ||||
| import { BusinessEnum } from "@/_BusinessTypeSetting/BusinessTypeSetting"; | ||||
| import { useGameItems } from "@/context/GameItemsContext"; | ||||
| import { AccountLoginRequest } from "@/define/Request/AccountRequest"; | ||||
| import { CommonAccountResponse, LineLoginRequest } from "@/define/Request/RegisterRequest"; | ||||
| import { Button, Cascader } from "antd"; | ||||
| import TextArea from "antd/es/input/TextArea"; | ||||
| import React, { useState } from "react"; | ||||
| @@ -17,7 +23,7 @@ const Login = () => { | ||||
| 	const serverType: typeof BusinessEnum.ServerType = BusinessEnum.ServerType; | ||||
| 	const [type, setType] = useState<number>(BusinessEnum.ServerType.Internal_Dev); | ||||
| 	const [isLogin, setIsLogin] = useState<boolean>(false); | ||||
| 	const [token, SetToken] = useState(""); | ||||
| 	const [token, SetToken] = useState("eyJhbGciOiJIUzI1NiJ9.Am-dhpCRUo9iBHYJ0kro12-zUlOyNAVOw9poXEkUV14hvkL2RPxVqqtrsYbS9_aoKep4EOFYROFTbv6MfVai7gomKdr07XkmTtADtkbchkfm-yuGXVzW1mYabf646_U66MnvXX2PHS-ATXDYYx5He9PJ-5lF9g5BmhtxUYPW98w.MGUUrFQbBeUBPDJeoKMilbqbg6IkwEqbu2oyJVSmw6M"); | ||||
| 	const options: Option[] = []; | ||||
| 	for (let i = 0, names: string[] = Object.keys(serverType); i < names.length; i++) { | ||||
| 		const key: string = names[i]; | ||||
| @@ -29,11 +35,59 @@ const Login = () => { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	async function login() { | ||||
| 	async function onClickLogin() { | ||||
| 		if (!token) { | ||||
| 			CSMessage.CreateYesMsg("請輸入token"); | ||||
| 			return; | ||||
| 		} | ||||
| 		setIsLogin(true); | ||||
| 		await onLoad(type); | ||||
| 		CoroutineV2.Single(login()).Start(); | ||||
| 	} | ||||
|  | ||||
| 	function* login() { | ||||
| 		yield* MainControl.Instance.ConnectAsync(); | ||||
| 		yield* registerLineLogin(); | ||||
| 	} | ||||
|  | ||||
| 	function* registerLineLogin() { | ||||
| 		let req: LineLoginRequest = new LineLoginRequest(token); | ||||
| 		yield req.SendAsync(true); | ||||
| 		let resp: INetResponse<CommonAccountResponse> = req.Result; | ||||
| 		if (!resp.IsValid) { | ||||
| 			//取得帳號失敗直接斷開SOCKET | ||||
| 			if (resp.Status != 12) { | ||||
| 				const msg: string = "Line Info Error. Error Code:" + req.Result.Status; | ||||
| 				CSMessage.CreateYesMsg(msg); | ||||
| 				setIsLogin(false); | ||||
| 				return; | ||||
| 			} | ||||
| 			console.warn("LINE帳號無綁定"); | ||||
| 			setIsLogin(false); | ||||
| 			return; | ||||
| 		} | ||||
| 		yield* serverAccountLogin(resp.Data.id, resp.Data.pw); | ||||
| 	} | ||||
|  | ||||
| 	/** 遊戲帳號登入取得玩家資料.統一登入時在刪除需要刪除的資料 */ | ||||
| 	function* serverAccountLogin(a: string, pw: string, partner: string = null): IterableIterator<any> { | ||||
| 		let hasAP: boolean = (a && a != "null" && a != "undefined" && pw && pw != "null" && pw != "undefined"); | ||||
| 		if (!hasAP) { | ||||
| 			CSMessage.CreateYesMsg("沒有帳號或密碼.請確認回傳接值."); | ||||
| 			setIsLogin(false); | ||||
| 			return; | ||||
| 		} | ||||
| 		let req: AccountLoginRequest = new AccountLoginRequest(a, pw, partner); | ||||
| 		yield req.SendAsync(true); | ||||
| 		let resp: INetResponse<any> = req.Result; | ||||
| 		if (!resp.IsValid) { | ||||
| 			CSMessage.CreateYesMsg("Login Account Error! Error Code : " + resp.Status); | ||||
| 			setIsLogin(false); | ||||
| 			return; | ||||
| 		} | ||||
| 		setPlayer({ | ||||
| 			...player, | ||||
| 			...resp.Data, | ||||
| 			token: token | ||||
| 		}); | ||||
| 		navigate(`/lobby/`); | ||||
| @@ -45,9 +99,9 @@ const Login = () => { | ||||
| 				<div style={boxStyle2}> | ||||
| 					<Cascader defaultValue={[BusinessEnum.ServerType[BusinessEnum.ServerType.Internal_Dev]]} options={options} onChange={(v: string[]) => setType(+v[0])} /> | ||||
| 					<br /> | ||||
| 					<TextArea rows={4} value={token} onChange={e => SetToken(e.target.value)} /> | ||||
| 					Token: <TextArea rows={4} value={token} onChange={e => SetToken(e.target.value)} /> | ||||
| 					<br /> | ||||
| 					<Button type="primary" onClick={login}>登入</Button> | ||||
| 					<Button type="primary" onClick={onClickLogin}>登入</Button> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		}</> | ||||
|   | ||||
							
								
								
									
										75
									
								
								src/UIControl/ModalContext.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/UIControl/ModalContext.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| import { Modal } from "antd"; | ||||
| import { ReactNode, createContext, useContext, useState } from "react"; | ||||
|  | ||||
| type ModalProviderProps = { | ||||
| 	children: ReactNode; | ||||
| }; | ||||
| const ModalContext = createContext<IModal>(undefined); | ||||
|  | ||||
| export function useModal() { | ||||
| 	return useContext(ModalContext); | ||||
| } | ||||
|  | ||||
| export let modalObj: IModal = null; | ||||
|  | ||||
| export function ModalProvider({ children }: ModalProviderProps) { | ||||
| 	const [isOpen, setIsOpen] = useState(false); | ||||
| 	const [confirmData, setConfirmData] = useState<IConfirmMessageData>(undefined); | ||||
|  | ||||
| 	function handleOpen(data: IConfirmMessageData): void { | ||||
| 		setConfirmData(data); | ||||
| 		setIsOpen(true); | ||||
| 	} | ||||
|  | ||||
| 	const handleClose = () => setIsOpen(false); | ||||
|  | ||||
| 	function handleConfirm(): void { | ||||
| 		confirmData?.handleConfirm && confirmData?.handleConfirm(); | ||||
| 		handleClose(); | ||||
| 	} | ||||
|  | ||||
| 	function handleCancel(): void { | ||||
| 		confirmData?.handleCancel && confirmData?.handleCancel(); | ||||
| 		handleClose(); | ||||
| 	} | ||||
|  | ||||
| 	const modal: IModal = modalObj = { | ||||
| 		isOpen, | ||||
| 		handleOpen, | ||||
| 		handleClose, | ||||
| 		confirmData, | ||||
| 	}; | ||||
|  | ||||
| 	return ( | ||||
| 		<ModalContext.Provider value={modal}> | ||||
| 			{children} | ||||
| 			<Modal title={confirmData?.title} open={isOpen} onOk={handleConfirm} onCancel={handleCancel} cancelText={confirmData?.cancelStr} style={{ top: "40%" }}> | ||||
| 				<p>{confirmData?.content}</p> | ||||
| 			</Modal> | ||||
| 		</ModalContext.Provider> | ||||
| 	); | ||||
| } | ||||
|  | ||||
|  | ||||
| export interface IModal { | ||||
| 	isOpen: boolean; | ||||
| 	handleOpen: (data: IConfirmMessageData) => void; | ||||
| 	handleClose: () => void; | ||||
| 	confirmData: IConfirmMessageData; | ||||
| } | ||||
|  | ||||
| export interface IConfirmMessageData { | ||||
| 	title?: string; | ||||
| 	subTitle?: string; | ||||
| 	content?: string; | ||||
| 	enterStr?: string; | ||||
| 	cancelStr?: string; | ||||
| 	isShowCancel?: boolean; | ||||
| 	isOrangeButton?: boolean; | ||||
| 	isNeedClickConfirmClosePanel?: boolean; | ||||
| 	handleCancel?: () => unknown; | ||||
| 	handleConfirm?: (...args: any) => unknown; | ||||
| 	render?: (data?: any) => ReactNode; | ||||
| 	newRender?: (data?: any) => JSX.Element; | ||||
| 	textAlign?: "center" | "left" | "right"; | ||||
| } | ||||
							
								
								
									
										15
									
								
								src/components/Image/Image.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/components/Image/Image.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| import { fallImg } from "@/utils"; | ||||
|  | ||||
| interface AvatarProps extends React.ImgHTMLAttributes<HTMLImageElement> { } | ||||
|  | ||||
| /** 防止掉圖時 上個預設圖 */ | ||||
| const Image = (props: AvatarProps) => { | ||||
| 	function onError(event: any) { | ||||
| 		event.target.src = fallImg; | ||||
| 	} | ||||
| 	return ( | ||||
| 		<img {...props} onError={onError} /> | ||||
| 	); | ||||
| }; | ||||
|  | ||||
| export default Image; | ||||
| @@ -1,5 +1,7 @@ | ||||
| import MainControlData from "@/Common/DataReceived/MainControlData"; | ||||
| import MainControl from "@/Common/MainControl/MainControl"; | ||||
| import BusinessTypeSetting, { BusinessEnum } from "@/_BusinessTypeSetting/BusinessTypeSetting"; | ||||
| import { GameData } from "@/define/gameData"; | ||||
| import { PlayerData } from "@/define/playerData"; | ||||
| import { IGameItems } from "@/types"; | ||||
| import { ReactNode, createContext, useContext, useState } from "react"; | ||||
| @@ -15,21 +17,20 @@ export function useGameItems() { | ||||
| export let gameObj: IGameItems = null; | ||||
|  | ||||
| export function GameItemsProvider({ children }: GameItemsProviderProps) { | ||||
| 	const [gameId, setGameId] = useState<number>(null); | ||||
| 	const [player, setPlayer] = useState<PlayerData>({ | ||||
| 		token: "", | ||||
| 	}); | ||||
| 	const [player, setPlayer] = useState<PlayerData>(initPlayerData()); | ||||
| 	const [gameData, setGameData] = useState<GameData>(initGameData()); | ||||
|  | ||||
| 	const game: IGameItems = gameObj = { | ||||
| 		onLoad, | ||||
| 		gameId, | ||||
| 		setGameId, | ||||
| 		player, | ||||
| 		setPlayer | ||||
| 		setPlayer, | ||||
| 		gameData, | ||||
| 		setGameData | ||||
| 	}; | ||||
|  | ||||
| 	async function onLoad(serverType: BusinessEnum.ServerType) { | ||||
| 		new MainControl(); | ||||
| 		new MainControlData(); | ||||
| 		await Promise.all([ | ||||
| 			// 設定執行環境 | ||||
| 			setBusinessType(serverType), | ||||
| @@ -88,3 +89,27 @@ export function GameItemsProvider({ children }: GameItemsProviderProps) { | ||||
| 		</GameItemsContext.Provider> | ||||
| 	); | ||||
| } | ||||
|  | ||||
| function initPlayerData(): PlayerData { | ||||
| 	return { | ||||
| 		token: undefined, | ||||
| 		aId: undefined, | ||||
| 		f: undefined, | ||||
| 		r: undefined, | ||||
| 		rf: undefined, | ||||
| 		name: undefined, | ||||
| 		a: undefined, | ||||
| 		m: 0, | ||||
| 		lp: undefined, | ||||
| 		tr: undefined, | ||||
| 		lct: undefined | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| function initGameData(): GameData { | ||||
| 	return { | ||||
| 		slotData: [], | ||||
| 		slotList: [], | ||||
| 		nowSlotId: undefined, | ||||
| 	}; | ||||
| } | ||||
|   | ||||
							
								
								
									
										12
									
								
								src/define/Game/Base/Slot.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/define/Game/Base/Slot.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| export * from "../Slot1"; | ||||
| export * from "../Slot1201"; | ||||
| export * from "../Slot1305"; | ||||
| export * from "../Slot32"; | ||||
| export * from "../Slot34"; | ||||
| export * from "../Slot48"; | ||||
| export * from "../Slot50"; | ||||
| export * from "../Slot62"; | ||||
| export * from "../Slot64"; | ||||
| export * from "../Slot65"; | ||||
| export * from "../Slot66"; | ||||
| export * from "./SlotBase"; | ||||
							
								
								
									
										192
									
								
								src/define/Game/Base/SlotBase.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								src/define/Game/Base/SlotBase.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,192 @@ | ||||
| import CSMessage from "@/Common/Message/CSMessage"; | ||||
| import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; | ||||
| import { CommonSlotSpinRequest } from "../Request/CommonSlotRequest"; | ||||
|  | ||||
|  | ||||
| export class SlotBase { | ||||
| 	//#region public | ||||
|  | ||||
| 	// public get ID(): number { return this._bj_Casino_Bot.LobbyScript.Slot; } | ||||
| 	public get FreeID(): number { return 1; } | ||||
| 	public get FreeCount(): number { return +this.GameRunData["free"][1]; } | ||||
| 	public get HasChoiceFreeGame(): boolean { return false; } | ||||
| 	public get SlotReqRespIsCount(): boolean { return false; } | ||||
| 	public get HasRetriggerFreeSpin(): boolean { return false; } | ||||
| 	public GameRunData: JSON = null; | ||||
|  | ||||
| 	//#endregion | ||||
|  | ||||
| 	//#region protected | ||||
|  | ||||
| 	protected id: number; | ||||
|  | ||||
| 	// protected _bj_Slot: BJ_Casino_Bot_Slot; | ||||
|  | ||||
| 	//#endregion | ||||
|  | ||||
| 	//#region Lifecycle | ||||
|  | ||||
| 	/** | ||||
| 	 * | ||||
| 	 */ | ||||
| 	constructor(id: number) { | ||||
| 		this.id = id; | ||||
| 		this.onLoad(); | ||||
| 	} | ||||
|  | ||||
| 	public async onLoad(): Promise<void> { | ||||
| 		// | ||||
| 	} | ||||
|  | ||||
| 	//#endregion | ||||
|  | ||||
| 	//#region Custom | ||||
|  | ||||
| 	public *Spin(bet: number): IterableIterator<any> { | ||||
| 		let gameRunData: JSON = null; | ||||
| 		let req: CommonSlotSpinRequest = new CommonSlotSpinRequest(this.id, bet); | ||||
| 		yield req.SendAsync(); | ||||
| 		let resp: INetResponse<JSON> = req.Result; | ||||
| 		if (resp.IsValid) { | ||||
| 			gameRunData = this.GameRunData = resp.Data; | ||||
| 		} else { | ||||
| 			CSMessage.NetError(resp.Method, resp.Status); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// public async Spin(): Promise<void> { | ||||
| 	// 	let gameRunData: JSON = null; | ||||
| 	// 	let req: CommonSlotSpinRequest = new CommonSlotSpinRequest(this.ID, this._bj_Slot.NowBet); | ||||
| 	// 	await req.SendAsync(); | ||||
| 	// 	let resp: INetResponse<JSON> = req.Result; | ||||
| 	// 	if (resp.IsValid) { | ||||
| 	// 		gameRunData = this.GameRunData = resp.Data; | ||||
| 	// 	} else { | ||||
| 	// 		CSMessage.NetError(resp.Method, resp.Status); | ||||
| 	// 	} | ||||
| 	// 	let money: number = gameRunData["money"] ? +gameRunData["money"] : 0; | ||||
| 	// 	let winMoney: number = 0; | ||||
| 	// 	let winMoneyLog: string = ""; | ||||
| 	// 	let freeLog: string = ""; | ||||
| 	// 	let resources: any[] = gameRunData["get"]; | ||||
| 	// 	let free: any = gameRunData["free"]; | ||||
| 	// 	let choiceFreeGame: boolean = gameRunData["rs"] === 0; | ||||
| 	// 	if (resources) { | ||||
| 	// 		winMoney = this._getWinMoney(resources); | ||||
| 	// 	} | ||||
| 	// 	if (choiceFreeGame && this.HasChoiceFreeGame) { | ||||
| 	// 		free = true; | ||||
| 	// 	} | ||||
| 	// 	if (free) { | ||||
| 	// 		let freeCount: number = await this._getFreeCount(); | ||||
| 	// 		let fswinMoney: number = 0; | ||||
| 	// 		let fsmoney: number = 0; | ||||
| 	// 		[freeCount, fswinMoney, fsmoney] = await this.FreeSpin(freeCount); | ||||
| 	// 		if (fsmoney > 0) { | ||||
| 	// 			money = fsmoney; | ||||
| 	// 		} | ||||
| 	// 		if (fswinMoney > 0) { | ||||
| 	// 			winMoney = fswinMoney; | ||||
| 	// 		} | ||||
| 	// 		freeLog = `, hasFree: ${freeCount}`; | ||||
| 	// 	} | ||||
| 	// 	if (winMoney > 0) { | ||||
| 	// 		winMoneyLog = `, winMoney: ${winMoney}`; | ||||
| 	// 	} | ||||
| 	// 	this._bj_Casino_Bot.UserData.Money = money; | ||||
| 	// 	this._bj_Casino_Bot.SetUI(); | ||||
| 	// 	let ratio: number = winMoney > 0 ? NumberEx.divide(winMoney, this._bj_Slot.NowBet) : 0; | ||||
| 	// 	if (this._bj_Slot.IsRatioStop.value && ratio >= this._bj_Slot.RatioStop.value) { | ||||
| 	// 		this._bj_Slot.OnclickStop(); | ||||
| 	// 	} | ||||
| 	// 	if (this._bj_Slot.IsCountStop.value && this._bj_Slot.CountStop.value === 0) { | ||||
| 	// 		this._bj_Slot.OnclickStop(); | ||||
| 	// 	} | ||||
| 	// 	if (ratio > 100) { | ||||
| 	// 		this._bj_Casino_Bot.AddLog(`Slot${this.ID} Spin Bet: ${this._bj_Slot.NowBet}, Ratio: ${ratio}, Money: ${money}${winMoneyLog}${freeLog}`); | ||||
| 	// 	} | ||||
| 	// 	// this._bj_Casino_Bot.AddLog(`Slot${this.ID} Spin Bet: ${this._bj_Slot.NowBet}, Money: ${money}${winMoneyLog}${freeLog}`); | ||||
| 	// } | ||||
|  | ||||
| 	// public async FreeSpin(freeCount: number): Promise<number[]> { | ||||
| 	// 	let fswinMoney: number = 0; | ||||
| 	// 	let fsmoney: number = 0; | ||||
| 	// 	for (let i: number = 0; i < freeCount; i++) { | ||||
| 	// 		let gameRunData: JSON = null; | ||||
| 	// 		let req: CommonSlotFgSpinRequest = new CommonSlotFgSpinRequest(this.ID); | ||||
| 	// 		await req.SendAsync(); | ||||
| 	// 		let resp: INetResponse<JSON> = req.Result; | ||||
| 	// 		if (resp.IsValid) { | ||||
| 	// 			gameRunData = resp.Data; | ||||
| 	// 			if (this.HasRetriggerFreeSpin) { | ||||
| 	// 				let retriggercount: number = this._getRetriggerFreeSpinCount(gameRunData); | ||||
| 	// 				freeCount += retriggercount; | ||||
| 	// 			} | ||||
| 	// 			if (i === freeCount - 1) { | ||||
| 	// 				let resources: any[] = gameRunData["get"]; | ||||
| 	// 				if (resources) { | ||||
| 	// 					fswinMoney = this._getWinMoney(resources); | ||||
| 	// 				} | ||||
| 	// 				fsmoney = gameRunData["money"] ? +gameRunData["money"] : 0; | ||||
| 	// 			} | ||||
| 	// 		} else { | ||||
| 	// 			CSMessage.NetError(resp.Method, resp.Status); | ||||
| 	// 		} | ||||
| 	// 		// this._bj_Casino_Bot.AddLog(`Slot${this.ID} FreeSpin MaxCount: ${freeCount}, Count: ${i + 1}`); | ||||
| 	// 	} | ||||
| 	// 	return [freeCount, fswinMoney, fsmoney]; | ||||
| 	// } | ||||
|  | ||||
| 	// protected _getWinMoney(resources: any[]): number { | ||||
| 	// 	for (let i: number = 0; i < resources.length; i++) { | ||||
| 	// 		const resource: any[] = resources[i]; | ||||
| 	// 		if (resource[0] === 1) { | ||||
| 	// 			return resource[1]; | ||||
| 	// 		} | ||||
| 	// 	} | ||||
| 	// 	return 0; | ||||
| 	// } | ||||
|  | ||||
| 	// protected _getRetriggerFreeSpinCount(gameRunData: JSON): number { | ||||
| 	// 	if (gameRunData["free"]) { | ||||
| 	// 		return gameRunData["free"][1]; | ||||
| 	// 	} | ||||
| 	// 	return 0; | ||||
| 	// } | ||||
|  | ||||
| 	// protected async _getFreeCount(): Promise<number> { | ||||
| 	// 	if (this.HasChoiceFreeGame) { | ||||
| 	// 		return await this._getChoiceFreeCount(); | ||||
| 	// 	} else { | ||||
| 	// 		return this.FreeCount; | ||||
| 	// 	} | ||||
| 	// } | ||||
|  | ||||
| 	// protected async _getChoiceFreeCount(): Promise<number> { | ||||
| 	// 	let id: number = this._getFreeID(); | ||||
| 	// 	let request: Slot_ChoiceRequest = new Slot_ChoiceRequest(id); | ||||
| 	// 	await request.SendAsync(true); | ||||
| 	// 	var result: INetResponse<number> = request.Result; | ||||
| 	// 	if (result.IsValid) { | ||||
| 	// 		if (this.SlotReqRespIsCount) { | ||||
| 	// 			return result.Data; | ||||
| 	// 		} else { | ||||
| 	// 			let slotNameSetting: string = CSSettingsV3.Slotset[this.ID].NameSetting; | ||||
| 	// 			let free_info_id: number = result.Data; | ||||
| 	// 			let slotSetting: any = CSSettingsV3[slotNameSetting]; | ||||
| 	// 			let freeInfo: any = slotSetting.FreeInfo; | ||||
| 	// 			let count: number = freeInfo[free_info_id].Spins; | ||||
| 	// 			return count; | ||||
| 	// 		} | ||||
| 	// 	} | ||||
| 	// 	return 0; | ||||
| 	// } | ||||
|  | ||||
| 	// protected _getFreeID(): number { | ||||
| 	// 	return this.FreeID; | ||||
| 	// } | ||||
|  | ||||
| 	//#endregion | ||||
| } | ||||
|  | ||||
| export default SlotBase; | ||||
							
								
								
									
										78
									
								
								src/define/Game/Request/CommonSlotRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/define/Game/Request/CommonSlotRequest.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
|  | ||||
| //======================================================================================= | ||||
|  | ||||
| import { NetRequestSD } from "../../../Engine/CatanEngine/NetManagerV2/NetRequestSD"; | ||||
|  | ||||
| /**共用MAIN SPIN協定 */ | ||||
| export interface SpinRequest { | ||||
| 	pay: number; | ||||
| } | ||||
|  | ||||
| export class CommonSlotSpinRequest extends NetRequestSD<SpinRequest, JSON> { | ||||
| 	private _id: number = 0; | ||||
|  | ||||
| 	get Method(): string { | ||||
| 		return "slot" + this._id + ".spin"; | ||||
| 	} | ||||
|  | ||||
| 	constructor(slotId: number, totalBet: number) { | ||||
| 		super(); | ||||
| 		this._id = slotId; | ||||
| 		this.Data = { | ||||
| 			pay: totalBet, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| export class CommonSlotFgSpinRequest extends NetRequestSD<any, JSON> { | ||||
| 	private _id: number = 0; | ||||
|  | ||||
| 	get Method(): string { | ||||
| 		return "slot" + this._id + ".fgspin"; | ||||
| 	} | ||||
|  | ||||
| 	constructor(slotId: number) { | ||||
| 		super(); | ||||
| 		this._id = slotId; | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| export class CommonSlotCollectUnlockRequest extends NetRequestSD<any, JSON> { | ||||
| 	private _id: number = 0; | ||||
| 	get Method(): string { | ||||
| 		return "collect" + this._id + ".unlock"; | ||||
| 	} | ||||
|  | ||||
| 	constructor(slotId: number, grid: number) { | ||||
| 		super(); | ||||
| 		this._id = slotId; | ||||
| 		this.Data = { | ||||
| 			Grid: grid, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| export class CommonSlotCollectSpinRequest extends NetRequestSD<any, JSON> { | ||||
| 	private _id: number = 0; | ||||
| 	get Method(): string { | ||||
| 		return "collect" + this._id + ".spin"; | ||||
| 	} | ||||
|  | ||||
| 	constructor(slotId: number) { | ||||
| 		super(); | ||||
| 		this._id = slotId; | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| /**賓果 ChangeSet協定 */ | ||||
| export class CommonBingoChangeSet extends NetRequestSD<any, JSON> { | ||||
| 	private _id: number = 0; | ||||
| 	get Method(): string { | ||||
| 		return "slot" + this._id + ".chset"; | ||||
| 	} | ||||
| 	constructor(slotId: number) { | ||||
| 		super(); | ||||
| 		this._id = slotId; | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
							
								
								
									
										78
									
								
								src/define/Game/Request/SlotRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/define/Game/Request/SlotRequest.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| import { NetRequestSD } from "@/Engine/CatanEngine/NetManagerV2/NetRequestSD"; | ||||
|  | ||||
| //======================================================================================= | ||||
| interface ChoiceRequest { | ||||
| } | ||||
|  | ||||
| /**五龍選擇協定 */ | ||||
| export class Slot_ChoiceRequest extends NetRequestSD<ChoiceRequest, number> { | ||||
| 	get Method(): string { | ||||
| 		return "slot.req"; | ||||
| 	} | ||||
|  | ||||
| 	constructor(id: number) { | ||||
| 		super(); | ||||
| 		this.Data = id; | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| interface GmRequest { | ||||
| 	pay: number; | ||||
| 	slot: string; | ||||
| 	type: number; | ||||
| } | ||||
|  | ||||
| export class Slot_GMRequest extends NetRequestSD<GmRequest, JSON> { | ||||
| 	get Method(): string { | ||||
| 		return "slot.gm"; | ||||
| 	} | ||||
|  | ||||
| 	get MethodBack(): string { | ||||
| 		return "slot" + this._id + ".spin"; | ||||
| 	} | ||||
|  | ||||
| 	private _id: number = 1; | ||||
|  | ||||
| 	constructor(id: number, totalBet: number, symbols: string, type: number) { | ||||
| 		super(); | ||||
| 		this._id = id; | ||||
| 		this.Data = { | ||||
| 			pay: totalBet, | ||||
| 			slot: symbols, | ||||
| 			type: type, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| export class Bingo_GMRequest extends NetRequestSD<GmRequest, JSON> { | ||||
| 	get Method(): string { | ||||
| 		return "bingo.gm"; | ||||
| 	} | ||||
|  | ||||
| 	get MethodBack(): string { | ||||
| 		return "slot" + this._id + ".spin"; | ||||
| 	} | ||||
|  | ||||
| 	private _id: number = 0; | ||||
|  | ||||
| 	constructor(id: number, totalBet: number, bingos: string, type: number) { | ||||
| 		super(); | ||||
| 		this._id = id; | ||||
| 		this.Data = { | ||||
| 			pay: totalBet, | ||||
| 			slot: bingos, | ||||
| 			type: type, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| /**前後端金額對不上協定 */ | ||||
| export class Slot_ErrorRequest extends NetRequestSD<any, JSON> { | ||||
| 	get Method(): string { | ||||
| 		return "slot.error"; | ||||
| 	} | ||||
| 	constructor() { | ||||
| 		super(); | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
							
								
								
									
										13
									
								
								src/define/Game/Slot1.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot1.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| import SlotBase from "./Base/SlotBase"; | ||||
|  | ||||
|  | ||||
| export class Slot1 extends SlotBase { | ||||
|     //#region public | ||||
|  | ||||
|     public get ID(): number { return 1; } | ||||
|     public get HasRetriggerFreeSpin(): boolean { return true; } | ||||
|  | ||||
|     //#endregion | ||||
| } | ||||
|  | ||||
| export default Slot1; | ||||
							
								
								
									
										13
									
								
								src/define/Game/Slot1201.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot1201.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| import SlotBase from "./Base/SlotBase"; | ||||
|  | ||||
|  | ||||
| export class Slot1201 extends SlotBase { | ||||
|     //#region public | ||||
|  | ||||
|     public get FreeCount(): number { return +this.GameRunData["free"]; } | ||||
|     public get HasRetriggerFreeSpin(): boolean { return true; } | ||||
|  | ||||
|     //#endregion | ||||
| } | ||||
|  | ||||
| export default Slot1201; | ||||
							
								
								
									
										13
									
								
								src/define/Game/Slot1305.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot1305.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| import SlotBase from "./Base/SlotBase"; | ||||
|  | ||||
|  | ||||
| export class Slot1305 extends SlotBase { | ||||
| 	//#region public | ||||
|  | ||||
| 	public get ID(): number { return 1305; } | ||||
| 	public get HasRetriggerFreeSpin(): boolean { return true; } | ||||
|  | ||||
| 	//#endregion | ||||
| } | ||||
|  | ||||
| export default Slot1305; | ||||
							
								
								
									
										13
									
								
								src/define/Game/Slot32.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot32.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| import SlotBase from "./Base/SlotBase"; | ||||
|  | ||||
|  | ||||
| export class Slot32 extends SlotBase { | ||||
| 	//#region public | ||||
|  | ||||
| 	public get ID(): number { return 32; } | ||||
| 	public get HasRetriggerFreeSpin(): boolean { return true; } | ||||
|  | ||||
| 	//#endregion | ||||
| } | ||||
|  | ||||
| export default Slot32; | ||||
							
								
								
									
										13
									
								
								src/define/Game/Slot34.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot34.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| import SlotBase from "./Base/SlotBase"; | ||||
|  | ||||
|  | ||||
| export class Slot34 extends SlotBase { | ||||
|     //#region public | ||||
|  | ||||
|     public get ID(): number { return 34; } | ||||
|     public get HasRetriggerFreeSpin(): boolean { return true; } | ||||
|  | ||||
|     //#endregion | ||||
| } | ||||
|  | ||||
| export default Slot34; | ||||
							
								
								
									
										16
									
								
								src/define/Game/Slot48.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/define/Game/Slot48.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| import SlotBase from "./Base/SlotBase"; | ||||
|  | ||||
|  | ||||
| export class Slot48 extends SlotBase { | ||||
|     //#region public | ||||
|  | ||||
|     public get ID(): number { return 48; } | ||||
|     public get FreeID(): number { return 3; } | ||||
|     public get HasChoiceFreeGame(): boolean { return true; } | ||||
|     public get SlotReqRespIsCount(): boolean { return true; } | ||||
|     public get HasRetriggerFreeSpin(): boolean { return true; } | ||||
|  | ||||
|     //#endregion | ||||
| } | ||||
|  | ||||
| export default Slot48; | ||||
							
								
								
									
										15
									
								
								src/define/Game/Slot50.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/define/Game/Slot50.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| import SlotBase from "./Base/SlotBase"; | ||||
|  | ||||
|  | ||||
| export class Slot50 extends SlotBase { | ||||
|     //#region public | ||||
|  | ||||
|     public get ID(): number { return 50; } | ||||
|     public get FreeID(): number { return 1; } | ||||
|     public get HasChoiceFreeGame(): boolean { return true; } | ||||
|     public get HasRetriggerFreeSpin(): boolean { return true; } | ||||
|  | ||||
|     //#endregion | ||||
| } | ||||
|  | ||||
| export default Slot50; | ||||
							
								
								
									
										31
									
								
								src/define/Game/Slot62.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/define/Game/Slot62.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| import SlotBase from "./Base/SlotBase"; | ||||
|  | ||||
|  | ||||
| export class Slot62 extends SlotBase { | ||||
|     //#region public | ||||
|  | ||||
|     public get ID(): number { return 62; } | ||||
|     public get FreeID(): number { return 3; } | ||||
|     public get HasChoiceFreeGame(): boolean { return true; } | ||||
|     public get HasRetriggerFreeSpin(): boolean { return true; } | ||||
|  | ||||
|     //#endregion | ||||
|  | ||||
|     //#region Custom | ||||
|  | ||||
|     protected _getFreeID(): number { | ||||
|         let gameRunData: JSON = this.GameRunData; | ||||
|         let scatterAmount: number = gameRunData["scatter"][0][0].length; | ||||
|         if (scatterAmount > 4) { | ||||
|             return 5; | ||||
|         } else if (scatterAmount > 3) { | ||||
|             return 4; | ||||
|         } else { | ||||
|             return this.FreeID; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     //#endregion | ||||
| } | ||||
|  | ||||
| export default Slot62; | ||||
							
								
								
									
										13
									
								
								src/define/Game/Slot64.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot64.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| import SlotBase from "./Base/SlotBase"; | ||||
|  | ||||
|  | ||||
| export class Slot64 extends SlotBase { | ||||
| 	//#region public | ||||
|  | ||||
| 	public get ID(): number { return 64; } | ||||
| 	public get HasRetriggerFreeSpin(): boolean { return true; } | ||||
|  | ||||
| 	//#endregion | ||||
| } | ||||
|  | ||||
| export default Slot64; | ||||
							
								
								
									
										13
									
								
								src/define/Game/Slot65.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot65.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| import SlotBase from "./Base/SlotBase"; | ||||
|  | ||||
|  | ||||
| export class Slot65 extends SlotBase { | ||||
| 	//#region public | ||||
|  | ||||
| 	public get ID(): number { return 65; } | ||||
| 	public get HasRetriggerFreeSpin(): boolean { return true; } | ||||
|  | ||||
| 	//#endregion | ||||
| } | ||||
|  | ||||
| export default Slot65; | ||||
							
								
								
									
										13
									
								
								src/define/Game/Slot66.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/define/Game/Slot66.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| import SlotBase from "./Base/SlotBase"; | ||||
|  | ||||
|  | ||||
| export class Slot66 extends SlotBase { | ||||
| 	//#region public | ||||
|  | ||||
| 	public get ID(): number { return 66; } | ||||
| 	public get HasRetriggerFreeSpin(): boolean { return true; } | ||||
|  | ||||
| 	//#endregion | ||||
| } | ||||
|  | ||||
| export default Slot66; | ||||
							
								
								
									
										9
									
								
								src/define/GameData.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/define/GameData.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| interface GameData { | ||||
| 	slotData: SlotData[]; | ||||
| 	slotList: number[]; | ||||
| 	nowSlotId: number; | ||||
| } | ||||
|  | ||||
| export type SlotData = [componyID: number, slotId: number, vip: number, status: number, tag: number] | ||||
|  | ||||
| export { type GameData }; | ||||
| @@ -1,5 +1,15 @@ | ||||
| interface PlayerData { | ||||
| 	token: string; | ||||
| 	aId: number; | ||||
| 	f: number; | ||||
| 	r: number; | ||||
| 	rf: number; | ||||
| 	name: string; | ||||
| 	a: number; | ||||
| 	m: number; | ||||
| 	lp: number; | ||||
| 	tr: number; | ||||
| 	lct: number; | ||||
| } | ||||
|  | ||||
| export { type PlayerData }; | ||||
|   | ||||
							
								
								
									
										311
									
								
								src/define/Request/AccountRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										311
									
								
								src/define/Request/AccountRequest.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,311 @@ | ||||
| import { NetRequestSD } from "@/Engine/CatanEngine/NetManagerV2/NetRequestSD"; | ||||
| import { NetRequest } from "../../Engine/CatanEngine/NetManagerV2/NetRequest"; | ||||
|  | ||||
| // ======================================================================================= | ||||
| /** 通用回傳SERVER創的遊戲帳號 */ | ||||
| export interface CommonAccountResponse { | ||||
| 	id: string; | ||||
| 	pw: string; | ||||
| } | ||||
|  | ||||
| // ======================================================================================= | ||||
| interface CreateResquest { | ||||
| 	p: number; | ||||
| 	d: string; | ||||
| } | ||||
| /** 直接玩(訪客給SERVER創帳號) */ | ||||
| export class AccountCreateRequest extends NetRequest<CreateResquest, CommonAccountResponse> { | ||||
| 	get Method(): string { | ||||
| 		return "account.create"; | ||||
| 	} | ||||
| 	/*constructor() { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			p: Config.GetRunDevice(), | ||||
| 			d: LocalStorageData.Instance.ComboDeviceID, | ||||
| 		}; | ||||
| 	}*/ | ||||
| } | ||||
| // ======================================================================================= | ||||
| interface LoginRequest { | ||||
| 	// p: number; | ||||
| 	// d: string; | ||||
| 	// fcm_token: string; | ||||
| 	id: number; | ||||
| 	pw: string; | ||||
| 	pl: number; | ||||
| 	// ver: string; | ||||
| } | ||||
| interface LoginResponse { | ||||
| 	pr: string; | ||||
| 	cu: string; | ||||
| } | ||||
| /** 通用登入 */ | ||||
| export class AccountLoginRequest extends NetRequest<LoginRequest, LoginResponse> { | ||||
| 	get Method(): string { | ||||
| 		return "account.login"; | ||||
| 	} | ||||
| 	constructor(account: string, password: string, partner: string) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			id: +account, | ||||
| 			pw: password, | ||||
| 			pl: 3 | ||||
| 		}; | ||||
| 		if (partner) { | ||||
| 			this.Data["pn"] = partner; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| interface SDLoginRequest { | ||||
| 	token: string; | ||||
| } | ||||
| export class SDAccountLoginRequest extends NetRequestSD<SDLoginRequest, LoginResponse> { | ||||
| 	get Method(): string { | ||||
| 		return "account.login"; | ||||
| 	} | ||||
| 	constructor(token: string) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			token: token, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ======================================================================================= | ||||
| interface CustomResquest { | ||||
| 	a: string; | ||||
| 	pw: string; | ||||
| } | ||||
|  | ||||
| /** 自定帳號榜定 */ | ||||
| export class CustomBindRequest extends NetRequest<CustomResquest, null> { | ||||
| 	get Method(): string { | ||||
| 		return "register.account_bind"; | ||||
| 	} | ||||
| 	constructor(account: string, password: string) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			a: account, | ||||
| 			pw: password, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| /** 自定帳號登入(回傳SERVER帳號) */ | ||||
| export class CustomLoginRequest extends NetRequest<string, CommonAccountResponse> { | ||||
| 	get Method(): string { | ||||
| 		return "register.account_login"; | ||||
| 	} | ||||
| 	constructor(account: string) { | ||||
| 		super(); | ||||
| 		this.Data = account; | ||||
| 	} | ||||
| } | ||||
| // ======================================================================================= | ||||
| interface FBResquest { | ||||
| 	t: string; | ||||
| } | ||||
| /** FB綁定 */ | ||||
| export class FBBindRequest extends NetRequest<FBResquest, null> { | ||||
| 	get Method(): string { | ||||
| 		return "register.fb_bind"; | ||||
| 	} | ||||
| 	constructor(token: string) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			t: token, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| /** FB登入(回傳SERVER帳號) */ | ||||
| export class FBLoginRequest extends NetRequest<FBResquest, CommonAccountResponse> { | ||||
| 	get Method(): string { | ||||
| 		return "register.fb_login"; | ||||
| 	} | ||||
| 	constructor(token: string) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			t: token, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| // ======================================================================================= | ||||
| interface GoogleResquest { | ||||
| 	c: string; | ||||
| } | ||||
| /** GOOGLE綁定 */ | ||||
| export class GoogleBindRequest extends NetRequest<GoogleResquest, null> { | ||||
| 	get Method(): string { | ||||
| 		return "register.google_bind"; | ||||
| 	} | ||||
| 	constructor(token: string) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			c: token, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| /** GOOGLE登入(回傳SERVER帳號) */ | ||||
| export class GoogleLoginRequest extends NetRequest<GoogleResquest, CommonAccountResponse> { | ||||
| 	get Method(): string { | ||||
| 		return "register.google_login"; | ||||
| 	} | ||||
| 	constructor(token: string) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			c: token, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| // ======================================================================================= | ||||
| interface AppleResquest { | ||||
| 	c: string; | ||||
| } | ||||
| /** APPEL綁定 */ | ||||
| export class AppleBindRequest extends NetRequest<AppleResquest, null> { | ||||
| 	get Method(): string { | ||||
| 		return "register.apple_bind"; | ||||
| 	} | ||||
| 	constructor(token: string) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			c: token, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| /** APPLE登入(回傳SERVER帳號) */ | ||||
| export class AppleLoginRequest extends NetRequest<AppleResquest, CommonAccountResponse> { | ||||
| 	get Method(): string { | ||||
| 		return "register.apple_login"; | ||||
| 	} | ||||
| 	constructor(token: string) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			c: token, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| // ======================================================================================= | ||||
| /** 電話確認 */ | ||||
| export class PhoneCheck extends NetRequest<PhoneCodeRequest, string> { | ||||
| 	get Method(): string { | ||||
| 		return "register.phone_check"; | ||||
| 	} | ||||
| 	constructor(p: string) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			p: p | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| /** 電話驗證 */ | ||||
| export interface PhoneCodeRequest { | ||||
| 	p: string; | ||||
| } | ||||
|  | ||||
| export class PhoneGet extends NetRequest<PhoneCodeRequest, string> { | ||||
| 	get Method(): string { | ||||
| 		return "register.phone_code"; | ||||
| 	} | ||||
| 	constructor(p: string) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			p: p | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export interface PhoneBindRequest { | ||||
| 	c: string; | ||||
| } | ||||
|  | ||||
| export class PhoneBind extends NetRequest<PhoneBindRequest, string> { | ||||
| 	get Method(): string { | ||||
| 		return "register.phone_bind"; | ||||
| 	} | ||||
| 	constructor(c: string) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			c: c | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ======================================================================================= | ||||
| /** 旗標更新 */ | ||||
| export class FlagOpenAdd extends NetRequest<number, string> { | ||||
| 	get Method(): string { | ||||
| 		return "flag.open_add"; | ||||
| 	} | ||||
| 	constructor(type: number) { | ||||
| 		super(); | ||||
| 		this.Data = type; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ======================================================================================== | ||||
| export interface ForgotInfo { | ||||
| 	a: string; | ||||
| 	p: string; | ||||
| } | ||||
|  | ||||
| /** 忘記密碼 */ | ||||
| export class ForgotPassword extends NetRequest<ForgotInfo, null> { | ||||
| 	get Method(): string { | ||||
| 		return "register.account_forget"; | ||||
| 	} | ||||
| 	constructor(account: string, phone: string) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			a: account, | ||||
| 			p: phone, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export interface ChangePasswordInfo { | ||||
| 	a: string; | ||||
| 	opw: string; | ||||
| 	pw: string; | ||||
| } | ||||
|  | ||||
| /** 修改密碼 */ | ||||
| export class ChangePassword extends NetRequest<ChangePasswordInfo, null> { | ||||
| 	get Method(): string { | ||||
| 		return "register.account_change"; | ||||
| 	} | ||||
| 	constructor(account: string, prePassword: string, password: string) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			a: account, | ||||
| 			opw: prePassword, | ||||
| 			pw: password | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ======================================================================================= | ||||
| export interface LineBindResponse { | ||||
| 	n: string; | ||||
| } | ||||
|  | ||||
| export class LineBind extends NetRequest<string, LineBindResponse> { | ||||
| 	get Method(): string { | ||||
| 		return "register.line_bind"; | ||||
| 	} | ||||
| 	constructor(token: string) { | ||||
| 		super(); | ||||
| 		this.Data = token; | ||||
| 	} | ||||
| } | ||||
| /** LINE登入(回傳SERVER帳號) */ | ||||
| export class LineLoginRequest extends NetRequest<string, CommonAccountResponse> { | ||||
| 	get Method(): string { | ||||
| 		return "register.line_login"; | ||||
| 	} | ||||
| 	constructor(token: string) { | ||||
| 		super(); | ||||
| 		this.Data = token; | ||||
| 	} | ||||
| } | ||||
| // ======================================================================================= | ||||
| @@ -3,6 +3,15 @@ import { NetRequest } from "@/Engine/CatanEngine/NetManagerV2/NetRequest"; | ||||
|  | ||||
| // #region Request | ||||
|  | ||||
| export type RpcGamInfoResponse = JSON | ||||
| export class GameInfoRequest extends NetRequest<null, RpcGamInfoResponse> { | ||||
| 	get Method(): string { | ||||
| 		return "game.info"; | ||||
| 	} | ||||
| 	constructor() { | ||||
| 		super(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export type RpcGameLaunchRequest = number[] | ||||
| export type RpcGameLaunchResponse = string | ||||
|   | ||||
							
								
								
									
										83
									
								
								src/define/Request/SlotRequest.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/define/Request/SlotRequest.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| import { NetRequestSD } from "@/Engine/CatanEngine/NetManagerV2/NetRequestSD"; | ||||
| import { LanguageManager } from "@/FormTableExt/Manage/Language/LanguageManager"; | ||||
| import { NetRequest } from "../../Engine/CatanEngine/NetManagerV2/NetRequest"; | ||||
|  | ||||
| //======================================================================================= | ||||
| /**取得歷史紀錄網頁網址協定 */ | ||||
| export class HistoryRequest extends NetRequest<any, JSON> { | ||||
| 	get Method(): string { | ||||
| 		return "history.url"; | ||||
| 	} | ||||
|  | ||||
| 	constructor(slotId: number) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			slot: slotId, | ||||
| 			lang: LanguageManager.UseLanguageUrlStr, | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| export class SlotInRequest extends NetRequestSD<any, JSON> { | ||||
| 	get Method(): string { | ||||
| 		return "slot.in"; | ||||
| 	} | ||||
| 	constructor(slotid: number, hall: number = 0, uid: number = 0) { | ||||
| 		super(); | ||||
| 		this.Data = { | ||||
| 			id: slotid | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| export class SlotOutRequest extends NetRequest<null, null> { | ||||
| 	get Method(): string { | ||||
| 		return "slot.out"; | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| export class FishOutRequest extends NetRequest<null, null> { | ||||
| 	get Method(): string { | ||||
| 		return "fish.out"; | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| export class TableOutRequest extends NetRequest<null, null> { | ||||
| 	get Method(): string { | ||||
| 		return "table.out"; | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| export class Table3002OutRequest extends NetRequest<any, JSON> { | ||||
| 	get Method(): string { | ||||
| 		return "two_sicbo.leave"; | ||||
| 	} | ||||
| 	constructor() { | ||||
| 		super(); | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| export class Table3003OutRequest extends NetRequest<any, JSON> { | ||||
| 	get Method(): string { | ||||
| 		return "nine_sicbo.leave"; | ||||
| 	} | ||||
| 	constructor() { | ||||
| 		super(); | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| export class Table3012OutRequest extends NetRequest<any, JSON> { | ||||
| 	get Method(): string { | ||||
| 		return "triple_baccarat.leave"; | ||||
| 	} | ||||
| 	constructor() { | ||||
| 		super(); | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| export class PinBallOutRequest extends NetRequest<null, null> { | ||||
| 	get Method(): string { | ||||
| 		return "pinball.out"; | ||||
| 	} | ||||
| } | ||||
| //======================================================================================= | ||||
| @@ -12,6 +12,7 @@ import { BaseEnumerator } from "./Engine/CatanEngine/CoroutineV2/Core/BaseEnumer | ||||
| import Game from "./UI/Game"; | ||||
| import Lobby from "./UI/Lobby"; | ||||
| import Login from "./UI/Login"; | ||||
| import { ModalProvider } from "./UIControl/ModalContext"; | ||||
| import "./index.css"; | ||||
| import "./utils/catan"; | ||||
|  | ||||
| @@ -35,7 +36,9 @@ const browserRouter: Router = createBrowserRouter(router); | ||||
| const hashRouter: Router = createHashRouter(router); | ||||
|  | ||||
| ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( | ||||
| 	<GameItemsProvider> | ||||
| 		<RouterProvider router={browserRouter} /> | ||||
| 	</GameItemsProvider> | ||||
| 	<ModalProvider> | ||||
| 		<GameItemsProvider> | ||||
| 			<RouterProvider router={browserRouter} /> | ||||
| 		</GameItemsProvider> | ||||
| 	</ModalProvider> | ||||
| ); | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| import { BusinessEnum } from "@/_BusinessTypeSetting/BusinessTypeSetting"; | ||||
| import { GameData } from "@/define/gameData"; | ||||
| import { PlayerData } from "@/define/playerData"; | ||||
|  | ||||
| export interface IGameItems { | ||||
| 	onLoad: (serverType: BusinessEnum.ServerType) => Promise<void>; | ||||
| 	gameId: number; | ||||
| 	setGameId: (v: number) => void; | ||||
| 	player: PlayerData; | ||||
| 	setPlayer: (v: PlayerData) => void; | ||||
| 	gameData: GameData; | ||||
| 	setGameData: (v: GameData) => void; | ||||
| } | ||||
| @@ -1,652 +1 @@ | ||||
| import { ResourceItemType } from "@/Common/ResourceItem/ResourceItemType"; | ||||
| import { BaseEnumerator } from "@/Engine/CatanEngine/CoroutineV2/Core/BaseEnumerator"; | ||||
| import { TableManager } from "@/Engine/CatanEngine/TableV3/TableManager"; | ||||
| import CSSettingsV3 from "@/FormTable/CSSettingsV3"; | ||||
| import { ShopMycardTableRow, ShopShow2TableRow } from "@/FormTable/Tables/ShopTable"; | ||||
| import { Cocos } from "@/assets/VueScript/Cocos"; | ||||
| import { CocosVueScript } from "@/assets/VueScript/CocosVueScript"; | ||||
| import GameData_Cocos from "@/assets/VueScript/share/GameData_Cocos"; | ||||
| import { FriendRequest } from "@/define/Request/FriendRequest"; | ||||
| import { TxnRequest } from "@/define/Request/TxnRequest"; | ||||
| import { VIPLevelMapForChat } from "@/map"; | ||||
| import Player from "@/modules/player"; | ||||
| import { UserBindFlag } from "@/modules/player/define/userbind_flag"; | ||||
| import { ChatRoomRole, Games, ItemCodeList, ItemPropsType, ItemSize, PriceList, SelectorItemProps, StringContentType, TagTypes, TxnCenterData } from "@/types"; | ||||
| import liff from "@line/liff"; | ||||
| import axios, { AxiosResponse } from "axios"; | ||||
| import { isMobile } from "react-device-detect"; | ||||
| import * as Scroll from "react-scroll"; | ||||
| import stringWidth from "string-width"; | ||||
| import BusinessTypeSetting, { FolderName } from "../_BusinessTypeSetting/BusinessTypeSetting"; | ||||
|  | ||||
| export const transArray = <T>(array: T[], split: number): T[][] => { | ||||
| 	const newArr = []; | ||||
| 	const copiedArr = array ? array?.slice() : []; | ||||
| 	const length = copiedArr?.length; | ||||
| 	for (let i = 0, j = 0; i < length; i += split, j++) { | ||||
| 		newArr[j] = copiedArr.splice(0, split); | ||||
| 	} | ||||
| 	return newArr; | ||||
| }; | ||||
|  | ||||
| /** 去掉英文+百分比% */ | ||||
| export function onlyNumber(stringText: string): number { | ||||
| 	const str = +stringText.replace(/[A-Za-z%]/g, ""); | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| export function wordsLimit(limit: number, string: string) { | ||||
| 	const length = string?.length; | ||||
| 	const isOverLimit = length > limit; | ||||
| 	const result = isOverLimit ? "..." : ""; | ||||
| 	return string?.substring(0, limit) + result; | ||||
| } | ||||
|  | ||||
| export const capitalize = (str: string) => | ||||
| 	`${str.charAt(0).toUpperCase()}${str.slice(1)}`; | ||||
|  | ||||
| export function checkForUnique(str: string): boolean { | ||||
| 	const chineseCharacterMatch = | ||||
| 		/[\p{Unified_Ideograph}\u3006\u3007][\ufe00-\ufe0f\u{e0100}-\u{e01ef}]?/gmu; | ||||
| 	const arr = str.match(chineseCharacterMatch); | ||||
| 	if (arr === null) return true; | ||||
| 	return !hasDuplicates(arr); | ||||
| } | ||||
|  | ||||
| export function onlyChinese(str: string) { | ||||
| 	const chineseCharacterMatch = | ||||
| 		/[\p{Unified_Ideograph}\u3006\u3007][\ufe00-\ufe0f\u{e0100}-\u{e01ef}]?/gmu; | ||||
| 	const arr = str.match(chineseCharacterMatch); | ||||
| 	return arr.join(""); | ||||
| } | ||||
|  | ||||
| export function hasDuplicates(array: string[]): boolean { | ||||
| 	return new Set(array).size !== array.length; | ||||
| } | ||||
|  | ||||
| export function generatePriceList( | ||||
| 	arr: [ID: number, ProductId: number, ShowMoney: number][], | ||||
| 	items: { [id: string]: [ID: number, price: number] }, | ||||
| 	priceRef: ShopMycardTableRow[], | ||||
| 	itemCodeList?: Map<number, ItemCodeList>, | ||||
| ): PriceList[] { | ||||
| 	if (itemCodeList) { | ||||
| 		arr = arr.filter((item) => itemCodeList.has(item[0])); | ||||
| 	} | ||||
| 	const MyCardPriceRefMap = new Map<number, number>( | ||||
| 		priceRef.map((item) => [item.Id, item.Price]), | ||||
| 	); | ||||
| 	const newArr: [ID: number, ProductId: number, ShowMoney: number][] = []; | ||||
| 	for (const item of Object.values(items)) { | ||||
| 		arr.forEach((v: [ID: number, ProductId: number, ShowMoney: number]) => { | ||||
| 			if (v[1] === item[0]) { | ||||
| 				newArr.push(v); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| 	return newArr | ||||
| 		.map((item) => ({ | ||||
| 			ID: item[0], | ||||
| 			points: item[2], | ||||
| 			price: MyCardPriceRefMap.get(item[1]), | ||||
| 		})) | ||||
| 		.sort((a, b) => b.price - a.price); | ||||
| } | ||||
|  | ||||
| /** 支付列表 */ | ||||
| export function generatePaymentList( | ||||
| 	arr: string[], | ||||
| 	priceRef: ShopShow2TableRow[], | ||||
| ): ShopShow2TableRow[] { | ||||
| 	const newArr: ShopShow2TableRow[] = []; | ||||
| 	for (const item of Object.values(priceRef)) { | ||||
| 		arr.forEach((x) => { | ||||
| 			if (item.Show && x === item.Key) newArr.push(item); | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	// priceRef.forEach((value: ShopShow2TableRow) =>  { | ||||
| 	// 	arr.includes(value.Key); | ||||
| 	// }) | ||||
| 	return newArr; | ||||
| } | ||||
|  | ||||
| /** getQueryParameters */ | ||||
| export function getQueryParameters(v: string): string { | ||||
| 	const queryParameters = new URLSearchParams(location.search); | ||||
| 	return queryParameters.get(v); | ||||
| } | ||||
|  | ||||
| export function createMap(obj: unknown) { | ||||
| 	return new Map(Object.entries(obj)); | ||||
| } | ||||
|  | ||||
| export function isArray(itemCode: string | string[]): boolean { | ||||
| 	return Array.isArray(itemCode); | ||||
| } | ||||
|  | ||||
| export function formatTime(date: Date): string { | ||||
| 	const hours = date.getHours(); | ||||
| 	const minutes = date.getMinutes(); | ||||
| 	const amPm = hours >= 12 ? "pm" : "am"; | ||||
| 	const formattedHours = hours % 12 === 0 ? 12 : hours % 12; | ||||
| 	const formattedMinutes = minutes < 10 ? "0" + minutes : minutes; | ||||
| 	return `${formattedHours}:${formattedMinutes} ${amPm}`; | ||||
| } | ||||
|  | ||||
| export function getCurrentLocalTime() { | ||||
| 	const date = new Date(); | ||||
| 	const utcTime = date.getTime(); | ||||
| 	return new Date(utcTime).toLocaleTimeString(); | ||||
| } | ||||
|  | ||||
| export function transferColorText(str: string): string { | ||||
| 	const regex = /color=/g; | ||||
| 	const replacement = "span style=color:"; | ||||
| 	const result = str.replace(regex, replacement); | ||||
| 	const regex2 = /color>/g; | ||||
| 	const replacement2 = "span>"; | ||||
| 	return result.replace(regex2, replacement2); | ||||
| } | ||||
|  | ||||
| export function generateItemsData( | ||||
| 	games: Map<string, number[]>, | ||||
| 	favoriteGames: number[], | ||||
| ): ItemPropsType[] { | ||||
| 	let itemsData: boolean | ItemPropsType[] = []; | ||||
| 	const s = new Set(favoriteGames); | ||||
| 	if (games.size) { | ||||
| 		// @ts-ignore | ||||
| 		for (const [gameID, [vendorID, id, VIPLimit, status, tag]] of games) { | ||||
| 			const dataObj: ItemPropsType = { | ||||
| 				id: gameID, | ||||
| 				vendorID: vendorID.toString(), | ||||
| 				img: { | ||||
| 					url: `${BusinessTypeSetting.UseDownloadUrl}${FolderName.Game}${id}/b`, | ||||
| 				}, | ||||
| 				size: ItemSize.small, | ||||
| 				tag: tag as unknown as TagTypes, | ||||
| 				lockBtn: VIPLimit, | ||||
| 				like: s.has(id), | ||||
| 				status, | ||||
| 			}; | ||||
|  | ||||
| 			itemsData.push(dataObj); | ||||
| 		} | ||||
| 	} else { | ||||
| 		itemsData = []; | ||||
| 	} | ||||
|  | ||||
| 	return itemsData; | ||||
| } | ||||
|  | ||||
| export function generateItemsDataMap(games: Games): Map<string, number[]> { | ||||
| 	const map = new Map(); | ||||
| 	for (const [gameID, value] of Object.entries(games)) { | ||||
| 		map.set(gameID, value); | ||||
| 	} | ||||
| 	return map; | ||||
| } | ||||
|  | ||||
| export function sortedGames(sorts: number[], map: Map<string, number[]>) { | ||||
| 	const obj = new Map(); | ||||
| 	sorts?.forEach((gameID) => { | ||||
| 		obj.set("" + gameID, map?.get("" + gameID)); | ||||
| 	}); | ||||
| 	return obj; | ||||
| } | ||||
|  | ||||
| export function addPropertiesToDefaultItem( | ||||
| 	games: any[], | ||||
| 	selectedID: number, | ||||
| ): SelectorItemProps[] { | ||||
| 	const index = games.findIndex((item) => parseInt(item.id) === selectedID); | ||||
| 	const newGames = games.slice(); | ||||
|  | ||||
| 	return newGames.map((g, i) => | ||||
| 		i === index | ||||
| 			? { ...g, selected: true, defaultItem: true } | ||||
| 			: { | ||||
| 				...g, | ||||
| 				selected: false, | ||||
| 				defaultItem: false, | ||||
| 			}, | ||||
| 	); | ||||
| } | ||||
|  | ||||
| export function switchObjToMap(games: Games) { | ||||
| 	// for (const [gameID, value] of Object.entries(games)) { | ||||
| 	//   map.set(gameID, value) | ||||
| 	// } | ||||
| 	return new Map(Object.entries(games)); | ||||
| } | ||||
|  | ||||
| export function hexToRgb( | ||||
| 	hex: string, | ||||
| 	// eslint-disable-next-line @typescript-eslint/typedef | ||||
| 	result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex), | ||||
| ) { | ||||
| 	const x = result ? result.map((i) => parseInt(i, 16)).slice(1) : null; | ||||
| 	return { | ||||
| 		r: x[0], | ||||
| 		g: x[1], | ||||
| 		b: x[2], | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| export function replaceBorderColor(string: string, color: string) { | ||||
| 	const hasComma = string.includes(","); | ||||
| 	if (hasComma) { | ||||
| 		const result = string.split(",").map((s, i) => { | ||||
| 			const index = s.indexOf("#"); | ||||
| 			const replaceStr = s.substring(index); | ||||
| 			return s.replace(replaceStr, i === 0 ? "black" : color); | ||||
| 		}); | ||||
| 		return result.join(","); | ||||
| 	} else { | ||||
| 		const index = string.indexOf("#"); | ||||
| 		const replaceStr = string.substring(index); | ||||
| 		return string.replace(replaceStr, color); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export function generateMessage(message: string) { | ||||
| 	return { | ||||
| 		AID: "10000000063", | ||||
| 		nickName: "masterkai", | ||||
| 		profileIMG: "./img/png/avatar.png", | ||||
| 		role: ChatRoomRole.player, | ||||
| 		message: message, | ||||
| 		created: getCurrentLocalTime(), | ||||
| 		vip: VIPLevelMapForChat.get(4), | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| export function getVIPLevelFromStr(vipStr: string) { | ||||
| 	const arr = vipStr.split("."); | ||||
| 	const str = arr[0]; | ||||
| 	return str.at(-1); | ||||
| } | ||||
|  | ||||
| interface Accumulator { | ||||
| 	[AID: number]: { | ||||
| 		AID: number; | ||||
| 		nickName: string; | ||||
| 		avatar: number; | ||||
| 		role: number; | ||||
| 		vip: number; | ||||
| 		messages: { | ||||
| 			message: string; | ||||
| 			created: number; | ||||
| 		}[]; | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| export function sleep(ms: any): Promise<any> { | ||||
| 	return new Promise((resolve) => setTimeout(resolve, ms)); | ||||
| } | ||||
|  | ||||
| export async function downloadJSON(formname: string) { | ||||
| 	const patchUrl: string = | ||||
| 		BusinessTypeSetting.UsePatch + BusinessTypeSetting.FolderUrlJson; | ||||
| 	let fileUrl: string = `${patchUrl}${formname}.json`; | ||||
| 	fileUrl = fileUrl + "?v=" + Date.now(); | ||||
| 	let resp: AxiosResponse<any, any> = null; | ||||
| 	axios.get(fileUrl).then((res: AxiosResponse<any, any>) => { | ||||
| 		loadJsonProcess(null, res, formname); | ||||
| 		resp = res; | ||||
| 	}); | ||||
| 	while (!resp) { | ||||
| 		await sleep(0.1); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| function loadJsonProcess( | ||||
| 	err: any, | ||||
| 	res: AxiosResponse<any, any>, | ||||
| 	formname: string, | ||||
| ) { | ||||
| 	res["name"] = formname; | ||||
| 	TableManager.AddJsonAsset(res.data); | ||||
| } | ||||
|  | ||||
| export function getProfileImgUrl(avatar: number, aId: number) { | ||||
| 	return avatar === 1 | ||||
| 		? `${BusinessTypeSetting.UseDownloadUrl}avatar/${aId}` | ||||
| 		: "./img/common/DefaultAvatar.png"; | ||||
| } | ||||
|  | ||||
| export const CssStringContent = ( | ||||
| 	StringKey: number, | ||||
| 	StringID: number | string, | ||||
| ): string => { | ||||
| 	switch (StringKey) { | ||||
| 		case StringContentType.String: | ||||
| 			return StringID?.toString(); | ||||
| 		case StringContentType.CSSString: | ||||
| 			return CSSettingsV3.prototype.CommonString(+StringID); | ||||
| 		case StringContentType.CSSMailString: | ||||
| 			return CSSettingsV3.prototype.CSSMailString(+StringID); | ||||
| 		case StringContentType.CSSNetworkString: | ||||
| 			return ""; // CSSettingsV3.Network.Priority[StringID][LanguageManager.GetMsgId()]; | ||||
| 		case StringContentType.HallString: | ||||
| 			/* 廳管1~4 但表格是從2號位開始 */ | ||||
| 			return CSSettingsV3.prototype.LobbyString(1 + +StringID); | ||||
|  | ||||
| 		default: | ||||
| 			break; | ||||
| 	} | ||||
| 	return; | ||||
| }; | ||||
|  | ||||
| export function txnDataTransformer( | ||||
| 	arr: TxnRequest.TxnInfo[], | ||||
| 	playerAid: number, | ||||
| ): TxnCenterData[] { | ||||
| 	return arr.map( | ||||
| 		([ | ||||
| 			sn, | ||||
| 			time, | ||||
| 			giver, | ||||
| 			receiver, | ||||
| 			status, | ||||
| 			fee, | ||||
| 			[[category, categoryId, quantity]], | ||||
| 		]) => ({ | ||||
| 			serialNum: sn, | ||||
| 			createdAt: time, | ||||
| 			giverAid: giver[0], | ||||
| 			giverName: giver[1], | ||||
| 			isGiver: giver[0] === playerAid, | ||||
| 			receiverAid: receiver[0], | ||||
| 			receiverName: receiver[1], | ||||
| 			status: +status, | ||||
| 			quantity, | ||||
| 			fee, | ||||
| 		}), | ||||
| 	); | ||||
| } | ||||
|  | ||||
| export function calculatedReward(rewards: [number, number][]) { | ||||
| 	const maximum = 6; | ||||
| 	const result = []; | ||||
| 	const couponType = ResourceItemType.Card_Coupon; | ||||
| 	rewards.forEach(([type, quantity]) => { | ||||
| 		if (type === couponType && quantity > maximum) { | ||||
| 			const packNum = Math.floor(quantity / maximum); | ||||
| 			const returnPack = Array.from({ length: packNum }, () => [ | ||||
| 				couponType, | ||||
| 				maximum, | ||||
| 			]); | ||||
| 			const remainder = quantity % maximum; | ||||
| 			const returnRemainder = remainder ? [couponType, remainder] : null; | ||||
| 			if (returnRemainder) { | ||||
| 				returnPack.push(returnRemainder); | ||||
| 			} | ||||
| 			returnPack.forEach((item) => result.push(item)); | ||||
| 		} else { | ||||
| 			result.push([type, quantity]); | ||||
| 		} | ||||
| 	}); | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| export const random = (min: number, max: number) => | ||||
| 	Math.floor(Math.random() * (max - min)) + min; | ||||
|  | ||||
| // Default color is a bright yellow | ||||
| const DEFAULT_COLOR = "hsl(50deg, 100%, 50%)"; | ||||
| export const generateSparkle = (color = DEFAULT_COLOR) => { | ||||
| 	return { | ||||
| 		id: "" + random(10000, 99999), | ||||
| 		createdAt: Date.now(), | ||||
| 		// Bright yellow color: | ||||
| 		color, | ||||
| 		size: random(20, 60), | ||||
| 		style: { | ||||
| 			// Pick a random spot in the available space | ||||
| 			top: random(0, 100) + "%", | ||||
| 			left: random(0, 100) + "%", | ||||
| 			// Float sparkles above sibling content | ||||
| 			zIndex: 2, | ||||
| 		}, | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| export const range = (start, end, step = 1) => { | ||||
| 	const output = []; | ||||
| 	if (typeof end === "undefined") { | ||||
| 		end = start; | ||||
| 		start = 0; | ||||
| 	} | ||||
| 	for (let i = start; i < end; i += step) { | ||||
| 		output.push(i); | ||||
| 	} | ||||
| 	return output; | ||||
| }; | ||||
|  | ||||
| export async function waitSetBusinessType() { | ||||
| 	while (!BusinessTypeSetting.UseHost) { | ||||
| 		await sleep(100); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 是否為好友 | ||||
|  * @param {number} aId AID | ||||
|  */ | ||||
| export function isMyFriend(aId: number): boolean { | ||||
| 	let isTrue: boolean = false; | ||||
| 	const playerData = Player.data.getState(); | ||||
| 	const lists: FriendRequest.ListFriendData = playerData.account.allowList; | ||||
| 	for (let i = 0; i < lists.length; i++) { | ||||
| 		const list: FriendRequest.SingleFriendData = lists[i]; | ||||
| 		if (list[0] === aId) { | ||||
| 			isTrue = true; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	return isTrue; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 是否為黑單 | ||||
|  * @param {number} aId AID | ||||
|  */ | ||||
| export function isMyDeny(aId: number): boolean { | ||||
| 	let isTrue: boolean = false; | ||||
| 	const playerData = Player.data.getState(); | ||||
| 	const lists: FriendRequest.ListFriendData = playerData.account.denyList; | ||||
| 	for (let i = 0; i < lists.length; i++) { | ||||
| 		const list: FriendRequest.SingleFriendData = lists[i]; | ||||
| 		if (list[0] === aId) { | ||||
| 			isTrue = true; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	return isTrue; | ||||
| } | ||||
|  | ||||
| export const sheetNameResourceTypeSwitcher = ( | ||||
| 	resourceType: ResourceItemType, | ||||
| ) => { | ||||
| 	switch (resourceType) { | ||||
| 		case ResourceItemType.Card_Coupon: | ||||
| 			return "CouponSetting"; | ||||
| 		case ResourceItemType.Card: | ||||
| 			return "Card1Setting"; | ||||
| 		default: | ||||
| 			return "Card1Setting"; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| export function escapeCodesNToBr(v: string): string { | ||||
| 	return v.replace(/\n/g, "<br>"); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 切割顯示字串長度 | ||||
|  * @param str | ||||
|  * @param showBytes 字元數(1中文2BYTES) | ||||
|  * @returns | ||||
|  */ | ||||
| export function trimString( | ||||
| 	str: string, | ||||
| 	showBytes: number = 12, | ||||
| 	ellipses: boolean = true, | ||||
| ): string { | ||||
| 	if (!str) { | ||||
| 		return str; | ||||
| 	} | ||||
| 	let bytes: number = stringWidth(str); | ||||
| 	if (bytes <= showBytes) { | ||||
| 		return str; | ||||
| 	} | ||||
| 	let byteAmount: number = 0; | ||||
| 	let strLength: number = str.length; | ||||
| 	for (let i: number = 0; i < strLength; i++) { | ||||
| 		let word: string = str[i]; | ||||
| 		bytes = stringWidth(word); | ||||
| 		byteAmount += bytes; | ||||
| 		if (byteAmount > showBytes) { | ||||
| 			let checkStr: string = str.substring(0, i + 1); | ||||
| 			let checkByte: number = stringWidth(checkStr); | ||||
| 			if (checkByte < showBytes) { | ||||
| 				byteAmount = checkByte; | ||||
| 				continue; | ||||
| 			} | ||||
| 			let result: string = str.substring(0, i); | ||||
| 			if (ellipses) { | ||||
| 				return result + "..."; | ||||
| 			} else { | ||||
| 				return result; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	console.error("Trim Nickname Error."); | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| /** CommonEventType */ | ||||
| export enum CommonEventType { | ||||
| 	/** Maintenance */ | ||||
| 	Maintenance, | ||||
| 	/**ActivityReRender */ | ||||
| 	ActivityReRender, | ||||
| } | ||||
|  | ||||
|  | ||||
| export function responsiveText(characters: number): number { | ||||
| 	if (characters <= 10) return 1.125; | ||||
| 	if (characters > 10 && characters <= 20) return 0.9; | ||||
| 	if (characters > 20) return 0.8; | ||||
| } | ||||
|  | ||||
| export function discount(numberOff: number): number { | ||||
| 	return (100 - numberOff) / 100; | ||||
| } | ||||
|  | ||||
| /** 預載字體 */ | ||||
| export function PreloadFont(fonts: string[]): void { | ||||
| 	// Check if API exists | ||||
| 	if (document && document.fonts) { | ||||
| 		// Do not block page loading | ||||
| 		setTimeout(function (): void { | ||||
| 			let successCount: number = 0; | ||||
| 			for (let i: number = 0; i < fonts.length; i++) { | ||||
| 				const font: string = fonts[i]; | ||||
| 				// eslint-disable-next-line no-loop-func | ||||
| 				document.fonts.load(`16px ${font}`).then(() => { | ||||
| 					// Make font using elements visible | ||||
| 					successCount++; | ||||
| 					if (successCount === fonts.length) { | ||||
| 						document.documentElement.classList.add("font-loaded"); | ||||
| 					} | ||||
| 				}); | ||||
| 			} | ||||
| 		}, 0); | ||||
| 	} else { | ||||
| 		// Fallback if API does not exist | ||||
| 		document.documentElement.classList.add("font-loaded"); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // PWA | ||||
| /** BeforeInstallPromptEvent */ | ||||
| export let deferredPrompt: any; | ||||
| window.addEventListener("beforeinstallprompt", (e) => { | ||||
| 	// Prevent Chrome 67 and earlier from automatically showing the prompt | ||||
| 	e.preventDefault(); | ||||
| 	// Stash the event so it can be triggered later. | ||||
| 	deferredPrompt = e; | ||||
| 	// Update UI to notify the user they can add to home screen | ||||
| 	Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.PWAInitOK, e); | ||||
| }); | ||||
| export function addToHomeScreen(): void { | ||||
| 	if (isMobile) { | ||||
| 		let url: string = | ||||
| 			BusinessTypeSetting.UsePatch + | ||||
| 			"addtohomescreen/index.html" + | ||||
| 			"?v=" + | ||||
| 			Date.now(); | ||||
| 		liff.openWindow({ | ||||
| 			url: url, | ||||
| 			external: true, | ||||
| 		}); | ||||
| 	} else { | ||||
| 		if (deferredPrompt) { | ||||
| 			// Show the prompt | ||||
| 			deferredPrompt.prompt(); | ||||
| 			// Wait for the user to respond to the prompt | ||||
| 			deferredPrompt.userChoice.then((choiceResult) => { | ||||
| 				if (choiceResult.outcome === "accepted") { | ||||
| 					// console.log("User accepted the A2HS prompt"); | ||||
| 					Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.PWAInitOK, false); | ||||
| 				} else { | ||||
| 					// console.log("User dismissed the A2HS prompt"); | ||||
| 				} | ||||
| 				deferredPrompt = null; | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export function getArray(count: number): number[] { | ||||
| 	const array: number[] = []; | ||||
| 	for (let i: number = 0; i < count; i++) { | ||||
| 		array.push(i); | ||||
| 	} | ||||
| 	return array; | ||||
| } | ||||
|  | ||||
| /** 判斷登入並且Line綁定完 */ | ||||
| export function checkWait(): boolean { | ||||
| 	const playerData = Player.data.getState(); | ||||
| 	const isLineBind: boolean = Player.hasUserBindFlag(UserBindFlag.LineBind); | ||||
| 	if (!BaseEnumerator.isInit) { | ||||
| 		return true; | ||||
| 	} else if (!CocosVueScript.Instance || !CocosVueScript.Instance?.GetLoginData()) { | ||||
| 		return true; | ||||
| 	} else if (!playerData.account.role && !isLineBind) { | ||||
| 		return true; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| export function scrollToBottom(dynamicListHeight: number, duration: number = 200) { | ||||
| 	Scroll.animateScroll.scrollTo(dynamicListHeight, { | ||||
| 		duration: duration, | ||||
| 		smooth: "easeInQuad", | ||||
| 		containerId: "scrollableDiv", | ||||
| 		offset: 50 | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| export function Copy(serialNum: string) { | ||||
| 	try { | ||||
| 		navigator.clipboard.writeText(serialNum); | ||||
| 	} | ||||
| 	catch (error) { | ||||
| 		console.error(error); | ||||
| 	} | ||||
| } | ||||
| export const fallImg: string = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="; | ||||
| @@ -1,235 +1,26 @@ | ||||
| import MainControl from "@/Common/MainControl/MainControl"; | ||||
| import { CoroutineV2 } from "@/Engine/CatanEngine/CoroutineV2/CoroutineV2"; | ||||
| import { TTeamBattleData } from "@/UI/RouterPage/GameContent/GameContentUtils"; | ||||
| import { Cocos } from "@/assets/VueScript/Cocos"; | ||||
| import { CommonEventCallBack } from "@/assets/VueScript/CocosVueScript"; | ||||
| import GameData_Cocos from "@/assets/VueScript/share/GameData_Cocos"; | ||||
| import { GiftCallBack, GiftEventEnum, PanelType, UpdateOneListInfo } from "@/components/ModalContent/TxnModal/txnUtils"; | ||||
| import CSMessage from "@/Common/Message/CSMessage"; | ||||
| import { INetResponse } from "@/Engine/CatanEngine/NetManagerV2/Core/INetResponse"; | ||||
| import { gameObj } from "@/context/GameItemsContext"; | ||||
| import { LocalStorage } from "@/define"; | ||||
| import { EActivitySyncType, RpcActivityComSyncResponse, TActivityComSyncData, TActivitySyncData } from "@/define/Request/ActivityRequest"; | ||||
| import { ResponseBackpackInfo } from "@/define/Request/BackpackRequest"; | ||||
| import { FriendRequest } from "@/define/Request/FriendRequest"; | ||||
| import { ProfileRequest } from "@/define/Request/ProfileRequest"; | ||||
| import { TxnRequest } from "@/define/Request/TxnRequest"; | ||||
| import { VipRequest } from "@/define/Request/VIPRequest"; | ||||
| import Player from "@/modules/player"; | ||||
| import { State } from "@/modules/player/define/data"; | ||||
| import { BackpackItemData } from "@/modules/player/define/data/backpack"; | ||||
| import { CommonEventType } from "."; | ||||
| import { GameInfoRequest } from "@/define/Request/GameRequest"; | ||||
|  | ||||
| let SN: number = 0; | ||||
|  | ||||
| export function profileInfo(data: ProfileRequest.InfoResponse): void { | ||||
| 	const playerData: State = Player.data.getState(); | ||||
| 	if (data.aId !== playerData.account.aId) { | ||||
| export function* gameSync(): IterableIterator<any> { | ||||
| 	const { gameData, setGameData } = gameObj; | ||||
| 	let req: GameInfoRequest = new GameInfoRequest(); | ||||
| 	yield req.SendAsync(); | ||||
| 	let resp: INetResponse<JSON> = req.Result; | ||||
| 	/** 0是UUID 1[0]是機台相關資訊 1[1]排序 */ | ||||
| 	if (resp.IsValid) { | ||||
| 		const respD: any = resp.Data; | ||||
| 	} else { | ||||
| 		CSMessage.NetError(resp.Method, resp.Status, "Get GameInfoRequest Error"); | ||||
| 		return; | ||||
| 	} | ||||
| 	playerData.account.name = data.name; | ||||
| 	playerData.account.message = data.msg; | ||||
| 	playerData.account.phone = data.phone; | ||||
| 	playerData.account.money = data.money; | ||||
| 	playerData.vip.level = data.vip; | ||||
| 	Player.data.setState(playerData); | ||||
| } | ||||
|  | ||||
| export function vipInfo(data: VipRequest.InfoResponse): void { | ||||
| 	const playerData: State = Player.data.getState(); | ||||
| 	playerData.vip.level = data.level; | ||||
| 	playerData.vip.totalBet = data.bet; | ||||
| 	playerData.vip.totalCharge = data.sv; | ||||
| 	playerData.vip.rich = data.rich; | ||||
| 	playerData.vip.et = data.et; | ||||
| 	Player.data.setState(playerData); | ||||
| } | ||||
|  | ||||
| export function friendAllowList(data: FriendRequest.ListFriendData): void { | ||||
| 	const playerData: State = Player.data.getState(); | ||||
| 	playerData.account.allowList = data; | ||||
| 	Player.data.setState(playerData); | ||||
| } | ||||
|  | ||||
| export function friendDenyList(data: FriendRequest.ListFriendData): void { | ||||
| 	const playerData: State = Player.data.getState(); | ||||
| 	playerData.account.denyList = data; | ||||
| 	Player.data.setState(playerData); | ||||
| } | ||||
|  | ||||
| export function activityComSync(data: RpcActivityComSyncResponse): void { | ||||
| 	const { teamBattleData, setTeamBattleData } = gameObj; | ||||
| 	for (let i = 0; i < data.length; i++) { | ||||
| 		const activityComSyncData: TActivityComSyncData = data[i]; | ||||
| 		const [id, activitySyncDatas] = activityComSyncData; | ||||
| 		// for (let j = 0; j < teamBattleData.length; j++) { | ||||
| 		// 	const teamBattle: TTeamBattleData = teamBattleData[j]; | ||||
| 		// 	const [teamBattleId, , ,] = teamBattle; | ||||
| 		// 	if (id === teamBattleId) { | ||||
| 		// 		for (let k = 0; k < activitySyncDatas.length; k++) { | ||||
| 		// 			const activitySyncData: TActivitySyncData = activitySyncDatas[k]; | ||||
| 		// 			const [type, value] = activitySyncData; | ||||
| 		// 			switch (type) { | ||||
| 		// 				case EActivitySyncType.IsOpen: { | ||||
| 		// 					teamBattleData[j][1] = -1; | ||||
| 		// 					setTeamBattleData(teamBattleData); | ||||
| 		// 					break; | ||||
| 		// 				} | ||||
|  | ||||
| 		// 				case EActivitySyncType.Sync: { | ||||
| 		// 					teamBattleData[j][1] = value; | ||||
| 		// 					setTeamBattleData(teamBattleData); | ||||
| 		// 					break; | ||||
| 		// 				} | ||||
|  | ||||
| 		// 				case EActivitySyncType.Task: { | ||||
|  | ||||
| 		// 					break; | ||||
| 		// 				} | ||||
|  | ||||
| 		// 				default: | ||||
| 		// 					break; | ||||
| 		// 			} | ||||
| 		// 		} | ||||
| 		// 		break; | ||||
| 		// 	} | ||||
| 		// } | ||||
|  | ||||
|  | ||||
| 		for (let j = 0; j < activitySyncDatas.length; j++) { | ||||
| 			const activitySyncData: TActivitySyncData = activitySyncDatas[j]; | ||||
| 			const [type, value] = activitySyncData; | ||||
| 			switch (type) { | ||||
| 				case EActivitySyncType.IsOpen: { | ||||
| 					// for (let k = 0; k < teamBattleData.length; k++) { | ||||
| 					// 	const teamBattle: TTeamBattleData = teamBattleData[k]; | ||||
| 					// 	const [teamBattleId, , ,] = teamBattle; | ||||
| 					// 	if (id === teamBattleId) { | ||||
| 					// 		teamBattleData[j][1] = value; | ||||
| 					// 		setTeamBattleData(teamBattleData); | ||||
| 					// 		break; | ||||
| 					// 	} | ||||
| 					// } | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 				case EActivitySyncType.Sync: { | ||||
| 					for (let k = 0; k < teamBattleData.length; k++) { | ||||
| 						const teamBattle: TTeamBattleData = teamBattleData[k]; | ||||
| 						const [teamBattleId, , ,] = teamBattle; | ||||
| 						if (id === teamBattleId) { | ||||
| 							teamBattleData[j][1] = value; | ||||
| 							setTeamBattleData(teamBattleData); | ||||
| 							break; | ||||
| 						} | ||||
| 					} | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 				case EActivitySyncType.Task: { | ||||
|  | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 				default: | ||||
| 					break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	CommonEventCallBack.DispatchCallback(CommonEventType.ActivityReRender, null); | ||||
| } | ||||
|  | ||||
| export function backpackInfo(data: ResponseBackpackInfo[], isAdd: boolean = false): void { | ||||
| 	const playerData: State = Player.data.getState(); | ||||
| 	const backpackList: BackpackItemData[] = isAdd ? playerData.backpack.Copy() : []; | ||||
| 	for (let i = 0; i < data.length; i++) { | ||||
| 		const backpackServerData = data[i]; | ||||
| 		const id: number = backpackServerData[1][0]; | ||||
| 		const count: number = backpackServerData[1][1]; | ||||
| 		for (let j = 0; j < count; j++) { | ||||
| 			const backpackClientData: BackpackItemData = { | ||||
| 				SN: SN, | ||||
| 				ResourceType: backpackServerData[0], | ||||
| 				ID: id, | ||||
| 				Viewed: false, | ||||
| 			}; | ||||
| 			backpackList.push(backpackClientData); | ||||
| 			SN++; | ||||
| 		} | ||||
| 	} | ||||
| 	if (!isAdd) { | ||||
| 		const oldBackpackListStr: string = localStorage.getItem(LocalStorage.Key.Backpack); | ||||
| 		if (oldBackpackListStr) { | ||||
| 			const oldBackpackList: BackpackItemData[] = JSON.parse(oldBackpackListStr); | ||||
| 			for (let i = 0; i < backpackList.length; i++) { | ||||
| 				const backpack: BackpackItemData = backpackList[i]; | ||||
| 				for (let j = 0; j < oldBackpackList.length; j++) { | ||||
| 					const oldBackpack: BackpackItemData = oldBackpackList[j]; | ||||
| 					if (backpack.ID === oldBackpack.ID && backpack.ResourceType === oldBackpack.ResourceType) { | ||||
| 						backpackList[i].Viewed = oldBackpack.Viewed; | ||||
| 						oldBackpackList.splice(j, 1); | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	playerData.backpack = backpackList; | ||||
| 	localStorage.setItem(LocalStorage.Key.Backpack, JSON.stringify(playerData.backpack)); | ||||
| 	Player.data.setState(playerData); | ||||
|  | ||||
| 	const totalUnreadCount: number = playerData.backpack.filter((item) => !item.Viewed).length; | ||||
| 	if (!MainControl.Instance.IsInGame) { | ||||
| 		Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.SetBackpackUnreadCount, totalUnreadCount); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| export function txnNew(data: TxnRequest.TxnInfo): void { | ||||
| 	const playerData = Player.data.getState(); | ||||
| 	const centerList = playerData.txn.centerList.slice(); | ||||
| 	centerList.push(data); | ||||
| 	playerData.txn.centerList = centerList; | ||||
| 	GiftCallBack.DispatchCallback(GiftEventEnum.ReFlash, null); | ||||
| 	Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.SetTxnUnreadCount, playerData.txn.centerList.length); | ||||
| 	Player.data.setState(playerData); | ||||
| } | ||||
|  | ||||
| export function txnCenter(data: TxnRequest.TxnInfo[]): void { | ||||
| 	const playerData = Player.data.getState(); | ||||
| 	playerData.txn.centerList = data; | ||||
| 	GiftCallBack.DispatchCallback(GiftEventEnum.ReFlash, null); | ||||
| 	Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.SetTxnUnreadCount, playerData.txn.centerList.length); | ||||
| 	Player.data.setState(playerData); | ||||
| } | ||||
|  | ||||
| export function txnTrade(data: TxnRequest.TradeResponse): void { | ||||
| 	const playerData: State = Player.data.getState(); | ||||
| 	const centerList: TxnRequest.TxnInfo[] = playerData.txn.centerList; | ||||
| 	let type: number = PanelType.RecordPanel; | ||||
| 	let status: number = +data.s; | ||||
| 	if (status < 20) { | ||||
| 		type = PanelType.CenterPanel; | ||||
| 		switch (status) { | ||||
| 			case 11: | ||||
| 			case 12: | ||||
| 			case 13: { | ||||
| 				for (let i: number = 0; i < centerList.length; i++) { | ||||
| 					const centerData: TxnRequest.TxnInfo = centerList[i]; | ||||
| 					if (centerData[0] == +data.id && centerData[3][0] == playerData.account.aId) { | ||||
| 						type = PanelType.RecordPanel; | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 			} | ||||
| 			default: | ||||
| 				break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	CoroutineV2.Single(UpdateOneListInfo(data.id, type)).Start(); | ||||
| } | ||||
|  | ||||
| export function txnUserAdd(data: TxnRequest.UserAddResponse): void { | ||||
| 	const playerData: State = Player.data.getState(); | ||||
| 	playerData.txn.receiverList.push(data.u); | ||||
| 	Player.data.setState(playerData); | ||||
| 	const data: any = JSON.parse(resp.Data[1]); | ||||
| 	const slotData = data[0]; | ||||
| 	const slotList: number[] = data[1][0]; | ||||
| 	setGameData({ | ||||
| 		...gameData, | ||||
| 		slotData, | ||||
| 		slotList | ||||
| 	}); | ||||
| } | ||||
| @@ -13,7 +13,7 @@ | ||||
| 		"allowSyntheticDefaultImports": true, | ||||
| 		"strict": false, | ||||
| 		"strictNullChecks": false, | ||||
| 		"forceConsistentCasingInFileNames": true, | ||||
| 		"forceConsistentCasingInFileNames": false, | ||||
| 		"noFallthroughCasesInSwitch": true, | ||||
| 		"module": "esnext", | ||||
| 		"moduleResolution": "node", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user