@occultus/task-api 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright © 2025 CTN Studios
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,6 @@
1
+ # Star Tenon Task API
2
+
3
+ > [!IMPORTANT]
4
+ > 该包仍处于开发阶段,可能会有一些问题亟待修复
5
+
6
+ 本包提供了方便的、基于脚本表单实现的任务 API。
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@occultus/task-api",
3
+ "version": "0.18.1",
4
+ "description": "Star Tenon task api",
5
+ "main": "src/index.ts",
6
+ "keywords": [
7
+ "Minecraft",
8
+ "Occultus SDK",
9
+ "Script API"
10
+ ],
11
+ "contributors": [
12
+ "FangLimao <mucigames@outlook.com>"
13
+ ],
14
+ "license": "MIT",
15
+ "author": "CTN Studios",
16
+ "dependencies": {
17
+ "@occultus/format-api": "0.18.1",
18
+ "@occultus/entity-api": "0.18.1",
19
+ "@occultus/text-api": "0.18.1",
20
+ "@occultus/item-api": "0.18.2"
21
+ },
22
+ "peerDependencies": {
23
+ "@minecraft/server": "2.3.0-beta.1.21.110-preview.20",
24
+ "@minecraft/server-ui": "2.1.0-beta.1.21.110-preview.20",
25
+ "@occultus/core": ">=0.18.2 || <0.19.0"
26
+ },
27
+ "devDependencies": {
28
+ "typedoc": "^0.28.9"
29
+ }
30
+ }
@@ -0,0 +1,131 @@
1
+ import { parseText, parseToRaw, TextProvider } from "@occultus/text-api";
2
+ import { Player } from "@minecraft/server";
3
+ import { TaskOptions } from "../interface/TaskOptions";
4
+ import { TaskStatus } from "../enum/TaskStaus";
5
+ import { TaskGroup } from "./TaskGroup";
6
+ import { TaskCenter } from "./TaskCenter";
7
+ import { MessageFormData } from "@minecraft/server-ui";
8
+ import { TaskUtils } from "../utils/TaskUtils";
9
+ import { LockedScreen } from "../ui/LockedScreen";
10
+
11
+ export class Task {
12
+ /**
13
+ * @param id 任务的唯一标识符
14
+ * @param name 任务名称
15
+ * @param description 任务描述
16
+ * @param options 任务的配置选项
17
+ */
18
+ constructor(
19
+ readonly id: string,
20
+ public name: TextProvider,
21
+ public description: TextProvider,
22
+ public options: TaskOptions
23
+ ) {}
24
+ /**
25
+ * 向玩家展示任务
26
+ * @param player 要展示任务的玩家
27
+ * @param backTo 关闭任务 UI 后返回的界面
28
+ */
29
+ display(player: Player, backTo?: Task | TaskCenter | TaskGroup) {
30
+ if (this.getStatus(player) === TaskStatus.Locked) {
31
+ this.lockedDisplay(player, backTo);
32
+ return;
33
+ }
34
+ const form = new MessageFormData();
35
+ form.title(parseText(this.name, player));
36
+ form.body(TaskUtils.generateTaskBody(this, player));
37
+ form.button1({ translate: "gui.back" });
38
+ if (this.getStatus(player) === TaskStatus.Done) {
39
+ // 任务已完成
40
+ form.button2({ translate: "ui.task.done" });
41
+ } else {
42
+ // 提交任务
43
+ form.button2({ translate: "ui.task.submit" });
44
+ }
45
+ form.show(player).then((result) => {
46
+ if (result.selection === 1) {
47
+ if (this.getStatus(player) === TaskStatus.Done) return;
48
+ if (this.checkConditions(player)) {
49
+ this.complete(player);
50
+ return;
51
+ }
52
+ player.sendMessage(TaskUtils.generateFailMessage(this, player));
53
+ return;
54
+ }
55
+ if (backTo) {
56
+ backTo.display(player);
57
+ }
58
+ });
59
+ }
60
+ /**
61
+ * 返回玩家是否可以在任务列表中看到该任务
62
+ * @param player
63
+ * @return 倘若玩家可以在任务列表中看到该任务返回`true`,否则返回`false`
64
+ */
65
+ isVisible(player: Player): boolean {
66
+ if(this.isAvailable(player)) return true;
67
+ if(this.options.hiddenWhenLocked) return false;
68
+ return true;
69
+ }
70
+ isAvailable(player: Player): boolean {
71
+ if(this.getStatus(player) === TaskStatus.Done) return true;
72
+ if(this.options.previousTask === "none") return true;
73
+ if(this.options.previousTask.getStatus(player) === TaskStatus.Done) return true;
74
+ return false;
75
+ }
76
+ protected lockedDisplay(
77
+ player: Player,
78
+ backTo?: Task | TaskCenter | TaskGroup
79
+ ) {
80
+ const screen = LockedScreen.create(this, player);
81
+ screen.show(player).then((response) => {
82
+ if (this.options.previousTask === "none") return;
83
+ if (response.selection === 1) {
84
+ this.options.previousTask.display(player, this);
85
+ }
86
+ backTo?.display(player);
87
+ });
88
+ }
89
+ /**
90
+ * 获取任务状态
91
+ * @param player 要获取任务状态的玩家
92
+ * @return 玩家的任务状态
93
+ */
94
+ getStatus(player: Player): TaskStatus {
95
+ if (player.hasTag("done:" + this.id)) return TaskStatus.Done;
96
+ if (this.options.previousTask === "none") return TaskStatus.Undone;
97
+ if (this.options.previousTask.getStatus(player) === TaskStatus.Done) {
98
+ return TaskStatus.Undone;
99
+ }
100
+ return TaskStatus.Locked;
101
+ }
102
+ /**
103
+ * 检查玩家是否能完成任务
104
+ * @param player
105
+ * @returns
106
+ */
107
+ protected checkConditions(player: Player): boolean {
108
+ const conditions = this.options.conditions;
109
+ if (conditions.length === 0) return true;
110
+ return conditions.every((condition) => condition.check(player));
111
+ }
112
+ /**
113
+ * 向玩家给予奖励
114
+ * @param player
115
+ */
116
+ protected giveAwards(player: Player) {
117
+ this.options.awards.forEach((award) => award.give(player));
118
+ }
119
+ protected complete(player: Player) {
120
+ player.addTag("done:" + this.id);
121
+ this.giveAwards(player);
122
+ player.onScreenDisplay.setActionBar({
123
+ rawtext: [
124
+ // 你完成了任务:
125
+ { translate: "ui.task.complete" },
126
+ parseToRaw(this.name, player),
127
+ ],
128
+ });
129
+ player.playSound(this.options.completeSound ?? "random.levelup");
130
+ }
131
+ }
@@ -0,0 +1,26 @@
1
+ import { CustomCommand, Player } from "@minecraft/server";
2
+ import { TextProvider } from "@occultus/text-api";
3
+ import { TaskCenterOptions } from "../interface/TaskCenterOptions";
4
+ import { TaskListScreen } from "../ui/TaskListScreen";
5
+ import { TaskUtils } from "../utils/TaskUtils";
6
+
7
+ export class TaskCenter {
8
+ constructor(
9
+ readonly id: string,
10
+ public name: TextProvider,
11
+ public description: TextProvider,
12
+ public options: TaskCenterOptions
13
+ ) {}
14
+ display(player: Player) {
15
+ const { screen, tasks } = TaskListScreen.create(this, player);
16
+ screen.show(player).then((response) => {
17
+ if (response.canceled) return;
18
+ if (response.selection === undefined) return;
19
+ tasks[response.selection].display(player, this);
20
+ });
21
+ }
22
+ addTrigger(itemComponent?: string, command?: CustomCommand) {
23
+ if (itemComponent) TaskUtils.registryComponent(itemComponent, this);
24
+ if (command) TaskUtils.registryCommand(command, this);
25
+ }
26
+ }
@@ -0,0 +1,91 @@
1
+ import { Player } from "@minecraft/server";
2
+ import { parseToRaw, TextProvider } from "@occultus/text-api";
3
+ import { TaskGroupOptions } from "../interface/TaskGroupOptions";
4
+ import { TaskStatus } from "../enum/TaskStaus";
5
+ import { ActionFormData, MessageFormData } from "@minecraft/server-ui";
6
+ import { Task } from "./Task";
7
+ import { TaskCenter } from "./TaskCenter";
8
+ import { LockedScreen } from "../ui/LockedScreen";
9
+ import { TaskListScreen } from "../ui/TaskListScreen";
10
+
11
+ export class TaskGroup {
12
+ constructor(
13
+ readonly id: string,
14
+ public name: TextProvider,
15
+ public description: TextProvider,
16
+ public options: TaskGroupOptions
17
+ ) {}
18
+ display(player: Player, backTo?: Task | TaskCenter | TaskGroup) {
19
+ if (this.getStatus(player) === TaskStatus.Locked) {
20
+ this.lockedDisplay(player);
21
+ return;
22
+ }
23
+ const { screen, tasks } = TaskListScreen.create(this, player);
24
+ screen.show(player).then((response) => {
25
+ if (response.canceled) {
26
+ return backTo?.display(player);
27
+ }
28
+ if (response.selection === undefined) {
29
+ return backTo?.display(player);
30
+ }
31
+ if (response.selection === 0) {
32
+ if(this.hasOwnedAward(player)){
33
+ // 你已经领取过该奖励!
34
+ player.onScreenDisplay.setActionBar({translate: "ui.taskGroup.award.owned"})
35
+ }
36
+ if (this.getStatus(player) === TaskStatus.Done) {
37
+ this.giveAward(player);
38
+ }
39
+ return backTo?.display(player);
40
+ }
41
+ tasks[response.selection - 1].display(player, this);
42
+ });
43
+ }
44
+ isVisible(player: Player): boolean {
45
+ if (this.isAvailable(player)) return true;
46
+ if (this.options.hiddenWhenLocked) return false;
47
+ return true;
48
+ }
49
+ isAvailable(player: Player): boolean {
50
+ if (this.getStatus(player) === TaskStatus.Done) return true;
51
+ if (this.options.previousTask === "none") return true;
52
+ if (this.options.previousTask.getStatus(player) === TaskStatus.Done)
53
+ return true;
54
+ return false;
55
+ }
56
+ getStatus(player: Player): TaskStatus {
57
+ if (
58
+ this.options.tasks.every(
59
+ (task) => task.getStatus(player) === TaskStatus.Done
60
+ )
61
+ ) {
62
+ return TaskStatus.Done;
63
+ }
64
+ if (this.options.previousTask === "none") return TaskStatus.Undone;
65
+ if (this.options.previousTask.getStatus(player) === TaskStatus.Done)
66
+ return TaskStatus.Undone;
67
+ return TaskStatus.Locked;
68
+ }
69
+ hasOwnedAward(player: Player): boolean {
70
+ return player.hasTag(`taskGroup.${this.id}.award`);
71
+ }
72
+ ownAward(player: Player) {
73
+ player.addTag(`taskGroup.${this.id}.award`);
74
+ }
75
+ protected lockedDisplay(
76
+ player: Player,
77
+ backTo?: Task | TaskCenter | TaskGroup
78
+ ) {
79
+ const screen = LockedScreen.create(this, player);
80
+ screen.show(player).then((response) => {
81
+ if (this.options.previousTask === "none") return;
82
+ if (response.selection === 1) {
83
+ this.options.previousTask.display(player, this);
84
+ }
85
+ backTo?.display(player);
86
+ });
87
+ }
88
+ protected giveAward(player: Player) {
89
+ this.options.awards.forEach((award) => award.give(player));
90
+ }
91
+ }
@@ -0,0 +1,29 @@
1
+ import { ItemStack, Player } from "@minecraft/server";
2
+ import { TextProvider } from "@occultus/text-api";
3
+ import { TaskAwards } from "./TaskAwards";
4
+ import { giveItem } from "@occultus/entity-api";
5
+
6
+ export class ItemAwards extends TaskAwards {
7
+ constructor(
8
+ protected itemType: string,
9
+ protected amount?: number
10
+ ) {
11
+ super(itemType);
12
+ }
13
+ getItem() {
14
+ return new ItemStack(this.itemType, this.amount);
15
+ }
16
+ give(player: Player) {
17
+ giveItem(player, this.getItem());
18
+ }
19
+ getTextProvider() {
20
+ const item = this.getItem();
21
+ return {
22
+ rawtext: [
23
+ { translate: item.localizationKey },
24
+ { text: " × " },
25
+ { text: item.amount.toString() },
26
+ ],
27
+ };
28
+ }
29
+ }
@@ -0,0 +1,23 @@
1
+ import { Player } from "@minecraft/server";
2
+ import { TextProvider } from "@occultus/text-api";
3
+
4
+ /**
5
+ * 任务奖励抽象基类
6
+ *
7
+ * 该类定义了游戏中任务奖励系统的基础结构,用于管理和分发各种类型的任务奖励,所有具体的奖励类型(如经验奖励、物品奖励、货币奖励等)都应继承此抽象类。
8
+ */
9
+ export abstract class TaskAwards {
10
+ /**
11
+ * @param data 奖励数据
12
+ */
13
+ constructor(protected data: unknown) {}
14
+ /**
15
+ * 向玩家发放奖励
16
+ * @param player
17
+ */
18
+ abstract give(player: Player): void;
19
+ /**
20
+ * 获取提示文本
21
+ */
22
+ abstract getTextProvider(): TextProvider;
23
+ }
@@ -0,0 +1,52 @@
1
+ import { ItemStack, Player } from "@minecraft/server";
2
+ import { TaskConditions } from "./TaskConditions";
3
+ import { getItemAmountInContainer } from "@occultus/item-api";
4
+
5
+ /**
6
+ * 物品条件
7
+ */
8
+ export class ItemConditions extends TaskConditions {
9
+ /**
10
+ * @param itemType 满足条件所需要的物品类型
11
+ * @param amount 满足条件所需要的物品数量,默认为 1
12
+ */
13
+ constructor(
14
+ protected itemType: string,
15
+ protected amount?: number
16
+ ) {
17
+ super(itemType);
18
+ }
19
+ getItem(){
20
+ return new ItemStack(this.itemType, this.amount)
21
+ }
22
+ check(player: Player) {
23
+ const container = player.getComponent("minecraft:inventory")?.container;
24
+ if (!container) return false;
25
+ const amount = getItemAmountInContainer(
26
+ container,
27
+ this.getItem().typeId
28
+ );
29
+ return amount >= this.getItem().amount;
30
+ }
31
+ getTextProvider(){
32
+ return {
33
+ rawtext: [
34
+ { translate: this.getItem().localizationKey },
35
+ { text: " × " },
36
+ { text: this.getItem().amount.toString() },
37
+ ],
38
+ };
39
+ };
40
+ getFailedReason(){
41
+ return {
42
+ rawtext: [
43
+ // 你缺少这些物品:
44
+ { translate: "task.condition.item.failed" },
45
+ { text: " " },
46
+ { translate: this.getItem().localizationKey },
47
+ { text: " × " },
48
+ { text: this.getItem().amount.toString() },
49
+ ],
50
+ }
51
+ };
52
+ }
@@ -0,0 +1,35 @@
1
+ import { Player } from "@minecraft/server";
2
+ import { TextProvider } from "@occultus/text-api";
3
+
4
+ /**
5
+ * 任务条件的抽象类
6
+ *
7
+ * 定义了任务条件的基本结构和必须实现的方法,所有具体的任务条件类都应该继承此抽象类并实现其抽象方法
8
+ */
9
+ export abstract class TaskConditions {
10
+ /**
11
+ * @param data 任务条件所需的数据
12
+ */
13
+ constructor(protected data: unknown) {}
14
+
15
+ /**
16
+ * 检查玩家是否满足任务条件
17
+ *
18
+ * @param player 要检查的玩家对象
19
+ * @return 如果玩家满足条件返回`true`,否则返回`false`
20
+ */
21
+ abstract check(player: Player): boolean;
22
+
23
+ /**
24
+ * 获取任务条件的文本,该文本将会在任务面板中显示
25
+ *
26
+ * @return 用于显示任务条件描述的文本
27
+ */
28
+ abstract getTextProvider(): TextProvider;
29
+ /**
30
+ * 获取条件检查失败时的原因说明文本
31
+ *
32
+ * @return 用于显示失败原因的文本
33
+ */
34
+ abstract getFailedReason(): TextProvider;
35
+ }
@@ -0,0 +1,14 @@
1
+ export enum TaskStatus {
2
+ /**
3
+ * 该任务/任务组前置任务未完成,已被锁定
4
+ */
5
+ Locked = -1,
6
+ /**
7
+ * 该任务/任务组已经解锁,但并没有完成
8
+ */
9
+ Undone = 0,
10
+ /**
11
+ * 该任务/任务组已经完成
12
+ */
13
+ Done = 1,
14
+ }
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ export * from "./api/Task"
2
+ export * from "./api/TaskGroup"
3
+ export * from "./api/TaskCenter"
4
+ export * from "./api/awards/ItemAwards"
5
+ export * from "./api/awards/TaskAwards"
6
+ export * from "./api/conditions/ItemConditions"
7
+ export * from "./api/conditions/TaskConditions"
8
+ export * from "./enum/TaskStaus"
9
+ export * from "./interface/TaskCenterOptions"
10
+ export * from "./interface/TaskGroupOptions"
11
+ export * from "./interface/TaskOptions"
@@ -0,0 +1,14 @@
1
+ import { Task } from "../api/Task";
2
+ import { TaskGroup } from "../api/TaskGroup";
3
+
4
+ /**
5
+ * 任务中心配置选项接口
6
+ */
7
+ export interface TaskCenterOptions {
8
+ /**
9
+ * 任务中心中包含的所有任务和任务组列表
10
+ *
11
+ * 可以是单个任务或任务组
12
+ */
13
+ tasks: (Task| TaskGroup)[];
14
+ }
@@ -0,0 +1,34 @@
1
+ import { TaskAwards } from "../api/awards/TaskAwards";
2
+ import { Task } from "../api/Task";
3
+ import { TaskGroup } from "../api/TaskGroup";
4
+
5
+ /**
6
+ * 任务组配置选项接口
7
+ */
8
+ export interface TaskGroupOptions {
9
+ /**
10
+ * 任务组中包含的任务列表
11
+ */
12
+ tasks: Task[];
13
+
14
+ /**
15
+ * 任务完成后的奖励列表
16
+ */
17
+ awards: TaskAwards[];
18
+
19
+ /**
20
+ * 前置任务,可以是单个任务、任务组或无前置任务
21
+ */
22
+ previousTask: Task | TaskGroup | "none";
23
+
24
+ /**
25
+ * 是否在锁定状态下隐藏任务组
26
+ * @default false
27
+ */
28
+ hiddenWhenLocked?: boolean;
29
+
30
+ /**
31
+ * 任务组的图标路径
32
+ */
33
+ iconPath?: string;
34
+ }
@@ -0,0 +1,46 @@
1
+ import { TextProvider } from "@occultus/text-api";
2
+ import { TaskAwards } from "../api/awards/TaskAwards";
3
+ import { TaskConditions } from "../api/conditions/TaskConditions";
4
+ import { Task } from "../api/Task";
5
+
6
+ /**
7
+ * 任务配置选项接口
8
+ */
9
+ export interface TaskOptions {
10
+ /**
11
+ * 任务完成后的奖励列表
12
+ */
13
+ awards: TaskAwards[];
14
+
15
+ /**
16
+ * 任务完成所需满足的条件列表
17
+ */
18
+ conditions: TaskConditions[];
19
+
20
+ /**
21
+ * 前置任务
22
+ * 可以是其他任务或无前置任务("none")
23
+ */
24
+ previousTask: Task | "none";
25
+
26
+ /**
27
+ * 是否在锁定状态下隐藏该任务
28
+ * @default false
29
+ */
30
+ hiddenWhenLocked?: boolean;
31
+
32
+ /**
33
+ * 任务完成时的音效资源路径
34
+ */
35
+ completeSound?: string;
36
+
37
+ /**
38
+ * 任务提示信息
39
+ */
40
+ tips?: TextProvider;
41
+
42
+ /**
43
+ * 任务图标的资源路径
44
+ */
45
+ iconPath?: string;
46
+ }
@@ -0,0 +1,30 @@
1
+ import { MessageFormData } from "@minecraft/server-ui";
2
+ import { Task } from "../api/Task";
3
+ import { TaskGroup } from "../api/TaskGroup";
4
+ import { Player } from "@minecraft/server";
5
+ import { Format } from "@occultus/format-api";
6
+ import { parseToRaw } from "@occultus/text-api";
7
+
8
+ export class LockedScreen {
9
+ static create(task: Task | TaskGroup, player: Player): MessageFormData {
10
+ const previous = task.options.previousTask;
11
+ if (previous === "none") {
12
+ throw new Error("Previous task is not set");
13
+ }
14
+ const form = new MessageFormData();
15
+ // 任务未解锁
16
+ form.title({ translate: "task.locked" });
17
+ // 你需要完成以下任务来解锁这组任务:
18
+ form.body({
19
+ rawtext: [
20
+ { translate: "task.locked.body" },
21
+ { text: Format.newLine },
22
+ parseToRaw(previous.name, player),
23
+ ],
24
+ });
25
+ form.button1({ translate: "gui.back" });
26
+ // 前往完成
27
+ form.button2({ translate: "ui.task.goto" });
28
+ return form;
29
+ }
30
+ }
@@ -0,0 +1,33 @@
1
+ import { ActionFormData } from "@minecraft/server-ui";
2
+ import { TaskCenter } from "../api/TaskCenter";
3
+ import { TaskGroup } from "../api/TaskGroup";
4
+ import { Player } from "@minecraft/server";
5
+ import { parseToRaw } from "@occultus/text-api";
6
+ import { Task } from "../api/Task";
7
+ import { TaskUtils } from "../utils/TaskUtils";
8
+
9
+ export class TaskListScreen {
10
+ private constructor(
11
+ readonly screen: ActionFormData,
12
+ readonly tasks: (Task | TaskGroup)[]
13
+ ) {}
14
+ static create(
15
+ origin: TaskCenter | TaskGroup,
16
+ player: Player
17
+ ): TaskListScreen {
18
+ const form = new ActionFormData();
19
+ form.title(parseToRaw(origin.name, player));
20
+ form.body(parseToRaw(origin.description, player));
21
+ if (origin instanceof TaskGroup) {
22
+ // 获取奖励
23
+ form.button({ translate: "" });
24
+ }
25
+ const tasks: (Task | TaskGroup)[] = [];
26
+ origin.options.tasks.forEach((task) => {
27
+ if (!task.isVisible(player)) return;
28
+ form.button(TaskUtils.getTaskListButtonName(task, player), task.options.iconPath);
29
+ tasks.push(task);
30
+ });
31
+ return { screen: form, tasks: tasks };
32
+ }
33
+ }
@@ -0,0 +1,116 @@
1
+ import {
2
+ CustomCommand,
3
+ CustomCommandSource,
4
+ CustomCommandStatus,
5
+ Player,
6
+ RawMessage,
7
+ system,
8
+ } from "@minecraft/server";
9
+ import { Task } from "../api/Task";
10
+ import { parseToRaw } from "@occultus/text-api";
11
+ import { Format, Color } from "@occultus/format-api";
12
+ import { TaskStatus } from "../enum/TaskStaus";
13
+ import { TaskGroup } from "../api/TaskGroup";
14
+ import { TaskCenter } from "../api/TaskCenter";
15
+
16
+ export class TaskUtils {
17
+ static generateTaskBody(task: Task, player: Player): RawMessage {
18
+ let texts: RawMessage[] = [];
19
+ texts.push(parseToRaw(task.description, player));
20
+ texts.push({ text: Format.newLine }, { text: Format.newLine });
21
+ // 提示:
22
+ if (task.options.tips) {
23
+ texts.push(
24
+ { translate: "ui.task.tips" },
25
+ parseToRaw(task.options.tips, player)
26
+ );
27
+ texts.push({ text: Format.newLine });
28
+ }
29
+
30
+ // 完成条件:
31
+ texts.push({ translate: "ui.task.condition" });
32
+ task.options.conditions.forEach((condition) => {
33
+ texts.push(parseToRaw(condition.getTextProvider(), player));
34
+ });
35
+ texts.push({ text: Format.newLine });
36
+
37
+ // 奖励:
38
+ texts.push({ translate: "ui.task.award" });
39
+ task.options.awards.forEach((award) => {
40
+ texts.push(parseToRaw(award.getTextProvider(), player));
41
+ });
42
+ texts.push({ text: Format.newLine });
43
+
44
+ return {
45
+ rawtext: texts,
46
+ };
47
+ }
48
+ static generateFailMessage(task: Task, player: Player): RawMessage {
49
+ let texts: RawMessage[] = [];
50
+ // 你无法提交该任务,因为:
51
+ texts.push({ translate: "ui.task.failed_reason" });
52
+ task.options.conditions.forEach((condition) => {
53
+ if (condition.check(player)) return;
54
+ // eg. 你没有获取 114514 个方漓猫
55
+ texts.push(parseToRaw(condition.getFailedReason(), player));
56
+ });
57
+ return {
58
+ rawtext: texts,
59
+ };
60
+ }
61
+ static getTaskListButtonName(
62
+ task: Task | TaskGroup,
63
+ player: Player
64
+ ): RawMessage {
65
+ const raw: RawMessage[] = [];
66
+ if (task.getStatus(player) === TaskStatus.Done) {
67
+ raw.push({ text: Color.darkGreen });
68
+ raw.push({ text: "✔" });
69
+ raw.push({ text: Format.reset }, { text: "" });
70
+ }
71
+ raw.push(parseToRaw(task.name, player));
72
+ return { rawtext: raw };
73
+ }
74
+ static generateGroupAwardButton(task: TaskGroup, player: Player): RawMessage {
75
+ const raw: RawMessage[] = [];
76
+ if (task.hasOwnedAward(player)) {
77
+ raw.push({ text: Color.darkGreen });
78
+ raw.push({ text: "✔" });
79
+ raw.push({ text: Format.reset }, { text: "" });
80
+ }
81
+ raw.push({ translate: "ui.task.getAward" });
82
+ return { rawtext: raw };
83
+ }
84
+ static registryComponent(componentName: string, center: TaskCenter) {
85
+ system.beforeEvents.startup.subscribe((arg) => {
86
+ arg.itemComponentRegistry.registerCustomComponent(componentName, {
87
+ onUse(arg0) {
88
+ center.display(arg0.source);
89
+ },
90
+ });
91
+ });
92
+ }
93
+ static registryCommand(command: CustomCommand, center: TaskCenter) {
94
+ system.beforeEvents.startup.subscribe((arg) => {
95
+ arg.customCommandRegistry.registerCommand(command, (origin) => {
96
+ system.run(() => {
97
+ if (origin.sourceType !== CustomCommandSource.Entity)
98
+ return {
99
+ status: CustomCommandStatus.Failure,
100
+ };
101
+ if (!(origin.sourceEntity instanceof Player))
102
+ return {
103
+ status: CustomCommandStatus.Failure,
104
+ };
105
+ center.display(origin.sourceEntity);
106
+ return {
107
+ status: CustomCommandStatus.Success,
108
+ };
109
+ });
110
+ return {
111
+ status: CustomCommandStatus.Failure,
112
+ };
113
+ });
114
+ });
115
+ }
116
+ }