2023-12-06 15:01:33 +08:00
|
|
|
import MainControl from "@/Common/MainControl/MainControl";
|
2023-12-05 17:27:18 +08:00
|
|
|
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";
|
2023-12-06 15:01:33 +08:00
|
|
|
import CSSettingsSDV3 from "@/FormTableSD/CSSettingsSDV3";
|
|
|
|
import { SlotsetTableRow } from "@/FormTableSD/Tables/SlotsetTable";
|
2023-12-06 13:56:43 +08:00
|
|
|
import A from "@/components/CustomA";
|
2023-12-05 17:27:18 +08:00
|
|
|
import { useGameItems } from "@/context/GameItemsContext";
|
|
|
|
import { SDAccountLoginRequest } from "@/define/Request/AccountRequest";
|
|
|
|
import { SlotInRequest } from "@/define/Request/SlotRequest";
|
2023-12-06 13:56:43 +08:00
|
|
|
import GameManager from "@/modules/GameManager";
|
|
|
|
import { Button, Checkbox, Dropdown, Flex, Input, MenuProps } from "antd";
|
|
|
|
import { CheckboxChangeEvent } from "antd/es/checkbox";
|
2023-12-06 15:01:33 +08:00
|
|
|
import dayjs from "dayjs";
|
2023-12-06 13:56:43 +08:00
|
|
|
import { ChangeEvent, useEffect, useState } from "react";
|
2023-12-05 17:27:18 +08:00
|
|
|
|
|
|
|
const SDGame = (props: ISDGame) => {
|
|
|
|
const { gameUrl, onClickSlotOut } = props;
|
|
|
|
const { player, setPlayer } = useGameItems();
|
|
|
|
const { gameData } = useGameItems();
|
2023-12-06 15:01:33 +08:00
|
|
|
const { m: money } = player;
|
2023-12-05 17:27:18 +08:00
|
|
|
const { nowSlotId } = gameData;
|
2023-12-06 13:56:43 +08:00
|
|
|
const [isOK, setIsOK] = useState<boolean>(false);
|
|
|
|
const [isSpin, setIsSpin] = useState<boolean>(false);
|
|
|
|
const [items, setItems] = useState<MenuProps["items"]>([]);
|
|
|
|
const [bet, setBet] = useState<number>(0);
|
|
|
|
const [delay, setDelay] = useState<number>(0.1);
|
2023-12-06 15:01:33 +08:00
|
|
|
const [isRatioStop, setIsRatioStop] = useState<boolean>(false);
|
|
|
|
const [ratioStop, setRatioStop] = useState<number>(200);
|
|
|
|
const [isCountStop, setIsCountStop] = useState<boolean>(false);
|
|
|
|
const [countStop, setCountStop] = useState<number>(200);
|
2023-12-06 13:56:43 +08:00
|
|
|
const [log, setLog] = useState<string[]>([]);
|
2023-12-05 17:27:18 +08:00
|
|
|
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;
|
|
|
|
|
2023-12-06 13:56:43 +08:00
|
|
|
GameManager.SlotData.SlotId = slotid;
|
2023-12-06 15:12:26 +08:00
|
|
|
GameManager.SlotData.IsRatioStop = isRatioStop;
|
|
|
|
GameManager.SlotData.RatioStop = ratioStop;
|
|
|
|
GameManager.SlotData.IsCountStop = isCountStop;
|
|
|
|
GameManager.SlotData.CountStop = countStop;
|
2023-12-05 17:27:18 +08:00
|
|
|
conn = new NetConnector("https://" + host, port);
|
|
|
|
conn.OnDataReceived.AddCallback(onNetDataReceived);
|
|
|
|
conn.OnDisconnected.AddCallback(onNetDisconnected);
|
2023-12-06 15:01:33 +08:00
|
|
|
loadJSON(slotid);
|
2023-12-06 13:56:43 +08:00
|
|
|
setSlotClass();
|
2023-12-05 17:27:18 +08:00
|
|
|
NetManagerSD.Initialize(conn);
|
|
|
|
console.log("[SDsocket] connecting...");
|
|
|
|
yield NetManagerSD.ConnectAsync();
|
|
|
|
yield* login(token);
|
2023-12-06 13:56:43 +08:00
|
|
|
yield* slotIn();
|
2023-12-05 17:27:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-06 13:56:43 +08:00
|
|
|
function* slotIn(): IterableIterator<any> {
|
|
|
|
let req: SlotInRequest = new SlotInRequest(GameManager.SlotData.SlotId);
|
2023-12-05 17:27:18 +08:00
|
|
|
yield req.SendAsync(true);
|
|
|
|
let resp: INetResponse<JSON> = req.Result;
|
|
|
|
if (resp.IsValid) {
|
2023-12-06 13:56:43 +08:00
|
|
|
const br: number[] = resp.Data["br"];
|
|
|
|
const db: number = resp.Data["db"];
|
|
|
|
const betGroup: MenuProps["items"] = [];
|
|
|
|
for (let i = 0; i < br.length; i++) {
|
|
|
|
betGroup.push({
|
|
|
|
key: i,
|
|
|
|
label: (
|
|
|
|
<A href="#" onClick={() => { setBet(br[i]); GameManager.SlotData.NowBet = br[i]; }}>
|
|
|
|
{br[i]}
|
|
|
|
</A>
|
|
|
|
),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
setItems(betGroup);
|
|
|
|
setBet(br[db]);
|
|
|
|
GameManager.SlotData.NowBet = br[db];
|
|
|
|
setIsOK(true);
|
2023-12-05 17:27:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-06 15:01:33 +08:00
|
|
|
async function loadJSON(slotid: number) {
|
|
|
|
let slotset: SlotsetTableRow = CSSettingsSDV3.Slotset[slotid];
|
|
|
|
let formName: string[] = slotset.FormName;
|
|
|
|
let parallel: Promise<void>[] = [];
|
|
|
|
for (let i: number = 0; i < formName.length; i++) {
|
|
|
|
await MainControl.DownloadFormSetting(formName[i]);
|
|
|
|
}
|
|
|
|
// set Form
|
|
|
|
await Promise.all(parallel);
|
|
|
|
}
|
|
|
|
|
2023-12-06 13:56:43 +08:00
|
|
|
async function setSlotClass() {
|
2023-12-05 17:27:18 +08:00
|
|
|
let slot: any;
|
|
|
|
const slotGroup: typeof import("../../define/Game/Base/Slot") = await import(/* @vite-ignore */`../../define/Game/Base/Slot`);
|
|
|
|
try {
|
2023-12-06 13:56:43 +08:00
|
|
|
slot = slotGroup[`Slot${GameManager.SlotData.SlotId}`];
|
2023-12-05 17:27:18 +08:00
|
|
|
} catch (error) {
|
|
|
|
//
|
|
|
|
}
|
|
|
|
if (!slot) {
|
|
|
|
slot = slotGroup.SlotBase;
|
|
|
|
}
|
2023-12-06 15:01:33 +08:00
|
|
|
GameManager.SlotData.SlotClass = new slot(GameManager.SlotData.SlotId, AddLog);
|
2023-12-06 13:56:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
async function OnClickSpin() {
|
|
|
|
GameManager.SlotData.IsSpin = true;
|
|
|
|
setIsSpin(true);
|
|
|
|
CoroutineV2.Single(spin()).Start();
|
|
|
|
}
|
|
|
|
|
|
|
|
function OnClickStop() {
|
|
|
|
GameManager.SlotData.IsSpin = false;
|
|
|
|
setIsSpin(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
function* spin(): IterableIterator<any> {
|
2023-12-06 15:01:33 +08:00
|
|
|
if (money < GameManager.SlotData.NowBet) {
|
|
|
|
noMoney();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (isCountStop) {
|
|
|
|
if (GameManager.SlotData.CountStop <= 0) {
|
|
|
|
OnClickStop();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
GameManager.SlotData.CountStop--;
|
|
|
|
setCountStop((v) => v - 1);
|
|
|
|
}
|
|
|
|
yield* GameManager.SlotData.SlotClass.Spin(bet, OnClickStop);
|
2023-12-06 13:56:43 +08:00
|
|
|
yield CoroutineV2.WaitTime(delay);
|
|
|
|
if (GameManager.SlotData.IsSpin) {
|
|
|
|
yield* spin();
|
|
|
|
} else {
|
2023-12-06 15:01:33 +08:00
|
|
|
GameManager.SlotData.IsSpin = false;
|
2023-12-06 13:56:43 +08:00
|
|
|
setIsSpin(false);
|
|
|
|
}
|
2023-12-05 17:27:18 +08:00
|
|
|
}
|
|
|
|
|
2023-12-06 15:01:33 +08:00
|
|
|
function noMoney(): void {
|
|
|
|
GameManager.SlotData.IsSpin = false;
|
|
|
|
AddLog(`金額不足: ${money}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
function AddLog(s: string) {
|
|
|
|
const todayTimeStr: string = dayjs().format("YYYY/MM/DD 00:00:00");
|
2023-12-06 13:56:43 +08:00
|
|
|
setLog((v) => {
|
|
|
|
if (v.length > 100) {
|
|
|
|
v.pop();
|
|
|
|
}
|
2023-12-06 15:01:33 +08:00
|
|
|
v.unshift(`${todayTimeStr} ${s}`);
|
2023-12-06 13:56:43 +08:00
|
|
|
return v;
|
|
|
|
});
|
2023-12-05 17:27:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**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}>
|
2023-12-06 13:56:43 +08:00
|
|
|
{isOK &&
|
|
|
|
<Flex gap="small" wrap="wrap">
|
|
|
|
<div style={controlStyle}>
|
|
|
|
<p>
|
|
|
|
押注
|
|
|
|
<Dropdown menu={{ items }} placement="bottom">
|
|
|
|
<Button>{bet}</Button>
|
|
|
|
</Dropdown>
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
延遲
|
|
|
|
<Input onInput={(e: ChangeEvent<HTMLInputElement>) => setDelay(+e.target.value)} type="text" value={delay} placeholder={delay.toString()} style={{ width: "10%" }} />
|
|
|
|
秒
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
倍率
|
2023-12-06 15:01:33 +08:00
|
|
|
<Checkbox onChange={(e: CheckboxChangeEvent) => { setIsRatioStop(e.target.checked); GameManager.SlotData.IsRatioStop = e.target.checked; }} />
|
|
|
|
{isRatioStop && <><Input onInput={(e: ChangeEvent<HTMLInputElement>) => { setRatioStop(+e.target.value); GameManager.SlotData.RatioStop = +e.target.value; }} type="text" value={ratioStop} placeholder={ratioStop.toString()} style={{ width: "10%" }} />倍</>}
|
2023-12-06 13:56:43 +08:00
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
轉數
|
2023-12-06 15:01:33 +08:00
|
|
|
<Checkbox onChange={(e: CheckboxChangeEvent) => { setIsCountStop(e.target.checked); GameManager.SlotData.IsCountStop = e.target.checked; }} />
|
|
|
|
{isCountStop && <><Input onInput={(e: ChangeEvent<HTMLInputElement>) => { setCountStop(+e.target.value); GameManager.SlotData.CountStop = +e.target.value; }} type="text" value={countStop} placeholder={countStop.toString()} style={{ width: "10%" }} />轉</>}
|
2023-12-06 13:56:43 +08:00
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
{isSpin
|
|
|
|
? <Button type="primary" onClick={OnClickStop} style={{ width: "20%" }}>Stop</Button>
|
|
|
|
: <Button type="primary" onClick={OnClickSpin} style={{ width: "20%" }}>Spin</Button>
|
|
|
|
}
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div style={{ height: "90vh", position: "relative", top: "0%", overflowY: "scroll" }}>
|
|
|
|
{log.map((log: string, index: number) => <p key={index}>{log}</p>)}
|
|
|
|
</div>
|
|
|
|
</Flex>}
|
|
|
|
<Button type="primary" danger onClick={onClickSlotOut} style={{ width: "20%", position: "fixed", bottom: "1%" }}>離開機台</Button>
|
2023-12-05 17:27:18 +08:00
|
|
|
</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%"
|
|
|
|
};
|