mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-07-24 07:21:47 +08:00
Compare commits
1 Commits
8883eca285
...
99b5483c59
Author | SHA1 | Date | |
---|---|---|---|
![]() |
99b5483c59 |
@ -6,7 +6,6 @@ import { TextAlign } from './textboxTyper';
|
|||||||
import { Page, PageExpose } from './page';
|
import { Page, PageExpose } from './page';
|
||||||
import { GameUI, IUIMountable, SetupComponentOptions } from '@motajs/system-ui';
|
import { GameUI, IUIMountable, SetupComponentOptions } from '@motajs/system-ui';
|
||||||
import { useKey } from '../use';
|
import { useKey } from '../use';
|
||||||
import { sleep } from 'mutate-animate';
|
|
||||||
|
|
||||||
export interface ConfirmBoxProps extends DefaultProps, TextContentProps {
|
export interface ConfirmBoxProps extends DefaultProps, TextContentProps {
|
||||||
text: string;
|
text: string;
|
||||||
@ -193,7 +192,7 @@ export const ConfirmBox = defineComponent<
|
|||||||
);
|
);
|
||||||
}, confirmBoxProps);
|
}, confirmBoxProps);
|
||||||
|
|
||||||
export type ChoiceKey = string | number;
|
export type ChoiceKey = string | number | symbol;
|
||||||
export type ChoiceItem = [key: ChoiceKey, text: string];
|
export type ChoiceItem = [key: ChoiceKey, text: string];
|
||||||
|
|
||||||
export interface ChoicesProps extends DefaultProps, TextContentProps {
|
export interface ChoicesProps extends DefaultProps, TextContentProps {
|
||||||
@ -212,7 +211,6 @@ export interface ChoicesProps extends DefaultProps, TextContentProps {
|
|||||||
titleFill?: CanvasStyle;
|
titleFill?: CanvasStyle;
|
||||||
pad?: number;
|
pad?: number;
|
||||||
interval?: number;
|
interval?: number;
|
||||||
selected?: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ChoicesEmits = {
|
export type ChoicesEmits = {
|
||||||
@ -235,8 +233,7 @@ const choicesProps = {
|
|||||||
'titleFont',
|
'titleFont',
|
||||||
'titleFill',
|
'titleFill',
|
||||||
'pad',
|
'pad',
|
||||||
'interval',
|
'interval'
|
||||||
'selected'
|
|
||||||
],
|
],
|
||||||
emits: ['choose']
|
emits: ['choose']
|
||||||
} satisfies SetupComponentOptions<
|
} satisfies SetupComponentOptions<
|
||||||
@ -286,7 +283,7 @@ export const Choices = defineComponent<
|
|||||||
>((props, { emit, attrs }) => {
|
>((props, { emit, attrs }) => {
|
||||||
const titleHeight = ref(0);
|
const titleHeight = ref(0);
|
||||||
const contentHeight = ref(0);
|
const contentHeight = ref(0);
|
||||||
const selected = ref(props.selected ?? 0);
|
const selected = ref(0);
|
||||||
const pageCom = ref<PageExpose>();
|
const pageCom = ref<PageExpose>();
|
||||||
const choiceSize = reactive<[number, number][]>([]);
|
const choiceSize = reactive<[number, number][]>([]);
|
||||||
|
|
||||||
@ -637,122 +634,6 @@ export function getChoice<T extends ChoiceKey = ChoiceKey>(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getChoiceRoute() {
|
|
||||||
const route = core.status.replay.toReplay[0];
|
|
||||||
if (!route.startsWith('choices:')) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return Number(route.slice(8));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 弹出一个确认框,然后将确认结果返回,与 getConfirm 不同的是内置录像支持,如果这个选择框需要进录像,
|
|
||||||
* 需要使用此方法。例如给玩家弹出一个确认框,并获取玩家是否确认:
|
|
||||||
* ```ts
|
|
||||||
* const confirm = await routedConfirm(
|
|
||||||
* // 在哪个 UI 控制器上打开,对于一般 UI 组件来说,直接填写 props.controller 即可
|
|
||||||
* props.controller,
|
|
||||||
* // 确认内容
|
|
||||||
* '确认要 xxx 吗?',
|
|
||||||
* // 确认框的位置,宽度由下一个参数指定,高度参数由组件内部计算得出,指定无效
|
|
||||||
* [240, 240, void 0, void 0, 0.5, 0.5],
|
|
||||||
* // 宽度设为 240
|
|
||||||
* 240,
|
|
||||||
* // 可以给选择框传入其他的 props,例如指定字体,此项可选
|
|
||||||
* { font: new Font('Verdana', 20) }
|
|
||||||
* );
|
|
||||||
* // 之后,就可以直接判断 confirm 来执行不同的操作了
|
|
||||||
* if (confirm) { ... }
|
|
||||||
* ```
|
|
||||||
* @param controller UI 控制器
|
|
||||||
* @param text 确认文本内容
|
|
||||||
* @param loc 确认框的位置
|
|
||||||
* @param width 确认框的宽度
|
|
||||||
* @param props 额外的 props,参考 {@link ConfirmBoxProps}
|
|
||||||
*/
|
|
||||||
export async function routedConfirm(
|
|
||||||
controller: IUIMountable,
|
|
||||||
text: string,
|
|
||||||
loc: ElementLocator,
|
|
||||||
width: number,
|
|
||||||
props?: Partial<ConfirmBoxProps>
|
|
||||||
) {
|
|
||||||
if (core.isReplaying()) {
|
|
||||||
const confirm = getChoiceRoute() === 1;
|
|
||||||
const timeout = core.control.__replay_getTimeout();
|
|
||||||
if (timeout === 0) return confirm;
|
|
||||||
const instance = controller.open(ConfirmBoxUI, {
|
|
||||||
...(props ?? {}),
|
|
||||||
text,
|
|
||||||
loc,
|
|
||||||
width,
|
|
||||||
defaultYes: confirm
|
|
||||||
});
|
|
||||||
await sleep(core.control.__replay_getTimeout());
|
|
||||||
controller.close(instance);
|
|
||||||
return confirm;
|
|
||||||
} else {
|
|
||||||
const confirm = await getConfirm(controller, text, loc, width, props);
|
|
||||||
core.status.route.push(`choices:${confirm ? 1 : 0}`);
|
|
||||||
return confirm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 弹出一个选择框,然后将选择结果返回,与 getChoice 不同的是内置录像支持,如果这个选择框需要进录像,
|
|
||||||
* 需要使用此方法。例如给玩家弹出一个选择框,并获取玩家选择了哪个:
|
|
||||||
* ```ts
|
|
||||||
* const choice = await routedChoice(
|
|
||||||
* // 在哪个 UI 控制器上打开,对于一般 UI 组件来说,直接填写 props.controller 即可
|
|
||||||
* props.controller,
|
|
||||||
* // 选项内容,参考 Choices 的注释
|
|
||||||
* [[0, '选项1'], [1, '选项2'], [2, '选项3']],
|
|
||||||
* // 选择框的位置,宽度由下一个参数指定,高度参数由组件内部计算得出,指定无效
|
|
||||||
* [240, 240, void 0, void 0, 0.5, 0.5],
|
|
||||||
* // 宽度设为 240
|
|
||||||
* 240,
|
|
||||||
* // 可以给选择框传入其他的 props,例如指定标题,此项可选
|
|
||||||
* { title: '选项标题' }
|
|
||||||
* );
|
|
||||||
* // 之后,就可以直接判断 choice 来执行不同的操作了
|
|
||||||
* if (choice === 0) { ... }
|
|
||||||
* ```
|
|
||||||
* @param controller UI 控制器
|
|
||||||
* @param choices 选择框的选项
|
|
||||||
* @param loc 选择框的位置
|
|
||||||
* @param width 选择框的宽度
|
|
||||||
* @param props 额外的 props,参考 {@link ChoicesProps}
|
|
||||||
*/
|
|
||||||
export async function routedChoices(
|
|
||||||
controller: IUIMountable,
|
|
||||||
choices: ChoiceItem[],
|
|
||||||
loc: ElementLocator,
|
|
||||||
width: number,
|
|
||||||
props?: Partial<ChoicesProps>
|
|
||||||
) {
|
|
||||||
if (core.isReplaying()) {
|
|
||||||
const selected = getChoiceRoute();
|
|
||||||
const timeout = core.control.__replay_getTimeout();
|
|
||||||
if (timeout === 0) return selected;
|
|
||||||
const instance = controller.open(ChoicesUI, {
|
|
||||||
...(props ?? {}),
|
|
||||||
choices,
|
|
||||||
loc,
|
|
||||||
width,
|
|
||||||
selected
|
|
||||||
});
|
|
||||||
await sleep(core.control.__replay_getTimeout());
|
|
||||||
controller.close(instance);
|
|
||||||
return selected;
|
|
||||||
} else {
|
|
||||||
const choice = await getChoice(controller, choices, loc, width, props);
|
|
||||||
const index = choices.findIndex(v => v[1] === choice);
|
|
||||||
core.status.route.push(`choices:${index}`);
|
|
||||||
return choice;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see {@link ConfirmBox} */
|
/** @see {@link ConfirmBox} */
|
||||||
export const ConfirmBoxUI = new GameUI('confirm-box', ConfirmBox);
|
export const ConfirmBoxUI = new GameUI('confirm-box', ConfirmBox);
|
||||||
/** @see {@link Choices} */
|
/** @see {@link Choices} */
|
||||||
|
@ -1363,6 +1363,20 @@ export function calMapWalls(floor: FloorIds, nocache: boolean = false) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* @__PURE__ */ export function drawPolygons(floor: FloorIds) {
|
||||||
|
const polygons = calMapPolygons(floor);
|
||||||
|
const ctx = core.createCanvas('polygons', 0, 0, 480, 480, 130);
|
||||||
|
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.lineJoin = 'round';
|
||||||
|
ctx.strokeStyle = 'white';
|
||||||
|
for (const p of polygons) {
|
||||||
|
for (const [x, y, w, h] of p) {
|
||||||
|
ctx.strokeRect(x, y, w, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class LayerShadowExtends implements ILayerRenderExtends {
|
export class LayerShadowExtends implements ILayerRenderExtends {
|
||||||
static shadowList: Set<LayerShadowExtends> = new Set();
|
static shadowList: Set<LayerShadowExtends> = new Set();
|
||||||
id: string = 'shadow';
|
id: string = 'shadow';
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { isMobile } from '../use';
|
import { isMobile } from '../use';
|
||||||
import { detailInfo, getSpecialHint } from '../tools/book';
|
import { detailInfo, getSpecialHint } from '../tools/book';
|
||||||
import Scroll from '../components/scroll.vue';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
fromBook?: boolean;
|
fromBook?: boolean;
|
||||||
|
@ -31,7 +31,12 @@
|
|||||||
class="detial-more"
|
class="detial-more"
|
||||||
v-if="panel === 'special'"
|
v-if="panel === 'special'"
|
||||||
>
|
>
|
||||||
<span id="enemy-target" class="button-text more"> </span>
|
<span
|
||||||
|
id="enemy-target"
|
||||||
|
class="button-text more"
|
||||||
|
@click="changePanel($event, 'target')"
|
||||||
|
><LeftOutlined />
|
||||||
|
</span>
|
||||||
<span
|
<span
|
||||||
id="critical-more"
|
id="critical-more"
|
||||||
class="button-text more"
|
class="button-text more"
|
||||||
@ -76,6 +81,7 @@ import { useDrag } from '../use';
|
|||||||
import EnemySpecial from '../panel/enemySpecial.vue';
|
import EnemySpecial from '../panel/enemySpecial.vue';
|
||||||
import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue';
|
import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue';
|
||||||
import EnemyCritical from '../panel/enemyCritical.vue';
|
import EnemyCritical from '../panel/enemyCritical.vue';
|
||||||
|
// import EnemyTarget from '../panel/enemyTarget.vue';
|
||||||
import { detailInfo } from '../tools/book';
|
import { detailInfo } from '../tools/book';
|
||||||
import { gameKey } from '@motajs/system-action';
|
import { gameKey } from '@motajs/system-action';
|
||||||
|
|
||||||
|
@ -1272,6 +1272,7 @@ control.prototype.startReplay = function (list) {
|
|||||||
core.status.replay.totalList = core.status.route.concat(list);
|
core.status.replay.totalList = core.status.route.concat(list);
|
||||||
core.status.replay.steps = 0;
|
core.status.replay.steps = 0;
|
||||||
core.status.replay.save = [];
|
core.status.replay.save = [];
|
||||||
|
core.createCanvas('replay', 0, core._PY_ - 40, core._PX_, 40, 199);
|
||||||
core.setOpacity('replay', 0.6);
|
core.setOpacity('replay', 0.6);
|
||||||
this._replay_drawProgress();
|
this._replay_drawProgress();
|
||||||
core.updateStatusBar(false, true);
|
core.updateStatusBar(false, true);
|
||||||
@ -1406,6 +1407,7 @@ control.prototype.rewindReplay = function () {
|
|||||||
steps: data.replay.steps,
|
steps: data.replay.steps,
|
||||||
save: save
|
save: save
|
||||||
};
|
};
|
||||||
|
core.createCanvas('replay', 0, core._PY_ - 40, core._PX_, 40, 199);
|
||||||
core.setOpacity('replay', 0.6);
|
core.setOpacity('replay', 0.6);
|
||||||
core.control._replay_drawProgress();
|
core.control._replay_drawProgress();
|
||||||
core.updateStatusBar(false, true);
|
core.updateStatusBar(false, true);
|
||||||
|
@ -2520,6 +2520,70 @@ events.prototype._precompile_switch = function (data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
events.prototype._action_choices = function (data, x, y, prefix) {
|
events.prototype._action_choices = function (data, x, y, prefix) {
|
||||||
|
data.choices = data.choices.filter(function (x) {
|
||||||
|
if (x._disabled) return false;
|
||||||
|
if (x.condition == null || x.condition == '') return true;
|
||||||
|
try {
|
||||||
|
return core.calValue(x.condition, prefix);
|
||||||
|
} catch (e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (data.choices.length == 0) return this.doAction();
|
||||||
|
if (core.isReplaying()) {
|
||||||
|
var action = core.status.replay.toReplay.shift();
|
||||||
|
if (
|
||||||
|
action.indexOf('choices:') == 0 &&
|
||||||
|
!(action == 'choices:none' && !data.timeout)
|
||||||
|
) {
|
||||||
|
var index = action.substring(8);
|
||||||
|
if (!this.__action_choices_replaying(data, index)) {
|
||||||
|
core.control._replay_error(action);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 容错录像
|
||||||
|
if (main.replayChecking) {
|
||||||
|
// 录像验证系统中选最后一项
|
||||||
|
if (action != 'choices:none')
|
||||||
|
core.status.replay.toReplay.unshift(action); // 首先归还刚才读出的下一步操作
|
||||||
|
core.events.__action_choices_replaying(data, -1);
|
||||||
|
} else {
|
||||||
|
// 正常游戏中弹窗选择
|
||||||
|
core.myprompt(
|
||||||
|
'录像回放出错!当前需要执行选择项但录像中未记录。\n如需修复请输入您要选的项(从0起),点击取消将不会修复。',
|
||||||
|
0,
|
||||||
|
function (value) {
|
||||||
|
if (value == null) {
|
||||||
|
core.control._replay_error(action);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (action != 'choices:none')
|
||||||
|
core.status.replay.toReplay.unshift(action); // 首先归还刚才读出的下一步操作
|
||||||
|
core.events.__action_choices_replaying(
|
||||||
|
data,
|
||||||
|
((parseInt(value) || 0) + data.choices.length) %
|
||||||
|
data.choices.length
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (data.timeout) {
|
||||||
|
core.status.event.interval = setTimeout(function () {
|
||||||
|
core.status.route.push('choices:none');
|
||||||
|
core.setFlag('timeout', 0);
|
||||||
|
core.doAction();
|
||||||
|
}, data.timeout);
|
||||||
|
}
|
||||||
|
core.status.event.timeout = new Date().getTime() + (data.timeout || 0);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < data.choices.length; i++) {
|
||||||
|
if (typeof data.choices[i] === 'string')
|
||||||
|
data.choices[i] = { text: data.choices[i] };
|
||||||
|
data.choices[i].text = core.replaceText(data.choices[i].text, prefix);
|
||||||
|
}
|
||||||
core.ui.drawChoices(
|
core.ui.drawChoices(
|
||||||
core.replaceText(data.text, prefix),
|
core.replaceText(data.text, prefix),
|
||||||
data.choices,
|
data.choices,
|
||||||
@ -2582,17 +2646,41 @@ events.prototype._precompile_choices = function (data) {
|
|||||||
|
|
||||||
events.prototype._action_confirm = function (data, x, y, prefix) {
|
events.prototype._action_confirm = function (data, x, y, prefix) {
|
||||||
data.text = core.replaceText(data.text, prefix);
|
data.text = core.replaceText(data.text, prefix);
|
||||||
core.ui.drawConfirmBox(
|
core.status.event.ui = { text: data.text, yes: data.yes, no: data.no };
|
||||||
data.text,
|
if (core.isReplaying()) {
|
||||||
() => {
|
var action = core.status.replay.toReplay.shift();
|
||||||
core.insertAction(data.yes ?? []);
|
if (
|
||||||
core.doAction();
|
action.indexOf('choices:') == 0 &&
|
||||||
},
|
!(action == 'choices:none' && !data.timeout)
|
||||||
() => {
|
) {
|
||||||
core.insertAction(data.no ?? []);
|
var index = action.substring(8);
|
||||||
core.doAction();
|
if (
|
||||||
|
index == 'none' ||
|
||||||
|
((index = parseInt(index)) >= 0 && index % 100 < 2)
|
||||||
|
) {
|
||||||
|
this.__action_confirm_replaying(data, index);
|
||||||
|
} else {
|
||||||
|
core.control._replay_error(action);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 录像中未记录选了哪个,则选默认值,而不是直接报错
|
||||||
|
if (action != 'choices:none')
|
||||||
|
core.status.replay.toReplay.unshift(action);
|
||||||
|
this.__action_confirm_replaying(data, data['default'] ? 0 : 1);
|
||||||
}
|
}
|
||||||
);
|
} else {
|
||||||
|
core.status.event.selection = data['default'] ? 0 : 1;
|
||||||
|
if (data.timeout) {
|
||||||
|
core.status.event.interval = setTimeout(function () {
|
||||||
|
core.status.route.push('choices:none');
|
||||||
|
core.setFlag('timeout', 0);
|
||||||
|
core.doAction();
|
||||||
|
}, data.timeout);
|
||||||
|
}
|
||||||
|
core.status.event.timeout = new Date().getTime() + (data.timeout || 0);
|
||||||
|
}
|
||||||
|
core.ui.drawConfirmBox(data.text);
|
||||||
};
|
};
|
||||||
|
|
||||||
events.prototype.__action_confirm_replaying = function (data, index) {
|
events.prototype.__action_confirm_replaying = function (data, index) {
|
||||||
|
1742
public/libs/ui.js
1742
public/libs/ui.js
File diff suppressed because it is too large
Load Diff
1
src/types/declaration/control.d.ts
vendored
1
src/types/declaration/control.d.ts
vendored
@ -1179,7 +1179,6 @@ interface Control {
|
|||||||
): boolean;
|
): boolean;
|
||||||
_setAutomaticRoute_drawRoute(step: any): void;
|
_setAutomaticRoute_drawRoute(step: any): void;
|
||||||
_setAutomaticRoute_setAutoSteps(step: any): void;
|
_setAutomaticRoute_setAutoSteps(step: any): void;
|
||||||
__replay_getTimeout(): number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare const control: new () => Control;
|
declare const control: new () => Control;
|
||||||
|
2
src/types/declaration/ui.d.ts
vendored
2
src/types/declaration/ui.d.ts
vendored
@ -764,7 +764,7 @@ interface Ui {
|
|||||||
*/
|
*/
|
||||||
drawChoices(
|
drawChoices(
|
||||||
content: string,
|
content: string,
|
||||||
choices: object[],
|
choices: string[],
|
||||||
width?: number,
|
width?: number,
|
||||||
ctx?: CtxRefer
|
ctx?: CtxRefer
|
||||||
): void;
|
): void;
|
||||||
|
Loading…
Reference in New Issue
Block a user