Compare commits
7 commits
master
...
VERSION_01
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbe0825e9b | ||
|
|
05d1fb34af | ||
|
|
39edb92f1c | ||
|
|
17003c457a | ||
|
|
ef6c92bd74 | ||
|
|
59f2ba9fbd | ||
|
|
e00e6b9b4c |
18 changed files with 424 additions and 252 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -50,3 +50,4 @@ build_server_xmlconf
|
|||
/node_modules/
|
||||
/log/
|
||||
/build-archive/
|
||||
/bin/
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ android {
|
|||
applicationId namespace
|
||||
minSdk 21
|
||||
targetSdk 32
|
||||
versionCode 1048005
|
||||
versionName "1.48.5"
|
||||
versionCode 1049000
|
||||
versionName "1.49"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
targetSdkVersion 32
|
||||
minSdkVersion 21
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
PUT RELEASE ANNOUNCEMENT LINES HERE
|
||||
The outfit merchants display images of their products now. In order not to fall behind, item sellers have polished their shop signs, to highlight item names.
|
||||
|
||||
This in turn prompted Gwen at Deniarn Accessories to cut her prices in half. All in all, it is a good time for some late Christmas shopping.
|
||||
|
||||
Please see the complete change log for further details: https://arianne-project.org/game/stendhal.html#changes
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@
|
|||
<string name="app_name">Stendhal</string>
|
||||
<string name="intent_url_scheme">stendhalprod8gps5y99pu</string>
|
||||
<string name="build_type">prod</string>
|
||||
<string name="build_version">1.48.5</string>
|
||||
<string name="build_version">1.49</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"$schema": "https://raw.githubusercontent.com/neutralinojs/neutralinojs/main/schemas/neutralino.config.schema.json",
|
||||
"applicationId": "org.stendhalgame.client",
|
||||
"version": "1.48.5",
|
||||
"version": "1.49",
|
||||
"defaultMode": "window",
|
||||
"port": 0,
|
||||
"documentRoot": "/resources/",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
@echo off
|
||||
|
||||
set STENDHAL_VERSION=1.48.5
|
||||
set STENDHAL_VERSION=1.49
|
||||
set SERVER_JAR=stendhal-server-%STENDHAL_VERSION%.jar
|
||||
|
||||
:: change to server directory
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
STENDHAL_VERSION="1.48.5"
|
||||
STENDHAL_VERSION="1.49"
|
||||
SERVER_JAR="stendhal-server-${STENDHAL_VERSION}.jar"
|
||||
|
||||
# change to server directory
|
||||
|
|
|
|||
|
|
@ -92,9 +92,9 @@ version_server = http://arianne.sourceforge.net/stendhal.version
|
|||
|
||||
# current version of stendhal
|
||||
version.old = 1.48
|
||||
version = 1.48.5
|
||||
version = 1.49
|
||||
# FIXME: dynamic method to set this property?
|
||||
version.android = 1048005
|
||||
version.android = 1049000
|
||||
|
||||
# javac options
|
||||
javac.deprecation = true
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
site_name: Stendhal 1.48.5 Reference Documentation
|
||||
site_name: Stendhal 1.49 Reference Documentation
|
||||
site_description: A fun, friendly, & free multiplayer online adventure game.
|
||||
copyright: Copyright © 2003-2025 Stendhal
|
||||
site_url: https://stendhalgame.org/
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ Changelog
|
|||
|
||||
*bug fixes*
|
||||
- fixed invalid head outfit index of Mr Ross
|
||||
- fixed silent NPC fixed paths
|
||||
- fixed silent NPC paths
|
||||
- fixed desktop webview client window freezing on Windows when closed
|
||||
- fixed nativehelper extension process not exiting cleanly on Windows
|
||||
- set User-Agent string for Wikipedia API requests
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ public class HttpClient {
|
|||
try {
|
||||
connection = (HttpURLConnection) url.openConnection();
|
||||
// Wikipedia API now requires User-Agent string
|
||||
connection.setRequestProperty("User-Agent", "StendhalClient/1.48.5 (https://arianne-project.org/contact.html)");
|
||||
connection.setRequestProperty("User-Agent", "StendhalClient/1.49 (https://arianne-project.org/contact.html)");
|
||||
connection.setConnectTimeout(myTimeout);
|
||||
connection.setInstanceFollowRedirects(true);
|
||||
connection.setUseCaches(false);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public class Debug {
|
|||
|
||||
/** version. */
|
||||
// Note: This line is updated by build.xml using a regexp so be sure to adjust it in case you modify this line.
|
||||
public static final String VERSION = "1.48.5";
|
||||
public static final String VERSION = "1.49";
|
||||
|
||||
/** pre release suffix */
|
||||
// Note: This line is updated by build.xml using a regexp so be sure to adjust it in case you modify this line.
|
||||
|
|
|
|||
|
|
@ -708,3 +708,16 @@ img#click-indicator {
|
|||
.pad-contents {
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
table.shoptable {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table.shoptable th, table.shoptable td {
|
||||
border: 1px solid var(--text-color);
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
td.number {
|
||||
text-align: right;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,14 +24,11 @@ import { PlayerLoggedOnEvent } from "./event/PlayerLoggedOnEvent";
|
|||
import { PlayerLoggedOutEvent } from "./event/PlayerLoggedOutEvent";
|
||||
import { ProgressStatusEvent } from "./event/ProgressStatusEvent";
|
||||
import { RPEvent } from "./event/RPEvent";
|
||||
import { ShowItemListEvent } from "./event/ShowItemListEvent";
|
||||
import { ShowOutfitListEvent } from "./event/ShowOutfitListEvent";
|
||||
import { SoundEvent } from "./event/SoundEvent";
|
||||
import { TradeEvent } from "./event/TradeEvent";
|
||||
import { ViewChangeEvent } from "./event/ViewChangeEvent";
|
||||
|
||||
import { ui } from "./ui/UI";
|
||||
|
||||
import { DialogContentComponent } from "./ui/toolkit/DialogContentComponent";
|
||||
|
||||
import { Chat } from "./util/Chat";
|
||||
|
||||
|
||||
|
|
@ -155,120 +152,8 @@ export class EventRegistry {
|
|||
}
|
||||
}); // reached_achievement
|
||||
|
||||
this.register("show_item_list", {
|
||||
execute: function(rpobject: RPObject) {
|
||||
let title = "Items";
|
||||
let caption = "";
|
||||
let items = [];
|
||||
|
||||
if (this.hasOwnProperty("title")) {
|
||||
title = this["title"];
|
||||
}
|
||||
if (this.hasOwnProperty("caption")) {
|
||||
caption = this["caption"];
|
||||
}
|
||||
if (this.hasOwnProperty("content")) {
|
||||
for (var obj in this["content"]) {
|
||||
if (this["content"].hasOwnProperty(obj)) {
|
||||
var slotObj = this["content"][obj];
|
||||
var data = this["content"][obj]["a"];
|
||||
const i = {
|
||||
clazz: data["class"],
|
||||
subclass: data["subclass"],
|
||||
img: data["class"] + "/" + data["subclass"] + ".png",
|
||||
price: data["price"],
|
||||
desc: data["description_info"]
|
||||
}
|
||||
|
||||
// seller shops prefix prices with "-"
|
||||
if (i.price.startsWith("-")) {
|
||||
i.price = i.price.substr(1);
|
||||
}
|
||||
items.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const content = new class extends DialogContentComponent {} ("empty-div-template");
|
||||
content.componentElement.classList.add("shopsign");
|
||||
const captionElement = document.createElement("div");
|
||||
captionElement.className = "horizontalgroup shopcaption";
|
||||
captionElement.textContent = caption + "\nItem\t-\tPrice\t-\tDescription";
|
||||
content.componentElement.appendChild(captionElement);
|
||||
const itemList = document.createElement("div");
|
||||
itemList.className = "shoplist";
|
||||
content.componentElement.appendChild(itemList);
|
||||
|
||||
// TODO: organize in columns & show item sprites
|
||||
for (const i of items) {
|
||||
const row = document.createElement("div");
|
||||
row.className = "horizontalgroup shoprow";
|
||||
const img = document.createElement("div");
|
||||
img.className = "shopcol";
|
||||
img.appendChild(stendhal.data.sprites.get(stendhal.paths.sprites + "/items/" + i.img));
|
||||
row.appendChild(img);
|
||||
const price = document.createElement("div");
|
||||
price.className = "shopcol";
|
||||
price.textContent = i.price;
|
||||
row.appendChild(price);
|
||||
const desc = document.createElement("div");
|
||||
desc.className = "shopcol shopcolr";
|
||||
desc.textContent = i.desc;
|
||||
row.appendChild(desc);
|
||||
itemList.appendChild(row);
|
||||
}
|
||||
|
||||
stendhal.ui.globalInternalWindow.set(
|
||||
ui.createSingletonFloatingWindow(title, content, 20, 20));
|
||||
}
|
||||
}); // show_item_list
|
||||
|
||||
this.register("show_outfit_list", {
|
||||
execute: function(rpobject: RPObject) {
|
||||
let title = "Outfits";
|
||||
let caption = "";
|
||||
let outfits = [];
|
||||
|
||||
if (this.hasOwnProperty("title")) {
|
||||
title = this["title"];
|
||||
}
|
||||
if (this.hasOwnProperty("caption")) {
|
||||
caption = this["caption"];
|
||||
}
|
||||
if (this.hasOwnProperty("outfits")) {
|
||||
for (let o of this["outfits"].split(":")) {
|
||||
o = o.split(";");
|
||||
if (o.length > 2) {
|
||||
outfits.push([o[0], o[1], o[2]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.hasOwnProperty("show_base")) {
|
||||
//Chat.log("normal", this["show_base"]);
|
||||
}
|
||||
|
||||
const content = new class extends DialogContentComponent {} ("empty-div-template");
|
||||
content.componentElement.classList.add("shopsign");
|
||||
const captionElement = document.createElement("div");
|
||||
captionElement.className = "horizontalgroup shopcaption";
|
||||
captionElement.textContent = caption;
|
||||
content.componentElement.appendChild(captionElement);
|
||||
const itemList = document.createElement("div");
|
||||
itemList.className = "shoplist";
|
||||
content.componentElement.appendChild(itemList);
|
||||
|
||||
// TODO: organize in columns & show outfit sprites
|
||||
for (const o of outfits) {
|
||||
const row = document.createElement("div");
|
||||
row.className = "horizontalgroup shoprow";
|
||||
row.textContent = o[0] + ": " + o[2];
|
||||
itemList.appendChild(row);
|
||||
}
|
||||
|
||||
stendhal.ui.globalInternalWindow.set(
|
||||
ui.createSingletonFloatingWindow(title, content, 20, 20));
|
||||
}
|
||||
}); // show_outfit_list
|
||||
this.register("show_item_list", new ShowItemListEvent());
|
||||
this.register("show_outfit_list", new ShowOutfitListEvent());
|
||||
|
||||
this.register("sound_event", new SoundEvent());
|
||||
|
||||
|
|
|
|||
122
src/js/stendhal/event/ShowItemListEvent.ts
Normal file
122
src/js/stendhal/event/ShowItemListEvent.ts
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/***************************************************************************
|
||||
* Copyright © 2024 - 2025 Faiumoni e. V. *
|
||||
***************************************************************************
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation; either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { RPEvent } from "./RPEvent";
|
||||
|
||||
import { ui } from "../ui/UI";
|
||||
import { DialogContentComponent } from "../ui/toolkit/DialogContentComponent";
|
||||
import { Chat } from "../util/Chat";
|
||||
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
export class ShowItemListEvent extends RPEvent {
|
||||
|
||||
title!: string;
|
||||
caption!: string;
|
||||
content!: any;
|
||||
|
||||
execute(_entity: any) {
|
||||
let title = "Items";
|
||||
let caption = "";
|
||||
let items = [];
|
||||
|
||||
if (this.hasOwnProperty("title")) {
|
||||
title = this["title"];
|
||||
}
|
||||
if (this.hasOwnProperty("caption")) {
|
||||
caption = this["caption"];
|
||||
}
|
||||
if (this.hasOwnProperty("content")) {
|
||||
for (let obj in this["content"]) {
|
||||
if (this["content"].hasOwnProperty(obj)) {
|
||||
let data = this["content"][obj]["a"];
|
||||
let item = {
|
||||
clazz: data["class"],
|
||||
subclass: data["subclass"],
|
||||
img: data["class"] + "/" + data["subclass"] + ".png",
|
||||
price: data["price"],
|
||||
desc: data["description_info"]
|
||||
}
|
||||
|
||||
// seller shops prefix prices with "-"
|
||||
if (item.price.startsWith("-")) {
|
||||
item.price = item.price.substr(1);
|
||||
}
|
||||
items.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const content = new class extends DialogContentComponent { }("empty-div-template");
|
||||
content.componentElement.classList.add("shopsign");
|
||||
// Create table
|
||||
const table = document.createElement("table");
|
||||
table.className = "shoptable";
|
||||
content.componentElement.appendChild(table);
|
||||
|
||||
// Caption
|
||||
const tableCaption = document.createElement("caption");
|
||||
tableCaption.className = "shopcaption";
|
||||
tableCaption.textContent = caption;
|
||||
table.appendChild(tableCaption);
|
||||
|
||||
// Header
|
||||
const thead = document.createElement("thead");
|
||||
const headerRow = document.createElement("tr");
|
||||
|
||||
const headers = ["Item", "Price", "Description"];
|
||||
for (const text of headers) {
|
||||
const th = document.createElement("th");
|
||||
th.textContent = text;
|
||||
headerRow.appendChild(th);
|
||||
}
|
||||
|
||||
thead.appendChild(headerRow);
|
||||
table.appendChild(thead);
|
||||
|
||||
// Body
|
||||
const tbody = document.createElement("tbody");
|
||||
|
||||
for (const i of items) {
|
||||
const row = document.createElement("tr");
|
||||
|
||||
// Item (image)
|
||||
const itemCell = document.createElement("td");
|
||||
itemCell.appendChild(
|
||||
stendhal.data.sprites.get(
|
||||
stendhal.paths.sprites + "/items/" + i.img
|
||||
)
|
||||
);
|
||||
row.appendChild(itemCell);
|
||||
|
||||
// Price
|
||||
const priceCell = document.createElement("td");
|
||||
priceCell.className = "number";
|
||||
priceCell.textContent = i.price;
|
||||
row.appendChild(priceCell);
|
||||
|
||||
// Description
|
||||
const descCell = document.createElement("td");
|
||||
descCell.innerHTML = Chat.formatLogEntry(i.desc);
|
||||
row.appendChild(descCell);
|
||||
|
||||
tbody.appendChild(row);
|
||||
}
|
||||
|
||||
table.appendChild(tbody);
|
||||
|
||||
stendhal.ui.globalInternalWindow.set(
|
||||
ui.createSingletonFloatingWindow(title, content, 20, 20));
|
||||
}
|
||||
|
||||
}
|
||||
146
src/js/stendhal/event/ShowOutfitListEvent.ts
Normal file
146
src/js/stendhal/event/ShowOutfitListEvent.ts
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/***************************************************************************
|
||||
* Copyright © 2024 - 2025 Faiumoni e. V. *
|
||||
***************************************************************************
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation; either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { RPEvent } from "./RPEvent";
|
||||
|
||||
import { ui } from "../ui/UI";
|
||||
import { DialogContentComponent } from "../ui/toolkit/DialogContentComponent";
|
||||
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
export class ShowOutfitListEvent extends RPEvent {
|
||||
|
||||
title!: string;
|
||||
caption!: string;
|
||||
outfits!: string;
|
||||
|
||||
execute(_entity: any) {
|
||||
let title = "Outfits";
|
||||
let caption = "";
|
||||
let outfits = [];
|
||||
|
||||
if (this.hasOwnProperty("title")) {
|
||||
title = this["title"];
|
||||
}
|
||||
if (this.hasOwnProperty("caption")) {
|
||||
caption = this["caption"];
|
||||
}
|
||||
if (this.hasOwnProperty("outfits")) {
|
||||
for (let o of this["outfits"].split(":")) {
|
||||
let parts = o.split(";");
|
||||
if (parts.length > 2) {
|
||||
outfits.push({
|
||||
name: parts[0],
|
||||
outfit: parts[1],
|
||||
price: parts[2]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.hasOwnProperty("show_base")) {
|
||||
//Chat.log("normal", this["show_base"]);
|
||||
}
|
||||
|
||||
const content = new class extends DialogContentComponent { }("empty-div-template");
|
||||
content.componentElement.classList.add("shopsign");
|
||||
|
||||
const table = document.createElement("table");
|
||||
table.className = "shoptable";
|
||||
content.componentElement.appendChild(table);
|
||||
|
||||
// Caption
|
||||
const tableCaption = document.createElement("caption");
|
||||
tableCaption.className = "shopcaption";
|
||||
tableCaption.textContent = caption;
|
||||
table.appendChild(tableCaption);
|
||||
|
||||
// Header
|
||||
const thead = document.createElement("thead");
|
||||
const headerRow = document.createElement("tr");
|
||||
|
||||
const headers = ["Name", "Outfit", "Price"];
|
||||
for (const text of headers) {
|
||||
const th = document.createElement("th");
|
||||
th.textContent = text;
|
||||
headerRow.appendChild(th);
|
||||
}
|
||||
|
||||
thead.appendChild(headerRow);
|
||||
table.appendChild(thead);
|
||||
|
||||
// Body
|
||||
const tbody = document.createElement("tbody");
|
||||
|
||||
for (const outfit of outfits) {
|
||||
const row = document.createElement("tr");
|
||||
|
||||
// Name
|
||||
const nameCell = document.createElement("td");
|
||||
nameCell.textContent = outfit.name;
|
||||
row.appendChild(nameCell);
|
||||
|
||||
// Image
|
||||
const imageCell = document.createElement("td");
|
||||
let url = ShowOutfitListEvent.outfitToUrl(outfit.outfit);
|
||||
const img1 = document.createElement("img");
|
||||
const img2 = document.createElement("img");
|
||||
img1.src = url;
|
||||
img2.src = url + "&offset=0";
|
||||
imageCell.append(img1);
|
||||
imageCell.append(img2);
|
||||
row.appendChild(imageCell);
|
||||
|
||||
// Price
|
||||
const priceCell = document.createElement("td");
|
||||
priceCell.className = "number";
|
||||
priceCell.textContent = outfit.price;
|
||||
row.appendChild(priceCell);
|
||||
|
||||
tbody.appendChild(row);
|
||||
}
|
||||
|
||||
table.appendChild(tbody);
|
||||
|
||||
stendhal.ui.globalInternalWindow.set(
|
||||
ui.createSingletonFloatingWindow(title, content, 20, 20));
|
||||
}
|
||||
|
||||
private static outfitToUrl(outfit?: string): string {
|
||||
if (!outfit) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Required order
|
||||
const order = ["body", "dress", "head", "mouth", "eyes", "mask", "hair", "hat", "detail"];
|
||||
|
||||
// Parse input into a map
|
||||
let values: Record<string, number> = {};
|
||||
|
||||
for (let part of outfit.split(",")) {
|
||||
let [key, value] = part.split("=");
|
||||
values[key] = Number(value);
|
||||
}
|
||||
|
||||
// Build path
|
||||
let parts = order.map(key => {
|
||||
let value = values[key] ?? 0;
|
||||
return `${key}-${value}-0`;
|
||||
});
|
||||
|
||||
let url =
|
||||
"https://stendhalgame.org/createoutfit.php?rewritten=true&dialog=shop&outfit=" +
|
||||
parts.join("_");
|
||||
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ import { Component } from "../toolkit/Component";
|
|||
import { MenuItem } from "../../action/MenuItem";
|
||||
import { UIComponentEnum } from "../UIComponentEnum";
|
||||
import { singletons } from "../../SingletonRepo";
|
||||
import { Chat } from "../../util/Chat";
|
||||
|
||||
declare var stendhal: any;
|
||||
|
||||
|
|
@ -106,13 +107,13 @@ export class ChatLogComponent extends Component {
|
|||
/**
|
||||
* Adds a line of text.
|
||||
*
|
||||
* @param type {string}
|
||||
* @param type
|
||||
* Message type.
|
||||
* @param message {string}
|
||||
* @param message
|
||||
* Text to be added.
|
||||
* @param orator {string}
|
||||
* @param orator
|
||||
* Name of entity making the expression (default: `undefined`).
|
||||
* @param timestamp {boolean}
|
||||
* @param timestamp
|
||||
* If `false`, suppresses prepending message with timestamp (default: `true`).
|
||||
*/
|
||||
public addLine(type: string, message: string, orator?: string, timestamp=true) {
|
||||
|
|
@ -131,7 +132,7 @@ export class ChatLogComponent extends Component {
|
|||
|
||||
const rcol = document.createElement("div");
|
||||
rcol.className = "logcolR log" + type;
|
||||
rcol.innerHTML += this.formatLogEntry(message);
|
||||
rcol.innerHTML += Chat.formatLogEntry(message);
|
||||
|
||||
const row = document.createElement("div");
|
||||
row.className = "logrow";
|
||||
|
|
@ -192,122 +193,7 @@ export class ChatLogComponent extends Component {
|
|||
this.add(row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats displayed text.
|
||||
*
|
||||
* @param message {string}
|
||||
* Text to parse for special characters.
|
||||
* @return {string}
|
||||
* Text formatted with keywords & item names highlighted.
|
||||
*/
|
||||
private formatLogEntry(message: string): string {
|
||||
if (!message) {
|
||||
return "";
|
||||
}
|
||||
let res = "";
|
||||
let delims = [" ", ",", ".", "!", "?", ":", ";"];
|
||||
let length = message.length;
|
||||
let inHighlight = false, inUnderline = false,
|
||||
inHighlightQuote = false, inUnderlineQuote = false;
|
||||
for (let i = 0; i < length; i++) {
|
||||
let c = message[i];
|
||||
|
||||
if (c === "\\") {
|
||||
let n = message[i + 1];
|
||||
res += n;
|
||||
i++;
|
||||
|
||||
// Highlight Start?
|
||||
} else if (c === "#") {
|
||||
if (inHighlight) {
|
||||
res += c;
|
||||
continue;
|
||||
}
|
||||
let n = message[i + 1];
|
||||
if (n === "#") {
|
||||
res += c;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (n === "'") {
|
||||
inHighlightQuote = true;
|
||||
i++;
|
||||
}
|
||||
inHighlight = true;
|
||||
res += "<span class=\"logh\">";
|
||||
|
||||
// Underline start?
|
||||
} else if (c === "§") {
|
||||
if (inUnderline) {
|
||||
res += c;
|
||||
continue;
|
||||
}
|
||||
let n = message[i + 1];
|
||||
if (n === "§") {
|
||||
res += c;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (n === "'") {
|
||||
inUnderlineQuote = true;
|
||||
i++;
|
||||
}
|
||||
inUnderline = true;
|
||||
res += "<span class=\"logi\">";
|
||||
|
||||
// End Highlight and Underline?
|
||||
} else if (c === "'") {
|
||||
if (inUnderlineQuote) {
|
||||
inUnderline = false;
|
||||
inUnderlineQuote = false;
|
||||
res += "</span>";
|
||||
continue;
|
||||
}
|
||||
if (inHighlightQuote) {
|
||||
inHighlight = false;
|
||||
inHighlightQuote = false;
|
||||
res += "</span>";
|
||||
continue;
|
||||
}
|
||||
res += c;
|
||||
|
||||
// HTML escape
|
||||
} else if (c === "<") {
|
||||
res += "<";
|
||||
|
||||
// End of word
|
||||
} else if (delims.indexOf(c) > -1) {
|
||||
let n = message[i + 1];
|
||||
if (c === " " || n === " " || n == undefined) {
|
||||
if (inUnderline && !inUnderlineQuote && !inHighlightQuote) {
|
||||
inUnderline = false;
|
||||
res += "</span>" + c;
|
||||
continue;
|
||||
}
|
||||
if (inHighlight && !inUnderlineQuote && !inHighlightQuote) {
|
||||
inHighlight = false;
|
||||
res += "</span>" + c;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
res += c;
|
||||
|
||||
// Normal characters
|
||||
} else {
|
||||
res += c;
|
||||
}
|
||||
}
|
||||
|
||||
// Close opened formattings
|
||||
if (inUnderline) {
|
||||
res += "</span>";
|
||||
}
|
||||
if (inHighlight) {
|
||||
res += "</span>";
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all text from log.
|
||||
|
|
|
|||
|
|
@ -99,4 +99,121 @@ export class Chat {
|
|||
Chat.log("client", message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats displayed text.
|
||||
*
|
||||
* @param message {string}
|
||||
* Text to parse for special characters.
|
||||
* @return {string}
|
||||
* Text formatted with keywords & item names highlighted.
|
||||
*/
|
||||
public static formatLogEntry(message: string): string {
|
||||
if (!message) {
|
||||
return "";
|
||||
}
|
||||
let res = "";
|
||||
let delims = [" ", ",", ".", "!", "?", ":", ";"];
|
||||
let length = message.length;
|
||||
let inHighlight = false, inUnderline = false,
|
||||
inHighlightQuote = false, inUnderlineQuote = false;
|
||||
for (let i = 0; i < length; i++) {
|
||||
let c = message[i];
|
||||
|
||||
if (c === "\\") {
|
||||
let n = message[i + 1];
|
||||
res += n;
|
||||
i++;
|
||||
|
||||
// Highlight Start?
|
||||
} else if (c === "#") {
|
||||
if (inHighlight) {
|
||||
res += c;
|
||||
continue;
|
||||
}
|
||||
let n = message[i + 1];
|
||||
if (n === "#") {
|
||||
res += c;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (n === "'") {
|
||||
inHighlightQuote = true;
|
||||
i++;
|
||||
}
|
||||
inHighlight = true;
|
||||
res += "<span class=\"logh\">";
|
||||
|
||||
// Underline start?
|
||||
} else if (c === "§") {
|
||||
if (inUnderline) {
|
||||
res += c;
|
||||
continue;
|
||||
}
|
||||
let n = message[i + 1];
|
||||
if (n === "§") {
|
||||
res += c;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (n === "'") {
|
||||
inUnderlineQuote = true;
|
||||
i++;
|
||||
}
|
||||
inUnderline = true;
|
||||
res += "<span class=\"logi\">";
|
||||
|
||||
// End Highlight and Underline?
|
||||
} else if (c === "'") {
|
||||
if (inUnderlineQuote) {
|
||||
inUnderline = false;
|
||||
inUnderlineQuote = false;
|
||||
res += "</span>";
|
||||
continue;
|
||||
}
|
||||
if (inHighlightQuote) {
|
||||
inHighlight = false;
|
||||
inHighlightQuote = false;
|
||||
res += "</span>";
|
||||
continue;
|
||||
}
|
||||
res += c;
|
||||
|
||||
// HTML escape
|
||||
} else if (c === "<") {
|
||||
res += "<";
|
||||
|
||||
// End of word
|
||||
} else if (delims.indexOf(c) > -1) {
|
||||
let n = message[i + 1];
|
||||
if (c === " " || n === " " || n == undefined) {
|
||||
if (inUnderline && !inUnderlineQuote && !inHighlightQuote) {
|
||||
inUnderline = false;
|
||||
res += "</span>" + c;
|
||||
continue;
|
||||
}
|
||||
if (inHighlight && !inUnderlineQuote && !inHighlightQuote) {
|
||||
inHighlight = false;
|
||||
res += "</span>" + c;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
res += c;
|
||||
|
||||
// Normal characters
|
||||
} else {
|
||||
res += c;
|
||||
}
|
||||
}
|
||||
|
||||
// Close opened formattings
|
||||
if (inUnderline) {
|
||||
res += "</span>";
|
||||
}
|
||||
if (inHighlight) {
|
||||
res += "</span>";
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue