Compare commits

...

8 Commits

19 changed files with 626 additions and 676 deletions

View File

@ -31,6 +31,7 @@ import {
TextAlign TextAlign
} from './textboxTyper'; } from './textboxTyper';
import { SetupComponentOptions } from '@motajs/system-ui'; import { SetupComponentOptions } from '@motajs/system-ui';
import { texture } from '../elements';
//#region TextContent //#region TextContent
@ -173,6 +174,8 @@ export const TextContent = defineComponent<
const renderContent = (canvas: MotaOffscreenCanvas2D) => { const renderContent = (canvas: MotaOffscreenCanvas2D) => {
const ctx = canvas.ctx; const ctx = canvas.ctx;
ctx.textBaseline = 'top'; ctx.textBaseline = 'top';
ctx.lineWidth = props.strokeWidth ?? 2;
ctx.lineJoin = 'round';
for (const data of renderable) { for (const data of renderable) {
if (data.cut) break; if (data.cut) break;
switch (data.type) { switch (data.type) {
@ -181,14 +184,15 @@ export const TextContent = defineComponent<
ctx.fillStyle = data.fillStyle; ctx.fillStyle = data.fillStyle;
ctx.strokeStyle = data.strokeStyle; ctx.strokeStyle = data.strokeStyle;
ctx.font = data.font; ctx.font = data.font;
const text = data.text.slice(0, data.pointer); const text = data.text.slice(0, data.pointer);
if (props.fill ?? true) {
ctx.fillText(text, data.x, data.y);
}
if (props.stroke) { if (props.stroke) {
ctx.strokeText(text, data.x, data.y); ctx.strokeText(text, data.x, data.y);
} }
if (props.fill ?? true) {
ctx.fillText(text, data.x, data.y);
}
break; break;
} }
case TextContentType.Icon: { case TextContentType.Icon: {
@ -248,6 +252,8 @@ export interface TextboxProps extends TextContentProps, DefaultProps {
titleStroke?: CanvasStyle; titleStroke?: CanvasStyle;
/** 标题文字与边框间的距离默认为4 */ /** 标题文字与边框间的距离默认为4 */
titlePadding?: number; titlePadding?: number;
/** 图标 */
icon?: AllIdsWithNone;
/** 最大宽度 */ /** 最大宽度 */
width: number; width: number;
} }
@ -307,30 +313,10 @@ export const Textbox = defineComponent<
keyof TextboxEmits, keyof TextboxEmits,
TextboxSlots TextboxSlots
>((props, { slots, expose, emit }) => { >((props, { slots, expose, emit }) => {
const contentData = shallowReactive<TextContentProps>({ width: 200 });
const data = shallowReactive<TextboxProps>({ width: 200 }); const data = shallowReactive<TextboxProps>({ width: 200 });
const setContentData = () => {
contentData.breakChars = props.breakChars ?? '';
contentData.font = props.font ?? new Font();
contentData.ignoreLineEnd = props.ignoreLineEnd ?? '';
contentData.ignoreLineStart = props.ignoreLineStart ?? '';
contentData.interval = props.interval ?? 0;
contentData.keepLast = props.keepLast ?? false;
contentData.lineHeight = props.lineHeight ?? 0;
contentData.text = props.text ?? '';
contentData.textAlign = props.textAlign ?? TextAlign.Left;
contentData.wordBreak = props.wordBreak ?? WordBreak.Space;
contentData.fill = props.fill ?? true;
contentData.stroke = props.stroke ?? false;
contentData.fillStyle = props.fillStyle ?? '#fff';
contentData.strokeStyle = props.strokeStyle ?? '#000';
contentData.strokeWidth = props.strokeWidth ?? 2;
contentData.loc = props.loc;
contentData.width = props.width;
};
const setTextboxData = () => { const setTextboxData = () => {
// Textbox
data.backColor = props.backColor ?? '#222'; data.backColor = props.backColor ?? '#222';
data.winskin = props.winskin; data.winskin = props.winskin;
data.padding = props.padding ?? 8; data.padding = props.padding ?? 8;
@ -341,9 +327,28 @@ export const Textbox = defineComponent<
data.width = props.width ?? props.loc?.[2] ?? 200; data.width = props.width ?? props.loc?.[2] ?? 200;
data.height = props.height ?? props.loc?.[3] ?? 200; data.height = props.height ?? props.loc?.[3] ?? 200;
data.title = props.title ?? ''; data.title = props.title ?? '';
data.icon = props.icon;
// TextContent
data.breakChars = props.breakChars ?? '';
data.font = props.font ?? new Font();
data.ignoreLineEnd = props.ignoreLineEnd ?? '';
data.ignoreLineStart = props.ignoreLineStart ?? '';
data.interval = props.interval ?? 0;
data.keepLast = props.keepLast ?? false;
data.lineHeight = props.lineHeight ?? 0;
data.text = props.text ?? '';
data.textAlign = props.textAlign ?? TextAlign.Left;
data.wordBreak = props.wordBreak ?? WordBreak.Space;
data.fill = props.fill ?? true;
data.stroke = props.stroke ?? false;
data.fillStyle = props.fillStyle ?? '#fff';
data.strokeStyle = props.strokeStyle ?? '#000';
data.strokeWidth = props.strokeWidth ?? 2;
data.loc = props.loc;
data.width = props.width;
}; };
setContentData();
setTextboxData(); setTextboxData();
watch(props, () => { watch(props, () => {
@ -361,23 +366,53 @@ export const Textbox = defineComponent<
const tw = ref(data.titlePadding! * 2); const tw = ref(data.titlePadding! * 2);
/** 标题高度 */ /** 标题高度 */
const th = ref(data.titlePadding! * 2); const th = ref(data.titlePadding! * 2);
const contentX = computed(() => {
if (hasIcon.value) {
return data.padding! + 40;
} else {
return data.padding!;
}
});
const contentY = computed(() => { const contentY = computed(() => {
const height = th.value; const height = th.value;
return data.title ? height : 0; return data.title ? height : 0;
}); });
const backHeight = computed(() => data.height! - contentY.value); const backHeight = computed(() => data.height! - contentY.value);
const contentWidth = computed(() => data.width! - data.padding! * 2); const contentWidth = computed(() => {
if (hasIcon.value) {
return data.width! - data.padding! * 2 - 40;
} else {
return data.width! - data.padding! * 2;
}
});
const contentHeight = computed( const contentHeight = computed(
() => data.height! - data.padding! * 2 - contentY.value () => data.height! - data.padding! * 2 - contentY.value
); );
const iconLoc = computed<ElementLocator>(() => {
const y = contentY.value;
const pad = data.padding!;
const icon = data.icon;
if (isNil(icon) || icon === 'none') {
return [];
} else {
const num = texture.idNumberMap[icon];
const renderable = texture.getRenderable(num);
if (!renderable) return [];
const [, , w, h] = renderable.render[0];
return [pad, pad + y, w, h];
}
});
const hasIcon = computed(() => {
return !isNil(data.icon) && data.icon !== 'none';
});
const onSetText = () => { const onSetText = () => {
nextTick(() => { nextTick(() => {
titleElement.value?.requestBeforeFrame(() => { titleElement.value?.requestBeforeFrame(() => {
if (titleElement.value) { if (titleElement.value) {
const { width, height } = titleElement.value; const { width, height } = titleElement.value;
tw.value = width + data.padding! * 2; tw.value = width + data.titlePadding! * 2;
th.value = height + data.padding! * 2; th.value = height + data.titlePadding! * 2;
} }
}); });
}); });
@ -385,6 +420,8 @@ export const Textbox = defineComponent<
//#region store //#region store
let lastTitle = data.title;
/** 结束打字机 */ /** 结束打字机 */
const storeEmits: TextboxStoreEmits = { const storeEmits: TextboxStoreEmits = {
endType() { endType() {
@ -397,23 +434,23 @@ export const Textbox = defineComponent<
hidden.value = false; hidden.value = false;
}, },
update(value) { update(value) {
if (data.title !== value.title) { if (value.title !== lastTitle) {
data.title = value.title;
onSetText(); onSetText();
lastTitle = value.title;
} }
}, },
setText(text) { setText(text) {
if (contentData.text === text) { if (data.text === text) {
content.value?.retype(); content.value?.retype();
} else { } else {
contentData.text = text; data.text = text;
} }
} }
}; };
const store = TextboxStore.use( const store = TextboxStore.use(
props.id ?? getNextTextboxId(), props.id ?? getNextTextboxId(),
contentData, data,
storeEmits storeEmits
); );
@ -447,7 +484,7 @@ export const Textbox = defineComponent<
id={props.id} id={props.id}
hidden={hidden.value} hidden={hidden.value}
alpha={data.alpha} alpha={data.alpha}
loc={props.loc} loc={data.loc}
> >
{data.title && ( {data.title && (
<container zIndex={10} loc={[0, 0, tw.value, th.value]}> <container zIndex={10} loc={[0, 0, tw.value, th.value]}>
@ -468,6 +505,7 @@ export const Textbox = defineComponent<
fillStyle={data.titleFill} fillStyle={data.titleFill}
strokeStyle={data.titleStroke} strokeStyle={data.titleStroke}
font={data.titleFont} font={data.titleFont}
strokeWidth={2}
></text> ></text>
</container> </container>
)} )}
@ -485,10 +523,23 @@ export const Textbox = defineComponent<
fillStyle={data.backColor} fillStyle={data.backColor}
></g-rect> ></g-rect>
)} )}
{hasIcon.value && (
<icon icon={data.icon as AllIds} loc={iconLoc.value} animate />
)}
{hasIcon.value && (
<g-rect
loc={iconLoc.value}
strokeStyle="gold"
fillStyle="#222"
lineWidth={2}
fill
stroke
/>
)}
<TextContent <TextContent
{...contentData} {...data}
ref={content} ref={content}
x={data.padding!} x={contentX.value}
y={contentY.value + data.padding!} y={contentY.value + data.padding!}
width={contentWidth.value} width={contentWidth.value}
height={contentHeight.value} height={contentHeight.value}
@ -531,7 +582,7 @@ export class TextboxStore extends EventEmitter<TextboxStoreEvent> {
typing: boolean = false; typing: boolean = false;
private constructor( private constructor(
private readonly data: TextboxProps, public readonly data: TextboxProps,
private readonly emits: TextboxStoreEmits private readonly emits: TextboxStoreEmits
) { ) {
super(); super();

View File

@ -336,6 +336,12 @@ export class TextContentTyper extends EventEmitter<TextContentTyperEvent> {
this.config[key] = value; this.config[key] = value;
} }
} }
if (config.font) {
this.config.fontFamily = config.font.family;
this.config.fontSize = config.font.size;
this.config.fontItalic = config.font.italic;
this.config.fontWeight = config.font.weight;
}
this.parser.setStatus({ this.parser.setStatus({
fillStyle: this.config.fillStyle, fillStyle: this.config.fillStyle,
fontFamily: this.config.fontFamily, fontFamily: this.config.fontFamily,
@ -528,7 +534,8 @@ export class TextContentTyper extends EventEmitter<TextContentTyperEvent> {
return; return;
} }
this.emit('typeStart'); this.emit('typeStart');
this.lastTypeTime = Date.now(); // 减去间隔是为了第一个字可以立刻打出来,不然看起来有延迟
this.lastTypeTime = Date.now() - this.config.interval - 1;
this.typing = true; this.typing = true;
} }
@ -628,11 +635,11 @@ export class TextContentParser {
* @param st * @param st
*/ */
setStatus(st: Partial<ParserStatus>) { setStatus(st: Partial<ParserStatus>) {
if (!isNil(st.fillStyle)) this.status.fillStyle = st.fillStyle; if (!isNil(st.fillStyle)) this.initStatus.fillStyle = st.fillStyle;
if (!isNil(st.fontSize)) this.status.fontSize = st.fontSize; if (!isNil(st.fontSize)) this.initStatus.fontSize = st.fontSize;
if (!isNil(st.fontFamily)) this.status.fontFamily = st.fontFamily; if (!isNil(st.fontFamily)) this.initStatus.fontFamily = st.fontFamily;
if (!isNil(st.fontItalic)) this.status.fontItalic = st.fontItalic; if (!isNil(st.fontItalic)) this.initStatus.fontItalic = st.fontItalic;
if (!isNil(st.fontWeight)) this.status.fontWeight = st.fontWeight; if (!isNil(st.fontWeight)) this.initStatus.fontWeight = st.fontWeight;
} }
/** /**
@ -856,6 +863,7 @@ export class TextContentParser {
this.font = this.buildFont(); this.font = this.buildFont();
this.resolved = ''; this.resolved = '';
this.wordBreak = [0]; this.wordBreak = [0];
this.wordBreakRule = this.config.wordBreak;
this.nodePointer = 0; this.nodePointer = 0;
this.blockPointer = 0; this.blockPointer = 0;
this.nowNode = 0; this.nowNode = 0;
@ -975,7 +983,6 @@ export class TextContentParser {
} }
this.addTextNode(text.length, false); this.addTextNode(text.length, false);
return this.splitLines(width); return this.splitLines(width);
} }
@ -1014,7 +1021,7 @@ export class TextContentParser {
this.blocks.forEach(v => { this.blocks.forEach(v => {
if (v.type !== TextContentType.Wait) { if (v.type !== TextContentType.Wait) {
width += v.width; width += v.width;
height = v.height; if (v.height > height) height = v.height;
} }
}); });
const line: ITextContentLine = { const line: ITextContentLine = {
@ -1198,7 +1205,11 @@ export class TextContentParser {
this.newLine(); this.newLine();
const nextStart = this.wordBreak[index]; const nextStart = this.wordBreak[index];
const nextEnd = this.wordBreak[end]; const nextEnd = this.wordBreak[end];
this.bsStart = index; if (index === this.bsStart) {
this.bsStart = this.bsStart + 1;
} else {
this.bsStart = index;
}
this.bsEnd = end; this.bsEnd = end;
const metrics = this.measure(node, nextStart, nextEnd); const metrics = this.measure(node, nextStart, nextEnd);
if (metrics.width < width) { if (metrics.width < width) {
@ -1338,11 +1349,9 @@ export class TextContentParser {
for (let i = 0; i < nodes.length; i++) { for (let i = 0; i < nodes.length; i++) {
const node = nodes[i]; const node = nodes[i];
if (node.type === TextContentType.Text) { if (node.type === TextContentType.Text) {
this.wordBreak = [node.text.length]; this.wordBreak = [0, node.text.length];
} }
const pointer = const block = this.generateBlock(node, 1);
node.type === TextContentType.Text ? node.text.length : 1;
const block = this.generateBlock(node, pointer);
this.pushBlock(block, 1); this.pushBlock(block, 1);
} }
this.newLine(); this.newLine();

View File

@ -66,8 +66,8 @@ export class Icon extends RenderItem<EIconEvent> implements IAnimateFrame {
* *
* @param id id * @param id id
*/ */
setIcon(id: AllIds | AllNumbers) { setIcon(id: AllIdsWithNone | AllNumbers) {
if (id === 0) { if (id === 0 || id === 'none') {
this.renderable = void 0; this.renderable = void 0;
return; return;
} }

View File

@ -1,6 +1,6 @@
import { createApp, Font } from '@motajs/render'; import { createApp, Font } from '@motajs/render';
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { MAIN_HEIGHT, MAIN_WIDTH } from './shared'; import { DEFAULT_FONT, MAIN_HEIGHT, MAIN_WIDTH } from './shared';
import { hook, loading } from '@user/data-base'; import { hook, loading } from '@user/data-base';
import { createLoopMap } from './loopMap'; import { createLoopMap } from './loopMap';
import { createElements } from './elements'; import { createElements } from './elements';
@ -45,7 +45,7 @@ export function createRender() {
sceneController.open(GameTitleUI, {}); sceneController.open(GameTitleUI, {});
}); });
Font.setDefaults(new Font('normal', 18)); Font.setDefaults(DEFAULT_FONT);
} }
export * from './components'; export * from './components';

View File

@ -1,4 +1,5 @@
import { ElementLocator } from '@motajs/render-core'; import { ElementLocator } from '@motajs/render-core';
import { Font } from '@motajs/render-style';
// 本文件为 UI 配置文件,你可以修改下面的每个常量来控制 UI 的显示参数,每个常量都有注释说明 // 本文件为 UI 配置文件,你可以修改下面的每个常量来控制 UI 的显示参数,每个常量都有注释说明
@ -60,15 +61,17 @@ export const CENTER_LOC: ElementLocator = [
/** 弹框的宽度,使用在内置 UI 与组件中,包括确认框、选择框、等待框等 */ /** 弹框的宽度,使用在内置 UI 与组件中,包括确认框、选择框、等待框等 */
export const POP_BOX_WIDTH = MAP_WIDTH / 2; export const POP_BOX_WIDTH = MAP_WIDTH / 2;
/** 默认字体 */
export const DEFAULT_FONT = new Font('normal', 18);
//#region 存档界面 //#region 存档界面
/** 存档缩略图尺寸 */ /** 存档缩略图尺寸 */
export const SAVE_ITEM_SIZE = 150; export const SAVE_ITEM_SIZE = MAP_BLOCK_WIDTH * 10;
/** 单个存档上方显示第几号存档的高度 */ /** 单个存档上方显示第几号存档的高度 */
export const SAVE_ITEM_TOP = 24; export const SAVE_ITEM_TOP = 24;
/** 单个存档下方显示这个存档信息的高度 */ /** 单个存档下方显示这个存档信息的高度 */
export const SAVE_ITEM_DOWN = 16; export const SAVE_ITEM_DOWN = 24;
/** 单个存档高度,包括存档下方的信息 */ /** 单个存档高度,包括存档下方的信息 */
export const SAVE_ITEM_HEIGHT = SAVE_ITEM_SIZE + SAVE_ITEM_TOP + SAVE_ITEM_DOWN; export const SAVE_ITEM_HEIGHT = SAVE_ITEM_SIZE + SAVE_ITEM_TOP + SAVE_ITEM_DOWN;
/** 存档间距 */ /** 存档间距 */

View File

@ -36,8 +36,7 @@ import {
RightStatusBar RightStatusBar
} from './statusBar'; } from './statusBar';
import { ReplayingStatus } from './toolbar'; import { ReplayingStatus } from './toolbar';
import { getHeroStatusOn, HeroSkill, NightSpecial } from '@user/data-state'; import { getHeroStatusOn } from '@user/data-state';
import { jumpIgnoreFloor } from '@user/legacy-plugin-data';
import { hook } from '@user/data-base'; import { hook } from '@user/data-base';
import { FloorDamageExtends, FloorItemDetail } from '../elements'; import { FloorDamageExtends, FloorItemDetail } from '../elements';
import { LayerGroupPortal } from '../legacy/portal'; import { LayerGroupPortal } from '../legacy/portal';
@ -76,14 +75,14 @@ const MainScene = defineComponent(() => {
const mainTextboxProps: Props<typeof Textbox> = { const mainTextboxProps: Props<typeof Textbox> = {
text: '', text: '',
hidden: true, hidden: true,
loc: [0, MAP_HEIGHT - 150, MAIN_WIDTH, 150], loc: [0, MAP_HEIGHT - 150, MAP_WIDTH, 150],
zIndex: 30, zIndex: 30,
fillStyle: '#fff', fillStyle: '#fff',
titleFill: 'gold', titleFill: 'gold',
font: new Font('normal'), font: new Font('normal'),
titleFont: new Font('normal', 20, 'px', 700), titleFont: new Font('normal', 20, 'px', 700),
winskin: 'winskin2.png', winskin: 'winskin2.png',
interval: 100, interval: 30,
lineHeight: 4, lineHeight: 4,
width: MAP_WIDTH width: MAP_WIDTH
}; };
@ -100,6 +99,13 @@ const MainScene = defineComponent(() => {
} }
}); });
const replayStatus: ReplayingStatus = reactive({
replaying: false,
playing: false,
speed: 1,
played: 0,
total: 0
});
const leftStatus: ILeftHeroStatus = reactive({ const leftStatus: ILeftHeroStatus = reactive({
hp: 0, hp: 0,
atk: 0, atk: 0,
@ -112,26 +118,10 @@ const MainScene = defineComponent(() => {
redKey: 0, redKey: 0,
floor: 'MT0', floor: 'MT0',
lv: '', lv: '',
regen: 0, replay: replayStatus
exAtk: 0,
magicDef: 0
});
const replayStatus: ReplayingStatus = reactive({
playing: false,
speed: 1,
played: 0,
total: 0
}); });
const rightStatus: IRightHeroStatus = reactive({ const rightStatus: IRightHeroStatus = reactive({
autoSkill: false, exampleHard: 0
skillName: '',
skillDesc: '',
jumpCount: 0,
springCount: 0,
floor: 'MT0',
replaying: false,
replayStatus,
night: 0
}); });
//#region 状态更新 //#region 状态更新
@ -140,7 +130,6 @@ const MainScene = defineComponent(() => {
hideStatus.value = core.getFlag('hideStatusBar', false); hideStatus.value = core.getFlag('hideStatusBar', false);
const hero = core.status.hero; const hero = core.status.hero;
const floor = core.status.floorId;
leftStatus.atk = getHeroStatusOn('atk'); leftStatus.atk = getHeroStatusOn('atk');
leftStatus.hp = getHeroStatusOn('hp'); leftStatus.hp = getHeroStatusOn('hp');
leftStatus.def = getHeroStatusOn('def'); leftStatus.def = getHeroStatusOn('def');
@ -152,35 +141,15 @@ const MainScene = defineComponent(() => {
leftStatus.redKey = core.itemCount('redKey'); leftStatus.redKey = core.itemCount('redKey');
leftStatus.floor = core.status.floorId; leftStatus.floor = core.status.floorId;
leftStatus.lv = core.getLvName(hero.lv); leftStatus.lv = core.getLvName(hero.lv);
leftStatus.regen = getHeroStatusOn('hpmax');
leftStatus.exAtk = getHeroStatusOn('mana');
leftStatus.magicDef = getHeroStatusOn('magicDef');
rightStatus.autoSkill = HeroSkill.getAutoSkill();
rightStatus.skillName = HeroSkill.getSkillName();
rightStatus.skillDesc = HeroSkill.getSkillDesc();
rightStatus.night = NightSpecial.getNight(floor);
rightStatus.floor = floor;
rightStatus.replaying = core.isReplaying();
const { pausing, speed, toReplay, totalList } = core.status.replay; const { pausing, speed, toReplay, totalList } = core.status.replay;
replayStatus.replaying = core.isReplaying();
replayStatus.playing = !pausing; replayStatus.playing = !pausing;
replayStatus.speed = speed; replayStatus.speed = speed;
replayStatus.played = totalList.length - toReplay.length; replayStatus.played = totalList.length - toReplay.length;
replayStatus.total = totalList.length; replayStatus.total = totalList.length;
if (HeroSkill.learnedSkill(HeroSkill.Jump)) {
if (jumpIgnoreFloor.has(floor)) { rightStatus.exampleHard = flags.hard;
rightStatus.jumpCount = -2;
} else {
rightStatus.jumpCount = 3 - (flags[`jump_${floor}`] ?? 0);
}
} else {
rightStatus.jumpCount = -1;
}
if (core.hasFlag('spring')) {
rightStatus.springCount = 50 - (flags.springCount ?? 0);
} else {
rightStatus.springCount = -1;
}
}; };
const updateDataFallback = () => { const updateDataFallback = () => {

View File

@ -69,8 +69,8 @@ const saveBtnProps = {
} satisfies SetupComponentOptions<SaveItemProps>; } satisfies SetupComponentOptions<SaveItemProps>;
export const SaveItem = defineComponent<SaveItemProps>(props => { export const SaveItem = defineComponent<SaveItemProps>(props => {
const font = new Font('normal', 18); const font = Font.defaults({ size: 18 });
const statusFont = new Font('normal', 14); const statusFont = Font.defaults({ size: 14 });
const w = computed(() => props.loc[2] ?? 200); const w = computed(() => props.loc[2] ?? 200);
const h = computed(() => props.loc[3] ?? 200); const h = computed(() => props.loc[3] ?? 200);
@ -93,6 +93,11 @@ export const SaveItem = defineComponent<SaveItemProps>(props => {
return `${hp}/${atk}/${def}`; return `${hp}/${atk}/${def}`;
} }
}); });
const timeText = computed(() => {
if (!props.data) return '';
const date = new Date(props.data.data.time);
return date.toLocaleString();
});
const strokeStyle = computed(() => { const strokeStyle = computed(() => {
if (props.selected) return props.inDelete ? 'red' : 'gold'; if (props.selected) return props.inDelete ? 'red' : 'gold';
@ -115,8 +120,8 @@ export const SaveItem = defineComponent<SaveItemProps>(props => {
<text <text
text={name.value} text={name.value}
font={font} font={font}
loc={[w.value / 2, SAVE_ITEM_TOP - 4]} loc={[w.value / 2, 0]}
anc={[0.5, 1]} anc={[0.5, 0]}
/> />
<g-rect <g-rect
loc={imgLoc.value} loc={imgLoc.value}
@ -143,7 +148,14 @@ export const SaveItem = defineComponent<SaveItemProps>(props => {
text={statusText.value} text={statusText.value}
fillStyle="yellow" fillStyle="yellow"
font={statusFont} font={statusFont}
loc={[w.value / 2, h.value - SAVE_ITEM_DOWN + 2]} loc={[w.value / 2, h.value - SAVE_ITEM_DOWN]}
anc={[0.5, 0]}
/>
<text
text={timeText.value}
fillStyle="yellow"
font={statusFont}
loc={[w.value / 2, h.value - SAVE_ITEM_DOWN + 12]}
anc={[0.5, 0]} anc={[0.5, 0]}
/> />
</container> </container>

View File

@ -1,26 +1,16 @@
import { GameUI, SetupComponentOptions } from '@motajs/system-ui'; import { GameUI, SetupComponentOptions } from '@motajs/system-ui';
import { computed, defineComponent, ref, watch } from 'vue'; import { computed, defineComponent, ref } from 'vue';
import { TextContent } from '../components'; import { TextContent } from '../components';
import { import { DefaultProps, ElementLocator, Font } from '@motajs/render';
DefaultProps,
ElementLocator,
Sprite,
Font,
MotaOffscreenCanvas2D
} from '@motajs/render';
import { transitionedColor } from '../use';
import { linear } from 'mutate-animate';
import { Scroll } from '../components';
import { getArea, MinimapDrawer } from '@motajs/legacy-ui';
import { import {
NumpadToolbar, NumpadToolbar,
PlayingToolbar, PlayingToolbar,
ReplayingStatus, ReplayingStatus,
ReplayingToolbar ReplayingToolbar
} from './toolbar'; } from './toolbar';
import { HeroSkill } from '@user/data-state';
import { openViewMap } from './viewmap'; import { openViewMap } from './viewmap';
import { mainUIController } from './controller'; import { mainUIController } from './controller';
import { MAIN_HEIGHT, STATUS_BAR_WIDTH } from '../shared';
export interface ILeftHeroStatus { export interface ILeftHeroStatus {
hp: number; hp: number;
@ -34,33 +24,12 @@ export interface ILeftHeroStatus {
redKey: number; redKey: number;
floor: FloorIds; floor: FloorIds;
lv: string; lv: string;
/** 生命回复 */ replay: ReplayingStatus;
regen: number;
/** 额外攻击 */
exAtk: number;
/** 魔法防御 */
magicDef: number;
} }
export interface IRightHeroStatus { export interface IRightHeroStatus {
/** 自动切换技能 */ /** 示例属性,以游戏难度作为示例 */
autoSkill: boolean; exampleHard: number;
/** 当前开启的技能 */
skillName: string;
/** 技能描述 */
skillDesc: string;
/** 跳跃剩余次数,-1 表示未开启,-2表示当前楼层不能跳 */
jumpCount: number;
/** 治愈之泉剩余次数,-1 表示未开启 */
springCount: number;
/** 当前楼层 */
floor: FloorIds;
/** 是否正在录像播放 */
replaying: boolean;
/** 录像播放状态 */
replayStatus: ReplayingStatus;
/** 极昼永夜 */
night: number;
} }
interface StatusBarProps<T> extends DefaultProps { interface StatusBarProps<T> extends DefaultProps {
@ -85,15 +54,20 @@ export const LeftStatusBar = defineComponent<StatusBarProps<ILeftHeroStatus>>(
const s = p.status; const s = p.status;
const f = core.formatBigNumber; const f = core.formatBigNumber;
const inNumpad = ref(false);
const floorName = computed(() => core.floors[s.floor]?.title ?? ''); const floorName = computed(() => core.floors[s.floor]?.title ?? '');
const key = (num: number) => { const key = (num: number) => {
return num.toString().padStart(2, '0'); return num.toString().padStart(2, '0');
}; };
const onNumpad = () => {
inNumpad.value = !inNumpad.value;
};
const font1 = Font.defaults({ size: 18 }); const font1 = Font.defaults({ size: 18 });
const font2 = Font.defaults({ size: 18, weight: 700 }); const font2 = Font.defaults({ size: 18, weight: 700 });
const font3 = Font.defaults({ size: 14, weight: 700 });
const iconLoc = (n: number): ElementLocator => { const iconLoc = (n: number): ElementLocator => {
return [16, 76 + 44 * n, 32, 32]; return [16, 76 + 44 * n, 32, 32];
@ -108,11 +82,6 @@ export const LeftStatusBar = defineComponent<StatusBarProps<ILeftHeroStatus>>(
return [width / 2, y, void 0, void 0, 0.5, 0.5]; return [width / 2, y, void 0, void 0, 0.5, 0.5];
}; };
const right = (y: number): ElementLocator => {
const width = p.loc[2] ?? 200;
return [width - 16, y, void 0, void 0, 1, 0.5];
};
const keyCount = 3; const keyCount = 3;
const keyY = 92 + 44 * 6; const keyY = 92 + 44 * 6;
const keyLoc = (n: number): ElementLocator => { const keyLoc = (n: number): ElementLocator => {
@ -137,30 +106,10 @@ export const LeftStatusBar = defineComponent<StatusBarProps<ILeftHeroStatus>>(
<text text={s.lv} loc={central(54)} font={font1}></text> <text text={s.lv} loc={central(54)} font={font1}></text>
<image image={hpIcon} loc={iconLoc(0)}></image> <image image={hpIcon} loc={iconLoc(0)}></image>
<text text={f(s.hp)} loc={textLoc(0)} font={font1}></text> <text text={f(s.hp)} loc={textLoc(0)} font={font1}></text>
<text
text={`+${f(s.regen)}/t`}
loc={right(110)}
font={font3}
fillStyle="#a7ffa7"
></text>
<image image={atkIcon} loc={iconLoc(1)}></image> <image image={atkIcon} loc={iconLoc(1)}></image>
<text text={f(s.atk)} loc={textLoc(1)} font={font1}></text> <text text={f(s.atk)} loc={textLoc(1)} font={font1}></text>
<text
text={`+${f(s.exAtk)}`}
loc={right(154)}
font={font3}
fillStyle="#ffd3d3"
></text>
<image image={defIcon} loc={iconLoc(2)}></image> <image image={defIcon} loc={iconLoc(2)}></image>
<text text={f(s.def)} loc={textLoc(2)} font={font1}></text> <text text={f(s.def)} loc={textLoc(2)} font={font1}></text>
{s.magicDef > 0 && (
<text
text={`+${f(s.magicDef)}`}
loc={right(198)}
font={font3}
fillStyle="#b0bdff"
></text>
)}
<image image={mdefIcon} loc={iconLoc(3)}></image> <image image={mdefIcon} loc={iconLoc(3)}></image>
<text text={f(s.mdef)} loc={textLoc(3)} font={font1}></text> <text text={f(s.mdef)} loc={textLoc(3)} font={font1}></text>
<image image={moneyIcon} loc={iconLoc(4)}></image> <image image={moneyIcon} loc={iconLoc(4)}></image>
@ -185,232 +134,59 @@ export const LeftStatusBar = defineComponent<StatusBarProps<ILeftHeroStatus>>(
font={font2} font={font2}
fillStyle="#f88" fillStyle="#f88"
></text> ></text>
<text <g-line
text="技能树" lineWidth={1}
loc={central(396)} strokeStyle="#888"
font={font1} line={[
cursor="pointer" 0,
></text> MAIN_HEIGHT - 113,
<text STATUS_BAR_WIDTH,
text="查看技能" MAIN_HEIGHT - 113
loc={central(428)} ]}
font={font1} />
cursor="pointer" {inNumpad.value ? (
></text> <NumpadToolbar
loc={[0, MAIN_HEIGHT - 113, STATUS_BAR_WIDTH, 113]}
onNumpad={onNumpad}
/>
) : s.replay.replaying ? (
<ReplayingToolbar
loc={[0, MAIN_HEIGHT - 113, STATUS_BAR_WIDTH, 113]}
status={s.replay}
/>
) : (
<PlayingToolbar
loc={[0, MAIN_HEIGHT - 113, STATUS_BAR_WIDTH, 113]}
onNumpad={onNumpad}
/>
)}
</container> </container>
); );
}, },
statusBarProps statusBarProps
); );
interface RightStatusBarMisc {
name: string;
value: string;
nameColor: string;
valueColor: string;
}
export const RightStatusBar = defineComponent<StatusBarProps<IRightHeroStatus>>( export const RightStatusBar = defineComponent<StatusBarProps<IRightHeroStatus>>(
p => { p => {
const font1 = new Font('normal', 18); // p.status 就是你在 main.tsx 中传入的属性内容,用法与左侧状态栏完全一致
const font2 = new Font('normal', 16);
const minimap = ref<Sprite>(); const text = `这里是右侧状态栏,如果左侧状态栏不够用可以在 \\r[gold]statusBar.tsx\\r 中编写内容,如果不需要此状态栏,可以在 \\r[gold]shared.ts\\r 中关闭此状态栏。`;
const inNumpad = ref(false);
const onNumpad = () => {
inNumpad.value = !inNumpad.value;
};
const s = p.status;
const skill = computed(() =>
s.autoSkill ? '已开启自动切换' : s.skillName
);
const skillDesc = computed(() =>
s.autoSkill ? '自动切换技能时,会自动选择最优技能' : s.skillDesc
);
const skillColor = transitionedColor('#284', 200, linear())!;
watch(
() => s.autoSkill,
value => {
skillColor.set(value ? '#284' : '#824');
}
);
const miscData = computed<RightStatusBarMisc[]>(() => {
const data: RightStatusBarMisc[] = [];
if (s.jumpCount !== -1) {
const text =
s.jumpCount === -2 ? '不可跳跃' : s.jumpCount.toString();
data.push({
name: '跳跃剩余',
nameColor: '#fff',
value: text,
valueColor: '#fff'
});
}
if (s.springCount >= 0) {
data.push({
name: '治愈之泉',
nameColor: '#a7ffa7',
value: s.springCount.toString(),
valueColor: '#a7ffa7'
});
}
if (s.night !== 0) {
const text = s.night.toString();
data.push({
name: '极昼永夜',
nameColor: '#a3f8ff',
value: s.night > 0 ? '+' + text : text,
valueColor: s.night > 0 ? '#a7ffa7' : '#ffa7a7'
});
}
return data;
});
const central = (y: number): ElementLocator => {
const width = p.loc[2] ?? 200;
return [width / 2, y, void 0, void 0, 0.5, 0.5];
};
const middle = (x: number, y: number): ElementLocator => {
return [x, y, void 0, void 0, 0, 0.5];
};
const changeAutoSkill = () => {
const auto = !s.autoSkill;
HeroSkill.setAutoSkill(auto);
core.status.route.push(`set:autoSkill:${auto}`);
core.updateStatusBar();
};
const area = getArea();
const minimapDrawer = new MinimapDrawer(
document.createElement('canvas')
);
minimapDrawer.noBorder = true;
minimapDrawer.scale = 4;
minimapDrawer.showInfo = true;
let linked = false;
const drawMinimap = (canvas: MotaOffscreenCanvas2D) => {
const ctx = canvas.ctx;
ctx.scale(
1 / core.domStyle.scale / devicePixelRatio,
1 / core.domStyle.scale / devicePixelRatio
);
if (!linked) {
minimapDrawer.link(canvas.canvas);
linked = true;
}
if (minimapDrawer.nowFloor !== s.floor) {
minimapDrawer.drawedThumbnail = {};
} else {
minimapDrawer.drawToTarget();
ctx.restore();
return;
}
minimapDrawer.nowFloor = s.floor;
minimapDrawer.nowArea =
Object.keys(area).find(v =>
area[v].includes(core.status.floorId)
) ?? '';
minimapDrawer.locateMap(minimapDrawer.nowFloor);
minimapDrawer.drawMap();
};
watch(
() => s.floor,
() => {
minimap.value?.update();
}
);
return () => { return () => {
return ( return (
<container loc={p.loc} hidden={p.hidden}> <container loc={p.loc} hidden={p.hidden}>
<g-rectr
loc={[10, 10, 160, 24]}
circle={[6]}
fillStyle={skillColor.ref.value}
onClick={changeAutoSkill}
cursor="pointer"
></g-rectr>
<text
loc={central(22)}
text={skill.value}
font={font1}
onClick={changeAutoSkill}
cursor="pointer"
/>
<TextContent <TextContent
loc={[10, 42, 160, 60]} loc={[8, 8]}
text={skillDesc.value} text={text}
font={new Font('normal', 14)} width={STATUS_BAR_WIDTH - 16}
width={160} autoHeight
lineHeight={4} lineHeight={8}
></TextContent> />
<g-line <text loc={[8, 270]} text="示例内容" />
line={[0, 107, 180, 107]} <text
strokeStyle="#888" loc={[8, 300]}
lineWidth={1} text={`游戏难度:${p.status.exampleHard}`}
zIndex={-20} />
></g-line>
<Scroll loc={[0, 107, 180, 100]}>
{miscData.value
.map((v, i) => {
return [
<text
text={v.name}
loc={middle(10, 16 + i * 22)}
fillStyle={v.nameColor}
font={font2}
></text>,
<text
text={v.value}
loc={middle(100, 16 + i * 22)}
fillStyle={v.valueColor}
font={font2}
></text>
];
})
.flat()}
</Scroll>
<g-line
line={[0, 207, 180, 207]}
strokeStyle="#888"
lineWidth={1}
zIndex={-20}
></g-line>
<sprite
ref={minimap}
loc={[10, 207, 160, 160]}
render={drawMinimap}
></sprite>
<g-line
line={[0, 367, 180, 367]}
strokeStyle="#888"
lineWidth={1}
zIndex={-20}
></g-line>
{inNumpad.value ? (
<NumpadToolbar
loc={[0, 367, 180, 113]}
onNumpad={onNumpad}
/>
) : s.replaying ? (
<ReplayingToolbar
loc={[0, 367, 180, 113]}
status={s.replayStatus}
/>
) : (
<PlayingToolbar
loc={[0, 367, 180, 113]}
onNumpad={onNumpad}
/>
)}
</container> </container>
); );
}; };

View File

@ -145,6 +145,8 @@ export const PlayingToolbar = defineComponent<
}, toolbarProps); }, toolbarProps);
export interface ReplayingStatus { export interface ReplayingStatus {
/** 是否处在录像播放状态 */
replaying: boolean;
/** 是否正在播放 */ /** 是否正在播放 */
playing: boolean; playing: boolean;
/** 录像播放速度 */ /** 录像播放速度 */
@ -153,6 +155,8 @@ export interface ReplayingStatus {
played: number; played: number;
/** 总长度 */ /** 总长度 */
total: number; total: number;
/** 是否是录像模式 */
replaying: boolean;
} }
export interface ReplayingProps extends ToolbarProps { export interface ReplayingProps extends ToolbarProps {
@ -378,3 +382,20 @@ export const NumpadToolbar = defineComponent<
</container> </container>
); );
}, toolbarProps); }, toolbarProps);
export const MixedToolbar = defineComponent<ReplayingProps>(props => {
const inNumpad = ref(false);
const onNumpad = () => {
inNumpad.value = !inNumpad.value;
};
return () =>
inNumpad.value ? (
<NumpadToolbar loc={props.loc} onNumpad={onNumpad} />
) : props.status.replaying ? (
<ReplayingToolbar loc={props.loc} status={props.status} />
) : (
<PlayingToolbar loc={props.loc} onNumpad={onNumpad} />
);
}, replayingProps);

View File

@ -52,6 +52,7 @@ export class Text extends RenderItem<ETextEvent> {
ctx.strokeStyle = this.strokeStyle ?? 'transparent'; ctx.strokeStyle = this.strokeStyle ?? 'transparent';
ctx.font = this.font.string(); ctx.font = this.font.string();
ctx.lineWidth = this.strokeWidth; ctx.lineWidth = this.strokeWidth;
ctx.lineJoin = 'round';
if (this.strokeStyle) { if (this.strokeStyle) {
ctx.strokeText(this.text, stroke, this.descent + stroke + SAFE_PAD); ctx.strokeText(this.text, stroke, this.descent + stroke + SAFE_PAD);

View File

@ -810,7 +810,11 @@ action
| comment_s | comment_s
| autoText_s | autoText_s
| scrollText_s | scrollText_s
| createTextbox_s
| deleteTextbox_s
| setText_s | setText_s
| createTip_s
| deleteTip_s
| tip_s | tip_s
| setValue_s | setValue_s
| setEquip_s | setEquip_s
@ -940,30 +944,27 @@ action
text_s text_s
: '标题' EvalString? '图标' EvalString? '像素坐标 x' IntString? 'y' IntString? '宽' IntString? '高' IntString? '维持文本' Bool '打字间隔' IntString? '行高' IntString? BGNL? Newline : '标题' EvalString? '图标' EvalString? '文本框id' EvalString? '像素坐标 x' IntString? 'y' IntString? '宽' IntString? '高' IntString? BGNL? Newline
EvalString_Multi Newline EvalString_Multi Newline
/* text_s /* text_s
tooltip : text显示一段文字剧情,选项较多请右键点击帮助 tooltip : text显示一段文字剧情文本框id 默认使用 main-textbox
helpUrl : /_docs/#/instruction helpUrl : /_docs/#/instruction
previewBlock : true previewBlock : true
allIds : ['EvalString_1'] allIds : ['EvalString_1']
default : ["小妖精","fairy","","","","",false,"","","欢迎使用事件编辑器"] default : ["","","","","","","","欢迎使用事件编辑器"]
EvalString_0= EvalString_0 ? (', "title": "'+EvalString_0+'"') : ''; EvalString_0= EvalString_0 ? (', "title": "'+EvalString_0+'"') : '';
EvalString_1= EvalString_1 ? (', "icon": "'+EvalString_1+'"') : ''; EvalString_1= EvalString_1 ? (', "icon": "'+EvalString_1+'"') : '';
EvalString_2= EvalString_2 ? (', "textbox": "'+EvalString_2+'"') : '';
IntString_0= IntString_0 ? (', "x": '+IntString_0) : ''; IntString_0= IntString_0 ? (', "x": '+IntString_0) : '';
IntString_1= IntString_1 ? (', "y": '+IntString_1) : ''; IntString_1= IntString_1 ? (', "y": '+IntString_1) : '';
IntString_2= IntString_2 ? (', "width": '+IntString_2) : ''; IntString_2= IntString_2 ? (', "width": '+IntString_2) : '';
IntString_3= IntString_3 ? (', "height": '+IntString_3) : ''; IntString_3= IntString_3 ? (', "height": '+IntString_3) : '';
IntString_4= IntString_4 ? (', "interval": '+IntString_4) : ''; var code = '{"type": "text"'+EvalString_0+EvalString_1+EvalString_2+IntString_0+IntString_1+IntString_2+IntString_3+', "text": "'+EvalString_Multi_0+'"},\n';
IntString_5= IntString_5 ? (', "lineHeight": '+IntString_5) : '';
var code = '{"type": "text"'+EvalString_0+EvalString_1+IntString_0+IntString_1+IntString_2+IntString_3+',"keepLast":'+Bool_0+IntString_4+IntString_5+'"text":"'+EvalString_Multi_0+'"},\n';
return code return code
*/; */;
comment_s comment_s
: '添加注释' ':' EvalString_Multi Newline : '添加注释' ':' EvalString_Multi Newline
@ -979,7 +980,7 @@ return code;
*/; */;
autoText_s autoText_s
: '自动剧情文本: 标题' EvalString? '图像' EvalString? '对话框效果' EvalString? '时间' Int BGNL? EvalString_Multi Newline : '自动剧情文本: 标题' EvalString? '图标' EvalString? '文本框id' EvalString? '像素坐标 x' IntString? 'y' IntString? '宽' IntString? '高' IntString? '时间' Int BGNL? EvalString_Multi Newline
/* autoText_s /* autoText_s
@ -987,40 +988,54 @@ tooltip : autoText自动剧情文本,用户无法跳过自动剧情文本,大
helpUrl : /_docs/#/instruction helpUrl : /_docs/#/instruction
doubleclicktext : EvalString_Multi_0 doubleclicktext : EvalString_Multi_0
allIds : ['EvalString_1'] allIds : ['EvalString_1']
default : ["小妖精","fairy","",3000,"用户无法跳过自动剧情文本,大段剧情文本请添加“是否跳过剧情”的提示"] default : ["","","","","","","",3000,"用户无法跳过自动剧情文本,大段剧情文本请添加“是否跳过剧情”的提示"]
var title=''; EvalString_0= EvalString_0 ? (', "title": "'+EvalString_0+'"') : '';
if (EvalString_0==''){ EvalString_1= EvalString_1 ? (', "icon": "'+EvalString_1+'"') : '';
if (EvalString_1=='' )title=''; EvalString_2= EvalString_2 ? (', "textbox": "'+EvalString_2+'"') : '';
else title='\\t['+EvalString_1+']'; IntString_0= IntString_0 ? (', "x": '+IntString_0) : '';
} else { IntString_1= IntString_1 ? (', "y": '+IntString_1) : '';
if (EvalString_1=='')title='\\t['+EvalString_0+']'; IntString_2= IntString_2 ? (', "width": '+IntString_2) : '';
else title='\\t['+EvalString_0+','+EvalString_1+']'; IntString_3= IntString_3 ? (', "height": '+IntString_3) : '';
} Int_0= ', "time": '+Int_0;
if(EvalString_2 && !(/^(up|center|down|hero|this)(,(hero|null|\d+,\d+|\d+))?$/.test(EvalString_2))) { var code = '{"type": "autoText"'+EvalString_0+EvalString_1+EvalString_2+IntString_0+IntString_1+IntString_2+IntString_3+Int0+', "text": "'+EvalString_Multi_0+'},\n';
throw new Error('对话框效果的用法请右键点击帮助');
}
EvalString_2 = EvalString_2 && ('\\b['+EvalString_2+']');
var code = '{"type": "autoText", "text": "'+title+EvalString_2+EvalString_Multi_0+'", "time": '+Int_0+'},\n';
return code; return code;
*/; */;
scrollText_s scrollText_s
: '滚动剧情文本:' '时间' Int '行距' Number '不等待执行完毕' Bool? BGNL? EvalString_Multi Newline : '滚动剧情文本事件将在 2.B.1 实装'
/* scrollText_s /* scrollText_s
tooltip : scrollText滚动剧情文本,将从下到上进行滚动显示。 tooltip : scrollText滚动剧情文本事件将在 2.B.1 实装
helpUrl : /_docs/#/instruction helpUrl : /_docs/#/instruction
doubleclicktext : EvalString_Multi_0 default : []
default : [5000,1.4,false,"时间是总时间可以使用setText事件来控制字体、颜色、大小、偏移量等"] return '{"type": "scrollText"}';
Bool_0 = Bool_0?', "async": true':'';
var code = '{"type": "scrollText", "text": "'+EvalString_Multi_0+'"'+Bool_0+', "time" :'+Int_0+', "lineHeight": '+Number_0+'},\n';
return code;
*/; */;
createTextbox_s
: '创建文本框将在 2.B.1 实装'
/* createTextbox_s
tooltip : createTextbox创建文本框事件将在 2.B.1 实装
helpUrl : /_docs/#/instruction
default : []
return '{"type": "createTextbox"},\n'
*/;
deleteTextbox_s
: '删除文本框将在 2.B.1 实装'
/* deleteTextbox_s
tooltip : deleteTextbox删除文本框事件将在 2.B.1 实装
helpUrl : /_docs/#/instruction
default : []
return '{"type": "deleteTextbox"},\n'
*/;
setText_s setText_s
: '设置剧情文本的属性' '位置像素x' IntString? 'y' IntString? '宽' IntString? '高' IntString? '字体类型' EvalString? '字体大小' IntString? '字体线宽' IntString? BGNL? : '配置文本框' '文本框id'EvalString '位置像素x' IntString? 'y' IntString? '宽' IntString? '高' IntString? '字体类型' EvalString? '字体大小' IntString? '字体线宽' IntString? '是否斜体' Bool? BGNL?
'是否斜体' Bool? '维持文本' Bool? '打字间隔' IntString? '行高' IntString? '文字颜色' ColorString? Colour '文字描边颜色' ColorString? Colour '描边线宽' IntString? '是否填充' Bool '是否描边' Bool BGNL? '维持文本' Bool? '打字间隔' IntString? '行高' IntString? '文字颜色' ColorString? Colour '文字描边颜色' ColorString? Colour '描边线宽' IntString? '是否填充' Bool '是否描边' Bool BGNL?
'背景色' ColorString? Colour '背景winskin' EvalString? '文字与边框距离' IntString? '标题是否填充' Bool '标题是否描边' Bool'标题与边框的距离' IntString? BGNL? '背景色' ColorString? Colour '背景winskin' EvalString? '文字与边框距离' IntString? '标题是否填充' Bool '标题是否描边' Bool'标题与边框的距离' IntString? BGNL?
'对齐方式' TextAlign_List '分词原则' WordBreak_List '行首禁则' EvalString? '行尾禁则' EvalString? '分词规则识别字符' EvalString? Newline '对齐方式' TextAlign_List '分词原则' WordBreak_List '行首禁则' EvalString? '行尾禁则' EvalString? '分词规则识别字符' EvalString? Newline
@ -1029,42 +1044,141 @@ setText_s
tooltip : setText设置文本的属性,颜色为RGB三元组或RGBA四元组,打字间隔为剧情文字添加的时间间隔,为整数或不填,字符间距为字符之间的距离,为整数或不填。 tooltip : setText设置文本的属性,颜色为RGB三元组或RGBA四元组,打字间隔为剧情文字添加的时间间隔,为整数或不填,字符间距为字符之间的距离,为整数或不填。
helpUrl : /_docs/#/instruction helpUrl : /_docs/#/instruction
previewBlock : true previewBlock : true
default : ["","","","","","","",false,false,"","","",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',"",true,false,"",'rgba(255,255,255,1)',"","",true,false,"",'null','space',"","",""] default : ["main-textbox","","","","","","","",false,false,"","","",'rgba(255,255,255,1)',"",'rgba(0,0,0,1)',"",true,false,"",'rgba(0,0,0,0.9)',"","",true,false,"",'null','null',"","",""]
Bool_0 = Bool_0 ? (', "fontItalic": '+Bool_0) : '';
Bool_1 = Bool_1 ? (', "keepLast": '+Bool_1) : '';
Bool_2 = !Bool_2 ? (', "fill": '+Bool_2) : '';
Bool_3 = Bool_3 ? (', "stroke": '+Bool_3) : '';
Bool_4 = !Bool_4 ? (', "titleFill": '+Bool_4) : '';
Bool_5 = Bool_5 ? (', "titleStroke": '+Bool_5) : '';
IntString_0= IntString_0 ? (', "x": '+IntString_0) : ''; IntString_0= IntString_0 ? (', "x": '+IntString_0) : '';
IntString_1 = IntString_1 ? (', "y": '+IntString_1) : ''; IntString_1 = IntString_1 ? (', "y": '+IntString_1) : '';
IntString_2 = IntString_2 ? (', "width": '+IntString_2) : ''; IntString_2 = IntString_2 ? (', "width": '+IntString_2) : '';
IntString_3 = IntString_3 ? (', "height": '+IntString_3) : ''; IntString_3 = IntString_3 ? (', "height": '+IntString_3) : '';
EvalString_0 = EvalString_0 ? (', "fontFamily": '+EvalString_0) : '';
IntString_4 = IntString_4 ? (', "fontSize": '+IntString_4) : ''; IntString_4 = IntString_4 ? (', "fontSize": '+IntString_4) : '';
IntString_5 = IntString_5 ? (', " interval": '+IntString_5) : ''; IntString_5 = IntString_5? (', "fontWeight": ' + IntString_5) : '';
IntString_6 = IntString_6 ? (', "lineHeight": ' + IntString_6) : ''; IntString_6 = IntString_6 ? (', "interval": '+IntString_6) : '';
IntString_7 = IntString_7? (', "strokeWidth": ' + IntString_7) : ''; IntString_7 = IntString_7 ? (', "lineHeight": ' + IntString_7) : '';
EvalString_1 = EvalString_1 ? (', "winskin": '+EvalString_1) : ''; IntString_8 = IntString_8? (', "strokeWidth": ' + IntString_8) : '';
IntString_8 = IntString_8? (', "padding": ' + IntString_8) : ''; IntString_9 = IntString_9? (', "padding": ' + IntString_9) : '';
IntString_9 = IntString_9? (', "titlePadding": ' + IntString_9) : ''; IntString_10 = IntString_10? (', "titlePadding": ' + IntString_10) : '';
EvalString_0 = EvalString_0 ? (', "textbox": "'+EvalString_0+'"') : '';
EvalString_1 = EvalString_1 ? (', "fontFamily": "'+EvalString_1+'"') : '';
EvalString_2 = EvalString_2 ? (', "winskin": "'+EvalString_2+'"') : '';
EvalString_3 = EvalString_3? (', "ignoreLineStart": "'+EvalString_3+'"') : '';
EvalString_4 = EvalString_4 ? (', "ignoreLineEnd": "'+EvalString_4+'"') : '';
EvalString_5 = EvalString_5 ? (', "breakChars": "'+EvalString_5+'"') : '';
ColorString_0=ColorString_0?(', "fillStyle": "rgba('+ColorString_0+')"'):'';
ColorString_1=ColorString_1?(', "strokeStyle": "rgba('+ColorString_1+')"'):'';
ColorString_2=ColorString_2?(', "backColor": "rgba('+ColorString_2+')"'):'';
TextAlign_List_0 = TextAlign_List_0==='null'?'':', "textAlign": "'+TextAlign_List_0+'"'; TextAlign_List_0 = TextAlign_List_0==='null'?'':', "textAlign": "'+TextAlign_List_0+'"';
WordBreak_List_0 = WordBreak_List_0==='null'?'':', "wordBreak": "'+WordBreak_List_0+'"'; WordBreak_List_0 = WordBreak_List_0==='null'?'':', "wordBreak": "'+WordBreak_List_0+'"';
EvalString_2 = EvalString_2? (', "ignoreLineStart": '+EvalString_2) : ''; var code =
EvalString_3 = EvalString_3 ? (', "ignoreLineEnd": '+EvalString_3) : ''; '{"type": "setText"'+
EvalString_4 = EvalString_4 ? (', "breakChars": '+EvalString_4) : ''; EvalString_0+ IntString_0+ IntString_1+ IntString_2+ IntString_3+ EvalString_1+ IntString_4+ IntString_5+ Bool_0+
ColorString_0=ColorString_0?(', "fillStyle": ['+ColorString_0+']'):''; Bool_1+ IntString_6+ IntString_7+ ColorString_0+ ColorString_1+ IntString_8+ Bool_2+ Bool_3+
ColorString_1=ColorString_1?(', "strokeStyle": ['+ColorString_1+']'):''; ColorString_2+ EvalString_2+ IntString_9+ Bool_4+ Bool_5+ IntString_10+
ColorString_2=ColorString_2?(', "backColor": ['+ColorString_2+']'):''; TextAlign_List_0+ WordBreak_List_0+ EvalString_3+ EvalString_4+ EvalString_5+
var code = '{"type": "setText"'+IntString_0+IntString_1+IntString_2+IntString_3+EvalString_0+IntString_4+', " fontItalic": '+Bool_0+', " keepLast": '+Bool_1+IntString_5+IntString_6+ColorString_0+ColorString_1+IntString_7 +',"fill":'+Bool_2+',"stroke":'+Bool_3+ColorString_2+EvalString_1+IntString_8+',"titleFill":'+Bool_4+',"titleStroke":'+Bool_5+IntString_9 +TextAlign_List_0+WordBreak_List_0+EvalString_2+EvalString_3+EvalString_4+'},\n'; '},\n';
return code; return code;
*/; */;
createTip_s
: '创建提示栏事件将在 2.B.1 实装'
/* createTip_s
tooltip : createTip创建提示栏事件将在 2.B.1 实装
helpUrl : /_docs/#/instruction
default : []
return '{"type": "createTip"}';
*/;
deleteTip_s
: '删除提示栏事件将在 2.B.1 实装'
/* deleteTip_s
tooltip : createTip删除提示栏事件将在 2.B.1 实装
helpUrl : /_docs/#/instruction
default : []
return '{"type": "deleteTip"}';
*/;
tip_s tip_s
: '显示提示' ':' EvalString '图标ID' IdString? Newline : '显示提示' '提示栏id' EvalString? '图标ID' IdString? BGNL?
'提示内容' EvalString Newline
/* tip_s /* tip_s
tooltip : tip显示一段提示文字 tooltip : tip显示一段提示文字
helpUrl : /_docs/#/instruction helpUrl : /_docs/#/instruction
allIds : ['IdString_0'] allIds : ['IdString_0']
default : ["这段话将在左上角以气泡形式显示",""] default : ["","","这段话将在左上角以气泡形式显示"]
IdString_0 = IdString_0 && (', "icon": "' + IdString_0 + '"'); EvalString_0 = EvalString_0 ? (', "tip": "' + EvalString_0 + '"') : '';
var code = '{"type": "tip", "text": "'+EvalString_0+'"'+IdString_0+'},\n'; IdString_0 = IdString_0 ? (', "icon": "' + IdString_0 + '"') : '';
EvalString_1 = EvalString_1 ? (', "text": "' + EvalString_1 + '"') : '';
var code = '{"type": "tip"'+EvalString_0+IdString_0+EvalString_1+'},\n';
return code;
*/;
confirm_s
: '显示确认框' ':' EvalString_Multi '超时毫秒数' Int BGNL? '确定的场合' ':' '(默认选中' Bool '' BGNL? Newline action+ '取消的场合' ':' BGNL? Newline action+ BEND Newline
/* confirm_s
tooltip : 弹出确认框
helpUrl : /_docs/#/instruction
default : ["确认要xxx吗?",0,false]
previewBlock : true
Bool_0 = Bool_0?', "default": true':''
Int_0 = Int_0 ? (', "timeout": '+Int_0) : '';
var code = ['{"type": "confirm"'+Int_0+Bool_0+', "text": "',EvalString_Multi_0,'",',
block.isCollapsed()?' "_collapsed": true,':'',
block.isEnabled()?'':' "_disabled": true,',
'\n"yes": [\n',action_0,'],\n',
'"no": [\n',action_1,']\n',
'},\n'].join('');
return code;
*/;
choices_s
: '选项' ':' EvalString_Multi? BGNL? '标题' EvalString? '图像' IdString? '超时毫秒数' Int BGNL? Newline choicesContext+ BEND Newline
/* choices_s
tooltip : choices: 给用户提供选项
helpUrl : /_docs/#/instruction
previewBlock : true
default : ["","","",0]
allIds : ['IdString_0']
EvalString_0 = EvalString_0 ? (', "title": "' + EvalString_0 + '"') : '';
IdString_0 = IdString_0 ? (', "icon": "' + IdString_0 + '"') : '';
EvalString_Multi_0 = EvalString_Multi_0 ?(', "text": "'+EvalString_Multi_0+'"'):'';
Int_0 = Int_0 ? (', "timeout": '+Int_0) : '';
var code = ['{"type": "choices"',EvalString_0,IdString_0,EvalString_Multi_0,Int_0,
block.isCollapsed()?', "_collapsed": true':'',
block.isEnabled()?'':', "_disabled": true',
', "choices": [\n',
choicesContext_0,
']},\n'].join('');
return code;
*/;
choicesContext
: '子选项' EvalString '图标' IdString? '颜色' ColorString? Colour '启用条件' EvalString? '出现条件' EvalString? BGNL? Newline action+
/* choicesContext
tooltip : 选项的选择
helpUrl : /_docs/#/instruction
default : ["提示文字:红钥匙","","","",""]
allIds : ['IdString_0']
colour : this.subColor
ColorString_0 = ColorString_0 ? (', "color": ['+ColorString_0+']') : '';
EvalString_1 = EvalString_1 && (', "need": "'+EvalString_1+'"');
EvalString_2 = EvalString_2 && (', "condition": "'+EvalString_2+'"');
IdString_0 = IdString_0?(', "icon": "'+IdString_0+'"'):'';
var collapsed=block.isCollapsed()?', "_collapsed": true':'';
var disabled=block.isEnabled()?'':', "_disabled": true';
var code = '{"text": "'+EvalString_0+'"'+IdString_0+ColorString_0+EvalString_1+EvalString_2+collapsed+disabled+', "action": [\n'+action_0+']},\n';
return code; return code;
*/; */;
@ -2470,76 +2584,6 @@ var code = '{"case": "'+expression_0+'"'+Bool_0+collapsed+disabled+', "action":
return code; return code;
*/; */;
choices_s
: '选项' ':' EvalString_Multi? BGNL? '标题' EvalString? '图像' IdString? '超时毫秒数' Int '宽度' IntString? BGNL? Newline choicesContext+ BEND Newline
/* choices_s
tooltip : choices: 给用户提供选项
helpUrl : /_docs/#/instruction
previewBlock : true
default : ["","流浪者","trader",0,'']
allIds : ['IdString_0']
var title='';
if (EvalString_0==''){
if (IdString_0=='')title='';
else title='\\t['+IdString_0+']';
} else {
if (IdString_0=='')title='\\t['+EvalString_0+']';
else title='\\t['+EvalString_0+','+IdString_0+']';
}
EvalString_Multi_0 = title+EvalString_Multi_0;
EvalString_Multi_0 = EvalString_Multi_0 ?(', "text": "'+EvalString_Multi_0+'"'):'';
Int_0 = Int_0 ? (', "timeout": '+Int_0) : '';
IntString_0 = IntString_0 ? (', "width": ' + IntString_0) : '';
var code = ['{"type": "choices"',EvalString_Multi_0,Int_0,IntString_0,
block.isCollapsed()?', "_collapsed": true':'',
block.isEnabled()?'':', "_disabled": true',
', "choices": [\n',
choicesContext_0,
']},\n'].join('');
return code;
*/;
choicesContext
: '子选项' EvalString '图标' IdString? '颜色' ColorString? Colour '启用条件' EvalString? '出现条件' EvalString? BGNL? Newline action+
/* choicesContext
tooltip : 选项的选择
helpUrl : /_docs/#/instruction
default : ["提示文字:红钥匙","","","",""]
allIds : ['IdString_0']
colour : this.subColor
ColorString_0 = ColorString_0 ? (', "color": ['+ColorString_0+']') : '';
EvalString_1 = EvalString_1 && (', "need": "'+EvalString_1+'"');
EvalString_2 = EvalString_2 && (', "condition": "'+EvalString_2+'"');
IdString_0 = IdString_0?(', "icon": "'+IdString_0+'"'):'';
var collapsed=block.isCollapsed()?', "_collapsed": true':'';
var disabled=block.isEnabled()?'':', "_disabled": true';
var code = '{"text": "'+EvalString_0+'"'+IdString_0+ColorString_0+EvalString_1+EvalString_2+collapsed+disabled+', "action": [\n'+action_0+']},\n';
return code;
*/;
confirm_s
: '显示确认框' ':' EvalString_Multi '超时毫秒数' Int BGNL? '确定的场合' ':' '(默认选中' Bool '' BGNL? Newline action+ '取消的场合' ':' BGNL? Newline action+ BEND Newline
/* confirm_s
tooltip : 弹出确认框
helpUrl : /_docs/#/instruction
default : ["确认要xxx吗?",0,false]
previewBlock : true
Bool_0 = Bool_0?', "default": true':''
Int_0 = Int_0 ? (', "timeout": '+Int_0) : '';
var code = ['{"type": "confirm"'+Int_0+Bool_0+', "text": "',EvalString_Multi_0,'",',
block.isCollapsed()?' "_collapsed": true,':'',
block.isEnabled()?'':' "_disabled": true,',
'\n"yes": [\n',action_0,'],\n',
'"no": [\n',action_1,']\n',
'},\n'].join('');
return code;
*/;
for_s for_s
: '循环遍历' ': ' expression '从' EvalString '到' EvalString '步增' EvalString BGNL? Newline action+ BEND Newline : '循环遍历' ': ' expression '从' EvalString '到' EvalString '步增' EvalString BGNL? Newline action+ BEND Newline

View File

@ -257,33 +257,60 @@ ActionParser.prototype.parseAction = function() {
return; return;
case "text": // 文字/对话 case "text": // 文字/对话
this.next = MotaActionBlocks['text_s'].xmlText([ this.next = MotaActionBlocks['text_s'].xmlText([
data.title, data.icon, data.x, data.y, data.width, data.height, data.keepLast,data.interval,data.lineHeight, this.next]); data.title,data.icon,data.textbox,data.x,data.y,data.width,data.height,data.text,this.next]);
break; break;
case "autoText": // 自动剧情文本 case "autoText": // 自动剧情文本
var info = this.getTitleAndPosition(data.text);
this.next = MotaActionBlocks['autoText_s'].xmlText([ this.next = MotaActionBlocks['autoText_s'].xmlText([
info[0],info[1],info[2],data.time,info[3],this.next]); data.title,data.icon,data.textbox,data.x,data.y,data.width,data.height,data.time,data.text,this.next]);
break; break;
case "scrollText": case "scrollText":
this.next = MotaActionBlocks['scrollText_s'].xmlText([ this.next = MotaActionBlocks['scrollText_s'].xmlText([this.next]);
data.time, data.lineHeight||1.4, data.async||false, this.EvalString_Multi(data.text), this.next]);
break; break;
case "comment": // 注释 case "comment": // 注释
this.next = MotaActionBlocks['comment_s'].xmlText([this.EvalString_Multi(data.text),this.next]); this.next = MotaActionBlocks['comment_s'].xmlText([this.EvalString_Multi(data.text),this.next]);
break; break;
case "createTextbox":
this.next = MotaActionBlocks['createTextbox_s'].xmlText([this.next]);
case "createTextbox":
this.next = MotaActionBlocks['deleteTextbox_s'].xmlText([this.next]);
case "setText": // 设置剧情文本的属性 case "setText": // 设置剧情文本的属性
//data.backColor=this.Colour(data.backColor); const parsedFillStyle = data.fillStyle ? data.fillStyle.slice(5, -1) : '';
//data.fillStyle=this.Colour(data.fillStyle); const parsedStrokeStyle = data.strokeStyle ? data.strokeStyle.slice(5, -1) : '';
//data.strokeStyle=this.Colour(data.strokeStyle); const parsedBackColor = data.backColor ? data.backColor.slice(5, -1) : '';
this.next = MotaActionBlocks['setText_s'].xmlText([ this.next = MotaActionBlocks['setText_s'].xmlText([
data.x,data.y,data.width,data.height,data.fontFamily,data.fontSize,data.fontWeight, data.textbox, data.x, data.y, data.width, data.height, data.fontFamily, data.fontSize, data.fontWeight, data.fontItalic,
data.fontItalic,data.keepLast,data.interval,data.lineHeight,,data.fillStyle,'rgba('+data.fillStyle+')', data.keepLast, data.interval, data.lineHeight, parsedFillStyle, data.fillStyle, parsedStrokeStyle, data.strokeStyle, data.strokeWidth, data.fill, data.stroke,
data.strokeStyle,'rgba('+data.strokeStyle+')',data.strokeWidth,data.fill,data.stroke,data.backColor,'rgba('+data.backColor+')', parsedBackColor, data.backColor, data.winskin, data.padding, data.titleFill, data.titleStroke, data.titlePadding,
data.winskin,data.padding,data.titleFill,data.titleStroke,data.titlePadding,data.textAlign,data.wordBreak,data.ignoreLineStart,data.ignoreLineEnd,data.breakChars,this.next]); data.textAlign, data.wordBreak, data.ignoreLineStart, data.ignoreLineEnd, data.breakChars, this.next
]);
break; break;
case "createTip":
this.next = MotaActionBlocks['createTip_s'].xmlText([this.next]);
case "deleteTip":
this.next = MotaActionBlocks['deletetip_s'].xmlText([this.next]);
case "tip": case "tip":
this.next = MotaActionBlocks['tip_s'].xmlText([ this.next = MotaActionBlocks['tip_s'].xmlText([
data.text,data.icon||"",this.next]); data.tip,data.icon||"",data.text,this.next]);
break;
case "confirm": // 显示确认框
this.next = MotaActionFunctions.xmlText('confirm_s', [
this.EvalString_Multi(data.text), data.timeout||0, data["default"],
this.insertActionList(data["yes"]),
this.insertActionList(data["no"]),
this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled);
break;
case "choices": // 提供选项
var text_choices = null;
for(var ii=data.choices.length-1,choice;choice=data.choices[ii];ii--) {
choice.color = this.Colour(choice.color);
text_choices=MotaActionFunctions.xmlText('choicesContext', [
choice.text,choice.icon,choice.color,'rgba('+choice.color+')',choice.need||'',choice.condition||'',this.insertActionList(choice.action),text_choices],
/* isShadow */false, /*comment*/ null, /*collapsed*/ choice._collapsed, /*disabled*/ choice._disabled);
}
if (!this.isset(data.text)) data.text = '';
var info = this.getTitleAndPosition(data.text);
this.next = MotaActionFunctions.xmlText('choices_s', [
info[3],info[0],info[1],data.timeout||0,text_choices,this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled);
break; break;
case "show": // 显示 case "show": // 显示
data.loc=data.loc||[]; data.loc=data.loc||[];
@ -722,13 +749,6 @@ ActionParser.prototype.parseAction = function() {
this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled);
} }
break; break;
case "confirm": // 显示确认框
this.next = MotaActionFunctions.xmlText('confirm_s', [
this.EvalString_Multi(data.text), data.timeout||0, data["default"],
this.insertActionList(data["yes"]),
this.insertActionList(data["no"]),
this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled);
break;
case "switch": // 多重条件分歧 case "switch": // 多重条件分歧
var case_caseList = null; var case_caseList = null;
for(var ii=data.caseList.length-1,caseNow;caseNow=data.caseList[ii];ii--) { for(var ii=data.caseList.length-1,caseNow;caseNow=data.caseList[ii];ii--) {
@ -740,19 +760,6 @@ ActionParser.prototype.parseAction = function() {
this.expandEvalBlock([data.condition]), this.expandEvalBlock([data.condition]),
case_caseList,this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); case_caseList,this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled);
break; break;
case "choices": // 提供选项
var text_choices = null;
for(var ii=data.choices.length-1,choice;choice=data.choices[ii];ii--) {
choice.color = this.Colour(choice.color);
text_choices=MotaActionFunctions.xmlText('choicesContext', [
choice.text,choice.icon,choice.color,'rgba('+choice.color+')',choice.need||'',choice.condition||'',this.insertActionList(choice.action),text_choices],
/* isShadow */false, /*comment*/ null, /*collapsed*/ choice._collapsed, /*disabled*/ choice._disabled);
}
if (!this.isset(data.text)) data.text = '';
var info = this.getTitleAndPosition(data.text);
this.next = MotaActionFunctions.xmlText('choices_s', [
info[3],info[0],info[1],data.timeout||0,data.width,text_choices,this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled);
break;
case "for": // 循环遍历 case "for": // 循环遍历
this.next = MotaActionFunctions.xmlText('for_s',[ this.next = MotaActionFunctions.xmlText('for_s',[
this.expandEvalBlock([data.name]), this.expandEvalBlock([data.name]),

View File

@ -19,8 +19,8 @@ editor_blocklyconfig=(function(){
'入口方块':[ '入口方块':[
'<label text="入口方块会根据当前类型在此数组中筛选,具体控制在editor_blockly.entranceCategoryCallback中"></label>', '<label text="入口方块会根据当前类型在此数组中筛选,具体控制在editor_blockly.entranceCategoryCallback中"></label>',
MotaActionFunctions.actionParser.parse([ MotaActionFunctions.actionParser.parse([
"欢迎使用事件编辑器", {"type": "text", "text": "欢迎使用事件编辑器"},
"本事件触发一次后会消失", {"type": "text", "text": "本事件触发一次后会消失"},
{"type": "hide", "time": 500}, {"type": "hide", "time": 500},
],'event'), ],'event'),
MotaActionFunctions.actionParser.parse({ MotaActionFunctions.actionParser.parse({
@ -96,16 +96,19 @@ editor_blocklyconfig=(function(){
], 'splitImages'), ], 'splitImages'),
], ],
'显示文字':[ '显示文字':[
MotaActionBlocks['text_s'].xmlText(),
MotaActionBlocks['comment_s'].xmlText(), MotaActionBlocks['comment_s'].xmlText(),
MotaActionBlocks['text_s'].xmlText(),
MotaActionBlocks['autoText_s'].xmlText(), MotaActionBlocks['autoText_s'].xmlText(),
MotaActionBlocks['scrollText_s'].xmlText(), MotaActionBlocks['scrollText_s'].xmlText(),
MotaActionBlocks['createTextbox_s'].xmlText(),
MotaActionBlocks['deleteTextbox_s'].xmlText(),
MotaActionBlocks['setText_s'].xmlText(), MotaActionBlocks['setText_s'].xmlText(),
MotaActionBlocks['createTip_s'].xmlText(),
MotaActionBlocks['deleteTip_s'].xmlText(),
MotaActionBlocks['tip_s'].xmlText(), MotaActionBlocks['tip_s'].xmlText(),
MotaActionBlocks['confirm_s'].xmlText(), MotaActionBlocks['confirm_s'].xmlText(),
MotaActionBlocks['choices_s'].xmlText([ MotaActionBlocks['choices_s'].xmlText([
'选择剑或者盾','流浪者','man',0,'',MotaActionBlocks['choicesContext'].xmlText([ '选择剑或者盾','流浪者','man','',MotaActionBlocks['choicesContext'].xmlText([
'剑','','',null,'','',MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [3,3]}]), '剑','','',null,'','',MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [3,3]}]),
]) ])
]), ]),

View File

@ -1100,11 +1100,8 @@ actions.prototype._clickAction_text = function () {
if (core.status.event.animateUI) return; if (core.status.event.animateUI) return;
const Store = Mota.require('@user/client-modules').TextboxStore; const Store = Mota.require('@user/client-modules').TextboxStore;
const store = Store.get('main-textbox'); const id = core.events.nowTextbox ?? 'main-textbox';
const store = Store.get(id);
// var data = core.clone(core.status.event.data.current);
// if (typeof data == 'string') data = { type: 'text', text: data };
// 打字机效果显示全部文字 // 打字机效果显示全部文字
if (store.typing) { if (store.typing) {
store.endType(); store.endType();
@ -1112,19 +1109,8 @@ actions.prototype._clickAction_text = function () {
} else { } else {
store.hide(); store.hide();
} }
// if (core.status.event.interval != null) {
// data.showAll = true;
// core.insertAction(data);
// core.doAction();
// return;
// }
if (!data.code) { core.doAction();
core.ui._animateUI('hide', null, core.doAction);
} else {
// 不清除对话框
core.doAction();
}
}; };
////// 自定义事件时的点击操作 ////// ////// 自定义事件时的点击操作 //////

View File

@ -876,6 +876,22 @@ control.prototype.setHeroOpacity = function (
////// 设置画布偏移 ////// 设置画布偏移
control.prototype.setGameCanvasTranslate = function (canvas, x, y) { control.prototype.setGameCanvasTranslate = function (canvas, x, y) {
// Deprecated. Use RenderItem.transform instead. // Deprecated. Use RenderItem.transform instead.
// For editor compatibility.
var c = core.dom.gameCanvas[canvas];
x = x * core.domStyle.scale;
y = y * core.domStyle.scale;
c.style.transform = 'translate(' + x + 'px,' + y + 'px)';
c.style.webkitTransform = 'translate(' + x + 'px,' + y + 'px)';
c.style.OTransform = 'translate(' + x + 'px,' + y + 'px)';
c.style.MozTransform = 'translate(' + x + 'px,' + y + 'px)';
if (main.mode === 'editor' && editor.isMobile) {
c.style.transform =
'translate(' +
(x / core._PX_) * 96 +
'vw,' +
(y / core._PY_) * 96 +
'vw)';
}
}; };
////// 加减画布偏移 ////// 加减画布偏移

View File

@ -1563,109 +1563,71 @@ events.prototype.__action_doAsyncFunc = function (isAsync, func) {
} }
}; };
events.prototype._action_text = function (data, x, y, prefix) { events.prototype._action_text = function (data) {
if (this.__action_checkReplaying()) return; if (this.__action_checkReplaying()) return;
const Store = Mota.require('@user/client-modules').TextboxStore; const Store = Mota.require('@user/client-modules').TextboxStore;
const store = Store.get('main-textbox'); const { textbox = 'main-textbox', text, icon = 'none', title = '' } = data;
const { text } = data; const store = Store.get(textbox);
let title = ''; if (!store) {
let inTitle = false; core.doAction();
let titleStartIndex = 0; return;
let titleEndIndex = 0;
for (let i = 0; i < text.length; i++) {
const char = text[i];
if (inTitle) {
if (char === '\\' && text[i + 1] === ']') {
title += ']';
i++;
} else if (char === ']') {
inTitle = false;
titleEndIndex = i + 1;
break;
} else {
title += char;
}
continue;
}
if (char === '\t' && text[i + 1] === '[') {
inTitle = true;
titleStartIndex = i;
// 跳转至方括号内
i++;
continue;
}
if (char === '\\' && text[i + 1] === 't' && text[i + 2] === '[') {
inTitle = true;
titleStartIndex = i;
// 跳转至方括号内
i += 2;
continue;
}
} }
const loc = store.data.loc?.slice() ?? [];
const showText = text.slice(0, titleStartIndex) + text.slice(titleEndIndex); loc[0] ??= 0;
loc[1] ??= 0;
loc[2] ??= 200;
loc[3] ??= 200;
const { x = loc[0], y = loc[1], width = loc[2], height = loc[3] } = data;
store.show(); store.show();
store.modify({ title }); store.modify({
store.setText(showText); title,
icon,
// data.text = core.replaceText(data.text, prefix); x,
// var ctx = data.code ? '__text__' + data.code : null; y,
// data.ctx = ctx; width,
// if (core.getContextByName(ctx) && !data.showAll) { height,
// core.ui._animateUI('hide', ctx, function () { loc: [x, y, width, height]
// core.ui.drawTextBox(data.text, data); });
// core.ui._animateUI('show', ctx, function () { store.setText(text);
// if (data.async) core.doAction(); core.events.nowTextbox = textbox;
// });
// });
// return;
// }
// core.ui.drawTextBox(data.text, data);
// if (!data.showAll) {
// core.ui._animateUI('show', ctx, function () {
// if (data.async) core.doAction();
// });
// }
}; };
events.prototype._action_moveTextBox = function (data, x, y, prefix) { events.prototype._action_autoText = function (data) {
if (this.__action_checkReplaying()) return; if (this.__action_checkReplaying()) return;
this.__action_doAsyncFunc( const Store = Mota.require('@user/client-modules').TextboxStore;
data.async, const { textbox = 'main-textbox', text, icon = 'none', title = '' } = data;
core.moveTextBox, const store = Store.get(textbox);
data.code, if (!store) {
this.__action_getLoc(data.loc, x, y, prefix), core.doAction();
data.relative, return;
data.moveMode, }
data.time const loc = store.data.loc?.slice() ?? [];
); loc[0] ??= 0;
}; loc[1] ??= 0;
loc[2] ??= 200;
loc[3] ??= 200;
const { x = loc[0], y = loc[1], width = loc[2], height = loc[3] } = data;
store.show();
store.modify({
title,
icon,
x,
y,
width,
height,
loc: [x, y, width, height]
});
store.setText(text);
events.prototype._action_clearTextBox = function (data, x, y, prefix) { setTimeout(() => {
if (this.__action_checkReplaying()) return; store.hide();
core.clearTextBox(data.code, core.doAction); core.doAction();
}; }, data.time ?? 3000);
events.prototype._action_autoText = function (data, x, y, prefix) {
if (this.__action_checkReplaying()) return;
data.text = core.replaceText(data.text, prefix);
core.ui.drawTextBox(data.text);
setTimeout(core.doAction, data.time || 3000);
}; };
events.prototype._action_scrollText = function (data, x, y, prefix) { events.prototype._action_scrollText = function (data, x, y, prefix) {
if (this.__action_checkReplaying()) return; if (this.__action_checkReplaying()) return;
data.text = core.replaceText(data.text, prefix); // todo: 2.B.1
this.__action_doAsyncFunc(
data.async,
core.drawScrollText,
data.text,
data.time || 5000,
data.lineHeight || 1.4
);
}; };
events.prototype._action_comment = function (data, x, y, prefix) { events.prototype._action_comment = function (data, x, y, prefix) {
@ -1676,8 +1638,85 @@ events.prototype._action__label = function (data, x, y, prefix) {
core.doAction(); core.doAction();
}; };
events.prototype._action_setText = function (data, x, y, prefix) { events.prototype._action_setText = function (data) {
this.setTextAttribute(data); const isNil = value => value === null || value === void 0;
const { textbox = 'main-textbox' } = data;
const Store = Mota.require('@user/client-modules').TextboxStore;
const { TextAlign, WordBreak } = Mota.require('@user/client-modules');
const Font = Mota.require('@motajs/render-style').Font;
const store = Store.get(textbox);
if (!store) {
core.doAction();
return;
}
// loc
const loc = store.data.loc?.slice() ?? [];
loc[0] ??= 0;
loc[1] ??= 0;
loc[2] ??= 200;
loc[3] ??= 200;
const { x = loc[0], y = loc[1], width = loc[2], height = loc[3] } = data;
const newLoc = [x, y, width, height];
// font
const { fontFamily, fontSize, fontWeight, fontItalic } = data;
const font = store.data.font ?? new Font();
const newFont = Font.clone(font, {
family: fontFamily,
size: fontSize,
weight: fontWeight,
italic: fontItalic
});
// config
const config = {
x,
y,
width,
height,
loc: newLoc,
font: newFont,
keepLast: data.keepLast,
interval: data.interval,
lineHeight: data.lineHeight,
fillStyle: data.fillStyle,
strokeStyle: data.strokeStyle,
strokeWidth: data.strokeWidth,
fill: isNil(data.fill),
stroke: !!data.stroke,
backColor: data.backColor,
winskin: data.winskin,
padding: data.padding,
titleFill: isNil(data.titleFill) ? 'gold' : 'transparent',
titleStroke: data.titleStroke ? 'black' : 'transparent',
titlePadding: data.titlePadding,
ignoreLineStart: data.ignoreLineStart,
ignoreLineEnd: data.ignoreLineEnd,
breakChars: data.breakChars
};
switch (data.textAlign) {
case 'left':
config.textAlign = TextAlign.Left;
break;
case 'center':
config.textAlign = TextAlign.Center;
break;
case 'right':
config.textAlign = TextAlign.Right;
break;
}
switch (data.wordBreak) {
case 'none':
config.wordBreak = WordBreak.None;
break;
case 'space':
config.wordBreak = WordBreak.Space;
break;
case 'all':
config.wordBreak = WordBreak.All;
break;
}
store.modify(config);
core.doAction(); core.doAction();
}; };
@ -1686,6 +1725,29 @@ events.prototype._action_tip = function (data, x, y, prefix) {
core.doAction(); core.doAction();
}; };
events.prototype._action_confirm = function (data, x, y, prefix) {
data.text = core.replaceText(data.text, prefix);
core.ui.drawConfirmBox(
data.text,
() => {
core.insertAction(data.yes ?? []);
core.doAction();
},
() => {
core.insertAction(data.no ?? []);
core.doAction();
}
);
};
events.prototype._action_choices = function (data, x, y, prefix) {
core.ui.drawChoices(
core.replaceText(data.text, prefix),
data.choices,
data.width
);
};
events.prototype._action_show = function (data, x, y, prefix) { events.prototype._action_show = function (data, x, y, prefix) {
data.loc = this.__action_getLoc2D(data.loc, x, y, prefix); data.loc = this.__action_getLoc2D(data.loc, x, y, prefix);
if (data.time > 0 && data.floorId == core.status.floorId) { if (data.time > 0 && data.floorId == core.status.floorId) {
@ -2519,14 +2581,6 @@ events.prototype._precompile_switch = function (data) {
return data; return data;
}; };
events.prototype._action_choices = function (data, x, y, prefix) {
core.ui.drawChoices(
core.replaceText(data.text, prefix),
data.choices,
data.width
);
};
events.prototype.__action_choices_replaying = function (data, index) { events.prototype.__action_choices_replaying = function (data, index) {
var selection = index; var selection = index;
if (index != 'none') { if (index != 'none') {
@ -2580,21 +2634,6 @@ events.prototype._precompile_choices = function (data) {
return data; return data;
}; };
events.prototype._action_confirm = function (data, x, y, prefix) {
data.text = core.replaceText(data.text, prefix);
core.ui.drawConfirmBox(
data.text,
() => {
core.insertAction(data.yes ?? []);
core.doAction();
},
() => {
core.insertAction(data.no ?? []);
core.doAction();
}
);
};
events.prototype.__action_confirm_replaying = function (data, index) { events.prototype.__action_confirm_replaying = function (data, index) {
if (index != 'none') { if (index != 'none') {
var timeout = Math.floor(index / 100) || 0; var timeout = Math.floor(index / 100) || 0;

View File

@ -21,6 +21,7 @@ function main() {
this.dom = { this.dom = {
body: document.body, body: document.body,
gameDraw: document.getElementById('game-draw'), gameDraw: document.getElementById('game-draw'),
gameCanvas: document.getElementsByClassName('gameCanvas'),
inputDiv: document.getElementById('inputDiv'), inputDiv: document.getElementById('inputDiv'),
inputMessage: document.getElementById('inputMessage'), inputMessage: document.getElementById('inputMessage'),
inputBox: document.getElementById('inputBox'), inputBox: document.getElementById('inputBox'),
@ -194,6 +195,10 @@ main.prototype.loadSync = function (mode, callback) {
}; };
main.prototype.loadAsync = async function (mode, callback) { main.prototype.loadAsync = async function (mode, callback) {
for (var i = 0; i < main.dom.gameCanvas.length; i++) {
main.canvas[main.dom.gameCanvas[i].id] =
main.dom.gameCanvas[i].getContext('2d');
}
main.mode = mode; main.mode = mode;
// 加载全塔属性代码 // 加载全塔属性代码

View File

@ -226,8 +226,14 @@ main.floors.MT14=
} }
], ],
"8,2": [ "8,2": [
"这一层有一个必须使用跳跃的地方需要1个跳跃次数你一共有3个跳跃次数请规划好", {
"不要吐槽为什么天气变化这么大(" "type": "text",
"text": "这一层有一个必须使用跳跃的地方需要1个跳跃次数你一共有3个跳跃次数请规划好"
},
{
"type": "text",
"text": "不要吐槽为什么天气变化这么大("
}
], ],
"80,3": [ "80,3": [
"你可以使用楼传传出去" "你可以使用楼传传出去"

View File

@ -27,6 +27,8 @@ type ItemCls = 'tools' | 'items' | 'equips' | 'constants';
*/ */
type AllIds = keyof IdToNumber; type AllIds = keyof IdToNumber;
type AllIdsWithNone = AllIds | 'none';
/** /**
* *
*/ */