Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
216 changes: 216 additions & 0 deletions 2001/ze_the_curse_of_blackwater/countdown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
//纯预设模版的倒计时脚本,游戏内对point_script实体输入RunScriptInput,值为endin_30,则触发30秒内结束战斗的倒计时
//回合重启或者输入值为stop时倒计时会直接停止
//局内需存在以下实体
//①、一个game_zone_player固实体,命名为countdown_game_zone_player_hide,实体内io:OnPlayerOutZone>countdown_hudhint>HideHudHint>>0>-1
//②、一个game_zone_player固实体,命名为countdown_game_zone_player_show,实体内io:OnPlayerOutZone>countdown_hudhint>ShowHudHint>>0>-1
//③、一个env_hudhint点实体,命名为countdown_hudhint
//④、一个point_script点实体,命名为countdown_script,并应用上该vjs
//纯数字倒计时和其他倒计时可以在文本模版和预设倒计时模版那里添加即可
import { Instance } from "cs_script/point_script";

// ============= 配置区域 =============
const CONFIG = {
ENTITY_NAMES: {
HUD_HINT: "countdown_hudhint",
ZONE_SHOW: "countdown_game_zone_player_show",
ZONE_HIDE: "countdown_game_zone_player_hide",
},
THINK_INTERVAL: 0.1,
ZERO_DISPLAY_TIME: 0.5 // 0 显示多久后消失(秒)
};

// 文本模板
const TEMPLATES = {
gateopen: "Gate will open in {time} sec",
dooropen: "Door will open in {time} sec",
doorclose: "Door will close in {time} sec",
doorbreak: "Door will break in {time} sec",
doormainofficeopen: "Door to the main office will open in {time} sec",
officedoorswillclose: "Office doors will close in {time} sec",
officedoorswillopen: "Office doors will open in {time} sec",
doorintooffice: "Door into office will open in {time} sec",
doortotherightside: "Door to the right side of the lab will open in {time} sec",
doorstoblackwaterundergroundlab: "Doors to Blackwater underground lab will open in {time} sec",
doortomainlabopen: "Door to main lab will open in {time} sec",
doortostorageroomopen: "Door to storage room will open in {time} sec",
doorwiththirdleveropen: "Door with third lever will open in {time} sec",
elevatorwillleave: "Elevator will leave in {time} sec",
emergencyexitopen: "The emergency exit will open in {time} sec",
secondlabopen: "Door to 2-nd lab will open in {time} sec",
sewerdooropen: "Sewer door will open in {time} sec",
secondleveropen: "Door with second lever will open in {time} sec",
firstleveropen: "Door with first lever will open in {time} sec",
maternitywardopen: "Door to maternity ward will open in {time} sec",
};

// =====================================

// 状态
const state = {
active: false,
endTime: 0,
lastSecond: -1,
template: "",
zeroEndTime: -1 // 0 显示截止时间
};

// HUD 控制
const HUD = {
show(message) {
if (message !== undefined) {
Instance.EntFireAtName({
name: CONFIG.ENTITY_NAMES.HUD_HINT,
input: "SetMessage",
value: message
});
}

Instance.EntFireAtName({
name: CONFIG.ENTITY_NAMES.ZONE_SHOW,
input: "CountPlayersInZone"
});
},

hide() {
Instance.EntFireAtName({
name: CONFIG.ENTITY_NAMES.ZONE_HIDE,
input: "CountPlayersInZone"
});
}
};

// ================= 核心倒计时 =================

class CountdownManager {

static think() {
if (!state.active) return;

const now = Instance.GetGameTime();
const remaining = state.endTime - now;
const seconds = Math.ceil(Math.max(0, remaining));

// ===== 已进入 0 显示阶段 =====
if (state.zeroEndTime > 0) {
if (now >= state.zeroEndTime) {
state.active = false;
state.zeroEndTime = -1;
HUD.hide();
return;
}

Instance.SetNextThink(now + CONFIG.THINK_INTERVAL);
return;
}

// ===== 第一次进入 0 =====
if (seconds === 0) {
state.lastSecond = 0;

HUD.show(
state.template.replace(/{time}/g, 0)
);

state.zeroEndTime = now + CONFIG.ZERO_DISPLAY_TIME;
Instance.SetNextThink(now + CONFIG.THINK_INTERVAL);
return;
}

// ===== 正常倒计时 =====
if (seconds !== state.lastSecond) {
state.lastSecond = seconds;

HUD.show(
state.template.replace(/{time}/g, seconds)
);
}

Instance.SetNextThink(now + CONFIG.THINK_INTERVAL);
}

static start(templateKey, seconds) {
const template = TEMPLATES[templateKey];
if (!template || seconds < 0) return false;

state.active = true;
state.template = template;
state.endTime = Instance.GetGameTime() + seconds;
state.lastSecond = -1;
state.zeroEndTime = -1;

HUD.show(template.replace(/{time}/g, seconds));

Instance.SetThink(CountdownManager.think);
Instance.SetNextThink(Instance.GetGameTime() + CONFIG.THINK_INTERVAL);

return true;
}

static stop() {
if (!state.active) return;
state.active = false;
state.zeroEndTime = -1;
HUD.hide();
}

static parse(input) {
if (input === "stop") return { type: "stop" };

const match = input.match(/^(.+)_([0-9]+)$/);
if (!match) return null;

return {
type: "countdown",
templateKey: match[1],
seconds: Number(match[2])
};
}
}

// ================= ScriptInput =================

function onInput(data) {
const input = data && data.value !== undefined ? data.value : data;
const parsed = CountdownManager.parse(input);

if (!parsed) return;

if (parsed.type === "stop") {
CountdownManager.stop();
} else {
CountdownManager.start(parsed.templateKey, parsed.seconds);
}
}

Instance.OnScriptInput("countdown", onInput);
Instance.OnScriptInput("stop", CountdownManager.stop);

// 预设倒计时
[
"secondlabopen_25",
"doorbreak_30",
"doorclose_15","doorclose_20","doorclose_25","doorclose_30",
"doorintooffice_15","doorintooffice_20",
"doormainofficeopen_10",
"dooropen_10","dooropen_15","dooropen_20","dooropen_25","dooropen_30","dooropen_40",
"doorstoblackwaterundergroundlab_30",
"doortomainlabopen_20",
"doortostorageroomopen_20","doortostorageroomopen_25","doortostorageroomopen_30",
"doortotherightside_15",
"doorwiththirdleveropen_20",
"elevatorwillleave_20",
"elevatorwillleave_40",
"emergencyexitopen_20","emergencyexitopen_30",
"firstleveropen_30",
"gateopen_60",
"maternitywardopen_40",
"officedoorswillclose_10","officedoorswillclose_20",
"secondlabopen_25",
"secondleveropen_30",
"sewerdooropen_30"
].forEach(preset => {
Instance.OnScriptInput(preset, () => onInput(preset));
});

// 回合开始自动重置
Instance.OnRoundStart(CountdownManager.stop);
Loading