279 lines
7.6 KiB
JavaScript
279 lines
7.6 KiB
JavaScript
const service = require("../../services/game-service");
|
|
const { formatCountdown, formatTime } = require("../../utils/format");
|
|
|
|
Page({
|
|
data: {
|
|
code: "",
|
|
room: null,
|
|
me: null,
|
|
readyToRender: false,
|
|
stageLabel: "",
|
|
countdown: "00:00",
|
|
survivors: 0,
|
|
seekers: 0,
|
|
captureCode: "",
|
|
captureTargets: [],
|
|
selectedTargetId: "",
|
|
submittedCode: "",
|
|
skillUsed: false,
|
|
canManage: false,
|
|
showDemoCode: false,
|
|
captureSubmitting: false,
|
|
errorMessage: "",
|
|
eventViews: []
|
|
},
|
|
|
|
onLoad(options) {
|
|
this.setData({ code: options.code || "" });
|
|
this.tick();
|
|
},
|
|
|
|
onShow() {
|
|
if (!this.data.code) return;
|
|
this.startTimer();
|
|
this.tick();
|
|
},
|
|
|
|
onHide() {
|
|
this.stopTimer();
|
|
},
|
|
|
|
onUnload() {
|
|
this.stopTimer();
|
|
},
|
|
|
|
startTimer() {
|
|
this.stopTimer();
|
|
this.timer = setInterval(() => this.tick(), 1000);
|
|
},
|
|
|
|
stopTimer() {
|
|
if (!this.timer) return;
|
|
clearInterval(this.timer);
|
|
this.timer = null;
|
|
},
|
|
|
|
tick() {
|
|
let room = service.getRoom(this.data.code);
|
|
if (!room) {
|
|
this.stopTimer();
|
|
this.setData({ readyToRender: false, errorMessage: "房间不存在或游戏数据已被清理" });
|
|
return;
|
|
}
|
|
if (room.status === "preparing" && Date.now() >= room.phaseEndsAt) {
|
|
room = service.beginPlaying(room.code);
|
|
wx.vibrateLong();
|
|
}
|
|
if (room.status === "playing") {
|
|
if (Date.now() >= room.phaseEndsAt) {
|
|
service.finishGame(room.code, "hiders", null, "timeout");
|
|
this.goResult();
|
|
return;
|
|
}
|
|
if (room.nextClueAt && Date.now() >= room.nextClueAt) {
|
|
service.revealClue(room.code);
|
|
wx.vibrateShort({ type: "medium" });
|
|
}
|
|
}
|
|
if (room.status === "finished") {
|
|
this.goResult();
|
|
return;
|
|
}
|
|
this.refresh();
|
|
},
|
|
|
|
refresh() {
|
|
const room = service.getRoom(this.data.code);
|
|
if (!room) {
|
|
this.stopTimer();
|
|
this.setData({ readyToRender: false, errorMessage: "房间不存在或游戏数据已被清理" });
|
|
return;
|
|
}
|
|
const me =
|
|
room.players.find((player) => player.id === service.USER_ID) ||
|
|
room.players[0];
|
|
const seconds = room.status === "paused"
|
|
? Math.ceil(room.pausedRemainingMs / 1000)
|
|
: Math.ceil((room.phaseEndsAt - Date.now()) / 1000);
|
|
const survivors = room.players.filter(
|
|
(player) => player.role === "hider" && player.status === "hiding"
|
|
).length;
|
|
const seekers = room.players.filter(
|
|
(player) => player.role === "seeker"
|
|
).length;
|
|
const captureTargets = room.players.filter(
|
|
(player) => player.role === "hider" && player.status === "hiding"
|
|
);
|
|
const selectedTargetId = captureTargets.some(
|
|
(player) => player.id === this.data.selectedTargetId
|
|
)
|
|
? this.data.selectedTargetId
|
|
: captureTargets.length ? captureTargets[0].id : "";
|
|
const currentSkill = me.role === "seeker" ? "radar" : "silent";
|
|
const captureCode = me.role === "seeker"
|
|
? service.getCaptureCode(room.code, selectedTargetId)
|
|
: service.getCaptureCode(room.code, me.id);
|
|
this.setData({
|
|
room,
|
|
errorMessage: "",
|
|
me,
|
|
readyToRender: true,
|
|
stageLabel: room.status === "preparing"
|
|
? "躲藏准备"
|
|
: room.status === "paused" ? "游戏已暂停" : "追逃进行中",
|
|
countdown: formatCountdown(seconds),
|
|
survivors,
|
|
seekers,
|
|
captureTargets,
|
|
selectedTargetId,
|
|
captureCode,
|
|
skillUsed: Boolean(me.skillsUsed && me.skillsUsed[currentSkill] > 0),
|
|
canManage: room.hostId === service.USER_ID || room.code === "731204",
|
|
showDemoCode: Boolean(room.runtime && room.runtime.demoAccelerated),
|
|
eventViews: room.events.slice(0, 6).map((event) => ({
|
|
...event,
|
|
time: formatTime(event.createdAt)
|
|
}))
|
|
});
|
|
},
|
|
|
|
useSkill() {
|
|
if (this.data.skillUsed) {
|
|
wx.showToast({ title: "本局体验技能已使用", icon: "none" });
|
|
return;
|
|
}
|
|
const skill = this.data.me.role === "seeker" ? "radar" : "silent";
|
|
try {
|
|
service.useSkill(this.data.code, skill);
|
|
wx.vibrateShort({ type: "heavy" });
|
|
this.refresh();
|
|
} catch (error) {
|
|
wx.showToast({ title: error.message, icon: "none" });
|
|
}
|
|
},
|
|
|
|
chooseCaptureTarget(event) {
|
|
this.setData({
|
|
selectedTargetId: event.currentTarget.dataset.id,
|
|
submittedCode: ""
|
|
});
|
|
this.refresh();
|
|
},
|
|
|
|
inputCaptureCode(event) {
|
|
this.setData({
|
|
submittedCode: event.detail.value.replace(/\D/g, "").slice(0, 4)
|
|
});
|
|
},
|
|
|
|
fillDemoCode() {
|
|
this.setData({ submittedCode: this.data.captureCode });
|
|
},
|
|
|
|
submitCapture() {
|
|
if (this.data.captureSubmitting) return;
|
|
this.setData({ captureSubmitting: true });
|
|
try {
|
|
const room = service.capture(
|
|
this.data.code,
|
|
this.data.selectedTargetId,
|
|
this.data.submittedCode
|
|
);
|
|
wx.vibrateLong();
|
|
this.setData({ submittedCode: "" });
|
|
if (room.status === "finished") {
|
|
this.goResult();
|
|
} else {
|
|
this.setData({ captureSubmitting: false });
|
|
wx.showToast({ title: "抓捕成功", icon: "success" });
|
|
this.refresh();
|
|
}
|
|
} catch (error) {
|
|
this.setData({ captureSubmitting: false });
|
|
wx.showToast({ title: error.message, icon: "none" });
|
|
}
|
|
},
|
|
|
|
showSafety() {
|
|
wx.showActionSheet({
|
|
itemList: ["我已安全,继续游戏", "联系房主", "退出并前往集合点"],
|
|
success: (result) => {
|
|
if (result.tapIndex === 1) {
|
|
wx.showModal({
|
|
title: "联系房主",
|
|
content: "当前原型暂不提供即时通讯,请通过约定的电话或微信联系房主。",
|
|
showCancel: false
|
|
});
|
|
}
|
|
if (result.tapIndex === 2) {
|
|
wx.showModal({
|
|
title: "确认退出?",
|
|
content: "请先确保自己处于安全位置,并前往约定集合点。",
|
|
confirmText: "安全退出",
|
|
confirmColor: "#d9554d",
|
|
success: (modalResult) => {
|
|
if (!modalResult.confirm) return;
|
|
try {
|
|
const room = service.quitGame(this.data.code);
|
|
if (room.status === "finished") {
|
|
this.goResult();
|
|
} else {
|
|
this.stopTimer();
|
|
service.clearCurrentRoom();
|
|
wx.reLaunch({ url: "/pages/home/home" });
|
|
}
|
|
} catch (error) {
|
|
wx.showToast({ title: error.message, icon: "none" });
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
togglePause() {
|
|
try {
|
|
if (this.data.room.status === "paused") {
|
|
service.resumeGame(this.data.code);
|
|
} else {
|
|
service.pauseGame(this.data.code);
|
|
}
|
|
this.refresh();
|
|
} catch (error) {
|
|
wx.showToast({ title: error.message, icon: "none" });
|
|
}
|
|
},
|
|
|
|
finishEarly() {
|
|
wx.showModal({
|
|
title: "提前结束游戏?",
|
|
content: "系统将根据当前存活情况立即生成本局战报。",
|
|
confirmText: "结束游戏",
|
|
confirmColor: "#d9554d",
|
|
success: (result) => {
|
|
if (!result.confirm) return;
|
|
try {
|
|
service.finishGame(this.data.code, "", service.USER_ID, "host_ended");
|
|
this.goResult();
|
|
} catch (error) {
|
|
wx.showToast({ title: error.message, icon: "none" });
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
goResult() {
|
|
this.stopTimer();
|
|
wx.redirectTo({
|
|
url: `/pages/result/result?code=${this.data.code}`
|
|
});
|
|
},
|
|
|
|
backHome() {
|
|
this.stopTimer();
|
|
service.clearCurrentRoom();
|
|
wx.reLaunch({ url: "/pages/home/home" });
|
|
}
|
|
});
|