Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Step editor improvements #297

Merged
merged 11 commits into from
Feb 23, 2024
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [Unreleased]

### Added
- Added proper support for the event steps `SHOW_MODAL_CHOICE` and `SET_MSG_EXPRESSION`.
- Added rendering of text colors in relevant events (such as `SHOW_MSG`).

### Changed
- `VarConditions` now use the string editor, as opposed to the JSON editor.
- Improved support for event/action step property previews - specifically for `Vec2`, `Vec3`, `Offset`, `Entity`, `EnemyType`, `NumberExpression`, `StringExpression`, `BooleanExpression`, `VarName`, `Effect`, and `Animation`.

### Fixed
- Events with children/branching steps (such as `IF`, `SHOW_CHOICE`, `SHOW_MODAL_CHOICE`, etc.) will no longer fully refresh upon any edits, causing focus to be reset.

## [1.0.1] 2023-08-20

### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class EnemyTypeWidgetOverlayComponent extends AbstractWidget implements O
'OTHER'
];
readonly partyAttributes: AttributeValue = {
type: 'string',
type: 'String',
description: '',
withNull: true,
options: this.makeOptions(this.partyOptions)
Expand All @@ -32,7 +32,7 @@ export class EnemyTypeWidgetOverlayComponent extends AbstractWidget implements O
'NORTH_WEST'
];
readonly faceAttributes: AttributeValue = {
type: 'string',
type: 'String',
description: '',
withNull: true,
options: this.makeOptions(this.faceOptions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ export class EventDetailComponent implements OnDestroy {
}

public loadEvent(event: AbstractEvent<any>) {
this.event = event;
this.loadSettings();
if(this.event !== event) {
this.event = event;
this.loadSettings();
}
}

private clearSubscriptions() {
Expand Down Expand Up @@ -96,6 +98,7 @@ export class EventDetailComponent implements OnDestroy {
instance.key = key;
instance.attribute = val;
const sub = instance.onChange.subscribe(() => this.update());

this.changeSubscriptions.push(sub);
return instance;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class EventHelperService {
if (valIf.elseStep) {
valIf.elseStep = valIf.elseStep.map((v: EventType) => this.getEventFromType(v, actionStep));
}
} else if (val.type === 'SHOW_CHOICE') {
} else if (val.type === 'SHOW_CHOICE' || val.type === 'SHOW_MODAL_CHOICE') {
const valChoice = val as any;
valChoice.options.forEach((option: any, index: number) => {
valChoice[index] = valChoice[index].map((v: EventType) => this.getEventFromType(v, actionStep));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SecurityContext } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { EntityAttributes } from '../../../../services/phaser/entities/cc-entity';
import { EntityAttributes, Base_WM_Type } from '../../../../services/phaser/entities/cc-entity';
import { Label } from '../../../../models/events';

export interface EventType {
type: string;
Expand Down Expand Up @@ -53,18 +54,69 @@ export abstract class AbstractEvent<T extends EventType> {
}

protected getPropString(key: string, value?: any): string {
if (!value) {
if (value === undefined) {
value = this.data[key as keyof T];
}
const attr = this.getAttributes();
if (attr && attr[key]) {
const type = attr[key].type;
if (type === 'Color') {
value = this.getColorRectangle(value);
} else if (type === 'Vec2' && value) {
value = this.getVec2String(value.x, value.y);
} else if (type === 'Entity') {
value = '[' + value.name + ']';
switch (type as Base_WM_Type) {
elluminance marked this conversation as resolved.
Show resolved Hide resolved
case 'Color':
value = this.getColorRectangle(value);
break;
case 'Vec2':
case 'Vec2Expression':
value = this.getVarExpressionValue(value, true);
if(typeof value !== 'string') {
value = this.getVec2String(value.x, value.y);
}
break;
case 'Vec3':
case 'Vec3Expression':
value = this.getVarExpressionValue(value, true);
if(typeof value !== 'string') {
value = this.getVec3String(value.x, value.y, value.z, value.lvl);
}
break;
case 'Offset':
if(value) {
value = this.getVec3String(value.x, value.y, value.z);
}
break;
case 'Entity':
if(value.player){
value = 'player';
} else if(value.self) {
value = 'self';
} else if(value.name) {
value = '[' + value.name + ']';
} else if (value.varName) {
value = `[Var: ${value.varName}]`;
} else if (value.party) {
value = `[Party: ${value.party}]`;
}
break;
case 'EnemyType':
value = '[' + value.type + ']';
break;
case 'NumberExpression':
case 'StringExpression':
case 'BooleanExpression':
value = this.getVarExpressionValue(value);
break;
case 'VarName':
if(value.indirect) {
value = `[indirect: ${value.indirect}]`;
} else if (value.actorAttrib) {
value = `[actorAttrib: ${value.indirect}]`;
}
break;
case 'Effect':
case 'Animation':
if(value) {
value = `${value.sheet}/${value.name}`;
}
break;
}
}

Expand All @@ -73,9 +125,28 @@ export abstract class AbstractEvent<T extends EventType> {
return `<span style="display: inline-block;"><span style="color: #858585">${key}</span>: ${value}</span>`;
}

protected getVarExpressionValue(value: any, supportsActorAttrib = false): any {
elluminance marked this conversation as resolved.
Show resolved Hide resolved
if(value.indirect) {
value = `[indirect: ${value.indirect}]`;
} else if(value.varName) {
value = `[varName: ${value.varName}]`;
} else if(value.actorAttrib && supportsActorAttrib) {
value = `[actorAttrib: ${value.actorAttrib}]`;
}
return value;
}

protected getVec2String(x: number, y: number): string {
return `(${this.sanitize(x)}, ${this.sanitize(y)})`;
}

protected getVec3String(x: number, y: number, z?: number, level?: number): string {
if(level !== undefined) {
return `(${this.sanitize(x)}, ${this.sanitize(y)}, lvl ${this.sanitize(level)})`;
} else {
return `(${this.sanitize(x)}, ${this.sanitize(y)}, ${this.sanitize(z!)})`;
}
}

protected getTypeString(color: string): string {
color = this.sanitize(color);
Expand All @@ -93,6 +164,38 @@ export abstract class AbstractEvent<T extends EventType> {
protected getColorRectangle(color: string): string {
return `<span style="background-color: ${this.sanitize(color)};">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>`;
}

protected getProcessedText(langLabel: Label): string {
Vegita2 marked this conversation as resolved.
Show resolved Hide resolved
const textColors = [
null,
'#ff6969',
'#65ff89',
'#ffe430',
'#808080',
'#ff8932',
];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just tried it out ingame, here is how it looks

image

and in the editor

image

So 2 differences

  • the orange one doesn't work \c[5]
  • \c[6] is not shown ingame (but we should keep it so the user knows he made an error with the text)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I forgot that orange is only rendered in the small font by default. I'll just disable it then.
As for the \c[6] (and other invalid colors), I do agree it should remain rendered just so the user will know they made a mistake as you said. I believe that was my intent in doing it like that from the beginning.

let text = langLabel?.en_US ?? '';

let inSpan = false;
text = text.replace(/\\c\[(\d+)\]|$/g, (substr, colorIndex) => {
const color = textColors[+colorIndex];
let replacement = '';
if(inSpan) {
replacement += '</span>';
inSpan = false;
}
if(color) {
replacement += `<span style="color: ${color}">`;
inSpan = true;
} else if (color !== null) {
//preserve the original color code untouched.
replacement += substr;
}
return replacement;
});

return text;
}

private sanitize(val: string | number) {
return this.domSanitizer.sanitize(SecurityContext.HTML, val) || '';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Person } from '../../../../models/events';
import { AbstractEvent, EventType } from './abstract-event';
import { EntityAttributes } from '../../../../services/phaser/entities/cc-entity';

interface AddMsgPersonData extends EventType {
person: Person;
Expand All @@ -10,7 +11,7 @@ interface AddMsgPersonData extends EventType {
}

export class AddMsgPerson extends AbstractEvent<AddMsgPersonData> {
private attributes = {
private attributes: EntityAttributes = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to add EntityAttributes everywhere. If you want to update these events you can instead extend from DefaultEvent which makes the attributes property unnecessary.

person: {
type: 'PersonExpression',
description: 'Person + Expression to add'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { AbstractEvent } from './abstract-event';
import { EntityAttributes } from '../../../../services/phaser/entities/cc-entity';

export class ClearSlowMotion extends AbstractEvent<any> {
private attributes = {
private attributes: EntityAttributes = {
name: {
type: 'String',
description: 'Name of slow motion to be removed'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { AbstractEvent } from './abstract-event';
import { EntityAttributes } from '../../../../services/phaser/entities/cc-entity';

export class DoAction extends AbstractEvent<any> {
private attributes = {
private attributes: EntityAttributes = {
entity: {
type: 'Entity',
description: 'Entity to move',
Expand Down Expand Up @@ -37,6 +38,7 @@ export class DoAction extends AbstractEvent<any> {
update() {
this.info = this.combineStrings(
this.getTypeString('#8fe174'),
this.getPropString('entity'),
this.getPropString('actions', '[' + this.data.action.length + ']'),
this.getPropString('repeating'),
this.getPropString('wait'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { ShowMsg } from './show-msg';
import { StartNpcTradeMenu } from './start-npc-trade-menu';
import { Wait } from './wait';
import { ShowSideMsg } from './show-side-msg';
import { ShowModalChoice } from './show-modal-choice';
import { SetMsgExpression } from './set-msg-expression';

type EventConstructor<T extends EventType> = new (domSanitizer: DomSanitizer, data: T, actionStep: boolean) => AbstractEvent<T>;

Expand Down Expand Up @@ -52,6 +54,8 @@ export class EventRegistryService {
this.register('START_NPC_TRADE_MENU', StartNpcTradeMenu);
this.register('OPEN_QUEST_DIALOG', OpenQuestDialog);
this.register('SHOW_SIDE_MSG', ShowSideMsg);
this.register('SHOW_MODAL_CHOICE', ShowModalChoice);
this.register('SET_MSG_EXPRESSION', SetMsgExpression);

}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { AbstractEvent, EventType } from './abstract-event';
import { EntityAttributes } from '../../../../services/phaser/entities/cc-entity';


export interface GotoLabelData extends EventType {
name: string;
}

export class GotoLabel extends AbstractEvent<GotoLabelData> {
private attributes = {
private attributes: EntityAttributes = {
name : {
type: 'String',
description: 'Label to goto.'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AbstractEvent, EventType } from './abstract-event';
import { EntityAttributes } from '../../../../services/phaser/entities/cc-entity';

export interface IfData extends EventType {
withElse: boolean;
Expand All @@ -8,7 +9,7 @@ export interface IfData extends EventType {
}

export class If extends AbstractEvent<IfData> {
private attributes = {
private attributes: EntityAttributes = {
condition: {
type: 'VarCondition',
description: 'Condition for IF statement'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { AbstractEvent, EventType } from './abstract-event';
import { EntityAttributes } from '../../../../services/phaser/entities/cc-entity';


export interface LabelData extends EventType {
name: string;
}

export class Label extends AbstractEvent<LabelData> {
private attributes = {
private attributes: EntityAttributes = {
name : {
type: 'String',
description: 'Name to reference this label by.'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { AbstractEvent } from './abstract-event';
import { EntityAttributes } from '../../../../services/phaser/entities/cc-entity';

export class SetCameraBetween extends AbstractEvent<any> {
private attributes = {
private attributes: EntityAttributes = {
entity1: {
type: 'Entity',
description: 'First entity'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { AbstractEvent } from './abstract-event';
import { EntityAttributes } from '../../../../services/phaser/entities/cc-entity';

export class SetCameraPos extends AbstractEvent<any> {
private attributes = {
private attributes: EntityAttributes = {
pos: {
type: 'Vec2',
description: 'Position to focus camera on',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { AbstractEvent } from './abstract-event';
import { EntityAttributes } from '../../../../services/phaser/entities/cc-entity';

export class SetCameraTarget extends AbstractEvent<any> {
private attributes = {
private attributes: EntityAttributes = {
entity: {
type: 'Entity',
description: 'Entity to focus camera on'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { AbstractEvent } from './abstract-event';
import { EntityAttributes } from '../../../../services/phaser/entities/cc-entity';

export class SetCameraZoom extends AbstractEvent<any> {
private attributes = {
private attributes: EntityAttributes = {
zoom: {
type: 'Number',
description: 'Zoom Value. 1=default, 2=twice pixel size',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Person } from '../../../../models/events';
import { EventType } from './abstract-event';
import { DefaultEvent } from './default-event';

interface SetMsgExpressionData extends EventType {
elluminance marked this conversation as resolved.
Show resolved Hide resolved
person: Person;
}

export class SetMsgExpression extends DefaultEvent<SetMsgExpressionData> {
private attributes = {
elluminance marked this conversation as resolved.
Show resolved Hide resolved
person: {
type: 'PersonExpression',
description: 'Person + Expression to change'
}
};

override update() {
this.info = this.combineStrings(
this.getTypeString('#7ea3ff'),
this.getPropString('person', this.data.person.person + '>&#8203;' + this.data.person.expression),
);
}

override generateNewDataInternal() {
return {
person: {}
};
}
}
Loading