Compare commits
7 commits
master
...
VERSION_01
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbe0825e9b | ||
|
|
05d1fb34af | ||
|
|
39edb92f1c | ||
|
|
17003c457a | ||
|
|
ef6c92bd74 | ||
|
|
59f2ba9fbd | ||
|
|
e00e6b9b4c |
223 changed files with 7988 additions and 7348 deletions
50
.github/workflows/android-build.yml
vendored
50
.github/workflows/android-build.yml
vendored
|
|
@ -7,56 +7,16 @@ on:
|
|||
pull_request:
|
||||
paths:
|
||||
- 'app/android/**'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- id: job_info
|
||||
uses: daleyjem/gh-job-id@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
job_name: 'build'
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
|
||||
- name: Set Up JDK
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'adopt'
|
||||
|
||||
- name: Validate Gradle Wrapper .jar
|
||||
run: |
|
||||
cd app/android/gradle/wrapper
|
||||
curl --location --output gradle-wrapper.jar.sha256 \
|
||||
https://services.gradle.org/distributions/gradle-7.5.1-wrapper.jar.sha256
|
||||
echo " gradle-wrapper.jar" >> gradle-wrapper.jar.sha256
|
||||
sha256sum --check gradle-wrapper.jar.sha256
|
||||
|
||||
- name: Build APKs with Ant
|
||||
uses: cedx/setup-ant@v6
|
||||
with:
|
||||
version: '1.10'
|
||||
- run: ant -noinput -buildfile build.xml android -Dgradle.params="assembleDebug assembleRelease"
|
||||
|
||||
- name: Failure Report
|
||||
uses: sarisia/actions-status-discord@v1
|
||||
if: failure()
|
||||
env:
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_DEVELOPMENT }}
|
||||
with:
|
||||
title: 'Android Build Failed'
|
||||
description: '${{ steps.job_info.outputs.html_url }}'
|
||||
nodetail: true
|
||||
- uses: sarisia/actions-status-discord@v1
|
||||
if: failure()
|
||||
env:
|
||||
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK_DEVLOG }}
|
||||
with:
|
||||
title: 'Android Build Failed'
|
||||
description: '${{ steps.job_info.outputs.html_url }}'
|
||||
nodetail: true
|
||||
- name: Build Android Packages
|
||||
run: cd app/android/client && gradle assemble
|
||||
|
|
|
|||
12
.github/workflows/codeql-analysis.yml
vendored
12
.github/workflows/codeql-analysis.yml
vendored
|
|
@ -29,15 +29,15 @@ jobs:
|
|||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
uses: github/codeql-action/init@v2
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
# with:
|
||||
# languages: go, javascript, csharp, python, cpp, java
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
#- name: Autobuild
|
||||
# uses: github/codeql-action/autobuild@v3
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
|
@ -46,7 +46,9 @@ jobs:
|
|||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
- run: ant -noinput -f build.xml clean compile
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -50,3 +50,4 @@ build_server_xmlconf
|
|||
/node_modules/
|
||||
/log/
|
||||
/build-archive/
|
||||
/bin/
|
||||
|
|
|
|||
11
.project
11
.project
|
|
@ -20,15 +20,4 @@
|
|||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
|
||||
</natures>
|
||||
<filteredResources>
|
||||
<filter>
|
||||
<id>1771748271774</id>
|
||||
<name></name>
|
||||
<type>30</type>
|
||||
<matcher>
|
||||
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
||||
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
||||
</matcher>
|
||||
</filter>
|
||||
</filteredResources>
|
||||
</projectDescription>
|
||||
|
|
|
|||
19
README.md
19
README.md
|
|
@ -30,28 +30,29 @@ button to create or log in to your account.
|
|||
### Mobile
|
||||
|
||||
Play using the [progressive web app](https://en.wikipedia.org/wiki/Progressive_web_app). Just visit
|
||||
[stendhalgame.org](https://stendhalgame.org/) in your mobile browser and click "install" when prompted.
|
||||
https://stendhalgame.org/ in your mobile browser and click "install" when prompted.
|
||||
|
||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" height="75">](https://f-droid.org/packages/org.stendhalgame.client/)
|
||||
|
||||
Play on your Android device using the dedicated app. You can get it from the
|
||||
[F-Droid App Store](https://f-droid.org/) or download it from [stendhalgame.org](https://stendhalgame.org/download.html).
|
||||
[F-Droid App Store](https://f-droid.org/) or download it from https://stendhalgame.org/download.html.
|
||||
|
||||
### Classic Desktop
|
||||
|
||||
[](https://arianne-project.org/download/stendhal.zip)
|
||||
|
||||
Play using the classic desktop client. You will need Java which you can download from
|
||||
[java.com](https://www.java.com/en/download) on Microsoft Windows. Java is included in
|
||||
[https://www.java.com](https://www.java.com/en/download) on Microsoft Windows. Java is included in
|
||||
most Linux distributions. Both Oracle Java and OpenJDK are supported.
|
||||
|
||||
Please download Stendhal from [stendhalgame.org](https://stendhalgame.org/download.html).<br>
|
||||
You can double click on `stendhal-starter.jar` and the client will run.<br>
|
||||
If you prefer to run from command line, then just execute this command in the stendhal folder:
|
||||
Please download Stendhal from [https://stendhalgame.org](https://stendhalgame.org)<br>
|
||||
You can double click on stendhal-starter.jar and the client will run.<br>
|
||||
If you prefer to run from command line, then just execute this command
|
||||
in the stendhal folder:
|
||||
|
||||
`java -jar stendhal-starter.jar`
|
||||
|
||||
There is a [manual](https://stendhalgame.org/wiki/Stendhal_Manual), and there is Help from the client menu icons in the upper right hand side of the game screen.
|
||||
There is a [manual](https://stendhalgame.org/wiki/Stendhal_Manual), and there is Help from the client menu icons in the upper right hand side of the game screen.
|
||||
|
||||
|
||||
## Development environment
|
||||
|
|
@ -66,7 +67,7 @@ There is a [manual](https://stendhalgame.org/wiki/Stendhal_Manual), and there is
|
|||
|
||||
Stendhal is free software. You can redistribute it and/or modify under the following terms:
|
||||
|
||||
- The **server**, **java client**, and **Android client**: *GNU General Public License* 2 or later as published by the Free Software Foundation
|
||||
- The **server**, **java client**, and **Android client**: *GNU General Public License* 2 or later as published by the Free
|
||||
- The **web client** and **native client**: *GNU Affero General Public License* 3 or later as published by the Free Software Foundation with the definition of "System libraries" being extended to include authentication providers and software distribution platforms.
|
||||
- The **nativehelper** extensions: *GNU Lesser General Public License* 3 or later as published by the Free Software Foundation
|
||||
|
||||
|
|
@ -75,6 +76,6 @@ even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
|
|||
[LICENSE.txt](LICENSE.txt) and [src/js/LICENSE.html](src/js/LICENSE.html) file for more details.
|
||||
|
||||
Stendhal(c) is copyright of Miguel Angel Blanch Lardin, 2005-2008, arianne_rpg at users dot sourceforge dot net and others<br>
|
||||
Stendhal(c) is copyright of the Arianne Project, 2006-2026, arianne-general at lists dot sourceforge dot net
|
||||
Stendhal(c) is copyright of the Arianne Project, 2006-2025, arianne-general at lists dot sourceforge dot net
|
||||
|
||||
Please have a look at the list of [contributors](doc/contributors.md#contributors).
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ android {
|
|||
applicationId namespace
|
||||
minSdk 21
|
||||
targetSdk 32
|
||||
versionCode 1049005
|
||||
versionName "1.49.5"
|
||||
versionCode 1049000
|
||||
versionName "1.49"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
targetSdkVersion 32
|
||||
minSdkVersion 21
|
||||
|
|
@ -26,7 +26,7 @@ android {
|
|||
}
|
||||
|
||||
// build output
|
||||
project.setProperty("archivesBaseName", "${namespace}-${defaultConfig.versionName}")
|
||||
project.setProperty("archivesBaseName", "${namespace}-${defaultConfig.versionCode}")
|
||||
project.setProperty("buildDir", "${projectDir}/../../../build/build_android_client")
|
||||
|
||||
/* A keystore.properties file can be placed in the root Android project directory and must
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ package org.stendhalgame.client;
|
|||
import java.util.Random;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
|
|
@ -190,11 +189,7 @@ public class ClientView extends WebView {
|
|||
if (!UrlHelper.isInternalUri(uri)) {
|
||||
// open external links in default browser/app
|
||||
// FIXME: should we ask for confirmation?
|
||||
try {
|
||||
MainActivity.get().startActivity(new Intent(Intent.ACTION_VIEW, uri));
|
||||
} catch (final ActivityNotFoundException e) {
|
||||
Notifier.toast("No app found to open this link");
|
||||
}
|
||||
MainActivity.get().startActivity(new Intent(Intent.ACTION_VIEW, uri));
|
||||
return true;
|
||||
}
|
||||
view.loadUrl(UrlHelper.checkClientUrl(uri.toString()));
|
||||
|
|
|
|||
|
|
@ -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.49.5</string>
|
||||
<string name="build_version">1.49</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionSha256Sum=f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4
|
||||
distributionSha256Sum=91a239400bb638f36a1795d8fdf7939d532cdc7d794d1119b7261aac158b1e60
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"$schema": "https://raw.githubusercontent.com/neutralinojs/neutralinojs/main/schemas/neutralino.config.schema.json",
|
||||
"applicationId": "org.stendhalgame.client",
|
||||
"version": "1.49.5",
|
||||
"version": "1.49",
|
||||
"defaultMode": "window",
|
||||
"port": 0,
|
||||
"documentRoot": "/resources/",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
@echo off
|
||||
|
||||
set STENDHAL_VERSION=1.49.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.49.5"
|
||||
STENDHAL_VERSION="1.49"
|
||||
SERVER_JAR="stendhal-server-${STENDHAL_VERSION}.jar"
|
||||
|
||||
# change to server directory
|
||||
|
|
|
|||
|
|
@ -91,10 +91,10 @@ updates_server_fallback = http://arianne.sourceforge.net/stendhal/updates
|
|||
version_server = http://arianne.sourceforge.net/stendhal.version
|
||||
|
||||
# current version of stendhal
|
||||
version.old = 1.49
|
||||
version = 1.49.5
|
||||
version.old = 1.48
|
||||
version = 1.49
|
||||
# FIXME: dynamic method to set this property?
|
||||
version.android = 1049005
|
||||
version.android = 1049000
|
||||
|
||||
# javac options
|
||||
javac.deprecation = true
|
||||
|
|
|
|||
85
build.xml
85
build.xml
|
|
@ -1,32 +1,81 @@
|
|||
<?xml version='1.0'?>
|
||||
|
||||
<project name="stendhal" default="help" basedir=".">
|
||||
<description>
|
||||
Project:
|
||||
Name: .......... ${game_name}
|
||||
Version: ....... ${version}
|
||||
Root: .......... ${basedir}
|
||||
|
||||
Build system:
|
||||
Ant version: ... ${ant.version.number}
|
||||
Ant home: ...... ${ant.location}
|
||||
Java version: .. ${java.version}
|
||||
Java home: ..... ${java.home}
|
||||
|
||||
Execute `ant help` for more information.
|
||||
</description>
|
||||
|
||||
<project name="stendhal" default="compile" basedir=".">
|
||||
<!--
|
||||
Sets a property (by name and value), or set of properties (from file or resource) in the project. Properties are case sensitive.
|
||||
Properties are immutable: whoever sets a property first freezes it for the rest of the build; they are most definitely not variables.
|
||||
-->
|
||||
|
||||
<property file="build.ant-private.properties"/>
|
||||
<property file="build.ant.properties"/>
|
||||
|
||||
<property name="build_tests" value="${buildroot}/build_tests"/>
|
||||
<property name="build_tests_report" value="${buildroot}/build_test_report"/>
|
||||
|
||||
<property name="build_client" value="${buildroot}/build_client"/>
|
||||
<property name="build_client_data" value="${buildroot}/build_client_data"/>
|
||||
<property name="build_client_sound_data" value="${buildroot}/build_client_sound_data"/>
|
||||
<property name="build_client_music_data" value="${buildroot}/build_client_music_data"/>
|
||||
|
||||
<property name="build_webclient" value="${buildroot}/build_webclient"/>
|
||||
|
||||
<property name="build_docker" value="${buildroot}/build_docker"/>
|
||||
<property name="buildtools_docker" value="buildtools/docker"/>
|
||||
|
||||
<property name="build_postman" value="${buildroot}/buildbot/"/>
|
||||
|
||||
<property name="build_server" value="${buildroot}/build_server"/>
|
||||
<property name="build_server_maps" value="${buildroot}/build_server_maps"/>
|
||||
<property name="build_server_script" value="${buildroot}/build_server_script"/>
|
||||
<property name="build_server_mods" value="${buildroot}/build_server_mods"/>
|
||||
<property name="build_server_xmlconf" value="${buildroot}/build_server_xmlconf"/>
|
||||
|
||||
<property name="build_stendhaltools" value="${buildroot}/build_stendhaltools"/>
|
||||
<property name="build_stendhaltextclient" value="${buildroot}/build_stendhaltextclient"/>
|
||||
|
||||
<property name="client_data" value="stendhal-data-${version}.jar"/>
|
||||
<property name="client_jarname" value="stendhal-${version}.jar"/>
|
||||
<property name="client_sound_data" value="stendhal-sound-data-${version}.jar"/>
|
||||
<property name="client_music_data" value="stendhal-music-data-${version}.jar"/>
|
||||
<property name="client_starter_jarname" value="stendhal-starter-${version}.jar"/>
|
||||
|
||||
<property name="dist_server_binary" value="${buildroot}/stendhal-server-${version}.zip" />
|
||||
|
||||
<property name="maps_jarname" value="stendhal-maps-${version}.jar"/>
|
||||
|
||||
<property name="server_jarname" value="stendhal-server-${version}.jar"/>
|
||||
<property name="xmlconf_jarname" value="stendhal-xmlconf-${version}.jar"/>
|
||||
|
||||
<property name="config_dir" value="data/conf"/>
|
||||
|
||||
<property name="schema_location" value="${config_dir}"/>
|
||||
|
||||
<property name="cobertura.dir" value="${libdir}/cobertura"/>
|
||||
|
||||
<condition property="exclude.signing" value="true">
|
||||
<not>
|
||||
<available file="keystore.ks"/>
|
||||
</not>
|
||||
</condition>
|
||||
<condition property="exclude.jardiff" value="true">
|
||||
<not>
|
||||
<available file="${build-archive}/stendhal-${version.old}.zip"/>
|
||||
</not>
|
||||
</condition>
|
||||
|
||||
<!-- time & date -->
|
||||
<tstamp>
|
||||
<format property="year" pattern="yyyy"/>
|
||||
<format property="date" pattern="yyyy-MM-dd"/>
|
||||
<format property="time" pattern="HH:mm:ss"/>
|
||||
</tstamp>
|
||||
<property name="datetime" value="${date} ${time}"/>
|
||||
|
||||
|
||||
<!-- Ant sub-modules -->
|
||||
|
||||
<import file="build-private.xml" optional="true"/>
|
||||
|
||||
<import file="${ant_modules}/properties.xml"/>
|
||||
<import file="${ant_modules}/info.xml"/>
|
||||
<import file="${ant_modules}/system.xml"/>
|
||||
<import file="${ant_modules}/apps.xml"/>
|
||||
<import file="${ant_modules}/main.xml"/>
|
||||
|
|
|
|||
|
|
@ -161,8 +161,7 @@
|
|||
</target> <!-- client_android_build -->
|
||||
|
||||
|
||||
<!-- Create Android client package for release and distribution. -->
|
||||
<target name="android">
|
||||
<target name="android" description="Create Android client package for release and distribution.">
|
||||
<echo
|
||||
if:set="exclude.webview"
|
||||
message="ANDROID_SDK_ROOT environment variable not set. Skipping Android WebView client build."/>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
<project xmlns:if="ant:if" xmlns:unless="ant:unless">
|
||||
|
||||
<!-- Delete all build files and directories. -->
|
||||
<target name="clean">
|
||||
<target name="clean" description="Delete all build files and directories.">
|
||||
<delete includeEmptyDirs="true" quiet="true">
|
||||
<fileset dir="${buildroot}" excludes="eclipse/" defaultExcludes="false"/>
|
||||
</delete>
|
||||
|
|
@ -19,16 +18,14 @@
|
|||
</target>
|
||||
|
||||
|
||||
<!-- Delete client data build files and directories. -->
|
||||
<target name="clean_client_data">
|
||||
<target name="clean_client_data" description="Delete client data build files and directories.">
|
||||
<delete dir="${build_client_data}"/>
|
||||
<delete dir="${build_client_music_data}"/>
|
||||
<delete dir="${build_client_sound_data}"/>
|
||||
</target>
|
||||
|
||||
|
||||
<!-- Delete web client build files and directories. -->
|
||||
<target name="cleanjs">
|
||||
<target name="cleanjs" description="Delete web client build files and directories.">
|
||||
<delete dir="${buildroot}/js"/>
|
||||
<delete dir="${buildroot}/ts"/>
|
||||
</target>
|
||||
|
|
|
|||
|
|
@ -19,15 +19,13 @@
|
|||
</condition>
|
||||
|
||||
|
||||
<!-- Build server and clients. -->
|
||||
<target name="jar" depends="client_build,server_build">
|
||||
<target name="jar" depends="client_build,server_build" description="Build server and clients.">
|
||||
<!-- XXX: client & server builds are not exclusive to NetBeans, remove this output? -->
|
||||
<echo>Built client and server for NetBeans.</echo>
|
||||
</target>
|
||||
|
||||
|
||||
<!-- Sign client distribution. -->
|
||||
<target name="signjar" unless="exclude.signing">
|
||||
<target name="signjar" unless="exclude.signing" description="Sign client distribution.">
|
||||
<signjar
|
||||
alias="${keystore.alias}"
|
||||
keystore="keystore.ks"
|
||||
|
|
@ -36,23 +34,20 @@
|
|||
</target>
|
||||
|
||||
|
||||
<!-- Generate JAR files for both client and server. -->
|
||||
<!-- XXX: why does this depend on "server_build" twice? -->
|
||||
<target name="compile" depends="server_build,client_build,server_build" />
|
||||
<target name="compile" depends="server_build,client_build,server_build" description="Generate JAR files for both client and server."/>
|
||||
|
||||
|
||||
<!-- Create all packages for Stendhal release. -->
|
||||
<target name="dist" depends="clean,dist_binary,dist_source,signupdates" />
|
||||
<target name="dist" depends="clean,dist_binary,dist_source,signupdates" description="Create all packages for Stendhal release."/>
|
||||
|
||||
|
||||
<!-- Create all binary packages for Stendhal release. -->
|
||||
<target name="dist_binary" depends="clean,dist_server_binary,dist_client_binary,dist_client_starter,dist_webclient_binary" />
|
||||
<target name="dist_binary" depends="clean,dist_server_binary,dist_client_binary,dist_client_starter,dist_webclient_binary"
|
||||
description="Create all binary packages for Stendhal release."/>
|
||||
|
||||
|
||||
<!-- START: source -->
|
||||
|
||||
<!-- Create all source packages for Stendhal release. -->
|
||||
<target name="dist_source">
|
||||
<target name="dist_source" description="Create all source packages for Stendhal release.">
|
||||
<mkdir dir="${buildroot}/stendhal-${version}-src"/>
|
||||
|
||||
<copy todir="${buildroot}/stendhal-${version}-src/src">
|
||||
|
|
@ -109,8 +104,7 @@
|
|||
|
||||
<!-- START: client data -->
|
||||
|
||||
<!-- Build client data files. -->
|
||||
<target name="build_client_data">
|
||||
<target name="build_client_data" description="Build client data files.">
|
||||
<!-- base data -->
|
||||
<mkdir dir="${build_client_data}"/>
|
||||
<copy todir="${build_client_data}/data/sprites">
|
||||
|
|
@ -185,8 +179,7 @@
|
|||
|
||||
<!-- START: server -->
|
||||
|
||||
<!-- Compile JAR file for Stendhal server. -->
|
||||
<target name="server_build" depends="init,checkxml">
|
||||
<target name="server_build" depends="init,checkxml" description="Compile JAR file for Stendhal server.">
|
||||
<mkdir dir="${build_server}"/>
|
||||
|
||||
<copy todir="${build_server}/data/conf" file="data/conf/stendhalcreateaccount.properties"/>
|
||||
|
|
@ -347,8 +340,7 @@
|
|||
</target> <!-- server_build -->
|
||||
|
||||
|
||||
<!-- Create server package for release and distribution. -->
|
||||
<target name="dist_server_binary" depends="server_build">
|
||||
<target name="dist_server_binary" depends="server_build" description="Create server package for release and distribution.">
|
||||
<mkdir dir="${buildroot}/stendhal-server-${version}"/>
|
||||
|
||||
<copy todir="${buildroot}/stendhal-server-${version}/data/script">
|
||||
|
|
@ -400,12 +392,10 @@
|
|||
</target> <!-- dist_server_binary -->
|
||||
|
||||
|
||||
<!-- Build and push container image. -->
|
||||
<target name="dist_docker" depends="docker_build,docker_push" />
|
||||
<target name="dist_docker" depends="docker_build,docker_push" description="Build and push container image."/>
|
||||
|
||||
|
||||
<!-- Prepare container image build. -->
|
||||
<target name="docker_build_prepare" depends="dist_server_binary">
|
||||
<target name="docker_build_prepare" depends="dist_server_binary" description="Prepare container image build.">
|
||||
<mkdir dir="${build_docker}" />
|
||||
<copy file="${buildtools_docker}/Dockerfile" todir="${build_docker}" />
|
||||
<copy file="${buildtools_docker}/.dockerignore" todir="${build_docker}" />
|
||||
|
|
@ -414,8 +404,7 @@
|
|||
</target> <!-- docker_build_prepare -->
|
||||
|
||||
|
||||
<!-- Build container image. -->
|
||||
<target name="docker_build" depends="docker_build_prepare">
|
||||
<target name="docker_build" depends="docker_build_prepare" description="Build container image.">
|
||||
<exec dir="${build_docker}" executable="docker">
|
||||
<arg value="build" />
|
||||
<arg value="-t" />
|
||||
|
|
@ -425,57 +414,28 @@
|
|||
</target> <!-- docker_build -->
|
||||
|
||||
|
||||
<!-- Push container image. -->
|
||||
<target name="docker_push" />
|
||||
<target name="docker_push" description="Push container image."/>
|
||||
|
||||
|
||||
<!-- Run server. -->
|
||||
<target name="server_run" depends="server_build,compilejs">
|
||||
<mkdir dir="run_srvr/libs"/>
|
||||
<mkdir dir="run_srvr/js"/>
|
||||
<target name="server_run" depends="server_build,compilejs" description="Run server.">
|
||||
<mkdir dir="run_srvr"/>
|
||||
|
||||
<copy todir="run_srvr">
|
||||
<fileset file="build/lib/${server_jarname}"/>
|
||||
<fileset file="build/lib/${xmlconf_jarname}"/>
|
||||
<fileset file="build/lib/${maps_jarname}"/>
|
||||
</copy>
|
||||
|
||||
<copy todir="run_srvr/libs">
|
||||
<fileset file="${marauroa_jar}" />
|
||||
<fileset file="${groovy_jar}" />
|
||||
<fileset file="${guava_jar}" />
|
||||
<fileset file="${log4j_jar}" />
|
||||
<fileset file="${mysqldriver_jar}" />
|
||||
<fileset file="${h2_jar}" />
|
||||
<fileset file="${hamcrest_jar}" />
|
||||
<fileset file="${tomcatcore_jar}" />
|
||||
<fileset file="${tomcatwebsocket_jar}" />
|
||||
<fileset file="${jakartaannotation_jar}" />
|
||||
<fileset file="${luaj_jar}" />
|
||||
<fileset file="${jsonsimple_jar}" />
|
||||
</copy>
|
||||
|
||||
<copy todir="run_srvr/js">
|
||||
<fileset dir="${srcjs}">
|
||||
<exclude name="stendhal/" />
|
||||
<exclude name="stendhal-compiled.js.map" />
|
||||
<exclude name=".gitignore" />
|
||||
</fileset>
|
||||
<fileset file="libs/marauroa.jar"/>
|
||||
<fileset file="libs/groovy.jar"/>
|
||||
<fileset file="libs/guava.jar"/>
|
||||
<fileset file="libs/log4j.jar"/>
|
||||
<fileset file="libs/${mysqldriver_jarname}"/>
|
||||
</copy>
|
||||
|
||||
<chmod file="run_srvr/${server_jarname}" perm="+x"/>
|
||||
|
||||
<java jar="run_srvr/${server_jarname}"
|
||||
fork="true"
|
||||
failonerror="true"
|
||||
maxmemory="256m">
|
||||
<arg value="-c" />
|
||||
<arg value="server.ini" />
|
||||
<arg value="-l" />
|
||||
<classpath>
|
||||
<pathelement location="${basedir}" />
|
||||
</classpath>
|
||||
</java>
|
||||
<exec dir="." executable="java">
|
||||
<arg line="-Xmx256m -cp run_srvr -jar run_srvr/${server_jarname} -c server.ini -l"/>
|
||||
</exec>
|
||||
|
||||
<!-- we've run the program, so delete the jars -->
|
||||
<delete dir="run_srvr"/>
|
||||
|
|
@ -486,8 +446,7 @@
|
|||
|
||||
<!-- START: java client -->
|
||||
|
||||
<!-- Compile client JAR file. -->
|
||||
<target name="client_build" depends="init,build_client_data">
|
||||
<target name="client_build" depends="init,build_client_data" description="Compile client JAR file.">
|
||||
<mkdir dir="${build_client}"/>
|
||||
|
||||
<copy todir="${build_client}/games/stendhal/client">
|
||||
|
|
@ -580,8 +539,7 @@
|
|||
</target> <!-- client_build -->
|
||||
|
||||
|
||||
<!-- Compile text client. -->
|
||||
<target name="compile_textclient">
|
||||
<target name="compile_stendhaltextclient" description="Compile text client.">
|
||||
<mkdir dir="${build_stendhaltextclient}"/>
|
||||
|
||||
<javac srcdir="${src}" destdir="${build_stendhaltextclient}" source="1.8" target="1.8" debug="${javac.debug}" debuglevel="${javac.debuglevel}" deprecation="${javac.deprecation}" includeantruntime="false">
|
||||
|
|
@ -602,12 +560,8 @@
|
|||
</javac>
|
||||
</target> <!-- compile_stendhaltextclient -->
|
||||
|
||||
<!-- Alias of `compile_textclient`. -->
|
||||
<target name="compile_stendhaltextclient" depends="compile_textclient" />
|
||||
|
||||
|
||||
<!-- Create Java client package for release and distribution. -->
|
||||
<target name="dist_client_binary" depends="clean_client_data,client_build">
|
||||
<target name="dist_client_binary" depends="clean_client_data,client_build" description="Create Java client package for release and distribution.">
|
||||
<mkdir dir="${buildroot}/stendhal-${version}"/>
|
||||
<mkdir dir="${buildroot}/stendhal-${version}/lib"/>
|
||||
<mkdir dir="${buildroot}/stendhal-${version}/log"/>
|
||||
|
|
@ -643,8 +597,8 @@
|
|||
</target> <!-- dist_client_binary -->
|
||||
|
||||
|
||||
<!-- Create Java client starter package (obsolete). -->
|
||||
<target name="dist_client_starter" depends="client_build">
|
||||
<!-- XXX: is this still used? -->
|
||||
<target name="dist_client_starter" depends="client_build" description="Create Java client starter package.">
|
||||
<mkdir dir="${buildroot}/stendhal-${version}"/>
|
||||
<copy todir="${buildroot}/stendhal-${version}" file="${lib}/${client_starter_jarname}"/>
|
||||
<copy todir="${buildroot}/stendhal-${version}/lib">
|
||||
|
|
@ -666,8 +620,7 @@
|
|||
</target> <!-- dist_client_starter -->
|
||||
|
||||
|
||||
<!-- Run Java client. -->
|
||||
<target name="client_run" depends="client_build">
|
||||
<target name="client_run" depends="client_build" description="Run Java client.">
|
||||
<mkdir dir="run_clnt"/>
|
||||
<mkdir dir="run_clnt/lib"/>
|
||||
|
||||
|
|
@ -703,9 +656,8 @@
|
|||
</target> <!-- client_run -->
|
||||
|
||||
|
||||
<!-- Run client for NetBeans trick. -->
|
||||
<!-- Netbeans won't let you choose ant options, so this does it for us-->
|
||||
<target name="run" depends="client_run" />
|
||||
<target name="run" depends="client_run" description="Run client for NetBeans trick."/>
|
||||
|
||||
<!-- END: java client -->
|
||||
|
||||
|
|
@ -713,42 +665,30 @@
|
|||
<!-- START: web client -->
|
||||
|
||||
<target name="js-prepare-marauroa">
|
||||
<mkdir dir="node_modules/marauroa"/>
|
||||
<unzip dest="node_modules/marauroa" src="libs/marauroa.jar">
|
||||
<mapper type="flatten"/>
|
||||
<mkdir dir="build/js"/>
|
||||
<unzip dest="build" src="libs/marauroa.jar">
|
||||
<patternset>
|
||||
<include name="js/**"/>
|
||||
</patternset>
|
||||
</unzip>
|
||||
|
||||
</target>
|
||||
|
||||
|
||||
<target name="js-prepare-build">
|
||||
<mkdir dir="node_modules/marauroa"/>
|
||||
<echo file="node_modules/marauroa/build.js">
|
||||
export function version(marauroa, stendhal) {
|
||||
stendhal.data = stendhal.data || {};
|
||||
<echo file="build/js/build.js">
|
||||
var stendhal = window.stendhal = window.stendhal || {};
|
||||
stendhal.data = stendhal.data || {};
|
||||
|
||||
stendhal.data.build = {
|
||||
version: "${version}",
|
||||
build: "${datetime}",
|
||||
dist: "webclient"
|
||||
}
|
||||
|
||||
//CI
|
||||
}
|
||||
stendhal.data.build = {
|
||||
version: "${version}",
|
||||
build: "${datetime}",
|
||||
dist: "webclient"
|
||||
}
|
||||
</echo>
|
||||
<antcall target="js-prepare-build-ci" />
|
||||
</target>
|
||||
|
||||
<target name="js-prepare-build-ci" if="ci.build.info">
|
||||
<loadfile property="cibuildinfo" srcFile="${ci.build.info}" failonerror="false" quiet="true"/>
|
||||
<replace file="node_modules/marauroa/build.js" token="//CI" value="${cibuildinfo}" />
|
||||
</target>
|
||||
|
||||
|
||||
<extension-point name="js-prepare" depends="js-prepare-node,js-prepare-contribs,js-prepare-marauroa,js-prepare-build"/>
|
||||
<extension-point name="js-prepare" depends="js-prepare-marauroa,js-prepare-build,js-prepare-node,js-prepare-contribs"/>
|
||||
|
||||
|
||||
<target name="js-prepare-node">
|
||||
|
|
@ -773,19 +713,72 @@ export function version(marauroa, stendhal) {
|
|||
|
||||
<!-- TODO: Do not write stendhal-compiled.js to the source directory tree but directly to the compiled directory tree -->
|
||||
<target name="js-invoke-compiler">
|
||||
|
||||
<exec executable="${executable.npx}" dir="${srcjs}/stendhal" failonerror="true">
|
||||
<arg value="tsc"/>
|
||||
</exec>
|
||||
|
||||
<exec executable="${executable.npx}" dir="${srcjs}/stendhal" failonerror="true">
|
||||
<arg value="esbuild"/>
|
||||
<arg value="--bundle"/>
|
||||
<arg value="--outfile=../stendhal-compiled.js"/>
|
||||
<arg value="--platform=browser"/>
|
||||
<!-- <arg value="- -minify"/> -->
|
||||
<arg value="main.ts"/>
|
||||
</exec>
|
||||
<property name="js-debug" value="--debug --formatting=PRETTY_PRINT --create_source_map ${srcjs}/stendhal-compiled.js.map --source_map_include_content"/>
|
||||
|
||||
<property name="js-files-license" value="${srcjs}/stendhal/license.js"/>
|
||||
<property name="js-files-marauroa" value="build/js/marauroa.js build/js/client-framework.js build/js/message-factory.js build/js/perception.js build/js/rpfactory.js build/js/inflate.js build/js/deserializer.js"/>
|
||||
<property name="js-files-config" value="build/js/build.js"/>
|
||||
<property name="js-files-lib1" value="${srcjs}/jsxgraph-util.js"/>
|
||||
<property name="js-files-lib2" value=""/>
|
||||
<property name="js-files-data1" value="${srcjs}/stendhal/data/sha3.js"/>
|
||||
<property name="js-files-data2" value=""/>
|
||||
<property name="js-files-entity5" value=""/>
|
||||
<property name="js-files-entity6" value=""/>
|
||||
<property name="js-files-ui1" value=""/>
|
||||
<property name="js-files-ui2" value=""/>
|
||||
<property name="js-files-ui3" value=""/>
|
||||
<property name="js-files-main1" value=""/>
|
||||
<property name="js-files-ui4" value=""/>
|
||||
<property name="js-files-main2" value=""/>
|
||||
<property name="js-files-main3" value=""/>
|
||||
<property name="js-files-ts" value="build/ts/*.js build/ts/**/*.js"/>
|
||||
<property name="js-files-ts2" value=""/>
|
||||
|
||||
|
||||
<java jar="buildtools/closure-compiler/compiler.jar"
|
||||
fork="true"
|
||||
failonerror="true"
|
||||
maxmemory="128m">
|
||||
<arg value="--language_in=ECMASCRIPT_2020"/>
|
||||
<arg value="--language_out=STABLE"/>
|
||||
<arg value="--compilation_level"/>
|
||||
<arg value="ADVANCED"/>
|
||||
<arg line="${js-debug}"/>
|
||||
<arg value="--process_common_js_modules"/>
|
||||
<arg value="--module_resolution=node"/>
|
||||
<arg value="--jscomp_off=checkVars"/>
|
||||
<!-- DEBUG: -->
|
||||
<!--<arg value="-\-jscomp_off=globalThis"/>-->
|
||||
|
||||
<arg value="--js_output_file=${srcjs}/stendhal-compiled.js"/>
|
||||
|
||||
<arg line="${js-files-license}"/>
|
||||
<arg line="${js-files-marauroa}"/>
|
||||
<arg line="${js-files-config}"/>
|
||||
<arg line="${js-files-lib1}"/>
|
||||
<arg line="${js-files-lib2}"/>
|
||||
<arg line="${js-files-data1}"/>
|
||||
<arg line="${js-files-data2}"/>
|
||||
<arg line="${js-files-entity5}"/>
|
||||
<arg line="${js-files-entity6}"/>
|
||||
<arg line="${js-files-ui1}"/>
|
||||
<arg line="${js-files-ui2}"/>
|
||||
<arg line="${js-files-ui3}"/>
|
||||
<arg line="${js-files-main1}"/>
|
||||
<arg line="${js-files-ui4}"/>
|
||||
<arg line="${js-files-main2}"/>
|
||||
<arg line="${js-files-main3}"/>
|
||||
<arg line="${js-files-ts}"/>
|
||||
<arg line="${js-files-ts2}"/>
|
||||
</java>
|
||||
|
||||
<echo file="${srcjs}/stendhal-compiled.js" append="true">
|
||||
//# sourceMappingURL=stendhal-compiled.js.map
|
||||
</echo>
|
||||
|
||||
<antcall target="compilejs-hook" />
|
||||
|
||||
|
|
@ -802,8 +795,7 @@ export function version(marauroa, stendhal) {
|
|||
</target>
|
||||
|
||||
|
||||
<!-- Compile web client. -->
|
||||
<target name="compilejs" depends="cleanjs">
|
||||
<target name="compilejs" depends="cleanjs" description="Compile web client.">
|
||||
<antcall target="js-prepare" unless:set="exclude.webclient"/>
|
||||
<antcall target="js-invoke-compiler" unless:set="exclude.webclient"/>
|
||||
|
||||
|
|
@ -812,8 +804,7 @@ export function version(marauroa, stendhal) {
|
|||
</target> <!-- compilejs -->
|
||||
|
||||
|
||||
<!-- Compile and stage web client files. -->
|
||||
<target name="webclient_build" depends="compilejs,clean_client_data,build_client_data">
|
||||
<target name="webclient_build" depends="compilejs,clean_client_data,build_client_data" description="Compile and stage web client files.">
|
||||
<mkdir dir="${build_webclient}"/>
|
||||
|
||||
<copy todir="${build_webclient}">
|
||||
|
|
@ -835,8 +826,10 @@ export function version(marauroa, stendhal) {
|
|||
</target> <!-- webclient_build -->
|
||||
|
||||
|
||||
<!-- Create web client package for release and distribution. -->
|
||||
<target name="dist_webclient_binary" depends="webclient_build">
|
||||
<target name="build_webclient" depends="webclient_build" description="Alias of webclient_build."/>
|
||||
|
||||
|
||||
<target name="dist_webclient_binary" depends="webclient_build" description="Create web client package for release and distribution.">
|
||||
<zip destfile="${buildroot}/stendhal-webclient-${version}.zip">
|
||||
<zipfileset dir="${build_client_data}"/>
|
||||
<zipfileset dir="${build_client_music_data}"/>
|
||||
|
|
|
|||
|
|
@ -12,8 +12,7 @@
|
|||
<delete dir="${buildroot}/build_docs"/>
|
||||
</target>
|
||||
|
||||
<!-- Generate HTML documentation for Java, TypeScript, and Lua APIs. -->
|
||||
<target name="docs" depends="luadocs,javadocs,tsdocs"/>
|
||||
<target name="docs" description="Generate HTML documentation for Java, TypeScript, and Lua APIs." depends="luadocs,javadocs,tsdocs"/>
|
||||
|
||||
|
||||
<!-- Java documentation -->
|
||||
|
|
|
|||
|
|
@ -1,86 +0,0 @@
|
|||
<?xml version='1.0'?>
|
||||
|
||||
<project>
|
||||
|
||||
<target name="info" description="Print project build information.">
|
||||
<echo level="info" message="Project:" />
|
||||
<echo level="info" message=" Name: .......... ${game_name}" />
|
||||
<echo level="info" message=" Version: ....... ${version}" />
|
||||
<echo level="info" message=" Root: .......... ${basedir}" />
|
||||
<echo level="info" />
|
||||
<echo level="info" message="Build system:" />
|
||||
<echo level="info" message=" Ant version: ... ${ant.version.number}" />
|
||||
<echo level="info" message=" Ant home: ...... ${ant.location}" />
|
||||
<echo level="info" message=" Java version: .. ${java.version}" />
|
||||
<echo level="info" message=" Java home: ..... ${java.home}" />
|
||||
</target>
|
||||
|
||||
<target name="help" description="Print project build and help information." depends="info">
|
||||
<echo level="info" message="Usage:" />
|
||||
<echo level="info" message=" ant <target> [<target>...]" />
|
||||
<echo level="info" />
|
||||
<echo level="info" />
|
||||
<echo level="info" message="=== TARGETS ===" />
|
||||
<echo level="info" />
|
||||
<echo level="info" message="General:" />
|
||||
<echo level="info" message=" info: ........................ Print project build information." />
|
||||
<echo level="info" message=" help: ........................ Print project build and help information." />
|
||||
<echo level="info" message=" init: ........................ Update version and resource info." />
|
||||
<echo level="info" message=" checkxml: .................... Verify XML files are well-formed." />
|
||||
<echo level="info" />
|
||||
<echo level="info" message="Build:" />
|
||||
<echo level="info" message=" server_build: ................ Compile JAR file for Stendhal server." />
|
||||
<echo level="info" message=" client_build: ................ Compile client JAR file." />
|
||||
<echo level="info" message=" webclient_build: ............. Compile and stage web client files." />
|
||||
<echo level="info" message=" compile_textclient: .......... Compile text client." />
|
||||
<echo level="info" message=" compile: ..................... Generate JAR files for both client and server." />
|
||||
<echo level="info" message=" compilejs: ................... Compile web client." />
|
||||
<echo level="info" message=" compile_tools: ............... Compile Stendhal build tools." />
|
||||
<echo level="info" message=" server_run: .................. Run server." />
|
||||
<echo level="info" message=" client_run: .................. Run Java client." />
|
||||
<echo level="info" message=" postman: ..................... Build postman bot." />
|
||||
<echo level="info" />
|
||||
<echo level="info" message="Testing:" />
|
||||
<echo level="info" message=" compile_tests: ............... Compile all tests." />
|
||||
<echo level="info" message=" run_tests: ................... Run all tests." />
|
||||
<echo level="info" message=" test: ........................ Compile and run all tests." />
|
||||
<echo level="info" />
|
||||
<echo level="info" message="Build cleaning:" />
|
||||
<echo level="info" message=" clean: ....................... Delete all build files and directories." />
|
||||
<echo level="info" message=" clean_client_data: ........... Delete client data build files and directories." />
|
||||
<echo level="info" message=" cleanjs: ..................... Delete web client build files and directories." />
|
||||
<echo level="info" />
|
||||
<echo level="info" message="Source maintanence:" />
|
||||
<echo level="info" message=" clean_whitespace: ............ Clean whitespace in source and other specified file types." />
|
||||
<echo level="info" />
|
||||
<echo level="info" message="Distribution:" />
|
||||
<echo level="info" message=" dist_source: ................. Create all source packages for Stendhal release." />
|
||||
<echo level="info" message=" dist_binary: ................. Create all binary packages for Stendhal release." />
|
||||
<echo level="info" message=" dist_server_binary: .......... Create server package for release and distribution." />
|
||||
<echo level="info" message=" dist_client_binary: .......... Create Java client package for release and distribution." />
|
||||
<echo level="info" message=" dist_webclient_binary: ....... Create web client package for release and distribution." />
|
||||
<echo level="info" message=" dist_client_starter: ......... Create Java client starter package (obsolete)." />
|
||||
<echo level="info" message=" dist: ........................ Create all packages for Stendhal release." />
|
||||
<echo level="info" message=" android: ..................... Create Android client package for release and distribution." />
|
||||
<echo level="info" />
|
||||
<echo level="info" message="Resources:" />
|
||||
<echo level="info" message=" rendermaps: .................. Convert TMX maps to PNG images scaled 1:16." />
|
||||
<echo level="info" message=" renderatlas: ................. Generate files for the Stendhal Atlas." />
|
||||
<echo level="info" message=" renderworldmap: .............. Export world.tmx map to PNG image." />
|
||||
<echo level="info" message=" updatemaps: .................. Load and save TMX maps to fix tilesets changes." />
|
||||
<echo level="info" />
|
||||
<echo level="info" message="Documentation:" />
|
||||
<echo level="info" message=" docs: ........................ Generate HTML documentation for Java, TypeScript, and Lua APIs." />
|
||||
<echo level="info" />
|
||||
<echo level="info" message="Localization:" />
|
||||
<echo level="info" message=" locale_template: ............. Creates a template for translating." />
|
||||
<echo level="info" message=" locale_update: ............... Update translation files from template." />
|
||||
<echo level="info" />
|
||||
<echo level="info" message="Aliases:" />
|
||||
<echo level="info" message=" compile_stendhaltextclient: .. Alias of `compile_textclient`." />
|
||||
<echo level="info" message=" compile_stendhaltools: ....... Alias of `compile_tools`." />
|
||||
<echo level="info" />
|
||||
<echo level="info" message="Execute `ant -p -v` for a full list of build targets." />
|
||||
</target>
|
||||
|
||||
</project>
|
||||
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
<project xmlns:if="ant:if" xmlns:unless="ant:unless">
|
||||
|
||||
<!-- Creates a template for translating. -->
|
||||
<target name="locale_template">
|
||||
<target name="locale_build_template" description="Creates a template for translating.">
|
||||
<echo unless:true="${python.present}" message="Python unavailable, cannot build locale template"/>
|
||||
|
||||
<exec executable="${executable.python}" if:true="${python.present}" failonerror="true">
|
||||
|
|
@ -12,8 +11,7 @@
|
|||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- Update translation files from template. -->
|
||||
<target name="locale_update">
|
||||
<target name="locale_update" description="Update translation files from template.">
|
||||
<echo unless:true="${python.present}" message="Python unavailable, cannot update translations"/>
|
||||
|
||||
<exec executable="${executable.python}" if:true="${python.present}" failonerror="true">
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
<project xmlns:if="ant:if" xmlns:unless="ant:unless">
|
||||
|
||||
<!-- Update version and resource info. -->
|
||||
<target name="init">
|
||||
<target name="init" description="Update version and resource info.">
|
||||
<mkdir dir="${lib}"/>
|
||||
|
||||
<!-- update version -->
|
||||
|
|
@ -90,8 +89,7 @@
|
|||
</target> <!-- init -->
|
||||
|
||||
|
||||
<!-- Verify XML files are well-formed. -->
|
||||
<target name="checkxml">
|
||||
<target name="checkxml" description="Verify XML files are well-formed.">
|
||||
<schemavalidate failonerror="yes" lenient="yes" warn="yes">
|
||||
<schema namespace="stendhal" file="${config_dir}/zones.xsd"/>
|
||||
<fileset dir="${config_dir}/zones">
|
||||
|
|
@ -169,8 +167,7 @@
|
|||
</target> <!-- checkxml -->
|
||||
|
||||
|
||||
<!-- Add date to pre-release test client. -->
|
||||
<target name="internalUpdatePrereleaseVersion" if="PRE_RELEASE">
|
||||
<target name="internalUpdatePrereleaseVersion" if="PRE_RELEASE" description="Add date to pre-release test client.">
|
||||
<tstamp prefix="date">
|
||||
<format property="iso" pattern="yyyy-MM-dd"/>
|
||||
</tstamp>
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
<import file="tools.xml" />
|
||||
|
||||
<!-- Convert TMX maps to PNG images scaled 1:16. -->
|
||||
<target name="rendermaps" depends="compile_stendhaltools">
|
||||
<target name="rendermaps" description="Convert TMX maps to PNG images scaled 1:16." depends="compile_stendhaltools">
|
||||
<taskdef name="maprenderer" classname="games.stendhal.tools.MapRenderer">
|
||||
<classpath>
|
||||
<pathelement path="${build_stendhaltools}"/>
|
||||
|
|
@ -24,8 +23,7 @@
|
|||
</target> <!-- rendermaps -->
|
||||
|
||||
|
||||
<!-- Generate files for the Stendhal Atlas. -->
|
||||
<target name="renderatlas" depends="compile_stendhaltools">
|
||||
<target name="renderatlas" description="Generate files for the Stendhal Atlas." depends="compile_stendhaltools">
|
||||
<taskdef name="maprenderer" classname="games.stendhal.tools.MapRenderer">
|
||||
<classpath>
|
||||
<pathelement path="${build_stendhaltools}"/>
|
||||
|
|
@ -60,8 +58,7 @@
|
|||
</target> <!-- renderatlas -->
|
||||
|
||||
|
||||
<!-- Export world.tmx map to PNG image. -->
|
||||
<target name="renderworldmap" depends="rendermaps">
|
||||
<target name="renderworldmap" description="Export world.tmx map to PNG image." depends="rendermaps">
|
||||
<!-- embed area images with area name -->
|
||||
<!-- FIXME: need to detect the Python "PIL" module to ensure script can run or
|
||||
write Java class that can do this -->
|
||||
|
|
@ -88,8 +85,7 @@
|
|||
</target> <!-- renderworldmap -->
|
||||
|
||||
|
||||
<!-- Load and save TMX maps to fix tilesets changes. -->
|
||||
<target name="updatemaps" depends="compile_stendhaltools">
|
||||
<target name="updatemaps" description="Load and save TMX maps to fix tilesets changes." depends="compile_stendhaltools">
|
||||
<taskdef name="mapupdater" classname="games.stendhal.tools.MapUpdater">
|
||||
<classpath>
|
||||
<pathelement path="${build_stendhaltools}"/>
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@
|
|||
<delete file="${build}/package/client/stendhal-starter.exe"/>
|
||||
</target>
|
||||
|
||||
<!-- Creates MSI installer package from current build. -->
|
||||
<target name="msiPackage" depends="stagePackage">
|
||||
<target name="msiPackage" description="Creates MSI installer package from current build" depends="stagePackage">
|
||||
<delete dir="${build}/package/msi-app-image"/>
|
||||
<exec executable="jpackage" dir="." failonerror="true">
|
||||
<arg line="--type app-image"/>
|
||||
|
|
@ -47,8 +46,7 @@
|
|||
</exec>
|
||||
</target> <!-- msiPackage -->
|
||||
|
||||
<!-- Creates DMG package from current build. -->
|
||||
<target name="dmgPackage" depends="stagePackage">
|
||||
<target name="dmgPackage" description="Creates DMG package from current build" depends="stagePackage">
|
||||
<delete dir="${build}/package/dmg-app-image"/>
|
||||
<exec executable="jpackage" dir="." failonerror="true">
|
||||
<arg line="--type app-image"/>
|
||||
|
|
@ -76,8 +74,7 @@
|
|||
</exec>
|
||||
</target> <!-- dmgPackage -->
|
||||
|
||||
<!-- Creates RPM package from current build. -->
|
||||
<target name="rpmPackage" depends="stagePackage">
|
||||
<target name="rpmPackage" description="Creates RPM package from current build" depends="stagePackage">
|
||||
<delete dir="${build}/package/rpm-app-image"/>
|
||||
<exec executable="jpackage" dir="." failonerror="true">
|
||||
<arg line="--type app-image"/>
|
||||
|
|
@ -110,8 +107,7 @@
|
|||
</exec>
|
||||
</target> <!-- rpmPackage -->
|
||||
|
||||
<!-- Creates DEB package from current build. -->
|
||||
<target name="debPackage" depends="stagePackage">
|
||||
<target name="debPackage" description="Creates DEB package from current build" depends="stagePackage">
|
||||
<delete dir="${build}/package/deb-app-image"/>
|
||||
<exec executable="jpackage" dir="." failonerror="true">
|
||||
<arg line="--type app-image"/>
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
<?xml version='1.0'?>
|
||||
|
||||
<project>
|
||||
|
||||
<!--
|
||||
Sets a property (by name and value), or set of properties (from file or resource) in the project. Properties are case sensitive.
|
||||
Properties are immutable: whoever sets a property first freezes it for the rest of the build; they are most definitely not variables.
|
||||
-->
|
||||
|
||||
<!-- store ant version number without extra details -->
|
||||
<antversion property="ant.version.number" />
|
||||
<!-- store ant home directory with system delimiter -->
|
||||
<property name="ant.location" location="${ant.home}" />
|
||||
|
||||
<property name="build_tests" value="${buildroot}/build_tests"/>
|
||||
<property name="build_tests_report" value="${buildroot}/build_test_report"/>
|
||||
|
||||
<property name="build_client" value="${buildroot}/build_client"/>
|
||||
<property name="build_client_data" value="${buildroot}/build_client_data"/>
|
||||
<property name="build_client_sound_data" value="${buildroot}/build_client_sound_data"/>
|
||||
<property name="build_client_music_data" value="${buildroot}/build_client_music_data"/>
|
||||
|
||||
<property name="build_webclient" value="${buildroot}/build_webclient"/>
|
||||
|
||||
<property name="build_docker" value="${buildroot}/build_docker"/>
|
||||
<property name="buildtools_docker" value="buildtools/docker"/>
|
||||
|
||||
<property name="build_postman" value="${buildroot}/buildbot/"/>
|
||||
|
||||
<property name="build_server" value="${buildroot}/build_server"/>
|
||||
<property name="build_server_maps" value="${buildroot}/build_server_maps"/>
|
||||
<property name="build_server_script" value="${buildroot}/build_server_script"/>
|
||||
<property name="build_server_mods" value="${buildroot}/build_server_mods"/>
|
||||
<property name="build_server_xmlconf" value="${buildroot}/build_server_xmlconf"/>
|
||||
|
||||
<property name="build_stendhaltools" value="${buildroot}/build_stendhaltools"/>
|
||||
<property name="build_stendhaltextclient" value="${buildroot}/build_stendhaltextclient"/>
|
||||
|
||||
<property name="client_data" value="stendhal-data-${version}.jar"/>
|
||||
<property name="client_jarname" value="stendhal-${version}.jar"/>
|
||||
<property name="client_sound_data" value="stendhal-sound-data-${version}.jar"/>
|
||||
<property name="client_music_data" value="stendhal-music-data-${version}.jar"/>
|
||||
<property name="client_starter_jarname" value="stendhal-starter-${version}.jar"/>
|
||||
|
||||
<property name="dist_server_binary" value="${buildroot}/stendhal-server-${version}.zip" />
|
||||
|
||||
<property name="maps_jarname" value="stendhal-maps-${version}.jar"/>
|
||||
|
||||
<property name="server_jarname" value="stendhal-server-${version}.jar"/>
|
||||
<property name="xmlconf_jarname" value="stendhal-xmlconf-${version}.jar"/>
|
||||
|
||||
<property name="config_dir" value="data/conf"/>
|
||||
|
||||
<property name="schema_location" value="${config_dir}"/>
|
||||
|
||||
<property name="cobertura.dir" value="${libdir}/cobertura"/>
|
||||
|
||||
<condition property="exclude.signing" value="true">
|
||||
<not>
|
||||
<available file="keystore.ks"/>
|
||||
</not>
|
||||
</condition>
|
||||
<condition property="exclude.jardiff" value="true">
|
||||
<not>
|
||||
<available file="${build-archive}/stendhal-${version.old}.zip"/>
|
||||
</not>
|
||||
</condition>
|
||||
|
||||
<!-- time & date -->
|
||||
<tstamp>
|
||||
<format property="year" pattern="yyyy"/>
|
||||
<format property="date" pattern="yyyy-MM-dd"/>
|
||||
<format property="time" pattern="HH:mm:ss"/>
|
||||
</tstamp>
|
||||
<property name="datetime" value="${date} ${time}"/>
|
||||
|
||||
</project>
|
||||
|
|
@ -7,8 +7,7 @@
|
|||
<import file="dist.xml" />
|
||||
<import file="tools.xml" />
|
||||
|
||||
<!-- Compile and run all tests. -->
|
||||
<target name="test" depends="compile_tests,prepare_serverini_for_tests,run_tests,report_test">
|
||||
<target name="test" description="Compile and run all tests." depends="compile_tests,prepare_serverini_for_tests,run_tests,report_test">
|
||||
<exec executable="curl">
|
||||
<arg value="-q"/>
|
||||
<arg value="-F"/>
|
||||
|
|
@ -22,8 +21,7 @@
|
|||
</target> <!-- test -->
|
||||
|
||||
|
||||
<!-- Compile all tests. -->
|
||||
<target name="compile_tests" depends="server_build,client_build,compile_stendhaltools,compile_stendhaltextclient,postman">
|
||||
<target name="compile_tests" description="Compile all tests." depends="server_build,client_build,compile_stendhaltools,compile_stendhaltextclient,postman">
|
||||
<mkdir dir="${build_tests}"/>
|
||||
|
||||
<copy todir="${build_tests}">
|
||||
|
|
@ -65,8 +63,7 @@
|
|||
</target> <!-- compile_tests -->
|
||||
|
||||
|
||||
<!-- Generate server.ini for testing. -->
|
||||
<target name="prepare_serverini_for_tests" unless="server.ini">
|
||||
<target name="prepare_serverini_for_tests" unless="server.ini" description="Generate server.ini for testing.">
|
||||
<echo file="server.ini">
|
||||
database_implementation=games.stendhal.server.core.engine.StendhalPlayerDatabase
|
||||
factory_implementation=games.stendhal.server.core.engine.StendhalRPObjectFactory
|
||||
|
|
@ -88,8 +85,7 @@ d = 9017093486007323270605414717455737376618092805104733236083857811315606869372
|
|||
</target> <!-- prepare_serverini_for_tests -->
|
||||
|
||||
|
||||
<!-- Run all tests. -->
|
||||
<target name="run_tests">
|
||||
<target name="run_tests" description="Run all tests.">
|
||||
<mkdir dir="${build_tests_report}"/>
|
||||
<taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
|
||||
<classpath path="buildtools/jacoco/jacocoant.jar"/>
|
||||
|
|
@ -151,8 +147,7 @@ d = 9017093486007323270605414717455737376618092805104733236083857811315606869372
|
|||
</target> <!-- run_tests -->
|
||||
|
||||
|
||||
<!-- Aggregate test results. -->
|
||||
<target name="report_test">
|
||||
<target name="report_test" description="Aggregate test results.">
|
||||
<mkdir dir="${build_tests_report}"/>
|
||||
<junitreport todir="${build_tests_report}" tofile="testresults.xml">
|
||||
<fileset dir="${build_tests_report}">
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
<import file="dist.xml" />
|
||||
|
||||
<!-- Compile Stendhal build tools. -->
|
||||
<target name="compile_tools">
|
||||
<target name="compile_stendhaltools" description="Compile Stendhal build tools.">
|
||||
<mkdir dir="${build_stendhaltools}"/>
|
||||
|
||||
<javac srcdir="${src}" destdir="${build_stendhaltools}" source="1.8" target="1.8" debug="${javac.debug}" debuglevel="${javac.debuglevel}" deprecation="${javac.deprecation}" includeantruntime="true">
|
||||
|
|
@ -29,11 +28,7 @@
|
|||
</javac>
|
||||
</target> <!-- compile_stendhaltools -->
|
||||
|
||||
<!-- Alias of `compile_tools`. -->
|
||||
<target name="compile_stendhaltools" depends="compile_tools" />
|
||||
|
||||
<!-- Clean whitespace in source and other specified file types. -->
|
||||
<target name="clean_whitespace" depends="compile_stendhaltools">
|
||||
<target name="clean_whitespace" description="Clean whitespace in source and other specified file types." depends="compile_stendhaltools">
|
||||
<!-- process main Java source, config, & scripting files -->
|
||||
<java classname="games.stendhal.tools.CleanWhitespace">
|
||||
<classpath>
|
||||
|
|
@ -60,22 +55,16 @@
|
|||
<pathelement path="${build_stendhaltools}"/>
|
||||
</classpath>
|
||||
<arg value="data/"/>
|
||||
<arg value="tiled/"/>
|
||||
<arg value="xml,xsd,lua,py"/>
|
||||
</java>
|
||||
|
||||
<!-- process Ant build configuration files -->
|
||||
<java classname="games.stendhal.tools.CleanWhitespace">
|
||||
<classpath>
|
||||
<pathelement path="${build_stendhaltools}"/>
|
||||
</classpath>
|
||||
<arg value="${ant_modules}" />
|
||||
<arg value="xml" />
|
||||
</java>
|
||||
</target> <!-- clean_whitespace -->
|
||||
|
||||
|
||||
<!-- Build postman bot. -->
|
||||
<target name="postman">
|
||||
<target name="cleanwhitespace" depends="clean_whitespace" description="Alias of clean_whitespace."/>
|
||||
|
||||
|
||||
<target name="postman" description="Build postman bot.">
|
||||
<mkdir dir="${buildroot}/buildbot"/>
|
||||
<javac srcdir="${src}" destdir="${buildroot}/buildbot" debug="${javac.debug}" debuglevel="${javac.debuglevel}" source="1.8" target="1.8" deprecation="${javac.deprecation}" includeantruntime="false">
|
||||
<include name="games/stendhal/bot/postman/*.java"/>
|
||||
|
|
@ -111,8 +100,7 @@
|
|||
</target> <!-- postman -->
|
||||
|
||||
|
||||
<!-- Sign updates. -->
|
||||
<target name="signupdates" depends="compile_stendhaltools,jardiff" unless="exclude.signing">
|
||||
<target name="signupdates" description="Sign updates." depends="compile_stendhaltools,jardiff" unless="exclude.signing">
|
||||
<taskdef name="updatesigner" classname="games.stendhal.tools.updateprop.UpdateSigner">
|
||||
<classpath>
|
||||
<pathelement path="."/>
|
||||
|
|
@ -128,8 +116,7 @@
|
|||
</target> <!-- signupdates -->
|
||||
|
||||
|
||||
<!-- Generate release changes info. -->
|
||||
<target name="jardiff" depends="client_build" unless="exclude.jardiff">
|
||||
<target name="jardiff" depends="client_build" unless="exclude.jardiff" description="Generate release changes info.">
|
||||
<echo>Creating update from ${version.old} to ${version}</echo>
|
||||
<delete>
|
||||
<fileset dir="${build-archive}">
|
||||
|
|
@ -173,9 +160,8 @@
|
|||
</target> <!-- jardiff -->
|
||||
|
||||
|
||||
<!-- Run enemy balancer. -->
|
||||
<!-- USAGE: ant balance -Dcreature="<creature_name>" -->
|
||||
<target name="balance" depends="compile_stendhaltools,server_build">
|
||||
<target name="balance" description="Run enemy balancer." depends="compile_stendhaltools,server_build">
|
||||
<java classname="games.stendhal.tools.BalanceRPGame">
|
||||
<classpath>
|
||||
<pathelement path="${build_stendhaltools}"/>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
site_name: Stendhal 1.49.5 Reference Documentation
|
||||
site_name: Stendhal 1.49 Reference Documentation
|
||||
site_description: A fun, friendly, & free multiplayer online adventure game.
|
||||
copyright: Copyright © 2003-2026 Stendhal
|
||||
copyright: Copyright © 2003-2025 Stendhal
|
||||
site_url: https://stendhalgame.org/
|
||||
nav:
|
||||
- Index: /reference/
|
||||
|
|
|
|||
1779
data/languages/en.txt
Normal file
1779
data/languages/en.txt
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1097,7 +1097,6 @@ venom gland=
|
|||
You see the venom gland of a giant king cobra. It is filled with deadly toxin.=
|
||||
|
||||
pelt=
|
||||
You see a pelt of animal skin. It's used to make clothes and leather armor.=
|
||||
|
||||
leather thread=
|
||||
You see a strand of sturdy leather thread.=
|
||||
|
|
@ -1266,9 +1265,6 @@ You see an imperial ring. It is imbued with the strength of a king.=
|
|||
enhanced imperial ring=
|
||||
You see an enhanced imperial ring. It eminates the auras of strength and defense.=
|
||||
|
||||
ring of clarity=
|
||||
You see a ring of clarity. You feel more aware while wearing it.=
|
||||
|
||||
|
||||
## scrolls
|
||||
|
||||
|
|
@ -1411,9 +1407,6 @@ You see a silvery gm token. Does it bring you pride?=
|
|||
bronze gm token=
|
||||
You see a bronze gm token. Does it bring you pride?=
|
||||
|
||||
four-leaf clover=
|
||||
You see a lucky four-leaf clover. What are the chances of finding one!?=
|
||||
|
||||
|
||||
## swords
|
||||
|
||||
|
|
@ -1642,7 +1635,6 @@ You see a killer bat which will suck your blood!=
|
|||
giant bat=
|
||||
|
||||
giant killer bat=
|
||||
You see a giant killer bat. As if small wasn't pesky enough, these giant ones are capable of taking down anyone who dares come before them.=
|
||||
|
||||
piglet=
|
||||
You see a piglet, a bit dirty.=
|
||||
|
|
@ -1710,7 +1702,6 @@ black bear=
|
|||
You see a strong black bear which hibernates in winter.=
|
||||
|
||||
polar bear=
|
||||
You see a polar bear which lives in the icy desert. Beware! It can take you down with its powerful claws!=
|
||||
|
||||
|
||||
## animal_aquatic
|
||||
|
|
@ -2277,7 +2268,6 @@ cannibal=
|
|||
You see a cannibal. He hunts you for cooking and eating your fresh meat! It's useless to tell him that your flesh is not good, better fight him or run away!=
|
||||
|
||||
elder cannibal=
|
||||
You see an elder cannibal. For years it has eaten humans. It will not stop until its hunger is satisfied.=
|
||||
|
||||
cannibal warrior=
|
||||
You see a cannibal warrior.=
|
||||
|
|
|
|||
Binary file not shown.
755
package-lock.json
generated
755
package-lock.json
generated
|
|
@ -1,736 +1,21 @@
|
|||
{
|
||||
"name": "stendhal",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "stendhal",
|
||||
"version": "1.0.0",
|
||||
"license": "AGPL-3.0-or-later",
|
||||
"devDependencies": {
|
||||
"esbuild": "0.28.1",
|
||||
"showdown": "^2.1.0",
|
||||
"typedoc": "^0.28.15",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz",
|
||||
"integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz",
|
||||
"integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz",
|
||||
"integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz",
|
||||
"integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz",
|
||||
"integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz",
|
||||
"integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz",
|
||||
"integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz",
|
||||
"integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz",
|
||||
"integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openharmony-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openharmony"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz",
|
||||
"integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz",
|
||||
"integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz",
|
||||
"integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@gerrit0/mini-shiki": {
|
||||
"version": "3.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.20.0.tgz",
|
||||
"integrity": "sha512-Wa57i+bMpK6PGJZ1f2myxo3iO+K/kZikcyvH8NIqNNZhQUbDav7V9LQmWOXhf946mz5c1NZ19WMsGYiDKTryzQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/engine-oniguruma": "^3.20.0",
|
||||
"@shikijs/langs": "^3.20.0",
|
||||
"@shikijs/themes": "^3.20.0",
|
||||
"@shikijs/types": "^3.20.0",
|
||||
"@shikijs/vscode-textmate": "^10.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/engine-oniguruma": {
|
||||
"version": "3.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.20.0.tgz",
|
||||
"integrity": "sha512-Yx3gy7xLzM0ZOjqoxciHjA7dAt5tyzJE3L4uQoM83agahy+PlW244XJSrmJRSBvGYELDhYXPacD4R/cauV5bzQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "3.20.0",
|
||||
"@shikijs/vscode-textmate": "^10.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/langs": {
|
||||
"version": "3.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.20.0.tgz",
|
||||
"integrity": "sha512-le+bssCxcSHrygCWuOrYJHvjus6zhQ2K7q/0mgjiffRbkhM4o1EWu2m+29l0yEsHDbWaWPNnDUTRVVBvBBeKaA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "3.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/themes": {
|
||||
"version": "3.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.20.0.tgz",
|
||||
"integrity": "sha512-U1NSU7Sl26Q7ErRvJUouArxfM2euWqq1xaSrbqMu2iqa+tSp0D1Yah8216sDYbdDHw4C8b75UpE65eWorm2erQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/types": "3.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/types": {
|
||||
"version": "3.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.20.0.tgz",
|
||||
"integrity": "sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@shikijs/vscode-textmate": "^10.0.2",
|
||||
"@types/hast": "^3.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@shikijs/vscode-textmate": {
|
||||
"version": "10.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz",
|
||||
"integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/hast": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
|
||||
"integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/unist": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/unist": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
|
||||
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true,
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "9.5.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.20.0 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.28.1",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz",
|
||||
"integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.28.1",
|
||||
"@esbuild/android-arm": "0.28.1",
|
||||
"@esbuild/android-arm64": "0.28.1",
|
||||
"@esbuild/android-x64": "0.28.1",
|
||||
"@esbuild/darwin-arm64": "0.28.1",
|
||||
"@esbuild/darwin-x64": "0.28.1",
|
||||
"@esbuild/freebsd-arm64": "0.28.1",
|
||||
"@esbuild/freebsd-x64": "0.28.1",
|
||||
"@esbuild/linux-arm": "0.28.1",
|
||||
"@esbuild/linux-arm64": "0.28.1",
|
||||
"@esbuild/linux-ia32": "0.28.1",
|
||||
"@esbuild/linux-loong64": "0.28.1",
|
||||
"@esbuild/linux-mips64el": "0.28.1",
|
||||
"@esbuild/linux-ppc64": "0.28.1",
|
||||
"@esbuild/linux-riscv64": "0.28.1",
|
||||
"@esbuild/linux-s390x": "0.28.1",
|
||||
"@esbuild/linux-x64": "0.28.1",
|
||||
"@esbuild/netbsd-arm64": "0.28.1",
|
||||
"@esbuild/netbsd-x64": "0.28.1",
|
||||
"@esbuild/openbsd-arm64": "0.28.1",
|
||||
"@esbuild/openbsd-x64": "0.28.1",
|
||||
"@esbuild/openharmony-arm64": "0.28.1",
|
||||
"@esbuild/sunos-x64": "0.28.1",
|
||||
"@esbuild/win32-arm64": "0.28.1",
|
||||
"@esbuild/win32-ia32": "0.28.1",
|
||||
"@esbuild/win32-x64": "0.28.1"
|
||||
}
|
||||
},
|
||||
"node_modules/linkify-it": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"uc.micro": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lunr": {
|
||||
"version": "2.3.9",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/markdown-it": {
|
||||
"version": "14.1.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
|
||||
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "^4.4.0",
|
||||
"linkify-it": "^5.0.0",
|
||||
"mdurl": "^2.0.0",
|
||||
"punycode.js": "^2.3.1",
|
||||
"uc.micro": "^2.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"markdown-it": "bin/markdown-it.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/mdurl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "9.0.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
|
||||
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/punycode.js": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
|
||||
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/showdown": {
|
||||
"version": "2.1.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"commander": "^9.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"showdown": "bin/showdown.js"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://www.paypal.me/tiviesantos"
|
||||
}
|
||||
},
|
||||
"node_modules/typedoc": {
|
||||
"version": "0.28.15",
|
||||
"resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.15.tgz",
|
||||
"integrity": "sha512-mw2/2vTL7MlT+BVo43lOsufkkd2CJO4zeOSuWQQsiXoV2VuEn7f6IZp2jsUDPmBMABpgR0R5jlcJ2OGEFYmkyg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@gerrit0/mini-shiki": "^3.17.0",
|
||||
"lunr": "^2.3.9",
|
||||
"markdown-it": "^14.1.0",
|
||||
"minimatch": "^9.0.5",
|
||||
"yaml": "^2.8.1"
|
||||
},
|
||||
"bin": {
|
||||
"typedoc": "bin/typedoc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18",
|
||||
"pnpm": ">= 10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x"
|
||||
"typescript": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
|
@ -738,29 +23,13 @@
|
|||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/uc.micro": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
|
||||
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
|
||||
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/eemeli"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"typescript": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,10 +28,11 @@
|
|||
},
|
||||
"homepage": "https://arianne-project.org",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"typescript": "^5.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "0.28.1",
|
||||
"showdown": "^2.1.0",
|
||||
"typedoc": "^0.28.15",
|
||||
"typescript": "^5.9.3"
|
||||
"typedoc": "^0.25.12"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.49.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.49.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.
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ div.logcolR {
|
|||
background: url(/data/gui/danger.png) repeat;
|
||||
}
|
||||
|
||||
.qm-button, canvas#held-object {
|
||||
.qm-button, img#held-object {
|
||||
position: absolute;
|
||||
display: none;
|
||||
opacity: 0.5;
|
||||
|
|
|
|||
1169
src/js/jsxgraph-util.js
Normal file
1169
src/js/jsxgraph-util.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -486,11 +486,14 @@
|
|||
<div class="shortcuts-dialog"></div>
|
||||
</template>
|
||||
|
||||
<canvas id="held-object" class="unselectable notarget" draggable="false"></canvas>
|
||||
<img id="held-object" class="hidden unselectable notarget" draggable="false">
|
||||
|
||||
<!-- place at end of document so drawn above all other elements -->
|
||||
<img id="click-indicator" class="unclickable notarget">
|
||||
|
||||
<!-- hidden canvas for manipulating images before being displayed -->
|
||||
<canvas id="drawing-stage" class="hidden"></canvas>
|
||||
|
||||
<script type="text/javascript" src="stendhal-compiled.js"></script>
|
||||
</body>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* Copyright © 2023-2026 - Faiumoni e. V. *
|
||||
* Copyright © 2023-2024 - Faiumoni e. V. *
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
|
@ -9,21 +9,25 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { marauroa, Deserializer, RPObject } from "marauroa"
|
||||
import { stendhal } from "./stendhal";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
import { StendhalPerceptionListener } from "./PerceptionListener";
|
||||
import { PerceptionListener } from "./PerceptionListener";
|
||||
import { singletons } from "./SingletonRepo";
|
||||
|
||||
import { Paths } from "./data/Paths";
|
||||
|
||||
import { Color } from "./data/color/Color";
|
||||
|
||||
import { EntityRegistry } from "./entity/EntityRegistry";
|
||||
import { Ground } from "./entity/Ground";
|
||||
import { RPObject } from "./entity/RPObject";
|
||||
|
||||
import { ui } from "./ui/UI";
|
||||
import { UIComponentEnum } from "./ui/UIComponentEnum";
|
||||
|
||||
import { BuddyListComponent } from "./ui/component/BuddyListComponent";
|
||||
import { MiniMapComponent } from "./ui/component/MiniMapComponent";
|
||||
import { PlayerEquipmentComponent } from "./ui/component/PlayerEquipmentComponent";
|
||||
import { ZoneInfoComponent } from "./ui/component/ZoneInfoComponent";
|
||||
|
||||
import { ChooseCharacterDialog } from "./ui/dialog/ChooseCharacterDialog";
|
||||
|
|
@ -36,12 +40,6 @@ import { SingletonFloatingWindow } from "./ui/toolkit/SingletonFloatingWindow";
|
|||
import { Chat } from "./util/Chat";
|
||||
import { DialogHandler } from "./util/DialogHandler";
|
||||
import { Globals } from "./util/Globals";
|
||||
import { TileMap } from "data/TileMap";
|
||||
import { OutfitStore } from "data/OutfitStore";
|
||||
import { TileStore } from "data/TileStore";
|
||||
import { WeatherRenderer } from "util/WeatherRenderer";
|
||||
import { ViewPort } from "ui/ViewPort";
|
||||
import { htmlImageStore } from "data/HTMLImageStore";
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -64,7 +62,6 @@ export class Client {
|
|||
|
||||
/** Singleton instance. */
|
||||
private static instance: Client;
|
||||
public loaded = false;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -81,7 +78,7 @@ export class Client {
|
|||
* Hidden singleton constructor.
|
||||
*/
|
||||
private constructor() {
|
||||
// empty
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -94,18 +91,19 @@ export class Client {
|
|||
}
|
||||
this.initialized = true;
|
||||
|
||||
// add version & build info to DOM for retrieval by browser
|
||||
document.documentElement.setAttribute("data-build-version", stendhal.data.build.version);
|
||||
document.documentElement.setAttribute("data-build-build", stendhal.data.build.build);
|
||||
|
||||
stendhal.paths = singletons.getPaths();
|
||||
stendhal.config = singletons.getConfigManager();
|
||||
stendhal.session = singletons.getSessionManager();
|
||||
stendhal.actions = singletons.getSlashActionRepo();
|
||||
new EntityRegistry().init();
|
||||
|
||||
this.initData();
|
||||
this.initSound();
|
||||
this.initUI();
|
||||
|
||||
// add version & build info to DOM for retrieval by browser
|
||||
document.documentElement.setAttribute("data-build-version", stendhal.data.build?.version);
|
||||
document.documentElement.setAttribute("data-build-build", stendhal.data.build?.build);
|
||||
this.initZone();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -119,6 +117,9 @@ export class Client {
|
|||
stendhal.data.cstatus = singletons.getCStatus();
|
||||
stendhal.data.cstatus.init();
|
||||
stendhal.data.group = singletons.getGroupManager();
|
||||
stendhal.data.outfit = singletons.getOutfitStore();
|
||||
stendhal.data.sprites = singletons.getSpriteStore();
|
||||
stendhal.data.map = singletons.getMap();
|
||||
// online players
|
||||
stendhal.players = [];
|
||||
}
|
||||
|
|
@ -140,9 +141,22 @@ export class Client {
|
|||
private initUI() {
|
||||
stendhal.ui = stendhal.ui || {};
|
||||
stendhal.ui.equip = singletons.getInventory();
|
||||
stendhal.ui.html = singletons.getHTMLManager();
|
||||
stendhal.ui.touch = singletons.getTouchHandler();
|
||||
stendhal.ui.viewport = singletons.getViewPort();
|
||||
// alias for backward-compat until changed in all source
|
||||
stendhal.ui.gamewindow = stendhal.ui.viewport;
|
||||
|
||||
stendhal.ui.getMenuStyle = Globals.getMenuStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds initial zone for user to enter world.
|
||||
*/
|
||||
private initZone() {
|
||||
stendhal.zone = singletons.getZone();
|
||||
stendhal.zone.ground = new Ground();
|
||||
}
|
||||
|
||||
/**
|
||||
* Main startup routines.
|
||||
|
|
@ -163,11 +177,11 @@ export class Client {
|
|||
singletons.getEventRegistry().init();
|
||||
|
||||
// initialize tileset animation data
|
||||
TileStore.get().init();
|
||||
singletons.getTileStore().init();
|
||||
// initialize emoji data
|
||||
singletons.getEmojiStore().init();
|
||||
// initialize outfit data
|
||||
OutfitStore.get().init();
|
||||
stendhal.data.outfit.init();
|
||||
|
||||
new DesktopUserInterfaceFactory().create();
|
||||
|
||||
|
|
@ -190,11 +204,11 @@ export class Client {
|
|||
stendhal.ui.globalInternalWindow = new DialogHandler();
|
||||
|
||||
// pre-cache images & sounds
|
||||
htmlImageStore.startupCache();
|
||||
stendhal.data.sprites.startupCache();
|
||||
stendhal.sound.startupCache();
|
||||
|
||||
if (document.getElementById("viewport")) {
|
||||
ViewPort.get().draw();
|
||||
stendhal.ui.gamewindow.draw.apply(stendhal.ui.gamewindow, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -245,14 +259,11 @@ export class Client {
|
|||
* Registers Marauroa event handlers.
|
||||
*/
|
||||
registerMarauroaEventHandlers() {
|
||||
marauroa.clientFramework.onDisconnect = function(_reason: string, _code: number, _wasClean: boolean) {
|
||||
marauroa.clientFramework.onDisconnect = function(_reason: string, _error: string) {
|
||||
if (!Client.instance.unloading) {
|
||||
Chat.logH("error", "Disconnected from server.");
|
||||
if (window.location.hostname !== "localhost" && window.location.hostname !== "127.0.0.1" && window.location.hostname !== "::1") {
|
||||
window.location.href = "/account/mycharacters.html";
|
||||
}
|
||||
}
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
marauroa.clientFramework.onLoginRequired = function(config: Record<string, string>) {
|
||||
if (config["client_login_url"]) {
|
||||
|
|
@ -270,25 +281,25 @@ export class Client {
|
|||
"Login",
|
||||
new LoginDialog(),
|
||||
100, 50).enableCloseButton(false);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
marauroa.clientFramework.onCreateAccountAck = function(username: string) {
|
||||
// TODO: We should login automatically
|
||||
alert("Account succesfully created, please login.");
|
||||
window.location.reload();
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
marauroa.clientFramework.onCreateCharacterAck = function(charname: string, _template: any) {
|
||||
// Client.get().chooseCharacter(charname);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
marauroa.clientFramework.onLoginFailed = function(_reason: string, _text: string) {
|
||||
alert("Login failed. " + _text);
|
||||
// TODO: Server closes the connection, so we need to open a new one
|
||||
window.location.reload();
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
marauroa.clientFramework.onAvailableCharacterDetails = (characters: {[key: string]: RPObject}) => {
|
||||
marauroa.clientFramework.onAvailableCharacterDetails = function(characters: {[key: string]: RPObject}) {
|
||||
SingletonFloatingWindow.closeAll();
|
||||
if (!Object.keys(characters).length && this.username) {
|
||||
marauroa.clientFramework.createCharacter(this.username, {});
|
||||
|
|
@ -320,9 +331,9 @@ export class Client {
|
|||
}
|
||||
items[i]["ack"] = true;
|
||||
}
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
marauroa.clientFramework.onTransfer = (items: any) => {
|
||||
marauroa.clientFramework.onTransfer = function(items: any) {
|
||||
var data = {} as any;
|
||||
var zoneName = ""
|
||||
for (var i in items) {
|
||||
|
|
@ -334,13 +345,34 @@ export class Client {
|
|||
this.onDataMap(items[i]["data"]);
|
||||
}
|
||||
}
|
||||
TileMap.get().onTransfer(zoneName, data);
|
||||
stendhal.data.map.onTransfer(zoneName, data);
|
||||
};
|
||||
|
||||
// update user interface on perceptions
|
||||
if (document.getElementById("viewport")) {
|
||||
// override perception listener
|
||||
marauroa.perceptionListener = new StendhalPerceptionListener();
|
||||
marauroa.perceptionListener = new PerceptionListener(marauroa.perceptionListener);
|
||||
marauroa.perceptionListener.onPerceptionEnd = function(_type: Int8Array, _timestamp: number) {
|
||||
stendhal.zone.sortEntities();
|
||||
(ui.get(UIComponentEnum.MiniMap) as MiniMapComponent).draw();
|
||||
(ui.get(UIComponentEnum.BuddyList) as BuddyListComponent).update();
|
||||
stendhal.ui.equip.update();
|
||||
(ui.get(UIComponentEnum.PlayerEquipment) as PlayerEquipmentComponent).update();
|
||||
if (!this.loaded) {
|
||||
this.loaded = true;
|
||||
// delay visibile change of client a little to allow for initialisation in the background for a smoother experience
|
||||
window.setTimeout(function() {
|
||||
let body = document.getElementById("body")!;
|
||||
body.style.cursor = "auto";
|
||||
document.getElementById("client")!.style.display = "block";
|
||||
document.getElementById("loginpopup")!.style.display = "none";
|
||||
|
||||
// initialize observer after UI is ready
|
||||
singletons.getUIUpdateObserver().init();
|
||||
ui.onDisplayReady();
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -388,19 +420,18 @@ export class Client {
|
|||
|
||||
document.getElementById("body")!.addEventListener("mouseenter", stendhal.main.onMouseEnter);
|
||||
|
||||
let gamewindow = document.getElementById("viewport")!;
|
||||
let viewPort = ViewPort.get();
|
||||
var gamewindow = document.getElementById("viewport")!;
|
||||
gamewindow.setAttribute("draggable", "true");
|
||||
gamewindow.addEventListener("mousedown", viewPort.onMouseDown);
|
||||
gamewindow.addEventListener("dblclick", viewPort.onMouseDown);
|
||||
gamewindow.addEventListener("dragstart", viewPort.onDragStart);
|
||||
gamewindow.addEventListener("mousemove", viewPort.onMouseMove);
|
||||
gamewindow.addEventListener("touchstart", viewPort.onMouseDown, {passive: true});
|
||||
gamewindow.addEventListener("touchend", viewPort.onTouchEnd);
|
||||
gamewindow.addEventListener("dragover", viewPort.onDragOver);
|
||||
gamewindow.addEventListener("drop", viewPort.onDrop);
|
||||
gamewindow.addEventListener("contextmenu", viewPort.onContentMenu);
|
||||
gamewindow.addEventListener("wheel", viewPort.onMouseWheel, {passive: true});
|
||||
gamewindow.addEventListener("mousedown", stendhal.ui.gamewindow.onMouseDown);
|
||||
gamewindow.addEventListener("dblclick", stendhal.ui.gamewindow.onMouseDown);
|
||||
gamewindow.addEventListener("dragstart", stendhal.ui.gamewindow.onDragStart);
|
||||
gamewindow.addEventListener("mousemove", stendhal.ui.gamewindow.onMouseMove);
|
||||
gamewindow.addEventListener("touchstart", stendhal.ui.gamewindow.onMouseDown);
|
||||
gamewindow.addEventListener("touchend", stendhal.ui.gamewindow.onTouchEnd);
|
||||
gamewindow.addEventListener("dragover", stendhal.ui.gamewindow.onDragOver);
|
||||
gamewindow.addEventListener("drop", stendhal.ui.gamewindow.onDrop);
|
||||
gamewindow.addEventListener("contextmenu", stendhal.ui.gamewindow.onContentMenu);
|
||||
gamewindow.addEventListener("wheel", stendhal.ui.gamewindow.onMouseWheel);
|
||||
|
||||
singletons.getJoystickController().registerGlobalEventHandlers();
|
||||
|
||||
|
|
@ -428,7 +459,7 @@ export class Client {
|
|||
document.addEventListener("click", Client.handleClickIndicator);
|
||||
document.addEventListener("touchend", Client.handleClickIndicator);
|
||||
};
|
||||
click_indicator.src = Paths.gui + "/click_indicator.png";
|
||||
click_indicator.src = stendhal.paths.gui + "/click_indicator.png";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -438,10 +469,8 @@ export class Client {
|
|||
* Information about map.
|
||||
*/
|
||||
onDataMap(data: any) {
|
||||
let map = TileMap.get();
|
||||
let viewPort = ViewPort.get();
|
||||
var zoneinfo = {} as {[key: string]: string};
|
||||
var deserializer = Deserializer.fromBase64(data);
|
||||
var deserializer = marauroa.Deserializer.fromBase64(data);
|
||||
deserializer.readAttributes(zoneinfo);
|
||||
(ui.get(UIComponentEnum.ZoneInfo) as ZoneInfoComponent).zoneChange(zoneinfo);
|
||||
|
||||
|
|
@ -452,29 +481,29 @@ export class Client {
|
|||
|
||||
// parallax background
|
||||
if (stendhal.config.getBoolean("effect.parallax")) {
|
||||
map.setParallax(zoneinfo["parallax"]);
|
||||
map.setIgnoredTiles(zoneinfo["parallax_ignore_tiles"]);
|
||||
stendhal.data.map.setParallax(zoneinfo["parallax"]);
|
||||
stendhal.data.map.setIgnoredTiles(zoneinfo["parallax_ignore_tiles"]);
|
||||
}
|
||||
|
||||
// coloring information
|
||||
if (zoneinfo["color"] && stendhal.config.getBoolean("effect.lighting")) {
|
||||
if (zoneinfo["color_method"]) {
|
||||
viewPort.setColorMethod(zoneinfo["color_method"]);
|
||||
stendhal.ui.gamewindow.setColorMethod(zoneinfo["color_method"]);
|
||||
}
|
||||
if (zoneinfo["blend_method"]) {
|
||||
viewPort.setBlendMethod(zoneinfo["blend_method"]);
|
||||
stendhal.ui.gamewindow.setBlendMethod(zoneinfo["blend_method"]);
|
||||
}
|
||||
const hsl = Color.numToHSL(Number(zoneinfo["color"]));
|
||||
viewPort.HSLFilter = hsl.toString();
|
||||
stendhal.ui.gamewindow.HSLFilter = hsl.toString();
|
||||
// deprecated
|
||||
viewPort.filter = "hue-rotate(" + hsl.H + "deg) saturate(" + hsl.S
|
||||
stendhal.ui.gamewindow.filter = "hue-rotate(" + hsl.H + "deg) saturate(" + hsl.S
|
||||
+ ") brightness(" + hsl.L + ")";
|
||||
} else {
|
||||
viewPort.HSLFilter = undefined;
|
||||
viewPort.filter = undefined;
|
||||
stendhal.ui.gamewindow.HSLFilter = undefined;
|
||||
stendhal.ui.gamewindow.filter = undefined;
|
||||
}
|
||||
|
||||
WeatherRenderer.get().update(zoneinfo["weather"]);
|
||||
singletons.getWeatherRenderer().update(zoneinfo["weather"]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -489,7 +518,7 @@ export class Client {
|
|||
*/
|
||||
onMouseEnter(e: MouseEvent) {
|
||||
// use Stendhal's built-in cursor for entire page
|
||||
(e.target as HTMLElement).style.cursor = "url(" + Paths.sprites + "/cursor/normal.png) 1 3, auto";
|
||||
(e.target as HTMLElement).style.cursor = "url(" + stendhal.paths.sprites + "/cursor/normal.png) 1 3, auto";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
195
src/js/stendhal/EventRegistry.ts
Normal file
195
src/js/stendhal/EventRegistry.ts
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2003-2024 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
import { RPEntity } from "./entity/RPEntity";
|
||||
import { RPObject } from "./entity/RPObject";
|
||||
|
||||
import { BestiaryEvent } from "./event/BestiaryEvent";
|
||||
import { ChatOptionsEvent } from "./event/ChatOptionsEvent";
|
||||
import { ExamineEvent } from "./event/ExamineEvent";
|
||||
import { GroupChangeEvent } from "./event/GroupChangeEvent";
|
||||
import { GroupInviteEvent } from "./event/GroupInviteEvent";
|
||||
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 { Chat } from "./util/Chat";
|
||||
|
||||
|
||||
export class EventRegistry {
|
||||
|
||||
private initialized = false;
|
||||
|
||||
/** Singleton instance. */
|
||||
private static instance: EventRegistry;
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves singleton instance.
|
||||
*/
|
||||
static get(): EventRegistry {
|
||||
if (!EventRegistry.instance) {
|
||||
EventRegistry.instance = new EventRegistry();
|
||||
}
|
||||
return EventRegistry.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hidden singleton constructor.
|
||||
*/
|
||||
private constructor() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers standard events.
|
||||
*/
|
||||
init() {
|
||||
if (this.initialized) {
|
||||
console.warn("tried to re-initialize EventRegistry");
|
||||
return;
|
||||
}
|
||||
this.initialized = true;
|
||||
|
||||
this.register("chat_options", new ChatOptionsEvent());
|
||||
this.register("examine", new ExamineEvent());
|
||||
this.register("group_change_event", new GroupChangeEvent());
|
||||
this.register("group_invite_event", new GroupInviteEvent());
|
||||
this.register("progress_status_event", new ProgressStatusEvent());
|
||||
this.register("trade_state_change_event", new TradeEvent());
|
||||
|
||||
this.register("attack", {
|
||||
execute: function(entity: RPEntity) {
|
||||
var target = entity.getAttackTarget();
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
if (this.hasOwnProperty("hit")) {
|
||||
var damage = parseInt(this["damage"], 10);
|
||||
if (damage !== 0) {
|
||||
target.onDamaged(entity, damage);
|
||||
} else {
|
||||
target.onBlocked(entity);
|
||||
}
|
||||
} else {
|
||||
target.onMissed(entity);
|
||||
}
|
||||
entity.onAttackPerformed(parseInt(this["type"], 10), this.hasOwnProperty("ranged"), this["weapon"]);
|
||||
}
|
||||
}); // attack
|
||||
|
||||
this.register("bestiary", new BestiaryEvent());
|
||||
|
||||
this.register("global_visual_effect", {
|
||||
execute: function(rpobject: RPObject) {
|
||||
// TODO: new GlobalVisualEffectEvent();
|
||||
}
|
||||
}); // global_visual_effect
|
||||
|
||||
this.register("image_event", {
|
||||
execute: function(rpobject: RPObject) {
|
||||
// TODO: new ImageEffectEvent();
|
||||
console.log("image_event", this, rpobject);
|
||||
}
|
||||
}); // image_event
|
||||
|
||||
this.register("player_logged_on", new PlayerLoggedOnEvent());
|
||||
this.register("player_logged_out", new PlayerLoggedOutEvent());
|
||||
|
||||
this.register("private_text", {
|
||||
soundTextEvents: {
|
||||
"privmsg": true,
|
||||
"support": true,
|
||||
"tutorial": true
|
||||
},
|
||||
|
||||
execute: function(rpobject: RPObject) {
|
||||
const ttype = this["texttype"].toLowerCase();
|
||||
const msg = this["text"].replace(/\\r\\n/g, "\n").replace(/\\r/g, "\n");
|
||||
|
||||
let profile;
|
||||
if (this.hasOwnProperty("profile")) {
|
||||
profile = this["profile"];
|
||||
} else if (ttype === "tutorial") {
|
||||
profile = "floattingladynpc";
|
||||
}
|
||||
|
||||
if (ttype === "server" && msg.includes("\n")) {
|
||||
Chat.log(ttype, msg.split("\n"), undefined, profile);
|
||||
} else {
|
||||
// scene settings messages should not disturb playing, just create some atmosphere
|
||||
const headed = ttype !== "scene_setting";
|
||||
Chat.log(ttype, msg, undefined, profile, headed);
|
||||
}
|
||||
|
||||
// play notification sound
|
||||
const notif = stendhal.config.get("chat.private.sound");
|
||||
if (notif && this.soundTextEvents[ttype]) {
|
||||
stendhal.sound.playGlobalizedEffect(notif);
|
||||
}
|
||||
}
|
||||
}); // private_text
|
||||
|
||||
this.register("reached_achievement", {
|
||||
execute: function(rpobject: RPObject) {
|
||||
stendhal.ui.gamewindow.addAchievementNotif(this["category"], this["title"], this["description"]);
|
||||
}
|
||||
}); // reached_achievement
|
||||
|
||||
this.register("show_item_list", new ShowItemListEvent());
|
||||
this.register("show_outfit_list", new ShowOutfitListEvent());
|
||||
|
||||
this.register("sound_event", new SoundEvent());
|
||||
|
||||
this.register("text", {
|
||||
execute: function(entity: RPEntity) {
|
||||
if (this.hasOwnProperty("range")) {
|
||||
entity.say(this["text"], this["range"]);
|
||||
} else {
|
||||
entity.say(this["text"]);
|
||||
}
|
||||
}
|
||||
}); // text
|
||||
|
||||
this.register("transition_graph", {
|
||||
execute: function(rpobject: RPObject) {
|
||||
// TODO: new TransitionGraphEvent();
|
||||
}
|
||||
}); // transition_graph
|
||||
|
||||
this.register("view_change", new ViewChangeEvent());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new event.
|
||||
*
|
||||
* @param _type
|
||||
* String identifier.
|
||||
* @param _event
|
||||
* Event to be registered.
|
||||
*/
|
||||
register(_type: string, _event: any) {
|
||||
if (_event instanceof RPEvent) {
|
||||
marauroa.rpeventFactory[_type] = _event;
|
||||
} else {
|
||||
marauroa.rpeventFactory[_type] =
|
||||
marauroa.util.fromProto(marauroa.rpeventFactory["_default"], _event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,24 +9,29 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { ui } from "ui/UI";
|
||||
import { stendhal } from "./stendhal";
|
||||
declare var stendhal: any;
|
||||
|
||||
import { RPObject, PerceptionListener } from "marauroa";
|
||||
import { UIComponentEnum } from "ui/UIComponentEnum";
|
||||
import { MiniMapComponent } from "ui/component/MiniMapComponent";
|
||||
import { BuddyListComponent } from "ui/component/BuddyListComponent";
|
||||
import { PlayerEquipmentComponent } from "ui/component/PlayerEquipmentComponent";
|
||||
import { singletons } from "SingletonRepo";
|
||||
import { Client } from "Client";
|
||||
import { Zone } from "entity/Zone";
|
||||
import { RPObject } from "./entity/RPObject";
|
||||
|
||||
|
||||
/**
|
||||
* Class to override `marauroa.perceptionListener` & handle creating
|
||||
* User object.
|
||||
*/
|
||||
export class StendhalPerceptionListener extends PerceptionListener {
|
||||
export class PerceptionListener {
|
||||
[key: string]: any;
|
||||
private readonly _super: any;
|
||||
|
||||
|
||||
constructor(perceptionListener: any) {
|
||||
this._super = perceptionListener;
|
||||
for (const prop of Object.getOwnPropertyNames(perceptionListener)) {
|
||||
if (typeof(this[prop]) === "undefined") {
|
||||
// members & methods that are not overridden by this class
|
||||
this[prop] = perceptionListener[prop];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Action when an object is added to the world.
|
||||
|
|
@ -37,7 +42,7 @@ export class StendhalPerceptionListener extends PerceptionListener {
|
|||
* `true` if object was added.
|
||||
* @see marauroa.perceptionListener.onAdded
|
||||
*/
|
||||
override onAdded(obj: RPObject): boolean {
|
||||
onAdded(obj: RPObject): boolean {
|
||||
if (obj["c"] === "player") {
|
||||
if (obj.hasOwnProperty("a")) {
|
||||
if (obj["a"]["name"] === stendhal.session.getCharName()) {
|
||||
|
|
@ -46,28 +51,6 @@ export class StendhalPerceptionListener extends PerceptionListener {
|
|||
}
|
||||
}
|
||||
}
|
||||
return super.onAdded(obj);
|
||||
}
|
||||
|
||||
override onPerceptionEnd(_type: Int8Array, _timestamp: number) {
|
||||
Zone.get().sortEntities();
|
||||
(ui.get(UIComponentEnum.MiniMap) as MiniMapComponent).draw();
|
||||
(ui.get(UIComponentEnum.BuddyList) as BuddyListComponent).update();
|
||||
stendhal.ui.equip.update();
|
||||
(ui.get(UIComponentEnum.PlayerEquipment) as PlayerEquipmentComponent).update();
|
||||
if (!Client.get().loaded) {
|
||||
Client.get().loaded = true;
|
||||
// delay visibile change of client a little to allow for initialisation in the background for a smoother experience
|
||||
window.setTimeout(function() {
|
||||
let body = document.getElementById("body")!;
|
||||
body.style.cursor = "auto";
|
||||
document.getElementById("client")!.style.display = "block";
|
||||
document.getElementById("loginpopup")!.style.display = "none";
|
||||
|
||||
// initialize observer after UI is ready
|
||||
singletons.getUIUpdateObserver().init();
|
||||
ui.onDisplayReady();
|
||||
}, 300);
|
||||
}
|
||||
return this._super.onAdded(obj);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* Copyright © 2003-2026 - Faiumoni e. V. *
|
||||
* Copyright © 2003-2024 - Faiumoni e. V. *
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
|
@ -10,35 +10,45 @@
|
|||
***************************************************************************/
|
||||
|
||||
import { Client } from "./Client";
|
||||
import { EventRegistry } from "./event/EventRegistry";
|
||||
import { EventRegistry } from "./EventRegistry";
|
||||
import { SlashActionRepo } from "./SlashActionRepo";
|
||||
|
||||
import { Zone } from "./entity/Zone";
|
||||
|
||||
import { ConfigManager } from "./util/ConfigManager";
|
||||
import { DownloadUtil } from "./util/DownloadUtil";
|
||||
import { DrawingStage } from "./util/DrawingStage";
|
||||
import { FacingHandler } from "./util/FacingHandler";
|
||||
import { KeyHandler } from "./util/KeyHandler";
|
||||
import { SessionManager } from "./util/SessionManager";
|
||||
import { WeatherRenderer } from "./util/WeatherRenderer";
|
||||
|
||||
import { CacheManager } from "./data/CacheManager";
|
||||
import { CStatus } from "./data/CStatus";
|
||||
import { CacheManager } from "./data/CacheManager";
|
||||
import { EmojiStore } from "./data/EmojiStore";
|
||||
import { GroupManager } from "./data/GroupManager";
|
||||
import { Map } from "./data/Map";
|
||||
import { OutfitStore } from "./data/OutfitStore";
|
||||
import { Paths } from "./data/Paths";
|
||||
import { SpriteStore, store } from "./data/SpriteStore";
|
||||
import { TileStore } from "./data/TileStore";
|
||||
|
||||
import { LoopedSoundSourceManager } from "./data/sound/LoopedSoundSourceManager";
|
||||
import { SoundManager } from "./data/sound/SoundManager";
|
||||
|
||||
import { Inventory } from "./ui/Inventory";
|
||||
import { SoftwareJoystickController } from "./ui/SoftwareJoystickController";
|
||||
import { ui } from "./ui/UI";
|
||||
import { UIComponentEnum } from "./ui/UIComponentEnum";
|
||||
import { HeldObjectManager } from "./ui/HeldObject";
|
||||
import { HTMLManager } from "./ui/HTMLManager";
|
||||
import { Inventory } from "./ui/Inventory";
|
||||
import { SoftwareJoystickController } from "./ui/SoftwareJoystickController";
|
||||
import { TouchHandler } from "./ui/TouchHandler";
|
||||
import { UIUpdateObserver } from "./ui/UIUpdateObserver";
|
||||
import { ViewPort } from "./ui/ViewPort";
|
||||
|
||||
import { ChatInputComponent } from "./ui/component/ChatInputComponent";
|
||||
|
||||
/**
|
||||
* @Deprecated use Class.get() directly to prevent dependency chain
|
||||
*/
|
||||
|
||||
export class SingletonRepo {
|
||||
|
||||
static getCStatus(): CStatus {
|
||||
|
|
@ -65,6 +75,10 @@ export class SingletonRepo {
|
|||
return DownloadUtil;
|
||||
}
|
||||
|
||||
static getDrawingStage(): DrawingStage {
|
||||
return DrawingStage.get();
|
||||
}
|
||||
|
||||
static getEmojiStore(): EmojiStore {
|
||||
return EmojiStore.get();
|
||||
}
|
||||
|
|
@ -81,6 +95,14 @@ export class SingletonRepo {
|
|||
return GroupManager.get();
|
||||
}
|
||||
|
||||
static getHeldObjectManager(): HeldObjectManager {
|
||||
return HeldObjectManager.get();
|
||||
}
|
||||
|
||||
static getHTMLManager(): HTMLManager {
|
||||
return HTMLManager.get();
|
||||
}
|
||||
|
||||
static getInventory(): Inventory {
|
||||
return Inventory.get();
|
||||
}
|
||||
|
|
@ -97,6 +119,14 @@ export class SingletonRepo {
|
|||
return LoopedSoundSourceManager.get();
|
||||
}
|
||||
|
||||
static getMap(): Map {
|
||||
return Map.get();
|
||||
}
|
||||
|
||||
static getOutfitStore(): OutfitStore {
|
||||
return OutfitStore.get();
|
||||
}
|
||||
|
||||
static getPaths(): typeof Paths {
|
||||
return Paths;
|
||||
}
|
||||
|
|
@ -113,10 +143,33 @@ export class SingletonRepo {
|
|||
return SoundManager.get();
|
||||
}
|
||||
|
||||
static getSpriteStore(): SpriteStore {
|
||||
return store;
|
||||
}
|
||||
|
||||
static getTileStore(): TileStore {
|
||||
return TileStore.get();
|
||||
}
|
||||
|
||||
static getTouchHandler(): TouchHandler {
|
||||
return TouchHandler.get();
|
||||
}
|
||||
|
||||
static getUIUpdateObserver(): UIUpdateObserver {
|
||||
return UIUpdateObserver.get();
|
||||
}
|
||||
|
||||
static getViewPort(): ViewPort {
|
||||
return ViewPort.get();
|
||||
}
|
||||
|
||||
static getWeatherRenderer(): WeatherRenderer {
|
||||
return WeatherRenderer.get();
|
||||
}
|
||||
|
||||
static getZone(): Zone {
|
||||
return Zone.get();
|
||||
}
|
||||
}
|
||||
|
||||
export const singletons = SingletonRepo;
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
import { stendhal } from "./stendhal";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
import { singletons } from "./SingletonRepo";
|
||||
|
||||
|
|
@ -766,7 +766,7 @@ export class SlashActionRepo {
|
|||
execute: (type: string, params: string[], remainder: string): boolean => {
|
||||
const newMode = !stendhal.config.getBoolean("input.doubleclick");
|
||||
stendhal.config.set("input.doubleclick", newMode);
|
||||
ViewPort.get().updateClickMode();
|
||||
stendhal.ui.gamewindow.updateClickMode();
|
||||
|
||||
if (newMode) {
|
||||
Chat.log("info", "Click mode is now set to double click.");
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
declare var stendhal: any;
|
||||
|
||||
import { ParamList } from "./ParamList";
|
||||
import { SlashAction } from "./SlashAction";
|
||||
|
|
@ -19,7 +20,6 @@ import { ui } from "../ui/UI";
|
|||
import { AboutDialog } from "../ui/dialog/AboutDialog";
|
||||
|
||||
import { Pair } from "../util/Pair";
|
||||
import { stendhal } from "../stendhal";
|
||||
|
||||
|
||||
export class AboutAction extends SlashAction {
|
||||
|
|
@ -28,7 +28,7 @@ export class AboutAction extends SlashAction {
|
|||
|
||||
execute(_type: string, _params: string[], _remainder: string): boolean {
|
||||
const wstate = stendhal.config.getWindowState("about");
|
||||
const offset = ui.getPageOffset();
|
||||
const offset = stendhal.ui.getPageOffset();
|
||||
|
||||
const content = new AboutDialog();
|
||||
const dialog = ui.createSingletonFloatingWindow(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2022-2026 - Stendhal *
|
||||
* (C) Copyright 2022-2024 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
|
@ -9,20 +9,21 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { singletons } from "../SingletonRepo";
|
||||
|
||||
import { ui } from "../ui/UI";
|
||||
import { UIComponentEnum } from "../ui/UIComponentEnum";
|
||||
import { FloatingWindow } from "../ui/toolkit/FloatingWindow";
|
||||
|
||||
import { Panel } from "ui/toolkit/Panel";
|
||||
import { ShowFloatingWindowComponent } from "../ui/component/ShowFloatingWindowComponent";
|
||||
import { SlashAction } from "./SlashAction";
|
||||
import { ShowFloatingWindowComponent } from "../ui/component/ShowFloatingWindowComponent";
|
||||
import { Panel } from "ui/toolkit/Panel";
|
||||
|
||||
import { Chat } from "../util/Chat";
|
||||
import { Debug } from "../util/Debug";
|
||||
|
||||
import { marauroa } from "marauroa";
|
||||
import { WeatherRenderer } from "util/WeatherRenderer";
|
||||
import { stendhal } from "../stendhal";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
/**
|
||||
* performances debugging actions
|
||||
|
|
@ -54,8 +55,6 @@ export class DebugAction extends SlashAction {
|
|||
Debug.setActive("screencap", !Debug.isActive("screencap"));
|
||||
Chat.log("client", "Screen capture debugging " + (Debug.isActive("screencap") ? "enabled"
|
||||
: "disabled"));
|
||||
} else if(params[0] === "light") {
|
||||
Debug.toggle("light");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -67,8 +66,7 @@ export class DebugAction extends SlashAction {
|
|||
" /debug ui [pop]",
|
||||
" /debug weather [<name>]",
|
||||
" /debug settings",
|
||||
" /debug touch",
|
||||
" /debug light"
|
||||
" /debug touch"
|
||||
];
|
||||
Chat.log("client", usage);
|
||||
}
|
||||
|
|
@ -137,9 +135,14 @@ export class DebugAction extends SlashAction {
|
|||
|
||||
if (weather) {
|
||||
weather = weather.replace(/ /g, "_");
|
||||
WeatherRenderer.get().update(weather);
|
||||
const wfilename = stendhal.paths.weather + "/" + weather + ".png";
|
||||
if (!stendhal.data.sprites.getCached(wfilename)) {
|
||||
Chat.logH("error", "unknown weather: " + wfilename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
singletons.getWeatherRenderer().update(weather);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@ import { SlashAction } from "./SlashAction";
|
|||
|
||||
import { ScreenCapture } from "../util/ScreenCapture";
|
||||
|
||||
import { stendhal } from "../stendhal";
|
||||
import { ViewPort } from "ui/ViewPort";
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
export class ScreenCaptureAction extends SlashAction {
|
||||
|
|
@ -36,7 +35,7 @@ export class ScreenCaptureAction extends SlashAction {
|
|||
return true;
|
||||
}
|
||||
this.recorder = new ScreenCapture();
|
||||
this.recorder.start(ViewPort.get().getElement());
|
||||
this.recorder.start(stendhal.ui.viewport.getElement() as HTMLCanvasElement);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { stendhal } from "../stendhal";
|
||||
declare var stendhal: any;
|
||||
|
||||
import { SlashAction } from "./SlashAction";
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ export class SettingsAction extends SlashAction {
|
|||
|
||||
execute(_type: string, _params: string[], _remainder: string): boolean {
|
||||
const wstate = stendhal.config.getWindowState("menu");
|
||||
const offset = ui.getPageOffset();
|
||||
const offset = stendhal.ui.getPageOffset();
|
||||
|
||||
const content = new SettingsDialog();
|
||||
const dialog = ui.createSingletonFloatingWindow(
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
declare var marauroa: any;
|
||||
|
||||
import { ParamList } from "./ParamList";
|
||||
import { Pair } from "../util/Pair";
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
import { stendhal } from "../stendhal";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
export class CStatus {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { stendhal } from "../stendhal";
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* Copyright © 2003-2026 - Stendhal *
|
||||
* Copyright © 2003-2023 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
|
@ -9,9 +9,10 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { JSONLoader } from "../util/JSONLoader";
|
||||
import { htmlImageStore } from "./HTMLImageStore";
|
||||
import { Paths } from "./Paths";
|
||||
import { JSONLoader } from "../util/JSONLoader";
|
||||
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
export class EmojiStore {
|
||||
|
|
@ -70,7 +71,7 @@ export class EmojiStore {
|
|||
if (!filename) {
|
||||
return;
|
||||
}
|
||||
return htmlImageStore.get(filename);
|
||||
return stendhal.data.sprites.get(filename);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { stendhal } from "../stendhal";
|
||||
declare var stendhal: any;
|
||||
|
||||
import { Entity } from "../entity/Entity";
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { stendhal } from "../stendhal";
|
||||
declare var stendhal: any;
|
||||
|
||||
import { SlashActionRepo } from "../SlashActionRepo";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,290 +0,0 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2003-2026 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* 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 { Paths } from "./Paths";
|
||||
import { ImageFilter } from "../sprite/image/ImageFilter";
|
||||
|
||||
export class HTMLImageStore {
|
||||
|
||||
private knownBrokenUrls: {[url: string]: boolean} = {};
|
||||
private images: {[filename: string]: CanvasImageSource} = {};
|
||||
|
||||
private knownShadows: {[key: string]: boolean} = {
|
||||
"24x32": true,
|
||||
"32x32": true,
|
||||
"32x48": true,
|
||||
"32x48_long": true,
|
||||
"48x64": true,
|
||||
"48x64_float": true,
|
||||
"64x48": true,
|
||||
"64x64": true,
|
||||
"64x85": true,
|
||||
"64x96": true,
|
||||
"76x64": true,
|
||||
"81x96": true,
|
||||
"96x96": true,
|
||||
"96x128": true,
|
||||
"128x96": true,
|
||||
"128x170": true,
|
||||
"144x128": true,
|
||||
"168x224": true,
|
||||
"192x192": true,
|
||||
"192x192_float": true,
|
||||
"192x256": true,
|
||||
"320x440": true,
|
||||
"ent": true
|
||||
};
|
||||
|
||||
// alternatives for known images that may be considered violent or mature
|
||||
private knownSafeSprites: {[filename: string]: boolean} = {
|
||||
[Paths.sprites + "/monsters/huge_animal/thing"]: true,
|
||||
[Paths.sprites + "/monsters/mutant/imperial_mutant"]: true,
|
||||
[Paths.sprites + "/monsters/undead/bloody_zombie"]: true,
|
||||
[Paths.sprites + "/npc/deadmannpc"]: true
|
||||
};
|
||||
|
||||
// TODO: move to animation.json
|
||||
animations: {[key: string]: any} = {
|
||||
idea: {
|
||||
"love": {delay: 100, offsetX: 24, offsetY: -8}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
get(filename: string): any {
|
||||
if (!filename) {
|
||||
return {};
|
||||
}
|
||||
if (filename.indexOf("undefined") > -1) {
|
||||
if (!this.knownBrokenUrls[filename]) {
|
||||
console.log("Broken image path: ", filename, new Error());
|
||||
}
|
||||
this.knownBrokenUrls[filename] = true;
|
||||
return {};
|
||||
}
|
||||
if (this.images[filename]) {
|
||||
return this.images[filename];
|
||||
}
|
||||
var temp = new Image();
|
||||
temp.onerror = (function(t: HTMLImageElement, store: HTMLImageStore) {
|
||||
return function() {
|
||||
if (t.src && !store.knownBrokenUrls[t.src]) {
|
||||
console.log("Broken image path:", t.src, new Error());
|
||||
store.knownBrokenUrls[t.src] = true;
|
||||
}
|
||||
const failsafe = store.getFailsafe();
|
||||
if (failsafe.src && t.src !== failsafe.src) {
|
||||
t.src = failsafe.src;
|
||||
}
|
||||
};
|
||||
})(temp, this);
|
||||
temp.src = filename;
|
||||
this.images[filename] = temp;
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates an image.
|
||||
*
|
||||
* @param img
|
||||
* Image to be rotated.
|
||||
* @param angle
|
||||
* Angle of rotation.
|
||||
*/
|
||||
private rotate(img: HTMLImageElement, angle: number) {
|
||||
const canvas = document.getElementById("drawing-stage")! as HTMLCanvasElement;
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
// make sure working with blank canvas
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
|
||||
ctx.translate(canvas.width / 2, canvas.height / 2);
|
||||
ctx.rotate(angle * Math.PI / 180);
|
||||
ctx.translate(-canvas.width / 2, -canvas.height / 2);
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
img.src = canvas.toDataURL("image/png");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a rotated image.
|
||||
*
|
||||
* @param filename
|
||||
* Path to target image file.
|
||||
* @param angle
|
||||
* Angle of rotation.
|
||||
* @return
|
||||
* HTMLImageElement.
|
||||
*/
|
||||
getRotated(filename: string, angle: number): any {
|
||||
if (angle == 0) {
|
||||
return this.get(filename);
|
||||
}
|
||||
const id = filename + "-rot" + angle;
|
||||
if (this.images[id]) {
|
||||
return this.get(id);
|
||||
}
|
||||
// NOTE: cannot use HTMLImageElement.cloneNode here, must get base image then transfer
|
||||
// `src` property when ready
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
img.onload = null;
|
||||
this.rotate(img, angle);
|
||||
}
|
||||
const baseImg = this.get(filename);
|
||||
if (baseImg.complete) {
|
||||
img.src = baseImg.src;
|
||||
} else {
|
||||
baseImg.onload = () => {
|
||||
baseImg.onload = null;
|
||||
img.src = baseImg.src;
|
||||
}
|
||||
}
|
||||
this.images[id] = img;
|
||||
return img;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an image to cache.
|
||||
*
|
||||
* @param {string} id
|
||||
* Cache identifier.
|
||||
* @param {SpriteImage}
|
||||
* Image to be cached.
|
||||
*/
|
||||
cache(id: string, image: CanvasImageSource) {
|
||||
this.images[id] = image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when we only want an image if it was previously cached.
|
||||
*
|
||||
* @param filename
|
||||
* Full file path.
|
||||
* @return
|
||||
* HTMLImageElement or undefined.
|
||||
*/
|
||||
getCached(filename: string): any {
|
||||
return this.images[filename];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the failsafe sprite.
|
||||
*
|
||||
* @return
|
||||
* HTMLImageElement with failsafe image data.
|
||||
*/
|
||||
getFailsafe(): HTMLImageElement {
|
||||
const filename = Paths.sprites + "/failsafe.png";
|
||||
let failsafe = this.images[filename];
|
||||
if (failsafe) {
|
||||
} else {
|
||||
failsafe = new Image();
|
||||
failsafe.src = filename;
|
||||
this.images[filename] = failsafe;
|
||||
}
|
||||
return failsafe as HTMLImageElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks cached images for a valid filename.
|
||||
*
|
||||
* @param filename
|
||||
* Image filename to be checked.
|
||||
* @return
|
||||
* Path to image or failsafe image file.
|
||||
*/
|
||||
checkPath(filename: string): string {
|
||||
return this.get(filename).src;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} fileName
|
||||
* @param {string} filter
|
||||
* @param {number=} param
|
||||
*/
|
||||
getFiltered(fileName: string, filter: string, param?: number) {
|
||||
const img = this.get(fileName);
|
||||
if (!img.complete || img.width === 0 || img.height === 0) {
|
||||
return img;
|
||||
}
|
||||
const filteredName = fileName + " " + filter + " " + param;
|
||||
let filtered = this.images[filteredName];
|
||||
if (typeof(filtered) === "undefined") {
|
||||
const canvas = document.createElement("canvas") as any;
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
ctx.drawImage(img, 0, 0);
|
||||
const imgData = ctx.getImageData(0, 0, img.width, img.height);
|
||||
new ImageFilter().filter(imgData, filter, param);
|
||||
ctx.putImageData(imgData, 0, 0);
|
||||
canvas.complete = true;
|
||||
this.images[filteredName] = filtered = canvas;
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves a shadow sprite if the style is available.
|
||||
*
|
||||
* @param shadowStyle
|
||||
* Style of shadow to get from cache.
|
||||
* @return
|
||||
* Image sprite or <code>undefined</code>.
|
||||
*/
|
||||
getShadow(shadowStyle: string): any {
|
||||
if (this.knownShadows[shadowStyle]) {
|
||||
const img = new Image();
|
||||
img.src = Paths.sprites + "/shadow/" + shadowStyle + ".png";
|
||||
return img;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is a "safe" image available for sprite.
|
||||
*
|
||||
* @param filename
|
||||
* The sprite image base file path.
|
||||
* @return
|
||||
* <code>true</code> if a known safe image is available.
|
||||
*/
|
||||
hasSafeImage(filename: string): boolean {
|
||||
return this.knownSafeSprites[filename] == true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called at startup to pre-cache certain images.
|
||||
*/
|
||||
startupCache() {
|
||||
// failsafe image
|
||||
this.getFailsafe();
|
||||
// tutorial profile
|
||||
this.get(Paths.sprites + "/npc/floattingladynpc.png");
|
||||
// achievement assets
|
||||
this.get(Paths.gui + "/banner_background.png");
|
||||
for (const cat of ["commerce", "deathmatch", "experience", "fighting", "friend",
|
||||
"interior_zone", "item", "obtain", "outside_zone", "production", "quest",
|
||||
"quest_ados_items", "quest_kill_blordroughs", "quest_kirdneh_item",
|
||||
"quest_mithrilbourgh_enemy_army", "quest_semos_monster", "special",
|
||||
"underground_zone"]) {
|
||||
this.get(Paths.achievements + "/" + cat + ".png");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SpriteStore singleton instance
|
||||
export const htmlImageStore = /* @__PURE__ */ new HTMLImageStore();
|
||||
174
src/js/stendhal/data/ImagePreloader.ts
Normal file
174
src/js/stendhal/data/ImagePreloader.ts
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2003-2023 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
/*
|
||||
* Start: http://www.webreference.com/programming/javascript/gr/column3/
|
||||
* ( https://web.archive.org/web/20110910064905/http://www.webreference.com:80/programming/javascript/gr/column3/index.html )
|
||||
*
|
||||
function ImagePreloader(images, callback) {
|
||||
// store the call-back
|
||||
this.callback = callback;
|
||||
|
||||
// initialize internal state.
|
||||
this.nLoaded = 0;
|
||||
this.nProcessed = 0;
|
||||
stendhal.data.map.aImages = new Array;
|
||||
|
||||
// record the number of images.
|
||||
this.nImages = images.length;
|
||||
|
||||
// for each image, call preload()
|
||||
for ( var i = 0; i < images.length; i++) {
|
||||
this.preload(images[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ImagePreloader.prototype.preload = function(image) {
|
||||
// create new Image object and add to array
|
||||
var oImage = new Image;
|
||||
stendhal.data.map.aImages.push(oImage);
|
||||
|
||||
// set up event handlers for the Image object
|
||||
oImage.onload = ImagePreloader.prototype.onload;
|
||||
oImage.onerror = ImagePreloader.prototype.onerror;
|
||||
oImage.onabort = ImagePreloader.prototype.onabort;
|
||||
|
||||
// assign pointer back to this.
|
||||
oImage.oImagePreloader = this;
|
||||
oImage.bLoaded = false;
|
||||
|
||||
// assign the .src property of the Image object
|
||||
oImage.src = image;
|
||||
};
|
||||
|
||||
ImagePreloader.prototype.onComplete = function() {
|
||||
this.nProcessed++;
|
||||
if (this.nProcessed == this.nImages) {
|
||||
this.callback();
|
||||
}
|
||||
};
|
||||
|
||||
ImagePreloader.prototype.onload = function() {
|
||||
this.bLoaded = true;
|
||||
this.oImagePreloader.nLoaded++;
|
||||
this.oImagePreloader.onComplete();
|
||||
};
|
||||
|
||||
ImagePreloader.prototype.onerror = function() {
|
||||
this.bError = true;
|
||||
this.oImagePreloader.onComplete();
|
||||
console.error("Error loading " + this.src);
|
||||
};
|
||||
|
||||
ImagePreloader.prototype.onabort = function() {
|
||||
this.bAbort = true;
|
||||
this.oImagePreloader.onComplete();
|
||||
console.error("Loading " + this.src + " was aborted");
|
||||
};
|
||||
*
|
||||
* End: http://www.webreference.com/programming/javascript/gr/column3/
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* preloads images
|
||||
*
|
||||
* @param images image url to load
|
||||
* @param callback callback to invoke
|
||||
* @constructor
|
||||
*/
|
||||
export class ImagePreloader extends Function {
|
||||
|
||||
oImagePreloader: ImagePreloader;
|
||||
src?: string;
|
||||
callback: Function;
|
||||
|
||||
// internal state
|
||||
bLoaded: boolean;
|
||||
bError: boolean;
|
||||
bAbort: boolean;
|
||||
nLoaded: number;
|
||||
nProcessed: number;
|
||||
|
||||
// number of images
|
||||
nImages: number;
|
||||
|
||||
|
||||
constructor(images: string[], callback: Function) {
|
||||
super();
|
||||
|
||||
this.oImagePreloader = {} as ImagePreloader;
|
||||
// store the call-back
|
||||
this.callback = callback;
|
||||
|
||||
// initialize internal state.
|
||||
this.bLoaded = false;
|
||||
this.bError = false;
|
||||
this.bAbort = false;
|
||||
this.nLoaded = 0;
|
||||
this.nProcessed = 0;
|
||||
stendhal.data.map.aImages = new Array();
|
||||
|
||||
// record the number of images.
|
||||
this.nImages = images.length;
|
||||
|
||||
// for each image, call preload()
|
||||
for (let i = 0; i < images.length; i++) {
|
||||
this.preload(images[i]);
|
||||
}
|
||||
}
|
||||
|
||||
preload(image: string) {
|
||||
// create new Image object and add to array
|
||||
const oImage = new Image() as any;
|
||||
stendhal.data.map.aImages.push(oImage);
|
||||
|
||||
// set up event handlers for the Image object
|
||||
oImage.onload = ImagePreloader.prototype.onload;
|
||||
oImage.onerror = ImagePreloader.prototype.onerror;
|
||||
oImage.onabort = ImagePreloader.prototype.onabort;
|
||||
|
||||
// assign pointer back to this
|
||||
oImage.oImagePreloader = this;
|
||||
oImage.bLoaded = false;
|
||||
|
||||
// assign the .src property of the Image object
|
||||
oImage.src = image;
|
||||
}
|
||||
|
||||
onComplete() {
|
||||
this.nProcessed++;
|
||||
if (this.nProcessed == this.nImages) {
|
||||
this.callback();
|
||||
}
|
||||
}
|
||||
|
||||
onload() {
|
||||
this.bLoaded = true;
|
||||
this.oImagePreloader.nLoaded++;
|
||||
this.oImagePreloader.onComplete();
|
||||
}
|
||||
|
||||
onerror() {
|
||||
this.bError = true;
|
||||
this.oImagePreloader.onComplete();
|
||||
console.error("Error loading " + this.src);
|
||||
}
|
||||
|
||||
onabort() {
|
||||
this.bAbort = true;
|
||||
this.oImagePreloader.onComplete();
|
||||
console.error("Loading " + this.src + " was aborted");
|
||||
}
|
||||
}
|
||||
|
|
@ -9,56 +9,54 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { Deserializer } from "marauroa"
|
||||
import { stendhal } from "../stendhal";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
import { Paths } from "./Paths";
|
||||
|
||||
import { LandscapeRenderingStrategy } from "../landscape/LandscapeRenderingStrategy";
|
||||
import { CombinedTilesetRenderingStrategy } from "../landscape/CombinedTilesetRenderingStrategy";
|
||||
import { LandscapeRenderingStrategy, CombinedTilesetRenderingStrategy } from "../landscape/LandscapeRenderingStrategy";
|
||||
import { IndividualTilesetRenderingStrategy } from "../landscape/IndividualTilesetRenderingStrategy";
|
||||
import { ParallaxBackground } from "../landscape/ParallaxBackground";
|
||||
|
||||
|
||||
export class TileMap {
|
||||
export class Map {
|
||||
|
||||
public currentZoneName = "";
|
||||
private currentZoneName = "";
|
||||
|
||||
public offsetX = 0;
|
||||
public offsetY = 0;
|
||||
public zoneSizeX = -1;
|
||||
public zoneSizeY = -1;
|
||||
public sizeX = 20;
|
||||
public sizeY = 15;
|
||||
private offsetX = 0;
|
||||
private offsetY = 0;
|
||||
private zoneSizeX = -1;
|
||||
private zoneSizeY = -1;
|
||||
private sizeX = 20;
|
||||
private sizeY = 15;
|
||||
|
||||
public tileWidth = 32;
|
||||
public tileHeight = 32;
|
||||
public zoom = 100;
|
||||
private tileWidth = 32;
|
||||
private tileHeight = 32;
|
||||
private zoom = 100;
|
||||
|
||||
public tilesetFilenames: string[] = [];
|
||||
public aImages = -1;
|
||||
public layerNames: any = -1;
|
||||
public layers: any = -1;
|
||||
public firstgids: any = -1;
|
||||
public gidsindex: any = [];
|
||||
private tilesetFilenames: string[] = [];
|
||||
private aImages = -1;
|
||||
private layerNames: any = -1;
|
||||
private layers: any = -1;
|
||||
private firstgids: any = -1;
|
||||
private gidsindex: any = [];
|
||||
|
||||
public drawingError = false;
|
||||
public targetTileWidth = 0;
|
||||
public targetTileHeight = 0;
|
||||
private drawingError = false;
|
||||
private targetTileWidth = 0;
|
||||
private targetTileHeight = 0;
|
||||
|
||||
public readonly layerGroups = [
|
||||
private readonly layerGroups: any = [
|
||||
["0_floor", "1_terrain", "2_object"],
|
||||
["3_roof", "4_roof_add"]
|
||||
];
|
||||
public readonly blendLayers = ["blend_ground", "blend_roof"]
|
||||
public layerGroupIndexes: any;
|
||||
private layerGroupIndexes: any;
|
||||
|
||||
public strategy: LandscapeRenderingStrategy;
|
||||
public protection: any;
|
||||
public collisionData: any;
|
||||
private strategy: LandscapeRenderingStrategy;
|
||||
private protection: any;
|
||||
private collisionData: any;
|
||||
|
||||
// alternatives for known images that may be considered violent or mature
|
||||
public knownSafeTilesets: string[] = [
|
||||
private knownSafeTilesets: string[] = [
|
||||
Paths.tileset + "/item/armor/bloodied_small_axe",
|
||||
Paths.tileset + "/item/blood/floor_stain",
|
||||
Paths.tileset + "/item/blood/floor_stains_2",
|
||||
|
|
@ -66,22 +64,22 @@ export class TileMap {
|
|||
Paths.tileset + "/item/blood/small_stains"
|
||||
];
|
||||
|
||||
public parallax: ParallaxBackground;
|
||||
public parallaxImage?: string;
|
||||
public ignoredTiles: string[];
|
||||
private parallax: ParallaxBackground;
|
||||
private parallaxImage?: string;
|
||||
private ignoredTiles: string[];
|
||||
|
||||
/** Singleton instance. */
|
||||
private static instance: TileMap;
|
||||
private static instance: Map;
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves singleton instance.
|
||||
*/
|
||||
static get(): TileMap {
|
||||
if (!TileMap.instance) {
|
||||
TileMap.instance = new TileMap();
|
||||
static get(): Map {
|
||||
if (!Map.instance) {
|
||||
Map.instance = new Map();
|
||||
}
|
||||
return TileMap.instance;
|
||||
return Map.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -126,8 +124,6 @@ export class TileMap {
|
|||
this.decodeMapLayer(content, "2_object");
|
||||
this.decodeMapLayer(content, "3_roof");
|
||||
this.decodeMapLayer(content, "4_roof_add");
|
||||
this.decodeMapLayer(content, "blend_ground");
|
||||
this.decodeMapLayer(content, "blend_roof");
|
||||
this.protection = this.decodeMapLayer(content, "protection");
|
||||
this.collisionData = this.decodeMapLayer(content, "collision");
|
||||
this.layerGroupIndexes = this.mapLayerGroup();
|
||||
|
|
@ -142,7 +138,7 @@ export class TileMap {
|
|||
|
||||
decodeTileset(content: any, name: string) {
|
||||
var layerData = content[name];
|
||||
var deserializer = Deserializer.fromBase64(layerData);
|
||||
var deserializer = marauroa.Deserializer.fromBase64(layerData);
|
||||
var amount = deserializer.readInt() as number;
|
||||
|
||||
this.tilesetFilenames = [];
|
||||
|
|
@ -196,7 +192,7 @@ export class TileMap {
|
|||
if (!layerData) {
|
||||
return;
|
||||
}
|
||||
var deserializer = Deserializer.fromDeflatedBase64(layerData);
|
||||
var deserializer = marauroa.Deserializer.fromDeflatedBase64(layerData);
|
||||
deserializer.readString(); // zone name
|
||||
this.zoneSizeX = deserializer.readInt();
|
||||
this.zoneSizeY = deserializer.readInt();
|
||||
|
|
@ -10,14 +10,11 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { DrawingStage } from "../util/DrawingStage";
|
||||
import { Pair } from "../util/Pair";
|
||||
import { StringUtil } from "../util/StringUtil";
|
||||
import { Paths } from "./Paths";
|
||||
|
||||
import { stendhal } from "../stendhal";
|
||||
import { ImageMetadata } from "sprite/image/ImageMetadata";
|
||||
import { MultilayerImageLoader } from "sprite/image/MultilayerImageLoader";
|
||||
import { OutfitStore } from "./OutfitStore";
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -116,7 +113,7 @@ export class Outfit {
|
|||
public getLayers(): Pair<string, number>[] {
|
||||
const layers: Pair<string, number>[] = [];
|
||||
// only include valid layers
|
||||
for (const name of OutfitStore.get().getLayerNames()) {
|
||||
for (const name of stendhal.data.outfit.getLayerNames()) {
|
||||
let index = this.layers[name];
|
||||
if (index != undefined) {
|
||||
layers.push(new Pair(name, index));
|
||||
|
|
@ -154,7 +151,7 @@ export class Outfit {
|
|||
* Color value or `undefined`.
|
||||
*/
|
||||
public getLayerColor(name: string): number|undefined {
|
||||
if (OutfitStore.get().isSkinLayer(name)) {
|
||||
if (stendhal.data.outfit.isSkinLayer(name)) {
|
||||
name = "skin";
|
||||
}
|
||||
return this.coloring && name in this.coloring ? this.coloring[name] : undefined;
|
||||
|
|
@ -196,14 +193,40 @@ export class Outfit {
|
|||
*
|
||||
* TODO:
|
||||
* - use dress layer based on body type
|
||||
*
|
||||
* @param {Function} callback
|
||||
* Function to pass image to when ready.
|
||||
*/
|
||||
async toImage(): Promise<ImageBitmap> {
|
||||
let parts: ImageMetadata[] = [];
|
||||
toImage(callback: Function) {
|
||||
const sig = this.getSignature();
|
||||
// get directly from cache since we don't want to return failsafe image
|
||||
let image: HTMLImageElement = stendhal.data.sprites.getCached(sig);
|
||||
|
||||
const onReady = function(e?: Event) {
|
||||
image.removeEventListener("load", onReady);
|
||||
callback(image);
|
||||
};
|
||||
|
||||
if (image instanceof HTMLImageElement) {
|
||||
if (image.height > 0) {
|
||||
onReady();
|
||||
} else {
|
||||
image.addEventListener("load", onReady);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const stage = DrawingStage.get();
|
||||
stage.reset();
|
||||
stage.setSize(48 * 3, 64 * 4);
|
||||
|
||||
let outfitLayers = this.getLayers();
|
||||
const detailIndex = this.getLayerIndex("detail") || 0;
|
||||
if (OutfitStore.get().detailHasRearLayer(detailIndex)) {
|
||||
if (stendhal.data.outfit.detailHasRearLayer(detailIndex)) {
|
||||
outfitLayers = [new Pair("detail-rear", detailIndex), ...outfitLayers];
|
||||
}
|
||||
|
||||
const layers: HTMLImageElement[] = [];
|
||||
for (const l of outfitLayers) {
|
||||
let layerName = l.first;
|
||||
let suffix = "";
|
||||
|
|
@ -212,21 +235,58 @@ export class Outfit {
|
|||
layerName = layerName.replace(/-rear$/, "");
|
||||
}
|
||||
const layerIndex = l.second;
|
||||
let layerPath = Paths.sprites + "/outfit/" + layerName + "/"
|
||||
let layerPath = stendhal.paths.sprites + "/outfit/" + layerName + "/"
|
||||
+ StringUtil.padLeft(""+layerIndex, "0", 3) + suffix;
|
||||
if (layerName === "body" && stendhal.config.getBoolean("effect.no-nude")) {
|
||||
// FIXME: some non-player pickable bodies don't have "no-nude" variant
|
||||
layerPath += "-nonude";
|
||||
}
|
||||
layerPath += ".png";
|
||||
let filter = undefined;
|
||||
let coloring = this.getLayerColor(layerName);
|
||||
if (coloring) {
|
||||
filter = "trueColor";
|
||||
const coloring = this.getLayerColor(layerName);
|
||||
if (typeof(coloring) === "undefined") {
|
||||
layers.push(stendhal.data.sprites.get(layerPath));
|
||||
} else {
|
||||
layers.push(stendhal.data.sprites.getFiltered(layerPath, "trueColor", coloring));
|
||||
}
|
||||
parts.push(new ImageMetadata(layerPath, filter, coloring));
|
||||
}
|
||||
|
||||
return await new MultilayerImageLoader(parts).load();
|
||||
if (layers.length == 0) {
|
||||
image = stendhal.data.sprites.getFailsafe();
|
||||
callback(image);
|
||||
return;
|
||||
}
|
||||
|
||||
let onAllLayersReady: Function;
|
||||
const onLayerReady = function(e?: Event) {
|
||||
for (const layer of layers) {
|
||||
if (!layer.complete || layer.height === 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
onAllLayersReady();
|
||||
};
|
||||
|
||||
onAllLayersReady = function() {
|
||||
for (const layer of layers) {
|
||||
layer.removeEventListener("load", onLayerReady);
|
||||
stage.drawImage(layer);
|
||||
}
|
||||
image = stage.toImage();
|
||||
stage.reset();
|
||||
stendhal.data.sprites.cache(sig, image);
|
||||
if (image.height > 0) {
|
||||
onReady();
|
||||
} else {
|
||||
image.addEventListener("load", onReady);
|
||||
}
|
||||
};
|
||||
|
||||
for (const layer of layers) {
|
||||
if (layer.height > 0) {
|
||||
onLayerReady();
|
||||
} else {
|
||||
layer.addEventListener("load", onLayerReady);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export class OutfitStore {
|
|||
|
||||
|
||||
// player pickable layers
|
||||
public readonly count: {[key: string]: number} = {
|
||||
private count: {[key: string]: number} = {
|
||||
"hat": 19,
|
||||
"hair": 57,
|
||||
"mask": 9,
|
||||
|
|
|
|||
618
src/js/stendhal/data/SpriteStore.ts
Normal file
618
src/js/stendhal/data/SpriteStore.ts
Normal file
|
|
@ -0,0 +1,618 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2003-2024 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
declare var stendhal: any;
|
||||
|
||||
import { Paths } from "./Paths";
|
||||
|
||||
|
||||
class SpriteImage extends Image {
|
||||
// number of times the image has been accessed after initial creation
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
export class SpriteStore {
|
||||
|
||||
private knownBrokenUrls: {[url: string]: boolean} = {};
|
||||
private images: {[filename: string]: SpriteImage} = {};
|
||||
|
||||
private knownShadows: {[key: string]: boolean} = {
|
||||
"24x32": true,
|
||||
"32x32": true,
|
||||
"32x48": true,
|
||||
"32x48_long": true,
|
||||
"48x64": true,
|
||||
"48x64_float": true,
|
||||
"64x48": true,
|
||||
"64x64": true,
|
||||
"64x85": true,
|
||||
"64x96": true,
|
||||
"76x64": true,
|
||||
"81x96": true,
|
||||
"96x96": true,
|
||||
"96x128": true,
|
||||
"128x96": true,
|
||||
"128x170": true,
|
||||
"144x128": true,
|
||||
"168x224": true,
|
||||
"192x192": true,
|
||||
"192x192_float": true,
|
||||
"192x256": true,
|
||||
"320x440": true,
|
||||
"ent": true
|
||||
};
|
||||
|
||||
// alternatives for known images that may be considered violent or mature
|
||||
private knownSafeSprites: {[filename: string]: boolean} = {
|
||||
[Paths.sprites + "/monsters/huge_animal/thing"]: true,
|
||||
[Paths.sprites + "/monsters/mutant/imperial_mutant"]: true,
|
||||
[Paths.sprites + "/monsters/undead/bloody_zombie"]: true,
|
||||
[Paths.sprites + "/npc/deadmannpc"]: true
|
||||
};
|
||||
|
||||
// TODO: move to animation.json
|
||||
private animations: {[key: string]: any} = {
|
||||
idea: {
|
||||
"love": {delay: 100, offsetX: 24, offsetY: -8}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Hidden singleton constructor.
|
||||
*/
|
||||
protected constructor() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
get(filename: string): any {
|
||||
if (!filename) {
|
||||
return {};
|
||||
}
|
||||
if (filename.indexOf("undefined") > -1) {
|
||||
if (!this.knownBrokenUrls[filename]) {
|
||||
console.log("Broken image path: ", filename, new Error());
|
||||
}
|
||||
this.knownBrokenUrls[filename] = true;
|
||||
return {};
|
||||
}
|
||||
if (this.images[filename]) {
|
||||
this.images[filename].counter++;
|
||||
return this.images[filename];
|
||||
}
|
||||
var temp = new Image() as SpriteImage;
|
||||
// TypeError: Image constructor: 'new' is required
|
||||
//~ var temp = new SpriteImage();
|
||||
temp.counter = 0;
|
||||
temp.onerror = (function(t: SpriteImage, store: SpriteStore) {
|
||||
return function() {
|
||||
if (t.src && !store.knownBrokenUrls[t.src]) {
|
||||
console.log("Broken image path:", t.src, new Error());
|
||||
store.knownBrokenUrls[t.src] = true;
|
||||
}
|
||||
const failsafe = store.getFailsafe();
|
||||
if (failsafe.src && t.src !== failsafe.src) {
|
||||
t.src = failsafe.src;
|
||||
}
|
||||
};
|
||||
})(temp, this);
|
||||
temp.src = filename;
|
||||
this.images[filename] = temp;
|
||||
return temp;
|
||||
}
|
||||
|
||||
getWithPromise(filename: string): any {
|
||||
return new Promise((resolve) => {
|
||||
if (typeof(this.images[filename]) != "undefined") {
|
||||
this.images[filename].counter++;
|
||||
resolve(this.images[filename]);
|
||||
}
|
||||
|
||||
const image = new Image() as SpriteImage;
|
||||
// TypeError: Image constructor: 'new' is required
|
||||
//~ const image = new SpriteImage();
|
||||
image.counter = 0;
|
||||
this.images[filename] = image;
|
||||
image.onload = () => resolve(image);
|
||||
image.src = filename;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates an image.
|
||||
*
|
||||
* @param img
|
||||
* Image to be rotated.
|
||||
* @param angle
|
||||
* Angle of rotation.
|
||||
*/
|
||||
private rotate(img: HTMLImageElement, angle: number) {
|
||||
const canvas = <HTMLCanvasElement> document.getElementById("drawing-stage")!;
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
// make sure working with blank canvas
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
|
||||
ctx.translate(canvas.width / 2, canvas.height / 2);
|
||||
ctx.rotate(angle * Math.PI / 180);
|
||||
ctx.translate(-canvas.width / 2, -canvas.height / 2);
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
img.src = canvas.toDataURL("image/png");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a rotated image.
|
||||
*
|
||||
* @param filename
|
||||
* Path to target image file.
|
||||
* @param angle
|
||||
* Angle of rotation.
|
||||
* @return
|
||||
* HTMLImageElement.
|
||||
*/
|
||||
getRotated(filename: string, angle: number): any {
|
||||
if (angle == 0) {
|
||||
return this.get(filename);
|
||||
}
|
||||
const id = filename + "-rot" + angle;
|
||||
if (this.images[id]) {
|
||||
return this.get(id);
|
||||
}
|
||||
// NOTE: cannot use HTMLImageElement.cloneNode here, must get base image then transfer
|
||||
// `src` property when ready
|
||||
const img = new Image() as SpriteImage;
|
||||
img.counter = 0;
|
||||
img.onload = () => {
|
||||
img.onload = null;
|
||||
this.rotate(img, angle);
|
||||
}
|
||||
const baseImg = this.get(filename);
|
||||
if (baseImg.complete) {
|
||||
img.src = baseImg.src;
|
||||
} else {
|
||||
baseImg.onload = () => {
|
||||
baseImg.onload = null;
|
||||
img.src = baseImg.src;
|
||||
}
|
||||
}
|
||||
this.images[id] = img;
|
||||
return img;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an image to cache.
|
||||
*
|
||||
* @param {string} id
|
||||
* Cache identifier.
|
||||
* @param {SpriteImage}
|
||||
* Image to be cached.
|
||||
*/
|
||||
cache(id: string, image: SpriteImage) {
|
||||
image.counter = 0;
|
||||
this.images[id] = image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when we only want an image if it was previously cached.
|
||||
*
|
||||
* @param filename
|
||||
* Full file path.
|
||||
* @return
|
||||
* HTMLImageElement or undefined.
|
||||
*/
|
||||
getCached(filename: string): any {
|
||||
return this.images[filename];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the failsafe sprite.
|
||||
*
|
||||
* @return
|
||||
* HTMLImageElement with failsafe image data.
|
||||
*/
|
||||
getFailsafe(): HTMLImageElement {
|
||||
const filename = Paths.sprites + "/failsafe.png";
|
||||
let failsafe = this.images[filename];
|
||||
if (failsafe) {
|
||||
failsafe.counter++;
|
||||
} else {
|
||||
failsafe = new Image() as SpriteImage;
|
||||
// TypeError: Image constructor: 'new' is required
|
||||
//~ failsafe = new SpriteImage();
|
||||
failsafe.counter = 0;
|
||||
failsafe.src = filename;
|
||||
this.images[filename] = failsafe;
|
||||
}
|
||||
return failsafe;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks cached images for a valid filename.
|
||||
*
|
||||
* @param filename
|
||||
* Image filename to be checked.
|
||||
* @return
|
||||
* Path to image or failsafe image file.
|
||||
*/
|
||||
checkPath(filename: string): string {
|
||||
return this.get(filename).src;
|
||||
}
|
||||
|
||||
/** deletes all objects that have not been accessed since this method was called last time */
|
||||
// TODO: call clean on map change
|
||||
clean() {
|
||||
for (var i in this.images) {
|
||||
console.log(typeof(this.images[i]));
|
||||
if (this.images[i] instanceof SpriteImage) {
|
||||
if (this.images[i].counter > 0) {
|
||||
this.images[i].counter--;
|
||||
} else {
|
||||
delete(this.images[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an image element whose image data is an area of a specified image.
|
||||
* If the area matches the original image, the image itself is returned.
|
||||
* Otherwise <em>a copy</em> of the image data is returned. This is meant
|
||||
* to be used for obtaining the drag image for drag and drop.
|
||||
*
|
||||
* @param image original image
|
||||
* @param width width of the area
|
||||
* @param height height of the area
|
||||
* @param {number=} offsetX optional. left x coordinate of the area
|
||||
* @param {number=} offsetY optional. top y coordinate of the area
|
||||
*/
|
||||
getAreaOf(image: HTMLImageElement, width: number, height: number,
|
||||
offsetX?: number, offsetY?: number): any {
|
||||
try {
|
||||
offsetX = offsetX || 0;
|
||||
offsetY = offsetY || 0;
|
||||
if ((image.width === width) && (image.height === height)
|
||||
&& (offsetX === 0) && (offsetY === 0)) {
|
||||
return image;
|
||||
}
|
||||
var canvas = document.createElement("canvas") as HTMLCanvasElement;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
var ctx = canvas.getContext("2d")!;
|
||||
ctx.drawImage(image, offsetX, offsetY, width, height, 0, 0, width, height);
|
||||
// Firefox would be able to use the canvas directly as a drag image, but
|
||||
// Chrome does not. This should work in any standards compliant browser.
|
||||
var newImage = new Image();
|
||||
newImage.src = canvas.toDataURL("image/png");
|
||||
return newImage;
|
||||
} catch (err) {
|
||||
if (err instanceof DOMException) {
|
||||
return this.getFailsafe();
|
||||
} else {
|
||||
// don't ignore other errors
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} fileName
|
||||
* @param {string} filter
|
||||
* @param {number=} param
|
||||
*/
|
||||
getFiltered(fileName: string, filter: string, param?: number) {
|
||||
const img = this.get(fileName);
|
||||
let filterFn;
|
||||
if (typeof(filter) === "undefined"
|
||||
|| !(filterFn = this.filter[filter])
|
||||
|| !img.complete || img.width === 0 || img.height === 0) {
|
||||
return img;
|
||||
}
|
||||
const filteredName = fileName + " " + filter + " " + param;
|
||||
let filtered: SpriteImage = this.images[filteredName];
|
||||
if (typeof(filtered) === "undefined") {
|
||||
const canvas = document.createElement("canvas") as any;
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
ctx.drawImage(img, 0, 0);
|
||||
const imgData = ctx.getImageData(0, 0, img.width, img.height);
|
||||
const data = imgData.data;
|
||||
filterFn(data, param);
|
||||
ctx.putImageData(imgData, 0, 0);
|
||||
canvas.complete = true;
|
||||
this.images[filteredName] = filtered = canvas as SpriteImage;
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} fileName
|
||||
* @param {string} filter
|
||||
* @param {number=} param
|
||||
*/
|
||||
getFilteredWithPromise(fileName: string, filter: string, param?: number) {
|
||||
const imgPromise = this.getWithPromise(fileName);
|
||||
return imgPromise.then(function (img: HTMLImageElement) {
|
||||
let filterFn: Function;
|
||||
if (typeof(filter) === "undefined"
|
||||
|| !(filterFn = stendhal.data.sprites.filter[filter])
|
||||
|| !img.complete || img.width === 0 || img.height === 0) {
|
||||
return img;
|
||||
}
|
||||
const filteredName = fileName + " " + filter + " " + param;
|
||||
let filtered: SpriteImage = stendhal.data.sprites.images[filteredName];
|
||||
if (typeof(filtered) === "undefined") {
|
||||
const canvas = document.createElement("canvas") as any;
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
ctx.drawImage(img, 0, 0);
|
||||
const imgData = ctx.getImageData(0, 0, img.width, img.height);
|
||||
const data = imgData.data;
|
||||
filterFn(data, param);
|
||||
ctx.putImageData(imgData, 0, 0);
|
||||
canvas.complete = true;
|
||||
stendhal.data.sprites.images[filteredName] = filtered = canvas as SpriteImage;
|
||||
}
|
||||
|
||||
return filtered;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/** Image filters */
|
||||
filter: {[key: string]: Function} = {
|
||||
// Helper functions
|
||||
/**
|
||||
* @param {Number} rgb
|
||||
* @return {Array<Number>}
|
||||
*/
|
||||
splitrgb: function(rgb: number): number[] {
|
||||
rgb &= 0xffffff;
|
||||
var b = rgb & 0xff;
|
||||
rgb >>>= 8;
|
||||
var g = rgb & 0xff;
|
||||
rgb >>>= 8;
|
||||
return [rgb, g, b];
|
||||
},
|
||||
|
||||
mergergb: function(rgbArray: number[]): number {
|
||||
const r = rgbArray[0] << 16;
|
||||
const g = rgbArray[1] << 8;
|
||||
return 0xffffff & (r | g | rgbArray[2]);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Array<Number>} rgb
|
||||
* @return {Array<Number>}
|
||||
*/
|
||||
rgb2hsl: function(rgb: number[]): number[] {
|
||||
var r = rgb[0] / 255;
|
||||
var g = rgb[1] / 255;
|
||||
var b = rgb[2] / 255;
|
||||
|
||||
var max, min, maxVar;
|
||||
// Find the max and minimum colors, and remember which one it was
|
||||
if (r > g) {
|
||||
max = r;
|
||||
min = g;
|
||||
maxVar = 0;
|
||||
} else {
|
||||
max = g;
|
||||
min = r;
|
||||
maxVar = 1;
|
||||
}
|
||||
if (b > max) {
|
||||
max = b;
|
||||
maxVar = 2;
|
||||
} else if (b < min) {
|
||||
min = b;
|
||||
}
|
||||
|
||||
// lightness
|
||||
var l = (max + min) / 2;
|
||||
var s, h;
|
||||
|
||||
// saturation
|
||||
var diff = max - min;
|
||||
if (diff < 0.000001) {
|
||||
s = 0;
|
||||
// hue not really defined, but set it to something reasonable
|
||||
h = 0;
|
||||
} else {
|
||||
if (l < 0.5) {
|
||||
s = diff / (max + min);
|
||||
} else {
|
||||
s = diff / (2 - max - min);
|
||||
}
|
||||
|
||||
// hue
|
||||
if (maxVar === 0) {
|
||||
h = (g - b) / diff;
|
||||
} else if (maxVar === 1) {
|
||||
h = 2 + (b - r) / diff;
|
||||
} else {
|
||||
h = 4 + (r - g) / diff;
|
||||
}
|
||||
// Normalize to range [0, 1]. It's more useful than the usual 360
|
||||
h /= 6;
|
||||
}
|
||||
|
||||
return [h, s, l];
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Array<Number>} hsl
|
||||
* @return {Array<Number>}
|
||||
*/
|
||||
hsl2rgb: function(hsl: number[]): number[] {
|
||||
var r, g, b;
|
||||
var h = hsl[0];
|
||||
var s = hsl[1];
|
||||
var l = hsl[2];
|
||||
|
||||
if (s < 0.0000001) {
|
||||
r = g = b = Math.floor(255 * l);
|
||||
} else {
|
||||
var tmp1, tmp2;
|
||||
if (l < 0.5) {
|
||||
tmp1 = l * (1 + s);
|
||||
} else {
|
||||
tmp1 = l + s - l * s;
|
||||
}
|
||||
tmp2 = 2 * l - tmp1;
|
||||
|
||||
var rf = stendhal.data.sprites.filter.hue2rgb(this.limitHue(h + 1/3), tmp2, tmp1);
|
||||
var gf = stendhal.data.sprites.filter.hue2rgb(this.limitHue(h), tmp2, tmp1);
|
||||
var bf = stendhal.data.sprites.filter.hue2rgb(this.limitHue(h - 1/3), tmp2, tmp1);
|
||||
|
||||
r = Math.floor(255 * rf) & 0xff;
|
||||
g = Math.floor(255 * gf) & 0xff;
|
||||
b = Math.floor(255 * bf) & 0xff;
|
||||
}
|
||||
|
||||
return [r, g, b];
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Number} hue
|
||||
* @param {Number} val1
|
||||
* @param {Number} val2
|
||||
*/
|
||||
hue2rgb: function(hue: number, val1: number, val2: number): number {
|
||||
var res = hue;
|
||||
if (6 * hue < 1) {
|
||||
res = val1 + (val2 - val1) * 6 * hue;
|
||||
} else if (2 * hue < 1) {
|
||||
res = val2;
|
||||
} else if (3 * hue < 2) {
|
||||
res = val1 + (val2 - val1) * (2/3 - hue) * 6;
|
||||
} else {
|
||||
res = val1;
|
||||
}
|
||||
|
||||
return res;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Number} hue
|
||||
*/
|
||||
limitHue: function(hue: number): number {
|
||||
var res = hue;
|
||||
if (res < 0) {
|
||||
res += 1;
|
||||
} else if (res > 1) {
|
||||
res -= 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a shadow sprite if the style is available.
|
||||
*
|
||||
* @param shadowStyle
|
||||
* Style of shadow to get from cache.
|
||||
* @return
|
||||
* Image sprite or <code>undefined</code>.
|
||||
*/
|
||||
getShadow(shadowStyle: string): any {
|
||||
if (this.knownShadows[shadowStyle]) {
|
||||
const img = new Image();
|
||||
img.src = Paths.sprites + "/shadow/" + shadowStyle + ".png";
|
||||
return img;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if there is a "safe" image available for sprite.
|
||||
*
|
||||
* @param filename
|
||||
* The sprite image base file path.
|
||||
* @return
|
||||
* <code>true</code> if a known safe image is available.
|
||||
*/
|
||||
hasSafeImage(filename: string): boolean {
|
||||
return this.knownSafeSprites[filename] == true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called at startup to pre-cache certain images.
|
||||
*/
|
||||
startupCache() {
|
||||
// failsafe image
|
||||
this.getFailsafe();
|
||||
// tutorial profile
|
||||
this.get(Paths.sprites + "/npc/floattingladynpc.png");
|
||||
// achievement assets
|
||||
this.get(Paths.gui + "/banner_background.png");
|
||||
for (const cat of ["commerce", "deathmatch", "experience", "fighting", "friend",
|
||||
"interior_zone", "item", "obtain", "outside_zone", "production", "quest",
|
||||
"quest_ados_items", "quest_kill_blordroughs", "quest_kirdneh_item",
|
||||
"quest_mithrilbourgh_enemy_army", "quest_semos_monster", "special",
|
||||
"underground_zone"]) {
|
||||
this.get(Paths.achievements + "/" + cat + ".png");
|
||||
}
|
||||
// weather
|
||||
for (const weather of ["clouds", "fog", "fog_heavy", "rain", "rain_heavy",
|
||||
"rain_light", "snow", "snow_heavy", "snow_light", "wave"]) {
|
||||
this.get(Paths.weather + "/" + weather + ".png");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hidden class to create the singleton instance internally.
|
||||
*/
|
||||
class SpriteStoreInternal extends SpriteStore {
|
||||
|
||||
/** Singleton instance. */
|
||||
private static instance: SpriteStore;
|
||||
|
||||
/**
|
||||
* Retrieves singleton instance.
|
||||
*/
|
||||
static get(): SpriteStore {
|
||||
if (!SpriteStoreInternal.instance) {
|
||||
SpriteStoreInternal.instance = new SpriteStore();
|
||||
}
|
||||
return SpriteStoreInternal.instance;
|
||||
}
|
||||
}
|
||||
|
||||
// SpriteStore singleton instance
|
||||
export const store = SpriteStoreInternal.get();
|
||||
// *** Image filters. Prevent the closure compiler from mangling the names. ***
|
||||
store.filter['trueColor'] = function(data: any, color: number) {
|
||||
var hslColor = stendhal.data.sprites.filter.rgb2hsl(stendhal.data.sprites.filter.splitrgb(color));
|
||||
var end = data.length;
|
||||
for (var i = 0; i < end; i += 4) {
|
||||
var rgb = [data[i], data[i + 1], data[i + 2]];
|
||||
var hsl = stendhal.data.sprites.filter.rgb2hsl(rgb);
|
||||
// Adjust the brightness
|
||||
var adj = hslColor[2] - 0.5; // [-0.5, 0.5]
|
||||
var tmp = hsl[2] - 0.5; // [-0.5, 0.5]
|
||||
// tweaks the middle lights either upward or downward, depending
|
||||
// on if source lightness is high or low
|
||||
var l = hsl[2] - 2.0 * adj * ((tmp * tmp) - 0.25);
|
||||
var resultHsl = [hslColor[0], hslColor[1], l];
|
||||
var resultRgb = stendhal.data.sprites.filter.hsl2rgb(resultHsl);
|
||||
data[i] = resultRgb[0];
|
||||
data[i+1] = resultRgb[1];
|
||||
data[i+2] = resultRgb[2];
|
||||
}
|
||||
};
|
||||
|
|
@ -12,6 +12,9 @@
|
|||
import { Paths } from "./Paths";
|
||||
import { JSONLoader } from "../util/JSONLoader";
|
||||
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
type AnimationMap = {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
|
@ -67,7 +70,7 @@ export class TileStore {
|
|||
this.landscapeMap = this.loadAnimations(
|
||||
loader.data["landscape"], Paths.tileset + "/");
|
||||
this.weatherMap = this.loadAnimations(
|
||||
loader.data["weather"], Paths.weather + "/");
|
||||
loader.data["weather"], stendhal.paths.weather + "/");
|
||||
};
|
||||
loader.load(Paths.tileset + "/animation.json");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* Copyright © 2003-2026 - Faiumoni e. V. *
|
||||
* Copyright © 2003-2024 - Faiumoni e. V. *
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
|
@ -9,11 +9,10 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
import { stendhal } from "../../stendhal";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
import { LoopedSoundSource } from "../../entity/LoopedSoundSource";
|
||||
import { Zone } from "entity/Zone";
|
||||
|
||||
|
||||
// server doesn't distinguish between music & looped sound effects so we
|
||||
|
|
@ -180,8 +179,8 @@ export class LoopedSoundSourceManager {
|
|||
*/
|
||||
private getZoneEntities(): LoopedSoundSource[] {
|
||||
const ents: LoopedSoundSource[] = [];
|
||||
if (Zone.get().entities) {
|
||||
for (const ent of Zone.get().entities) {
|
||||
if (stendhal.zone.entities) {
|
||||
for (const ent of stendhal.zone.entities) {
|
||||
if (ent instanceof LoopedSoundSource) {
|
||||
ents.push(ent);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { AbstractEnum } from "../enum/AbstractEnum";
|
|||
/**
|
||||
* Available layers of sound.
|
||||
*
|
||||
* string names should match `games.stendhal.common.constants.SoundLayer`
|
||||
* NOTE: string names should match `games.stendhal.common.constants.SoundLayer`
|
||||
*/
|
||||
export class SoundLayer extends AbstractEnum<string> {
|
||||
|
||||
|
|
@ -29,6 +29,9 @@ export class SoundLayer extends AbstractEnum<string> {
|
|||
static readonly SFX = new SoundLayer("sfx");
|
||||
static readonly GUI = new SoundLayer("gui");
|
||||
|
||||
/** Value is required. */
|
||||
override readonly value!: string;
|
||||
|
||||
|
||||
private constructor(value: string) {
|
||||
super(value);
|
||||
|
|
@ -44,7 +47,7 @@ export class SoundLayer extends AbstractEnum<string> {
|
|||
static names(): string[] {
|
||||
const names: string[] = [];
|
||||
for (const layer of SoundLayer.layers) {
|
||||
names.push(layer.value!);
|
||||
names.push(layer.value);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,15 +9,16 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
import { stendhal } from "../../stendhal";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
import { SoundFactory } from "./SoundFactory";
|
||||
import { SoundObject } from "./SoundFactory";
|
||||
import { SoundLayer } from "./SoundLayer";
|
||||
|
||||
import { singletons } from "../../SingletonRepo";
|
||||
|
||||
import { ui } from "../../ui/UI";
|
||||
import { Paths } from "../Paths";
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -243,7 +244,7 @@ export class SoundManager {
|
|||
let snd = this.cache[soundName] || this.cacheGlobal[soundName];
|
||||
if (!snd) {
|
||||
// add new sound to cache
|
||||
snd = this.load(soundName, Paths.sounds + "/" + soundName + ".ogg");
|
||||
snd = this.load(soundName, stendhal.paths.sounds + "/" + soundName + ".ogg");
|
||||
}
|
||||
|
||||
if (!this.cache[soundName]) {
|
||||
|
|
@ -405,7 +406,7 @@ export class SoundManager {
|
|||
volume=1.0): SoundObject|undefined {
|
||||
// load into cache so playEffect doesn't look in "data/sounds"
|
||||
if (!this.cache[musicName]) {
|
||||
this.load(musicName, Paths.music + "/" + musicName + ".ogg");
|
||||
this.load(musicName, stendhal.paths.music + "/" + musicName + ".ogg");
|
||||
}
|
||||
return this.playLocalizedLoop(x, y, radius, layer, musicName, volume);
|
||||
}
|
||||
|
|
@ -423,7 +424,7 @@ export class SoundManager {
|
|||
playGlobalizedMusic(musicName: string, volume=1.0): SoundObject|undefined {
|
||||
// load into cache so playEffect doesn't look in "data/sounds"
|
||||
if (!this.cache[musicName]) {
|
||||
this.load(musicName, Paths.music + "/" + musicName + ".ogg");
|
||||
this.load(musicName, stendhal.paths.music + "/" + musicName + ".ogg");
|
||||
}
|
||||
return this.playGlobalizedLoop(musicName, "music", volume);
|
||||
}
|
||||
|
|
@ -795,6 +796,6 @@ export class SoundManager {
|
|||
startupCache() {
|
||||
// login sound
|
||||
this.load("ui/login",
|
||||
Paths.sounds + "/ui/login.ogg", true);
|
||||
stendhal.paths.sounds + "/ui/login.ogg", true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,7 @@ import { Entity } from "./Entity";
|
|||
import { Direction } from "../util/Direction";
|
||||
import { MathUtil } from "../util/MathUtil";
|
||||
|
||||
import { stendhal } from "../stendhal";
|
||||
import { TileMap } from "data/TileMap";
|
||||
import { Zone } from "./Zone";
|
||||
declare var stendhal: any;
|
||||
|
||||
export class ActiveEntity extends Entity {
|
||||
|
||||
|
|
@ -232,10 +230,9 @@ export class ActiveEntity extends Entity {
|
|||
var startY = Math.floor(this["_y"]);
|
||||
var endX = Math.ceil(this["_x"] + this["width"]);
|
||||
var endY = Math.ceil(this["_y"] + this["height"]);
|
||||
let map = TileMap.get();
|
||||
for (var y = startY; y < endY; y++) {
|
||||
for (var x = startX; x < endX; x++) {
|
||||
if (map.collision(x, y)) {
|
||||
if (stendhal.data.map.collision(x, y)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -261,8 +258,8 @@ export class ActiveEntity extends Entity {
|
|||
var thisEndY = Math.ceil(this["_y"] + this["height"]);
|
||||
|
||||
var i;
|
||||
for (i in Zone.get().entities) {
|
||||
var other = Zone.get().entities[i];
|
||||
for (i in stendhal.zone.entities) {
|
||||
var other = stendhal.zone.entities[i];
|
||||
if (!this.isObstacle(other)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2003-2026 - Stendhal *
|
||||
* (C) Copyright 2003-2024 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
|
@ -9,13 +9,9 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { RenderingContext2D } from "util/Types";
|
||||
import { Entity } from "./Entity";
|
||||
import { Paths } from "../data/Paths";
|
||||
|
||||
import { stendhal } from "../stendhal";
|
||||
import { ImageSprite } from "sprite/image/ImageSprite";
|
||||
import { images } from "sprite/image/ImageManager";
|
||||
declare var stendhal: any;
|
||||
|
||||
export class Blood extends Entity {
|
||||
|
||||
|
|
@ -24,30 +20,27 @@ export class Blood extends Entity {
|
|||
|
||||
constructor() {
|
||||
super();
|
||||
this.imageSprite = new ImageSprite(
|
||||
images.load(Paths.sprites + "/combat/blood_red.png"),
|
||||
0, 0, 32, 32
|
||||
);
|
||||
this.sprite = {
|
||||
height: 32,
|
||||
width: 32,
|
||||
filename: stendhal.paths.sprites + "/combat/blood_red.png"
|
||||
};
|
||||
}
|
||||
|
||||
override set(key: string, value: any) {
|
||||
super.set(key, value);
|
||||
if (key === "amount") {
|
||||
this.imageSprite!.offsetY = parseInt(value, 10) * 32;
|
||||
this.sprite.offsetY = parseInt(value, 10) * 32;
|
||||
} else if (key === "class") {
|
||||
this.imageSprite?.free();
|
||||
this.imageSprite = new ImageSprite(
|
||||
images.load(Paths.sprites + "/combat/blood_" + value + ".png"),
|
||||
0, parseInt(this["amount"], 10) * 32, 32, 32
|
||||
);
|
||||
this.sprite.filename = stendhal.paths.sprites + "/combat/blood_" + value + ".png";
|
||||
}
|
||||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/walk.png) 1 3, auto";
|
||||
override getCursor(x: number, y: number) {
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/walk.png) 1 3, auto";
|
||||
}
|
||||
|
||||
override drawSpriteAt(ctx: RenderingContext2D, x: number, y: number) {
|
||||
override drawSpriteAt(ctx: CanvasRenderingContext2D, x: number, y: number) {
|
||||
if (!stendhal.config.getBoolean("effect.blood")) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,13 +19,23 @@ import { FloatingWindow } from "../ui/toolkit/FloatingWindow";
|
|||
import { ItemInventoryComponent } from "../ui/component/ItemInventoryComponent";
|
||||
|
||||
import { Chat } from "../util/Chat";
|
||||
import { Paths } from "../data/Paths";
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
import { stendhal } from "../stendhal";
|
||||
import { Entity } from "./Entity";
|
||||
import { ImageSprite } from "sprite/image/ImageSprite";
|
||||
import { images } from "sprite/image/ImageManager";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
let OPEN_SPRITE = {
|
||||
filename: stendhal.paths.sprites + "/chest.png",
|
||||
height: 32,
|
||||
width: 32,
|
||||
offsetY: 32
|
||||
};
|
||||
|
||||
let CLOSED_SPRITE = {
|
||||
filename: stendhal.paths.sprites + "/chest.png",
|
||||
height: 32,
|
||||
width: 32
|
||||
};
|
||||
|
||||
export class Chest extends PopupInventory {
|
||||
|
||||
|
|
@ -33,22 +43,16 @@ export class Chest extends PopupInventory {
|
|||
override minimapStyle = Color.CHEST;
|
||||
|
||||
override zIndex = 5000;
|
||||
sprite = CLOSED_SPRITE;
|
||||
open = false;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.imageSprite = new ImageSprite(
|
||||
images.load(Paths.sprites + "/chest.png"),
|
||||
0, 0, 32, 32);
|
||||
}
|
||||
|
||||
override set(key: string, value: any) {
|
||||
super.set(key, value);
|
||||
if (key === "open") {
|
||||
this.imageSprite!.offsetY = 32;
|
||||
this.sprite = OPEN_SPRITE;
|
||||
this.open = true;
|
||||
}
|
||||
if (this.isNextTo(marauroa.me as Entity)) {
|
||||
if (this.isNextTo(marauroa.me)) {
|
||||
this.openInventoryWindow();
|
||||
}
|
||||
}
|
||||
|
|
@ -56,7 +60,7 @@ export class Chest extends PopupInventory {
|
|||
override unset(key: string) {
|
||||
super.unset(key);
|
||||
if (key === "open") {
|
||||
this.imageSprite!.offsetY = 0;
|
||||
this.sprite = CLOSED_SPRITE;
|
||||
this.open = false;
|
||||
if (this.inventory && this.inventory.isOpen()) {
|
||||
this.inventory.close();
|
||||
|
|
@ -147,7 +151,7 @@ export class Chest extends PopupInventory {
|
|||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/bag.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/bag.png) 1 3, auto";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,6 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { CorpseSlot } from "./CorpseSlot";
|
||||
import { RenderingContext2D } from "util/Types";
|
||||
import { ActivityIndicatorSprite } from "../sprite/ActivityIndicatorSprite";
|
||||
|
||||
import { ItemInventoryComponent } from "../ui/component/ItemInventoryComponent";
|
||||
|
|
@ -19,14 +17,9 @@ import { FloatingWindow } from "../ui/toolkit/FloatingWindow";
|
|||
import { Chat } from "../util/Chat";
|
||||
|
||||
import { PopupInventory } from "./PopupInventory";
|
||||
import { Paths } from "../data/Paths";
|
||||
import { singletons } from "../SingletonRepo";
|
||||
|
||||
import { marauroa, RPObject, RPZone } from "marauroa"
|
||||
import { stendhal } from "../stendhal";
|
||||
import { images } from "sprite/image/ImageManager";
|
||||
import { ImageSprite } from "sprite/image/ImageSprite";
|
||||
import { ViewPort } from "ui/ViewPort";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
export class Corpse extends PopupInventory {
|
||||
|
||||
|
|
@ -47,42 +40,61 @@ export class Corpse extends PopupInventory {
|
|||
override set(key: string, value: any) {
|
||||
super.set(key, value);
|
||||
|
||||
let bloodEnabled = stendhal.config.getBoolean("effect.blood");
|
||||
this.sprite = this.sprite || {};
|
||||
const bloodEnabled = stendhal.config.getBoolean("effect.blood");
|
||||
|
||||
if (bloodEnabled && (key === "image")) {
|
||||
this.imageSprite?.free();
|
||||
this.imageSprite = new ImageSprite(
|
||||
images.load(Paths.sprites + "/corpse/" + value + ".png"));
|
||||
this.sprite.filename = stendhal.paths.sprites + "/corpse/" + value + ".png";
|
||||
} else if (!bloodEnabled && (key === "harmless_image")) {
|
||||
this.imageSprite?.free();
|
||||
this.imageSprite = new ImageSprite(
|
||||
images.load(Paths.sprites + "/corpse/" + value + ".png"));
|
||||
this.sprite.filename = stendhal.paths.sprites + "/corpse/" + value + ".png";
|
||||
}
|
||||
}
|
||||
|
||||
override draw(ctx: RenderingContext2D) {
|
||||
let image = this.imageSprite?.imageRef?.image;
|
||||
if (!image) {
|
||||
override draw(ctx: CanvasRenderingContext2D) {
|
||||
if (!this.sprite) {
|
||||
return;
|
||||
}
|
||||
super.draw(ctx);
|
||||
|
||||
if (this.indicator && !this.isEmpty()) {
|
||||
let viewPort = ViewPort.get();
|
||||
const tileW = viewPort.targetTileWidth;
|
||||
const tileH = viewPort.targetTileHeight;
|
||||
let width = image.width < tileW ? tileW : image.width;
|
||||
let height = image.height < tileH ? tileH : image.height;
|
||||
let offsetX = Math.floor((this["width"] * tileW - width) / 2);
|
||||
let offsetY = Math.floor((this["height"] * tileH - height) / 2);
|
||||
let dx = this["x"] * tileW + offsetX;
|
||||
let dy = this["y"] * tileH + offsetY;
|
||||
this.indicator.draw(ctx, dx, dy, width);
|
||||
const tileW = stendhal.ui.gamewindow.targetTileWidth;
|
||||
const tileH = stendhal.ui.gamewindow.targetTileHeight;
|
||||
if (this.sprite.width == undefined || this.sprite.height == undefined) {
|
||||
const image = stendhal.data.sprites.get(this.sprite.filename);
|
||||
if (image.complete) {
|
||||
this.sprite.width = image.width < tileW ? tileW : image.width;
|
||||
this.sprite.height = image.height < tileH ? tileH : image.height;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const offsetX = Math.floor((this["width"] * tileW - this.sprite.width) / 2);
|
||||
const offsetY = Math.floor((this["height"] * tileH - this.sprite.height) / 2);
|
||||
const dx = this["x"] * tileW + offsetX;
|
||||
const dy = this["y"] * tileH + offsetY;
|
||||
|
||||
this.indicator.draw(ctx, dx, dy, this.sprite.width);
|
||||
}
|
||||
}
|
||||
|
||||
override createSlot(name: string) {
|
||||
let slot = new CorpseSlot();
|
||||
var slot = marauroa.util.fromProto(marauroa.rpslotFactory["_default"], {
|
||||
add: function(object: any) {
|
||||
marauroa.rpslotFactory["_default"].add.apply(this, arguments);
|
||||
if (this._objects.length > 0) {
|
||||
this._parent.autoOpenIfDesired();
|
||||
}
|
||||
},
|
||||
|
||||
del: function(key: any) {
|
||||
marauroa.rpslotFactory["_default"].del.apply(this, arguments);
|
||||
if (this._objects.length == 0) {
|
||||
this._parent.closeCorpseInventory();
|
||||
}
|
||||
}
|
||||
});
|
||||
slot._name = name;
|
||||
slot._objects = [];
|
||||
slot._parent = this;
|
||||
return slot;
|
||||
}
|
||||
|
|
@ -156,18 +168,18 @@ export class Corpse extends PopupInventory {
|
|||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
if (this.isEmpty()) {
|
||||
return "url(" + Paths.sprites + "/cursor/emptybag.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/emptybag.png) 1 3, auto";
|
||||
}
|
||||
|
||||
// owner
|
||||
if (!this["corpse_owner"] || (this["corpse_owner"] == marauroa.me["_name"])) {
|
||||
return "url(" + Paths.sprites + "/cursor/bag.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/bag.png) 1 3, auto";
|
||||
}
|
||||
|
||||
if ((stendhal.data.group.lootmode === "shared") && (stendhal.data.group.members[this["corpse_owner"]])) {
|
||||
return "url(" + Paths.sprites + "/cursor/bag.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/bag.png) 1 3, auto";
|
||||
}
|
||||
return "url(" + Paths.sprites + "/cursor/lockedbag.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/lockedbag.png) 1 3, auto";
|
||||
}
|
||||
|
||||
public override isDraggable(): boolean {
|
||||
|
|
@ -177,9 +189,4 @@ export class Corpse extends PopupInventory {
|
|||
private isEmpty() {
|
||||
return !this["content"] || this["content"]._objects.length === 0;
|
||||
}
|
||||
|
||||
override destroy(parent: RPObject|RPZone): void {
|
||||
this.indicator?.free();
|
||||
super.destroy(parent);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2003-2026 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* 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 { Corpse } from "./Corpse";
|
||||
import { RPSlot } from "marauroa";
|
||||
|
||||
export class CorpseSlot extends RPSlot {
|
||||
|
||||
public _name?: string;
|
||||
public _parent?: Corpse;
|
||||
|
||||
override add(object: any) {
|
||||
super.add(object);
|
||||
if (this._objects.length > 0) {
|
||||
this._parent?.autoOpenIfDesired();
|
||||
}
|
||||
}
|
||||
|
||||
override del(key: any) {
|
||||
super.del(key);
|
||||
if (this._objects.length == 0) {
|
||||
this._parent?.closeCorpseInventory();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -16,10 +16,9 @@ import { EntityOverlayRegistry } from "../data/EntityOverlayRegistry";
|
|||
import { Color } from "../data/color/Color";
|
||||
|
||||
import { SkillEffect } from "../sprite/action/SkillEffect";
|
||||
import { Paths } from "../data/Paths";
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
import { stendhal } from "../stendhal";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
export class Creature extends RPEntity {
|
||||
|
||||
|
|
@ -28,7 +27,7 @@ export class Creature extends RPEntity {
|
|||
override titleStyle = "#ffc8c8";
|
||||
|
||||
|
||||
override set(key: string, value: any) {
|
||||
override set(key: string, value: string) {
|
||||
super.set(key, value);
|
||||
|
||||
if (key === "name") {
|
||||
|
|
@ -53,7 +52,7 @@ export class Creature extends RPEntity {
|
|||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/attack.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/attack.png) 1 3, auto";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2003-2026 - Stendhal *
|
||||
* (C) Copyright 2003-2024 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
|
@ -9,62 +9,53 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { MenuItem } from "../action/MenuItem";
|
||||
import { RPEntity } from "./RPEntity";
|
||||
import { MenuItem} from "../action/MenuItem";
|
||||
|
||||
import { RenderingContext2D } from "util/Types";
|
||||
import { Color } from "../data/color/Color";
|
||||
import { Paths } from "../data/Paths";
|
||||
|
||||
import { marauroa } from "marauroa";
|
||||
import { images } from "sprite/image/ImageManager";
|
||||
import { ImageSprite } from "sprite/image/ImageSprite";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
export class DomesticAnimal extends RPEntity {
|
||||
|
||||
override minimapStyle = Color.DOMESTICANIMAL;
|
||||
|
||||
override init() {
|
||||
this.imageSprite = new ImageSprite(
|
||||
images.load(Paths.sprites + "/" + this["_rpclass"] + ".png"));
|
||||
this["largeWeight"] = this["largeWeight"] || 20;
|
||||
if (this["_rpclass"] == "sheep") {
|
||||
this["largeWeight"] = 60;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override drawMain(ctx: RenderingContext2D) {
|
||||
|
||||
let image = this.imageSprite?.imageRef?.image
|
||||
if (!image) {
|
||||
return;
|
||||
override drawMain(ctx: CanvasRenderingContext2D) {
|
||||
if (!this.imagePath && this["_rpclass"]) {
|
||||
this["largeWeight"] = this["largeWeight"] | 20;
|
||||
if (this["_rpclass"] == "sheep") {
|
||||
this["largeWeight"] = 60;
|
||||
}
|
||||
this.imagePath = stendhal.paths.sprites + "/" + this["_rpclass"] + ".png";
|
||||
}
|
||||
|
||||
let localX = this["_x"] * 32;
|
||||
let localY = this["_y"] * 32;
|
||||
|
||||
let nFrames = 3;
|
||||
let nDirections = 4;
|
||||
let yRow = this["dir"] - 1;
|
||||
if (this["weight"] >= this["largeWeight"]) {
|
||||
yRow += 4;
|
||||
var localX = this["_x"] * 32;
|
||||
var localY = this["_y"] * 32;
|
||||
var image = stendhal.data.sprites.get(this.imagePath);
|
||||
if (image.height) {
|
||||
var nFrames = 3;
|
||||
var nDirections = 4;
|
||||
var yRow = this["dir"] - 1;
|
||||
if (this["weight"] >= this["largeWeight"]) {
|
||||
yRow += 4;
|
||||
}
|
||||
this["drawHeight"] = image.height / nDirections / 2;
|
||||
this["drawWidth"] = image.width / nFrames;
|
||||
var drawX = ((this["width"] * 32) - this["drawWidth"]) / 2;
|
||||
var frame = 0;
|
||||
if (this["speed"] > 0) {
|
||||
// % Works normally with *floats* (just whose bright idea was
|
||||
// that?), so use floor() as a workaround
|
||||
frame = Math.floor(Date.now() / 100) % nFrames;
|
||||
}
|
||||
var drawY = (this["height"] * 32) - this["drawHeight"];
|
||||
ctx.drawImage(image, frame * this["drawWidth"], yRow * this["drawHeight"], this["drawWidth"], this["drawHeight"], localX + drawX, localY + drawY, this["drawWidth"], this["drawHeight"]);
|
||||
}
|
||||
this["drawHeight"] = image.height / nDirections / 2;
|
||||
this["drawWidth"] = image.width / nFrames;
|
||||
let drawX = ((this["width"] * 32) - this["drawWidth"]) / 2;
|
||||
let frame = 0;
|
||||
if (this["speed"] > 0) {
|
||||
// % Works normally with *floats* (just whose bright idea was
|
||||
// that?), so use floor() as a workaround
|
||||
frame = Math.floor(Date.now() / 100) % nFrames;
|
||||
}
|
||||
let drawY = (this["height"] * 32) - this["drawHeight"];
|
||||
ctx.drawImage(image, frame * this["drawWidth"], yRow * this["drawHeight"], this["drawWidth"], this["drawHeight"], localX + drawX, localY + drawY, this["drawWidth"], this["drawHeight"]);
|
||||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/look.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/look.png) 1 3, auto";
|
||||
}
|
||||
|
||||
override buildActions(list: MenuItem[]) {
|
||||
|
|
|
|||
|
|
@ -9,45 +9,32 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { RenderingContext2D } from "util/Types";
|
||||
import { MenuItem } from "../action/MenuItem";
|
||||
import { Portal } from "./Portal";
|
||||
import { Paths } from "../data/Paths";
|
||||
import { ImageSprite } from "sprite/image/ImageSprite";
|
||||
import { images } from "sprite/image/ImageManager";
|
||||
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
export class Door extends Portal {
|
||||
|
||||
override zIndex = 5000;
|
||||
|
||||
override set(key: string, value: any) {
|
||||
super.set(key, value);
|
||||
if (key === "class") {
|
||||
if (this.imageSprite) {
|
||||
this.imageSprite?.free();
|
||||
this.imageSprite = new ImageSprite(
|
||||
images.load(Paths.sprites + "/doors/" + value + ".png"),
|
||||
0, 0, 0, 0);
|
||||
override draw(ctx: CanvasRenderingContext2D) {
|
||||
let imagePath = stendhal.paths.sprites + "/doors/" + this["class"] + ".png";
|
||||
let image = stendhal.data.sprites.get(imagePath);
|
||||
if (image.height) {
|
||||
let height = image.height / 2;
|
||||
let x = (this["x"] * 32) - ((image.width - 32) / 2);
|
||||
let y = (this["y"] * 32) - ((height - 32) / 2);
|
||||
|
||||
var offsetY = height;
|
||||
if (this["open"] === "") {
|
||||
offsetY = 0;
|
||||
}
|
||||
ctx.drawImage(image, 0, offsetY, image.width, height, x, y, image.width, height);
|
||||
}
|
||||
}
|
||||
|
||||
override draw(ctx: RenderingContext2D) {
|
||||
let image = this.imageSprite?.imageRef?.image;
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
let height = image.height / 2;
|
||||
let x = (this["x"] * 32) - ((image.width - 32) / 2);
|
||||
let y = (this["y"] * 32) - ((height - 32) / 2);
|
||||
|
||||
let offsetY = height;
|
||||
if (this["open"] === "") {
|
||||
offsetY = 0;
|
||||
}
|
||||
ctx.drawImage(image, 0, offsetY, image.width, height, x, y, image.width, height);
|
||||
}
|
||||
|
||||
override buildActions(list: MenuItem[]) {
|
||||
list.push({
|
||||
title: "Look",
|
||||
|
|
@ -64,7 +51,7 @@ export class Door extends Portal {
|
|||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/portal.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/portal.png) 1 3, auto";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2003-2026 - Stendhal *
|
||||
* (C) Copyright 2003-2024 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
|
@ -9,17 +9,12 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { RPObject, RPZone } from "marauroa";
|
||||
import { RenderingContext2D } from "util/Types";
|
||||
import { MenuItem } from "../action/MenuItem";
|
||||
import { Paths } from "../data/Paths";
|
||||
import { Chat } from "../util/Chat";
|
||||
import { RPObject } from "./RPObject";
|
||||
|
||||
import { htmlImageStore } from "data/HTMLImageStore";
|
||||
import { marauroa } from "marauroa";
|
||||
import { HTMLUtil } from "ui/HTMLUtil";
|
||||
import { ViewPort } from "ui/ViewPort";
|
||||
import { ImageSprite } from "../sprite/image/ImageSprite";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
/**
|
||||
* General entity
|
||||
|
|
@ -30,7 +25,6 @@ export class Entity extends RPObject {
|
|||
minimapShow = false;
|
||||
minimapStyle = "rgb(200,255,200)";
|
||||
zIndex = 10000;
|
||||
imageSprite?: ImageSprite;
|
||||
|
||||
override set(key: string, value: any) {
|
||||
super.set(key, value);
|
||||
|
|
@ -143,10 +137,10 @@ export class Entity extends RPObject {
|
|||
/**
|
||||
* is this entity visible to a specific action
|
||||
*
|
||||
* @param _filter 0: short left click
|
||||
* @param filter 0: short left click
|
||||
* @return true, if the entity is visible, false otherwise
|
||||
*/
|
||||
isVisibleToAction(_filter?: boolean) {
|
||||
isVisibleToAction(filter: boolean) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -185,7 +179,7 @@ export class Entity extends RPObject {
|
|||
// action replaces "Look" command (e. g. "look closely" on signs)
|
||||
if (this["action"]) {
|
||||
list.push({
|
||||
title: HTMLUtil.niceName(this["action"]),
|
||||
title: stendhal.ui.html.niceName(this["action"]),
|
||||
type: this.actionAliasToAction(this["action"])
|
||||
});
|
||||
} else {
|
||||
|
|
@ -210,8 +204,8 @@ export class Entity extends RPObject {
|
|||
this["_x"] = this["x"];
|
||||
}
|
||||
|
||||
draw(ctx: RenderingContext2D) {
|
||||
if (this.sprite || this.imageSprite) {
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
if (this.sprite) {
|
||||
this.drawSprite(ctx);
|
||||
}
|
||||
}
|
||||
|
|
@ -219,27 +213,23 @@ export class Entity extends RPObject {
|
|||
/**
|
||||
* draws a standard sprite
|
||||
*/
|
||||
drawSprite(ctx: RenderingContext2D) {
|
||||
drawSprite(ctx: CanvasRenderingContext2D) {
|
||||
this.drawSpriteAt(ctx, this["x"] * 32, this["y"] * 32);
|
||||
}
|
||||
|
||||
drawSpriteAt(ctx: RenderingContext2D, x: number, y: number) {
|
||||
if (this.imageSprite) {
|
||||
this.imageSprite.drawOnto(ctx, x, y, this.getWidth() * 32, this.getHeight() * 32);
|
||||
} else {
|
||||
let image = htmlImageStore.get(this.sprite.filename);
|
||||
if (image.height) {
|
||||
let offsetX = this.sprite.offsetX || 0;
|
||||
let offsetY = this.sprite.offsetY || 0;
|
||||
let width = this.sprite.width || image.width;
|
||||
let height = this.sprite.height || image.height;
|
||||
drawSpriteAt(ctx: CanvasRenderingContext2D, x: number, y: number) {
|
||||
var image = stendhal.data.sprites.get(this.sprite.filename);
|
||||
if (image.height) {
|
||||
var offsetX = this.sprite.offsetX || 0;
|
||||
var offsetY = this.sprite.offsetY || 0;
|
||||
var width = this.sprite.width || image.width;
|
||||
var height = this.sprite.height || image.height;
|
||||
|
||||
// use entity dimensions to center sprite
|
||||
x += Math.floor((this.getWidth() * 32 - width) / 2);
|
||||
y += Math.floor((this.getHeight() * 32 - height) / 2);
|
||||
|
||||
ctx.drawImage(image, offsetX, offsetY, width, height, x, y, width, height);
|
||||
}
|
||||
// use entity dimensions to center sprite
|
||||
x += Math.floor((this.getWidth() * 32 - width) / 2);
|
||||
y += Math.floor((this.getHeight() * 32 - height) / 2);
|
||||
|
||||
ctx.drawImage(image, offsetX, offsetY, width, height, x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -284,7 +274,7 @@ export class Entity extends RPObject {
|
|||
cursor = this["cursor"];
|
||||
}
|
||||
|
||||
return "url(" + Paths.sprites + "/cursor/" + cursor.toLowerCase().replace("_", "") + ".png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/" + cursor.toLowerCase().replace("_", "") + ".png) 1 3, auto";
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -330,17 +320,16 @@ export class Entity extends RPObject {
|
|||
* Checks if within vieport area.
|
||||
*/
|
||||
public inView(): boolean {
|
||||
let viewPort = ViewPort.get();
|
||||
const view_rect: any = {};
|
||||
view_rect.left = viewPort.offsetX;
|
||||
view_rect.right = view_rect.left + viewPort.width;
|
||||
view_rect.top = viewPort.offsetY;
|
||||
view_rect.bottom = view_rect.top + viewPort.height;
|
||||
view_rect.left = stendhal.ui.gamewindow.offsetX;
|
||||
view_rect.right = view_rect.left + stendhal.ui.gamewindow.width;
|
||||
view_rect.top = stendhal.ui.gamewindow.offsetY;
|
||||
view_rect.bottom = view_rect.top + stendhal.ui.gamewindow.height;
|
||||
|
||||
const pixelX = this["x"] * viewPort.targetTileWidth
|
||||
+ Math.floor(viewPort.targetTileWidth / 2);
|
||||
const pixelY = this["y"] * viewPort.targetTileHeight
|
||||
+ Math.floor(viewPort.targetTileHeight / 2);
|
||||
const pixelX = this["x"] * stendhal.ui.gamewindow.targetTileWidth
|
||||
+ Math.floor(stendhal.ui.gamewindow.targetTileWidth / 2);
|
||||
const pixelY = this["y"] * stendhal.ui.gamewindow.targetTileHeight
|
||||
+ Math.floor(stendhal.ui.gamewindow.targetTileHeight / 2);
|
||||
|
||||
const ent_rect: any = {};
|
||||
// horizontal orientation is centered
|
||||
|
|
@ -353,8 +342,4 @@ export class Entity extends RPObject {
|
|||
return ent_rect.right > view_rect.left && ent_rect.left < view_rect.right
|
||||
&& ent_rect.bottom > view_rect.top && ent_rect.top < view_rect.bottom
|
||||
}
|
||||
|
||||
override destroy(_parent: RPObject|RPZone) {
|
||||
this.imageSprite?.free();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2003-2026 - Stendhal *
|
||||
* (C) Copyright 2003-2023 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
declare var marauroa: any;
|
||||
|
||||
import { Blood } from "./Blood";
|
||||
import { Chest} from "./Chest";
|
||||
|
|
@ -35,46 +35,41 @@ import { User } from "./User";
|
|||
import { VisibleEntity } from "./VisibleEntity";
|
||||
import { WalkBlocker } from "./WalkBlocker";
|
||||
|
||||
export class EntityRegistry {
|
||||
|
||||
public init() {
|
||||
marauroa.rpobjectFactory.register("area", InvisibleEntity);
|
||||
marauroa.rpobjectFactory.register("baby_dragon", DomesticAnimal);
|
||||
marauroa.rpobjectFactory.register("blackboard", Sign);
|
||||
marauroa.rpobjectFactory.register("blocktarget", InvisibleEntity);
|
||||
marauroa.rpobjectFactory.register("block", VisibleEntity);
|
||||
marauroa.rpobjectFactory.register("blood", Blood);
|
||||
marauroa.rpobjectFactory.register("cat", DomesticAnimal);
|
||||
marauroa.rpobjectFactory.register("chest", Chest);
|
||||
marauroa.rpobjectFactory.register("corpse", Corpse);
|
||||
marauroa.rpobjectFactory.register("creature", Creature);
|
||||
marauroa.rpobjectFactory.register("_default", UnknownEntity);
|
||||
marauroa.rpobjectFactory.register("domesticanimal", DomesticAnimal);
|
||||
marauroa.rpobjectFactory.register("door", Door);
|
||||
marauroa.rpobjectFactory.register("flyover", InvisibleEntity);
|
||||
marauroa.rpobjectFactory.register("food", Food);
|
||||
marauroa.rpobjectFactory.register("game_board", GameBoard);
|
||||
marauroa.rpobjectFactory.register("gate", Gate);
|
||||
marauroa.rpobjectFactory.register("growing_entity_spawner", GrowingEntitySpawner);
|
||||
marauroa.rpobjectFactory.register("house_portal", Portal);
|
||||
marauroa.rpobjectFactory.register("invisible_entity", InvisibleEntity);
|
||||
marauroa.rpobjectFactory.register("item", Item);
|
||||
marauroa.rpobjectFactory.register("looped_sound_source", LoopedSoundSource);
|
||||
marauroa.rpobjectFactory.register("npc", NPC);
|
||||
marauroa.rpobjectFactory.register("plant_grower", VisibleEntity);
|
||||
marauroa.rpobjectFactory.register("player", Player);
|
||||
marauroa.rpobjectFactory.register("portal", Portal);
|
||||
marauroa.rpobjectFactory.register("rented_sign", Sign);
|
||||
marauroa.rpobjectFactory.register("sheep", DomesticAnimal);
|
||||
marauroa.rpobjectFactory.register("sign", Sign);
|
||||
marauroa.rpobjectFactory.register("tiled_entity", InvisibleEntity);
|
||||
marauroa.rpobjectFactory.register("training_dummy", TrainingDummy);
|
||||
marauroa.rpobjectFactory.register("unknown", UnknownEntity);
|
||||
marauroa.rpobjectFactory.register("useable_entity", UseableEntity);
|
||||
marauroa.rpobjectFactory.register("user", User);
|
||||
marauroa.rpobjectFactory.register("visible_entity", VisibleEntity);
|
||||
marauroa.rpobjectFactory.register("walkblocker", WalkBlocker);
|
||||
marauroa.rpobjectFactory.register("wall", InvisibleEntity);
|
||||
marauroa.rpobjectFactory.register("weather_entity", InvisibleEntity);
|
||||
}
|
||||
}
|
||||
marauroa.rpobjectFactory["area"] = InvisibleEntity;
|
||||
marauroa.rpobjectFactory["baby_dragon"] = DomesticAnimal;
|
||||
marauroa.rpobjectFactory["blackboard"] = Sign;
|
||||
marauroa.rpobjectFactory["blocktarget"] = InvisibleEntity;
|
||||
marauroa.rpobjectFactory["block"] = VisibleEntity;
|
||||
marauroa.rpobjectFactory["blood"] = Blood;
|
||||
marauroa.rpobjectFactory["cat"] = DomesticAnimal;
|
||||
marauroa.rpobjectFactory["chest"] = Chest;
|
||||
marauroa.rpobjectFactory["corpse"] = Corpse;
|
||||
marauroa.rpobjectFactory["creature"] = Creature;
|
||||
marauroa.rpobjectFactory["_default"] = UnknownEntity;
|
||||
marauroa.rpobjectFactory["domesticanimal"] = DomesticAnimal;
|
||||
marauroa.rpobjectFactory["door"] = Door;
|
||||
marauroa.rpobjectFactory["flyover"] = InvisibleEntity;
|
||||
marauroa.rpobjectFactory["food"] = Food;
|
||||
marauroa.rpobjectFactory["game_board"] = GameBoard;
|
||||
marauroa.rpobjectFactory["gate"] = Gate
|
||||
marauroa.rpobjectFactory["growing_entity_spawner"] = GrowingEntitySpawner;
|
||||
marauroa.rpobjectFactory["house_portal"] = Portal;
|
||||
marauroa.rpobjectFactory["invisible_entity"] = InvisibleEntity;
|
||||
marauroa.rpobjectFactory["item"] = Item;
|
||||
marauroa.rpobjectFactory["looped_sound_source"] = LoopedSoundSource;
|
||||
marauroa.rpobjectFactory["npc"] = NPC;
|
||||
marauroa.rpobjectFactory["plant_grower"] = VisibleEntity;
|
||||
marauroa.rpobjectFactory["player"] = Player;
|
||||
marauroa.rpobjectFactory["portal"] = Portal;
|
||||
marauroa.rpobjectFactory["rented_sign"] = Sign;
|
||||
marauroa.rpobjectFactory["sheep"] = DomesticAnimal;
|
||||
marauroa.rpobjectFactory["sign"] = Sign;
|
||||
marauroa.rpobjectFactory["tiled_entity"] = InvisibleEntity;
|
||||
marauroa.rpobjectFactory["training_dummy"] = TrainingDummy;
|
||||
marauroa.rpobjectFactory["unknown"] = UnknownEntity;
|
||||
marauroa.rpobjectFactory["useable_entity"] = UseableEntity;
|
||||
marauroa.rpobjectFactory["user"] = User;
|
||||
marauroa.rpobjectFactory["visible_entity"] = VisibleEntity;
|
||||
marauroa.rpobjectFactory["walkblocker"] = WalkBlocker;
|
||||
marauroa.rpobjectFactory["wall"] = InvisibleEntity;
|
||||
marauroa.rpobjectFactory["weather_entity"] = InvisibleEntity;
|
||||
|
|
|
|||
|
|
@ -10,33 +10,33 @@
|
|||
***************************************************************************/
|
||||
|
||||
import { Entity } from "./Entity";
|
||||
import { Paths } from "../data/Paths";
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
import { ImageSprite } from "sprite/image/ImageSprite";
|
||||
import { images } from "sprite/image/ImageManager";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
export class Food extends Entity {
|
||||
|
||||
override zIndex = 5000;
|
||||
|
||||
override init() {
|
||||
this.imageSprite = new ImageSprite(
|
||||
images.load(Paths.sprites + "/food.png"),
|
||||
0, this["amount"] * 32, 32, 32);
|
||||
}
|
||||
|
||||
override set(key: string, value: any) {
|
||||
super.set(key, value);
|
||||
if (key === "amount") {
|
||||
if (this.imageSprite) {
|
||||
this.imageSprite.offsetY = this["amount"] * 32;
|
||||
}
|
||||
this._amount = parseInt(value, 10);
|
||||
}
|
||||
// TODO: play sound effect
|
||||
}
|
||||
|
||||
override draw(ctx: CanvasRenderingContext2D) {
|
||||
var image = stendhal.data.sprites.get(stendhal.paths.sprites + "/food.png");
|
||||
if (image.height) {
|
||||
var localX = this["x"] * 32;
|
||||
var localY = this["y"] * 32;
|
||||
var offset = this._amount * 32;
|
||||
ctx.drawImage(image, 0, offset, 32, 32, localX, localY, 32, 32);
|
||||
}
|
||||
}
|
||||
|
||||
override onclick(_x: number, _y: number) {
|
||||
var action = {
|
||||
"type": "look",
|
||||
|
|
@ -50,7 +50,7 @@ export class Food extends Entity {
|
|||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/look.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/look.png) 1 3, auto";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,24 +9,28 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { Paths } from "../data/Paths";
|
||||
import { Entity } from "./Entity";
|
||||
|
||||
import { stendhal } from "../stendhal";
|
||||
import { ImageSprite } from "sprite/image/ImageSprite";
|
||||
import { images } from "sprite/image/ImageManager";
|
||||
declare var stendhal: any;
|
||||
|
||||
export class GameBoard extends Entity {
|
||||
|
||||
override minimapShow = false;
|
||||
override zIndex = 100;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.sprite = {
|
||||
height: 32 * 3,
|
||||
width: 32 * 3
|
||||
};
|
||||
}
|
||||
|
||||
override set(key: string, value: any) {
|
||||
super.set(key, value);
|
||||
if (key === "class") {
|
||||
let filename = Paths.sprites + "/gameboard/" + this["class"] + ".png";
|
||||
this.imageSprite?.free();
|
||||
this.imageSprite = new ImageSprite(images.load(filename), 0, 0, 3*32, 3*32);
|
||||
this.sprite.filename = stendhal.paths.sprites + "/gameboard/"
|
||||
+ this["class"] + ".png";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -35,7 +39,7 @@ export class GameBoard extends Entity {
|
|||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/walk.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/walk.png) 1 3, auto";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,45 +9,30 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { RenderingContext2D } from "util/Types";
|
||||
import { MenuItem } from "../action/MenuItem";
|
||||
import { Entity } from "./Entity";
|
||||
import { Paths } from "../data/Paths";
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
import { images } from "sprite/image/ImageManager";
|
||||
import { ImageSprite } from "sprite/image/ImageSprite";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
export class Gate extends Entity {
|
||||
|
||||
override zIndex = 5000;
|
||||
private locked = false;
|
||||
|
||||
override init() {
|
||||
this.imageSprite?.free();
|
||||
this.imageSprite = new ImageSprite(
|
||||
images.load(Paths.sprites + "/doors/" + this["image"] + "_" + this["orientation"] + ".png"),
|
||||
0, 0, 0, 0);
|
||||
}
|
||||
|
||||
override set(key: string, value: any) {
|
||||
super.set(key, value);
|
||||
if (key === "resistance") {
|
||||
this.locked = parseInt(value, 10) !== 0;
|
||||
this["locked"] = parseInt(value, 10) !== 0;
|
||||
} else if (key === "image" || key === "orientation") {
|
||||
if (this.imageSprite) {
|
||||
this.imageSprite?.free();
|
||||
this.imageSprite = new ImageSprite(
|
||||
images.load(Paths.sprites + "/doors/" + this["image"] + "_" + this["orientation"] + ".png"),
|
||||
0, 0, 0, 0);
|
||||
}
|
||||
// Force re-evaluation of the sprite
|
||||
delete this["_image"];
|
||||
}
|
||||
}
|
||||
|
||||
override buildActions(list: MenuItem[]) {
|
||||
var id = this["id"];
|
||||
list.push({
|
||||
title: (this.locked) ? "Open" : "Close",
|
||||
title: (this["locked"]) ? "Open" : "Close",
|
||||
action: function(_entity: Entity) {
|
||||
var action = {
|
||||
"type": "use",
|
||||
|
|
@ -59,18 +44,20 @@ export class Gate extends Entity {
|
|||
});
|
||||
}
|
||||
|
||||
override draw(ctx: RenderingContext2D) {
|
||||
let image = this.imageSprite?.imageRef?.image;
|
||||
if (!image) {
|
||||
return;
|
||||
override draw(ctx: CanvasRenderingContext2D) {
|
||||
if (this._image == undefined) {
|
||||
var filename = stendhal.paths.sprites + "/doors/" + this["image"] + "_" + this["orientation"] + ".png";
|
||||
this._image = stendhal.data.sprites.get(filename);
|
||||
}
|
||||
if (this._image.height) {
|
||||
var xOffset = -32 * Math.floor(this._image.width / 32 / 2);
|
||||
var height = this._image.height / 2;
|
||||
var yOffset = -32 * Math.floor(height / 32 / 2);
|
||||
var localX = this["_x"] * 32 + xOffset;
|
||||
var localY = this["_y"] * 32 + yOffset;
|
||||
var yStart = (this["locked"]) ? height : 0;
|
||||
ctx.drawImage(this._image, 0, yStart, this._image.width, height, localX, localY, this._image.width, height);
|
||||
}
|
||||
let xOffset = -32 * Math.floor(image.width / 32 / 2);
|
||||
let height = image.height / 2;
|
||||
let yOffset = -32 * Math.floor(height / 32 / 2);
|
||||
let localX = this["_x"] * 32 + xOffset;
|
||||
let localY = this["_y"] * 32 + yOffset;
|
||||
let yStart = (this.locked) ? height : 0;
|
||||
ctx.drawImage(image, 0, yStart, image.width, height, localX, localY, image.width, height);
|
||||
}
|
||||
|
||||
override isVisibleToAction(_filter: boolean) {
|
||||
|
|
@ -87,7 +74,7 @@ export class Gate extends Entity {
|
|||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/activity.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/activity.png) 1 3, auto";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,12 +9,8 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { Paths } from "../data/Paths";
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
import { stendhal } from "../stendhal";
|
||||
import { TileMap } from "data/TileMap";
|
||||
import { ViewPort } from "ui/ViewPort";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -35,42 +31,39 @@ export class Ground {
|
|||
* @return Direction of the zone to change to, <code>null</code> if no zone change should happen
|
||||
*/
|
||||
private calculateZoneChangeDirection(x: number, y: number): string|null {
|
||||
let map = TileMap.get();
|
||||
if (x < 15) {
|
||||
return "4"; // LEFT
|
||||
}
|
||||
if (x > map.zoneSizeX * 32 - 15) {
|
||||
if (x > stendhal.data.map.zoneSizeX * 32 - 15) {
|
||||
return "2"; // RIGHT
|
||||
}
|
||||
if (y < 15) {
|
||||
return "1"; // UP
|
||||
}
|
||||
if (y > map.zoneSizeY * 32 - 15) {
|
||||
if (y > stendhal.data.map.zoneSizeY * 32 - 15) {
|
||||
return "3"; // DOWN
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
getCursor(x: number, y: number): string {
|
||||
let map = TileMap.get();
|
||||
if ((x < 15) || (y < 15) || (x > map.zoneSizeX * 32 - 15) || (y > map.zoneSizeY * 32 - 15)) {
|
||||
return "url(" + Paths.sprites + "/cursor/walkborder.png) 1 3, auto"
|
||||
if ((x < 15) || (y < 15) || (x > stendhal.data.map.zoneSizeX * 32 - 15) || (y > stendhal.data.map.zoneSizeY * 32 - 15)) {
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/walkborder.png) 1 3, auto"
|
||||
}
|
||||
var worldX = Math.floor(x / 32);
|
||||
var worldY = Math.floor(y / 32);
|
||||
if (map.collision(worldX, worldY)) {
|
||||
return "url(" + Paths.sprites + "/cursor/stop.png) 1 3, auto";
|
||||
if (stendhal.data.map.collision(worldX, worldY)) {
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/stop.png) 1 3, auto";
|
||||
}
|
||||
return "url(" + Paths.sprites + "/cursor/walk.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/walk.png) 1 3, auto";
|
||||
}
|
||||
|
||||
onclick(x: number, y: number, dblclick: boolean) {
|
||||
if (!stendhal.config.getBoolean("pathfinding")) {
|
||||
return;
|
||||
}
|
||||
let viewPort = ViewPort.get();
|
||||
var gameX = x + viewPort.offsetX;
|
||||
var gameY = y + viewPort.offsetY;
|
||||
var gameX = x + stendhal.ui.gamewindow.offsetX;
|
||||
var gameY = y + stendhal.ui.gamewindow.offsetY;
|
||||
var action = {
|
||||
"type": "moveto",
|
||||
"x": "" + Math.floor(gameX / 32),
|
||||
|
|
|
|||
|
|
@ -9,33 +9,16 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { RenderingContext2D } from "util/Types";
|
||||
import { MenuItem } from "../action/MenuItem";
|
||||
import { Entity } from "./Entity";
|
||||
import { Paths } from "../data/Paths";
|
||||
import { singletons } from "../SingletonRepo";
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
import { ImageSprite } from "sprite/image/ImageSprite";
|
||||
import { images } from "sprite/image/ImageManager";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
export class GrowingEntitySpawner extends Entity {
|
||||
override zIndex = 3000;
|
||||
|
||||
|
||||
override set(key: string, value: any) {
|
||||
super.set(key, value);
|
||||
if (key === "class") {
|
||||
this.imageSprite?.free();
|
||||
let className = value.replace(" ", "_");
|
||||
this.imageSprite = new ImageSprite(
|
||||
images.load(Paths.sprites + "/" + className + ".png"),
|
||||
0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* is this entity visible to a specific action
|
||||
*
|
||||
|
|
@ -65,23 +48,34 @@ export class GrowingEntitySpawner extends Entity {
|
|||
marauroa.clientFramework.sendAction(action);
|
||||
}
|
||||
|
||||
override draw(ctx: RenderingContext2D) {
|
||||
let localX = this["x"] * 32;
|
||||
let localY = this["y"] * 32;
|
||||
let image = this.imageSprite?.imageRef?.image;
|
||||
if (!image) {
|
||||
return;
|
||||
/**
|
||||
* draw RPEntities
|
||||
*/
|
||||
override draw(ctx: CanvasRenderingContext2D) {
|
||||
var localX = this["x"] * 32;
|
||||
var localY = this["y"] * 32;
|
||||
|
||||
// FIXME:
|
||||
// temporary fix, problem lies higher up
|
||||
// appears to only affect button_mushroom_grower
|
||||
// could be issue in marauroa
|
||||
let class_name = this["class"];
|
||||
if (class_name.includes(" ")) {
|
||||
class_name = class_name.replace(" ", "_");
|
||||
}
|
||||
|
||||
let count = parseInt(this["max_ripeness"], 10) + 1;
|
||||
let drawHeight = image.height / count;
|
||||
let yRow = this["ripeness"];
|
||||
ctx.drawImage(image, 0, yRow * drawHeight, image.width, drawHeight,
|
||||
var image = stendhal.data.sprites.get(stendhal.paths.sprites + "/" + class_name + ".png");
|
||||
if (image.height) { // image.complete is true on missing image files
|
||||
var count = parseInt(this["max_ripeness"], 10) + 1;
|
||||
var drawHeight = image.height / count;
|
||||
var yRow = this["ripeness"];
|
||||
ctx.drawImage(image, 0, yRow * drawHeight, image.width, drawHeight,
|
||||
localX, localY - drawHeight + 32, image.width, drawHeight);
|
||||
}
|
||||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/harvest.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/harvest.png) 1 3, auto";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,10 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { Paths } from "../data/Paths";
|
||||
import { Entity } from "./Entity";
|
||||
|
||||
declare var stendhal: any;
|
||||
|
||||
export class InvisibleEntity extends Entity {
|
||||
|
||||
override isVisibleToAction(_filter: boolean) {
|
||||
|
|
@ -19,7 +20,7 @@ export class InvisibleEntity extends Entity {
|
|||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/walk.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/walk.png) 1 3, auto";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2003-2026 - Stendhal *
|
||||
* (C) Copyright 2003-2023 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
|
@ -9,16 +9,14 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { RenderingContext2D } from "util/Types";
|
||||
import { MenuItem } from "../action/MenuItem";
|
||||
import { Paths } from "../data/Paths";
|
||||
import { TextSprite } from "../sprite/TextSprite";
|
||||
import { Entity } from "./Entity";
|
||||
import { ItemMap } from "./ItemMap";
|
||||
import { MenuItem } from "../action/MenuItem";
|
||||
import { Entity } from "./Entity";
|
||||
import { TextSprite } from "../sprite/TextSprite";
|
||||
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
import { marauroa } from "marauroa";
|
||||
import { images } from "sprite/image/ImageManager";
|
||||
import { ImageSprite } from "sprite/image/ImageSprite";
|
||||
|
||||
export class Item extends Entity {
|
||||
|
||||
|
|
@ -30,10 +28,15 @@ export class Item extends Entity {
|
|||
// animation
|
||||
private frameTimeStamp = 0;
|
||||
private animated: boolean|null = null;
|
||||
|
||||
private xFrames: number|null = null;
|
||||
private yFrames: number|null = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.sprite = {
|
||||
height: 32,
|
||||
width: 32
|
||||
};
|
||||
this.quantityTextSprite = new TextSprite("", "white", "10px sans-serif");
|
||||
}
|
||||
|
||||
|
|
@ -69,50 +72,36 @@ export class Item extends Entity {
|
|||
override set(key: string, value: any) {
|
||||
super.set(key, value);
|
||||
if (key === "class" || key === "subclass") {
|
||||
if (this["class"] && this["subclass"]) {
|
||||
this.imageSprite?.free();
|
||||
this.imageSprite = new ImageSprite(
|
||||
images.load(Paths.sprites + "/items/" + this["class"] + "/" + this["subclass"] + ".png"),
|
||||
0, (this["state"] || 0) * 32, 32, 32);
|
||||
}
|
||||
} else if (key === "state") {
|
||||
if (this.imageSprite) {
|
||||
this.imageSprite.offsetY = (this["state"] || 0) * 32
|
||||
}
|
||||
} else if (key === "quantity") {
|
||||
this.sprite.filename = stendhal.paths.sprites + "/items/"
|
||||
+ this["class"] + "/" + this["subclass"] + ".png";
|
||||
}
|
||||
if (key === "quantity") {
|
||||
this.quantityTextSprite = new TextSprite(this.formatQuantity(), "white", "10px sans-serif");
|
||||
}
|
||||
}
|
||||
|
||||
override draw(ctx: RenderingContext2D) {
|
||||
override draw(ctx: CanvasRenderingContext2D) {
|
||||
this.sprite.offsetY = (this["state"] || 0) * 32
|
||||
this.stepAnimation();
|
||||
|
||||
this.drawAt(ctx, this["x"] * 32, this["y"] * 32);
|
||||
}
|
||||
|
||||
drawAt(ctx: RenderingContext2D, x: number, y: number) {
|
||||
let image = this.imageSprite?.imageRef?.image;
|
||||
if (!image) {
|
||||
return;
|
||||
drawAt(ctx: CanvasRenderingContext2D, x: number, y: number) {
|
||||
if (this.sprite) {
|
||||
this.drawSpriteAt(ctx, x, y);
|
||||
let textMetrics = this.quantityTextSprite.getTextMetrics(ctx);
|
||||
this.quantityTextSprite.draw(ctx, x + (32 - textMetrics.width), y + 6);
|
||||
}
|
||||
this.drawSpriteAt(ctx, x, y);
|
||||
let textMetrics = this.quantityTextSprite.getTextMetrics(ctx);
|
||||
if (!textMetrics) {
|
||||
throw new Error("textMetrics is undefined");
|
||||
}
|
||||
this.quantityTextSprite.draw(ctx, x + (32 - textMetrics.width), y + 6);
|
||||
}
|
||||
|
||||
public stepAnimation() {
|
||||
let image = this.imageSprite?.imageRef?.image;
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
const currentTimeStamp = +new Date();
|
||||
// if (this.frameTimeStamp == 0) {
|
||||
// this.frameTimeStamp = currentTimeStamp;
|
||||
// this.imageSprite?.offsetX = 0;
|
||||
// }
|
||||
if (currentTimeStamp - this.frameTimeStamp >= 100) {
|
||||
if (this.frameTimeStamp == 0) {
|
||||
this.frameTimeStamp = currentTimeStamp;
|
||||
this.sprite.offsetX = 0;
|
||||
this.sprite.offsetY = 0;
|
||||
} else if (currentTimeStamp - this.frameTimeStamp >= 100) {
|
||||
// FIXME: need proper FPS limit
|
||||
this.setXFrameIndex(this.getXFrameIndex() + 1);
|
||||
this.frameTimeStamp = currentTimeStamp;
|
||||
|
|
@ -139,7 +128,7 @@ export class Item extends Entity {
|
|||
} else {
|
||||
cursor = ItemMap.getCursor(this["class"], this["name"]);
|
||||
}
|
||||
return "url(" + Paths.sprites + "/cursor/" + cursor + ".png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/" + cursor + ".png) 1 3, auto";
|
||||
}
|
||||
|
||||
public getToolTip(): string {
|
||||
|
|
@ -153,31 +142,51 @@ export class Item extends Entity {
|
|||
}
|
||||
|
||||
public isAnimated(): boolean {
|
||||
if (this.animated === null) {
|
||||
let image = this.imageSprite?.imageRef?.image
|
||||
if (image) {
|
||||
this.animated = (image.width / 32) > 1;
|
||||
}
|
||||
if (!stendhal.data.sprites.get(this.sprite.filename).height) {
|
||||
return false;
|
||||
}
|
||||
return this.animated || false;
|
||||
if (this.animated == null) {
|
||||
// store animation state
|
||||
this.animated = (stendhal.data.sprites.get(this.sprite.filename).width / 32) > 1;
|
||||
}
|
||||
|
||||
return this.animated;
|
||||
}
|
||||
|
||||
private setXFrameIndex(idx: number) {
|
||||
let image = this.imageSprite?.imageRef.image
|
||||
if (!image) {
|
||||
return;
|
||||
if (this.xFrames == null) {
|
||||
const img = stendhal.data.sprites.get(this.sprite.filename);
|
||||
this.xFrames = img.width / 32;
|
||||
}
|
||||
let frames = image.width / 32;
|
||||
if (idx >= frames) {
|
||||
|
||||
if (idx >= this.xFrames) {
|
||||
// restart
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
this.imageSprite!.offsetX = idx * 32;
|
||||
this.sprite.offsetX = idx * 32;
|
||||
}
|
||||
|
||||
private setYFrameIndex(idx: number) {
|
||||
if (this.yFrames == null) {
|
||||
const img = stendhal.data.sprites.get(this.sprite.filename);
|
||||
this.yFrames = img.height / 32;
|
||||
}
|
||||
|
||||
if (idx >= this.yFrames) {
|
||||
// restart
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
this.sprite.offsetY = idx * 32;
|
||||
}
|
||||
|
||||
public getXFrameIndex(): number {
|
||||
return (this.imageSprite?.offsetX || 0) / 32;
|
||||
return (this.sprite.offsetX || 0) / 32;
|
||||
}
|
||||
|
||||
public getYFrameIndex(): number {
|
||||
return (this.sprite.offsetY || 0) / 32;
|
||||
}
|
||||
|
||||
public override isDraggable(): boolean {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import { MenuItem } from "../action/MenuItem";
|
|||
|
||||
const config = singletons.getConfigManager();
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
declare var marauroa: any;
|
||||
|
||||
const defaultUse = {
|
||||
title: "Use",
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ import { RPEntity } from "./RPEntity";
|
|||
import { EntityOverlayRegistry } from "../data/EntityOverlayRegistry";
|
||||
|
||||
import { Color } from "../data/color/Color";
|
||||
import { RenderingContext2D } from "util/Types";
|
||||
import { Paths } from "../data/Paths";
|
||||
|
||||
declare var stendhal: any;
|
||||
|
||||
export class NPC extends RPEntity {
|
||||
override minimapStyle = Color.NPC;
|
||||
|
|
@ -28,7 +28,7 @@ export class NPC extends RPEntity {
|
|||
this["base_hp"] = 100;
|
||||
}
|
||||
|
||||
override set(key: string, value: any) {
|
||||
override set(key: string, value: string) {
|
||||
super.set(key, value);
|
||||
|
||||
if (key === "name") {
|
||||
|
|
@ -42,7 +42,7 @@ export class NPC extends RPEntity {
|
|||
}
|
||||
}
|
||||
|
||||
override drawTop(ctx: RenderingContext2D) {
|
||||
override drawTop(ctx: CanvasRenderingContext2D) {
|
||||
var localX = this["_x"] * 32;
|
||||
var localY = this["_y"] * 32;
|
||||
if (typeof(this["no_hpbar"]) == "undefined") {
|
||||
|
|
@ -54,7 +54,7 @@ export class NPC extends RPEntity {
|
|||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/look.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/look.png) 1 3, auto";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
import { stendhal } from "../stendhal";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
import { RPEntity } from "./RPEntity";
|
||||
|
||||
|
|
@ -22,8 +22,6 @@ import { UIComponentEnum } from "../ui/UIComponentEnum";
|
|||
import { GroupPanelComponent } from "../ui/component/GroupPanelComponent";
|
||||
|
||||
import { Color } from "../data/color/Color";
|
||||
import { RenderingContext2D } from "util/Types";
|
||||
import { Paths } from "../data/Paths";
|
||||
|
||||
|
||||
export class Player extends RPEntity {
|
||||
|
|
@ -171,7 +169,7 @@ export class Player extends RPEntity {
|
|||
}
|
||||
}
|
||||
|
||||
override draw(ctx: RenderingContext2D) {
|
||||
override draw(ctx: CanvasRenderingContext2D) {
|
||||
if (this.isIgnored()) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -238,8 +236,8 @@ export class Player extends RPEntity {
|
|||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
if (this.isVisibleToAction(false)) {
|
||||
return "url(" + Paths.sprites + "/cursor/look.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/look.png) 1 3, auto";
|
||||
}
|
||||
return "url(" + Paths.sprites + "/cursor/walk.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/walk.png) 1 3, auto";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { marauroa, RPObject, RPZone } from "marauroa";
|
||||
|
||||
import { RenderingContext2D } from "util/Types";
|
||||
import { Entity } from "./Entity";
|
||||
import { RPObject } from "./RPObject";
|
||||
|
||||
declare var marauroa: any;
|
||||
|
||||
|
||||
export class PopupInventory extends Entity {
|
||||
|
|
@ -20,7 +20,7 @@ export class PopupInventory extends Entity {
|
|||
protected maxDistToView = 4;
|
||||
|
||||
|
||||
override draw(ctx: RenderingContext2D) {
|
||||
override draw(ctx: CanvasRenderingContext2D) {
|
||||
super.draw(ctx);
|
||||
if (this.inventory && this.inventory.isOpen() && !this.canViewContents()) {
|
||||
// player has moved too far away
|
||||
|
|
@ -32,9 +32,9 @@ export class PopupInventory extends Entity {
|
|||
// inheriting classes can override
|
||||
}
|
||||
|
||||
override destroy(parent: RPObject|RPZone) {
|
||||
override destroy(_parent: RPObject) {
|
||||
this.closeInventoryWindow();
|
||||
super.destroy(parent);
|
||||
super.destroy(_parent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -13,10 +13,9 @@ import { Entity } from "./Entity";
|
|||
import { MenuItem } from "../action/MenuItem";
|
||||
|
||||
import { Color } from "../data/color/Color";
|
||||
import { Paths } from "../data/Paths";
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
import { TileMap } from "data/TileMap";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
export class Portal extends Entity {
|
||||
|
||||
|
|
@ -60,8 +59,7 @@ export class Portal extends Entity {
|
|||
*/
|
||||
override getDefaultAction() {
|
||||
// don't try to walk to if on collision tile
|
||||
let map = TileMap.get();
|
||||
if (map.collision(this["x"], this["y"])) {
|
||||
if (stendhal.data.map.collision(this["x"], this["y"])) {
|
||||
return {
|
||||
"type": "use",
|
||||
"target": "#" + this["id"],
|
||||
|
|
@ -77,7 +75,7 @@ export class Portal extends Entity {
|
|||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/portal.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/portal.png) 1 3, auto";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2003-2026 - Stendhal *
|
||||
* (C) Copyright 2003-2024 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
|
@ -9,35 +9,30 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { marauroa } from "marauroa";
|
||||
import { stendhal } from "../stendhal";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
import { singletons } from "../SingletonRepo";
|
||||
import { MenuItem } from "../action/MenuItem";
|
||||
import { ActiveEntity } from "./ActiveEntity";
|
||||
import { Entity } from "./Entity";
|
||||
import { singletons } from "../SingletonRepo";
|
||||
import { MenuItem } from "../action/MenuItem";
|
||||
|
||||
import { Color } from "../data/color/Color";
|
||||
|
||||
import { Chat } from "../util/Chat";
|
||||
import { Nature } from "../util/Nature";
|
||||
|
||||
import { EmojiSprite } from "../sprite/EmojiSprite";
|
||||
import { Floater } from "../sprite/Floater";
|
||||
import { EmojiSprite } from "../sprite/EmojiSprite";
|
||||
import { OverlaySpriteImpl } from "../sprite/OverlaySpriteImpl";
|
||||
import { SpeechBubble } from "../sprite/SpeechBubble";
|
||||
import { TextSprite } from "../sprite/TextSprite";
|
||||
|
||||
import { BarehandAttackSprite } from "../sprite/action/BarehandAttackSprite";
|
||||
//import { MeleeAttackSprite } from "../sprite/action/MeleeAttackSprite";
|
||||
import { RangedAttackSprite } from "../sprite/action/RangedAttackSprite";
|
||||
|
||||
import { htmlImageStore } from "data/HTMLImageStore";
|
||||
import { ImageWithDimensions } from "data/ImageWithDimensions";
|
||||
import { OutfitStore } from "data/OutfitStore";
|
||||
import { ViewPort } from "ui/ViewPort";
|
||||
import { RenderingContext2D } from "util/Types";
|
||||
import { Paths } from "../data/Paths";
|
||||
import { statusIconDrawer } from "sprite/indicator/StatusIconDrawer";
|
||||
|
||||
var HEALTH_BAR_HEIGHT = 6;
|
||||
|
||||
|
|
@ -59,7 +54,7 @@ export class RPEntity extends ActiveEntity {
|
|||
// for adjusting entity hp bar & title vertical position
|
||||
protected titleDrawYOffset: number = 0;
|
||||
// canvas for merging outfit layers to be drawn
|
||||
private octx?: RenderingContext2D;
|
||||
private octx?: CanvasRenderingContext2D;
|
||||
|
||||
private attackers: {[key: string]: any} = { size: 0 };
|
||||
|
||||
|
|
@ -209,11 +204,11 @@ export class RPEntity extends ActiveEntity {
|
|||
* Text to display.
|
||||
*/
|
||||
addSpeechBubble(text: string) {
|
||||
ViewPort.get().addTextSprite(new SpeechBubble(text, this));
|
||||
stendhal.ui.gamewindow.addTextSprite(new SpeechBubble(text, this));
|
||||
}
|
||||
|
||||
addEmoji(emoji: HTMLImageElement) {
|
||||
ViewPort.get().addEmojiSprite(new EmojiSprite(emoji, this));
|
||||
stendhal.ui.gamewindow.addEmojiSprite(new EmojiSprite(emoji, this));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -223,8 +218,8 @@ export class RPEntity extends ActiveEntity {
|
|||
return typeof(this["no_shadow"]) === "undefined";
|
||||
}
|
||||
|
||||
drawMultipartOutfit(ctx: RenderingContext2D) {
|
||||
const store = OutfitStore.get();
|
||||
drawMultipartOutfit(ctx: CanvasRenderingContext2D) {
|
||||
const store = singletons.getOutfitStore();
|
||||
// layers in draw order
|
||||
var layers = store.getLayerNames();
|
||||
|
||||
|
|
@ -249,7 +244,7 @@ export class RPEntity extends ActiveEntity {
|
|||
if (stendhal.config.getBoolean("effect.shadows") && this.castsShadow()) {
|
||||
// dressed entities should use 48x64 sprites
|
||||
// FIXME: this will not display correctly for horse outfit
|
||||
const shadow = htmlImageStore.getShadow("48x64");
|
||||
const shadow = stendhal.data.sprites.getShadow("48x64");
|
||||
|
||||
if (shadow && shadow.complete && shadow.height) {
|
||||
// draw shadow below other layers
|
||||
|
|
@ -260,21 +255,23 @@ export class RPEntity extends ActiveEntity {
|
|||
if (this.octx) {
|
||||
this.octx.clearRect(0, 0, this.octx.canvas.width, this.octx.canvas.height);
|
||||
}
|
||||
if (store.detailHasRearLayer(outfit["detail"])) {
|
||||
if (stendhal.data.outfit.detailHasRearLayer(outfit["detail"])) {
|
||||
layers.splice(0, 0, "detail-rear");
|
||||
outfit["detail-rear"] = outfit["detail"];
|
||||
}
|
||||
for (const layer of layers) {
|
||||
// hair is not drawn under certain hats/helmets
|
||||
if (layer == "hair" && !store.drawHair(outfit["hat"])) {
|
||||
if (layer == "hair" && !stendhal.data.outfit.drawHair(outfit["hat"])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const lsprite = this.getOutfitPart(layer, outfit[layer], outfit["body"]);
|
||||
if (lsprite && lsprite.complete && lsprite.height) {
|
||||
if (!this.octx) {
|
||||
let ocanvas = new OffscreenCanvas(lsprite.width, lsprite.height);
|
||||
let ocanvas = document.createElement("canvas");
|
||||
this.octx = ocanvas.getContext("2d")!;
|
||||
ocanvas.width = lsprite.width;
|
||||
ocanvas.height = lsprite.height;
|
||||
}
|
||||
this.octx!.drawImage(lsprite, 0, 0);
|
||||
}
|
||||
|
|
@ -305,28 +302,27 @@ export class RPEntity extends ActiveEntity {
|
|||
n = "0" + index;
|
||||
}
|
||||
|
||||
let store = OutfitStore.get();
|
||||
if (part === "body" && index < 3 && stendhal.config.getBoolean("effect.no-nude")) {
|
||||
n += "-nonude";
|
||||
} else if (part === "dress" && store.drawBustyDress(index, body)) {
|
||||
} else if (part === "dress" && stendhal.data.outfit.drawBustyDress(index, body)) {
|
||||
n += "b";
|
||||
} else if (part.endsWith("-rear")) {
|
||||
n += "-rear";
|
||||
part = part.replace(/-rear$/, "");
|
||||
}
|
||||
|
||||
const filename = Paths.sprites + "/outfit/" + part + "/" + n + ".png";
|
||||
const filename = stendhal.paths.sprites + "/outfit/" + part + "/" + n + ".png";
|
||||
const colors = this["outfit_colors"];
|
||||
let colorname;
|
||||
if (store.isSkinLayer(part)) {
|
||||
if (stendhal.data.outfit.isSkinLayer(part)) {
|
||||
colorname = "skin";
|
||||
} else {
|
||||
colorname = part;
|
||||
}
|
||||
if (typeof(colors) !== "undefined" && (typeof(colors[colorname]) !== "undefined")) {
|
||||
return htmlImageStore.getFiltered(filename, "trueColor", colors[colorname]);
|
||||
return stendhal.data.sprites.getFiltered(filename, "trueColor", colors[colorname]);
|
||||
} else {
|
||||
return htmlImageStore.get(filename);
|
||||
return stendhal.data.sprites.get(filename);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -335,7 +331,7 @@ export class RPEntity extends ActiveEntity {
|
|||
* extends past top edge.
|
||||
*/
|
||||
public setStatusBarOffset() {
|
||||
const screenOffsetY = ViewPort.get().offsetY;
|
||||
const screenOffsetY = stendhal.ui.gamewindow.offsetY;
|
||||
const entityBottom = (this["_y"] * 32) + (this["height"] * 32);
|
||||
// FIXME: how to get text height dynamically?
|
||||
const entityTop = entityBottom - this["drawHeight"]
|
||||
|
|
@ -351,70 +347,138 @@ export class RPEntity extends ActiveEntity {
|
|||
/**
|
||||
* draw RPEntities
|
||||
*/
|
||||
override draw(ctx: RenderingContext2D) {
|
||||
override draw(ctx: CanvasRenderingContext2D) {
|
||||
if (typeof(this["ghostmode"]) != "undefined" && marauroa.me && !marauroa.me.isAdmin()) {
|
||||
return;
|
||||
}
|
||||
this.drawCombat(ctx);
|
||||
this.drawMain(ctx);
|
||||
this.drawAttack(ctx);
|
||||
statusIconDrawer.drawStatusIcons(this, ctx);
|
||||
this.drawStatusIcons(ctx);
|
||||
}
|
||||
|
||||
drawMain(ctx: RenderingContext2D) {
|
||||
drawMain(ctx: CanvasRenderingContext2D) {
|
||||
if (typeof(this["outfit"]) != "undefined" || typeof(this["outfit_ext"]) != "undefined") {
|
||||
this.drawMultipartOutfit(ctx);
|
||||
} else {
|
||||
this.drawSingleOutfit(ctx);
|
||||
let filename = stendhal.paths.sprites + "/" + this.spritePath + "/" + this["class"];
|
||||
if (typeof(this["subclass"]) != "undefined") {
|
||||
filename = filename + "/" + this["subclass"];
|
||||
}
|
||||
|
||||
// check for safe image
|
||||
if (!stendhal.config.getBoolean("effect.blood") && stendhal.data.sprites.hasSafeImage(filename)) {
|
||||
filename = filename + "-safe.png";
|
||||
} else {
|
||||
filename = filename + ".png";
|
||||
}
|
||||
|
||||
let image = stendhal.data.sprites.get(filename);
|
||||
|
||||
if (stendhal.config.getBoolean("effect.shadows") && this.castsShadow()) {
|
||||
// check for configured shadow style
|
||||
let shadow_style = this["shadow_style"];
|
||||
if (typeof(shadow_style) === "undefined") {
|
||||
// default to sprite dimensions
|
||||
shadow_style = (image.width / 3) + "x" + (image.height / 4);
|
||||
}
|
||||
|
||||
const shadow = stendhal.data.sprites.getShadow(shadow_style);
|
||||
|
||||
// draw shadow first
|
||||
if (typeof(shadow) !== "undefined") {
|
||||
this.drawSpriteImage(ctx, shadow);
|
||||
}
|
||||
}
|
||||
|
||||
this.drawSpriteImage(ctx, image);
|
||||
this.drawOverlayAnimation(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
drawSingleOutfit(ctx: RenderingContext2D) {
|
||||
let filename = Paths.sprites + "/" + this.spritePath + "/" + this["class"];
|
||||
if (typeof(this["subclass"]) != "undefined") {
|
||||
filename = filename + "/" + this["subclass"];
|
||||
drawStatusIcons(ctx: CanvasRenderingContext2D) {
|
||||
|
||||
function _drawAnimatedIcon(icon: CanvasImageSource, delay: number, nFrames: number, xdim: number, ydim: number, x: number, y: number) {
|
||||
var frame = Math.floor(Date.now() / delay) % nFrames;
|
||||
ctx.drawImage(icon, frame * xdim, 0, xdim, ydim, x, y, xdim, ydim);
|
||||
}
|
||||
function drawAnimatedIcon(iconPath: string, delay: number, x: number, y: number, fWidth?: number) {
|
||||
var icon = stendhal.data.sprites.get(iconPath);
|
||||
var dimH = icon.height;
|
||||
var dimW = typeof(fWidth) !== "undefined" ? fWidth : dimH;
|
||||
var nFrames = icon.width / dimW;
|
||||
_drawAnimatedIcon(icon, delay, nFrames, dimW, dimH, x, y);
|
||||
}
|
||||
function drawAnimatedIconWithFrames(iconPath: string, nFrames: number, delay: number, x: number, y: number) {
|
||||
var icon = stendhal.data.sprites.get(iconPath);
|
||||
var ydim = icon.height;
|
||||
var xdim = icon.width / nFrames;
|
||||
_drawAnimatedIcon(icon, delay, nFrames, xdim, ydim, x, y);
|
||||
}
|
||||
|
||||
// check for safe image
|
||||
if (!stendhal.config.getBoolean("effect.blood") && htmlImageStore.hasSafeImage(filename)) {
|
||||
filename = filename + "-safe.png";
|
||||
} else {
|
||||
filename = filename + ".png";
|
||||
var x = this["_x"] * 32 - 10;
|
||||
var y = (this["_y"] + 1) * 32;
|
||||
if (this.hasOwnProperty("choking")) {
|
||||
ctx.drawImage(stendhal.data.sprites.get(stendhal.paths.sprites + "/ideas/choking.png"), x, y - 10);
|
||||
} else if (this.hasOwnProperty("eating")) {
|
||||
ctx.drawImage(stendhal.data.sprites.get(stendhal.paths.sprites + "/ideas/eat.png"), x, y - 10);
|
||||
}
|
||||
|
||||
let image = htmlImageStore.get(filename);
|
||||
|
||||
if (stendhal.config.getBoolean("effect.shadows") && this.castsShadow()) {
|
||||
// check for configured shadow style
|
||||
let shadow_style = this["shadow_style"];
|
||||
if (typeof(shadow_style) === "undefined") {
|
||||
// default to sprite dimensions
|
||||
shadow_style = (image.width / 3) + "x" + (image.height / 4);
|
||||
}
|
||||
|
||||
const shadow = htmlImageStore.getShadow(shadow_style);
|
||||
|
||||
// draw shadow first
|
||||
if (typeof(shadow) !== "undefined") {
|
||||
this.drawSpriteImage(ctx, shadow);
|
||||
// NPC and pet idea icons
|
||||
if (this.hasOwnProperty("idea")) {
|
||||
const idea = stendhal.paths.sprites + "/ideas/" + this["idea"] + ".png";
|
||||
const ani = stendhal.data.sprites.animations.idea[this["idea"]];
|
||||
if (ani) {
|
||||
drawAnimatedIcon(idea, ani.delay, x + ani.offsetX * this["width"],
|
||||
y - this["drawHeight"] + ani.offsetY);
|
||||
} else {
|
||||
ctx.drawImage(stendhal.data.sprites.get(idea), x + 32 * this["width"],
|
||||
y - this["drawHeight"]);
|
||||
}
|
||||
}
|
||||
|
||||
this.drawSpriteImage(ctx, image);
|
||||
this.drawOverlayAnimation(ctx);
|
||||
if (this.hasOwnProperty("away")) {
|
||||
drawAnimatedIcon(stendhal.paths.sprites + "/ideas/away.png", 1500, x + 32 * this["width"], y - this["drawHeight"]);
|
||||
}
|
||||
if (this.hasOwnProperty("grumpy")) {
|
||||
drawAnimatedIcon(stendhal.paths.sprites + "/ideas/grumpy.png", 1000, x + 5, y - this["drawHeight"]);
|
||||
}
|
||||
if (this.hasOwnProperty("last_player_kill_time")) {
|
||||
drawAnimatedIconWithFrames(stendhal.paths.sprites + "/ideas/pk.png", 12, 300, x, y - this["drawHeight"]);
|
||||
}
|
||||
// status affects
|
||||
if (this.hasOwnProperty("poisoned")) {
|
||||
drawAnimatedIcon(stendhal.paths.sprites + "/status/poison.png", 100, x + 32 * this["width"] - 10, y - this["drawHeight"]);
|
||||
}
|
||||
if (this.hasOwnProperty("status_confuse")) {
|
||||
drawAnimatedIcon(stendhal.paths.sprites + "/status/confuse.png", 200, x + 32 * this["width"] - 14, y - this["drawHeight"] + 16);
|
||||
}
|
||||
if (this.hasOwnProperty("status_shock")) {
|
||||
drawAnimatedIcon(stendhal.paths.sprites + "/status/shock.png", 200, x + 32 * this["width"] - 25, y - 32, 38);
|
||||
}
|
||||
// NPC job icons
|
||||
let nextX = x;
|
||||
if (this.hasOwnProperty("job_healer")) {
|
||||
ctx.drawImage(stendhal.data.sprites.get(stendhal.paths.sprites + "/status/healer.png"), nextX, y - 10);
|
||||
nextX += 12;
|
||||
}
|
||||
if (this.hasOwnProperty("job_merchant")) {
|
||||
ctx.drawImage(stendhal.data.sprites.get(stendhal.paths.sprites + "/status/merchant.png"), nextX, y - 10);
|
||||
nextX += 12;
|
||||
}
|
||||
if (this.hasOwnProperty("job_producer")) {
|
||||
ctx.drawImage(stendhal.data.sprites.get(stendhal.paths.sprites + "/status/producer.png"), nextX, y - 16);
|
||||
nextX += 16;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Draw colored ellipses (or rectangles on browsers that do not support
|
||||
* ellipses) when the entity is being attacked, or is attacking the user.
|
||||
*/
|
||||
drawCombat(ctx: RenderingContext2D) {
|
||||
drawCombat(ctx: CanvasRenderingContext2D) {
|
||||
if (this.attackers.size > 0) {
|
||||
ctx.lineWidth = 1;
|
||||
/*
|
||||
* As of 2015-9-15 RenderingContext2D.ellipse() is not
|
||||
* As of 2015-9-15 CanvasRenderingContext2D.ellipse() is not
|
||||
* supported in most browsers. Fall back to rectangles on these.
|
||||
* Also on Chrome 45.0.2454.85 ellipse() does not seem to support
|
||||
* the begin angle parameter correctly, nor does the stroke
|
||||
|
|
@ -475,7 +539,7 @@ export class RPEntity extends ActiveEntity {
|
|||
* the coordinates where to start floating. The method should return true
|
||||
* when the floater should be removed.
|
||||
*/
|
||||
drawFloaters(ctx: RenderingContext2D) {
|
||||
drawFloaters(ctx: CanvasRenderingContext2D) {
|
||||
var centerX = (this["_x"] + this["width"] / 2) * 32;
|
||||
var topY = (this["_y"] + 1) * 32 - this["drawHeight"];
|
||||
// Grab an unchanging copy
|
||||
|
|
@ -491,10 +555,10 @@ export class RPEntity extends ActiveEntity {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param {RenderingContext2D} ctx
|
||||
* @param {CanvasRenderingContext2D} ctx
|
||||
* @param {Image} image
|
||||
*/
|
||||
drawSpriteImage(ctx: RenderingContext2D, image: CanvasImageSource & ImageWithDimensions) {
|
||||
drawSpriteImage(ctx: CanvasRenderingContext2D, image: CanvasImageSource & ImageWithDimensions) {
|
||||
var localX = this["_x"] * 32;
|
||||
var localY = this["_y"] * 32;
|
||||
if (image.height) { // image.complete is true on missing image files
|
||||
|
|
@ -546,7 +610,7 @@ export class RPEntity extends ActiveEntity {
|
|||
}
|
||||
}
|
||||
|
||||
drawTop(ctx: RenderingContext2D) {
|
||||
drawTop(ctx: CanvasRenderingContext2D) {
|
||||
var localX = this["_x"] * 32;
|
||||
var localY = this["_y"] * 32;
|
||||
this.drawFloaters(ctx);
|
||||
|
|
@ -554,7 +618,7 @@ export class RPEntity extends ActiveEntity {
|
|||
this.drawTitle(ctx, localX, localY + this.statusBarYOffset);
|
||||
}
|
||||
|
||||
drawHealthBar(ctx: RenderingContext2D, x: number, y: number) {
|
||||
drawHealthBar(ctx: CanvasRenderingContext2D, x: number, y: number) {
|
||||
var drawX = x + ((this["width"] * 32) - this["drawWidth"]) / 2;
|
||||
var drawY = y + (this["height"] * 32) - this["drawHeight"]
|
||||
- HEALTH_BAR_HEIGHT + this.titleDrawYOffset;
|
||||
|
|
@ -591,48 +655,42 @@ export class RPEntity extends ActiveEntity {
|
|||
}
|
||||
}
|
||||
|
||||
drawTitle(ctx: RenderingContext2D, x: number, y: number) {
|
||||
drawTitle(ctx: CanvasRenderingContext2D, x: number, y: number) {
|
||||
if (this.titleTextSprite) {
|
||||
let textMetrics = this.titleTextSprite.getTextMetrics(ctx);
|
||||
if (!textMetrics) {
|
||||
throw new Error("textMetrics is undefined");
|
||||
}
|
||||
var drawY = y + (this["height"] * 32) - this["drawHeight"]
|
||||
- HEALTH_BAR_HEIGHT + this.titleDrawYOffset;
|
||||
this.titleTextSprite.draw(ctx, x + (this["width"] * 32 - textMetrics.width) / 2, drawY - 5 - HEALTH_BAR_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
drawAttack(ctx: RenderingContext2D) {
|
||||
drawAttack(ctx: CanvasRenderingContext2D) {
|
||||
if (!this.attackSprite) {
|
||||
return;
|
||||
}
|
||||
if (this.attackSprite.expired()) {
|
||||
// sprite expired & should be removed
|
||||
// NOTE: if this is done after `this.attackSprite.draw` animation doesn't look right
|
||||
this.attackSprite.free();
|
||||
this.attackSprite = undefined;
|
||||
return;
|
||||
}
|
||||
let viewPort = ViewPort.get();
|
||||
var localX = this["_x"] * 32;
|
||||
var localY = this["_y"] * 32;
|
||||
var localW = this["width"] * viewPort.targetTileWidth;
|
||||
var localH = this["height"] * viewPort.targetTileHeight;
|
||||
var localW = this["width"] * stendhal.ui.gamewindow.targetTileWidth;
|
||||
var localH = this["height"] * stendhal.ui.gamewindow.targetTileHeight;
|
||||
this.attackSprite.draw(ctx, localX, localY, localW, localH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an animation over entity sprite.
|
||||
*
|
||||
* @param {RenderingContext2D} ctx
|
||||
* @param {CanvasRenderingContext2D} ctx
|
||||
* Canvas context to draw on.
|
||||
*/
|
||||
private drawOverlayAnimation(ctx: RenderingContext2D) {
|
||||
private drawOverlayAnimation(ctx: CanvasRenderingContext2D) {
|
||||
if (this.overlay && this.overlay.draw(ctx, this["drawOffsetX"], this["drawOffsetY"],
|
||||
this["drawWidth"], this["drawHeight"])) {
|
||||
// overlay sprite expired
|
||||
this.overlay.free();
|
||||
this.overlay = undefined;
|
||||
}
|
||||
}
|
||||
|
|
@ -652,21 +710,21 @@ export class RPEntity extends ActiveEntity {
|
|||
}
|
||||
|
||||
onDamaged(_source: Entity, damage: number) {
|
||||
this.attackResult = this.createResultIcon(Paths.sprites + "/combat/hitted.png");
|
||||
this.attackResult = this.createResultIcon(stendhal.paths.sprites + "/combat/hitted.png");
|
||||
var sounds = ["attack-melee-01", "attack-melee-02", "attack-melee-03", "attack-melee-04", "attack-melee-05", "attack-melee-06", "attack-melee-07"];
|
||||
var index = Math.floor(Math.random() * Math.floor(sounds.length));
|
||||
stendhal.sound.playLocalizedEffect(this["_x"], this["_y"], 20, 3, sounds[index], 1);
|
||||
}
|
||||
|
||||
onBlocked(_source: Entity) {
|
||||
this.attackResult = this.createResultIcon(Paths.sprites + "/combat/blocked.png");
|
||||
this.attackResult = this.createResultIcon(stendhal.paths.sprites + "/combat/blocked.png");
|
||||
var sounds = ["clang-metallic-1", "clang-dull-1"];
|
||||
var index = Math.floor(Math.random() * Math.floor(sounds.length));
|
||||
stendhal.sound.playLocalizedEffect(this["_x"], this["_y"], 20, 3, sounds[index], 1);
|
||||
}
|
||||
|
||||
onMissed(_source: Entity) {
|
||||
this.attackResult = this.createResultIcon(Paths.sprites + "/combat/missed.png");
|
||||
this.attackResult = this.createResultIcon(stendhal.paths.sprites + "/combat/missed.png");
|
||||
}
|
||||
|
||||
protected onHPChanged(change: number) {
|
||||
|
|
@ -721,8 +779,8 @@ export class RPEntity extends ActiveEntity {
|
|||
createResultIcon(imagePath: string) {
|
||||
return {
|
||||
initTime: Date.now(),
|
||||
image: htmlImageStore.get(imagePath),
|
||||
draw: function(ctx: RenderingContext2D, x: number, y: number) {
|
||||
image: stendhal.data.sprites.get(imagePath),
|
||||
draw: function(ctx: CanvasRenderingContext2D, x: number, y: number) {
|
||||
ctx.drawImage(this.image, x, y);
|
||||
return (Date.now() - this.initTime > 1200);
|
||||
}
|
||||
|
|
@ -735,7 +793,6 @@ export class RPEntity extends ActiveEntity {
|
|||
weapon = undefined;
|
||||
}
|
||||
|
||||
this.attackSprite?.free();
|
||||
if (ranged) {
|
||||
this.attackSprite = new RangedAttackSprite(this, this.getAttackTarget()!,
|
||||
Nature.VALUES[nature].color, weapon);
|
||||
|
|
@ -753,12 +810,12 @@ export class RPEntity extends ActiveEntity {
|
|||
const imagePath = Nature.VALUES[nature].getWeaponPath(weapon);
|
||||
/*
|
||||
if (weapon.startsWith("blade_strike")) {
|
||||
this.attackSprite = new BarehandAttackSprite(this, imagePath);
|
||||
this.attackSprite = new BarehandAttackSprite(this, stendhal.data.sprites.get(imagePath));
|
||||
} else {
|
||||
this.attackSprite = new MeleeAttackSprite(this, imagePath);
|
||||
}
|
||||
*/
|
||||
this.attackSprite = new BarehandAttackSprite(this, imagePath);
|
||||
this.attackSprite = new BarehandAttackSprite(this, stendhal.data.sprites.get(imagePath));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -787,10 +844,10 @@ export class RPEntity extends ActiveEntity {
|
|||
}
|
||||
}
|
||||
|
||||
override destroy(obj: Entity) {
|
||||
this._target?.onAttackStopped(this);
|
||||
this.overlay?.free();
|
||||
super.destroy(obj);
|
||||
override destroy(_obj: Entity) {
|
||||
if (this._target) {
|
||||
this._target.onAttackStopped(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
96
src/js/stendhal/entity/RPObject.ts
Normal file
96
src/js/stendhal/entity/RPObject.ts
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2003-2023 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
declare var marauroa: any;
|
||||
|
||||
|
||||
/**
|
||||
* base class for RPObjects
|
||||
*/
|
||||
export class RPObject {
|
||||
[key: string]: any;
|
||||
|
||||
onEvent(e: any) {
|
||||
var event = marauroa.rpeventFactory.create(e["c"]);
|
||||
for (var i in e["a"]) {
|
||||
if (e["a"].hasOwnProperty(i)) {
|
||||
event[i] = e["a"][i];
|
||||
}
|
||||
event["_rpclass"] = e["c"];
|
||||
}
|
||||
|
||||
// Event slots
|
||||
for (var slot in e["s"]) {
|
||||
if (e["s"].hasOwnProperty(slot)) {
|
||||
event[slot] = e["s"][slot];
|
||||
}
|
||||
}
|
||||
event.execute(this);
|
||||
}
|
||||
|
||||
set(key: string, value: object) {
|
||||
this[key] = value;
|
||||
}
|
||||
|
||||
setMapEntry(map: string, key: string, value: object) {
|
||||
this[map][key] = value;
|
||||
}
|
||||
|
||||
unset(key: string) {
|
||||
delete this[key];
|
||||
}
|
||||
|
||||
unsetMapEntry(map: string, key: string) {
|
||||
delete this[map][key];
|
||||
}
|
||||
|
||||
destroy(_parent: RPObject) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
createSlot(name: string) {
|
||||
var slot = marauroa.rpslotFactory.create(name);
|
||||
slot._parent = this;
|
||||
return slot;
|
||||
}
|
||||
|
||||
init() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves object width.
|
||||
*/
|
||||
public getWidth(): number {
|
||||
return this["width"] || 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves object height.
|
||||
*/
|
||||
public getHeight(): number {
|
||||
return this["height"] || 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this object is nested.
|
||||
*/
|
||||
public isContained(): boolean {
|
||||
return this._parent !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the parent object.
|
||||
*/
|
||||
public getContainer(): RPObject {
|
||||
return <RPObject> this._parent;
|
||||
}
|
||||
}
|
||||
|
|
@ -9,49 +9,37 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { RPObject, RPZone} from "marauroa";
|
||||
import { Entity } from "./Entity";
|
||||
import { ActivityIndicatorSprite } from "../sprite/ActivityIndicatorSprite";
|
||||
import { RenderingContext2D } from "util/Types";
|
||||
import { Paths } from "../data/Paths";
|
||||
import { singletons } from "../SingletonRepo";
|
||||
|
||||
import { stendhal } from "../stendhal";
|
||||
import { images } from "sprite/image/ImageManager";
|
||||
import { ImageSprite } from "sprite/image/ImageSprite";
|
||||
declare var stendhal: any;
|
||||
|
||||
export class Sign extends Entity {
|
||||
override zIndex = 5000;
|
||||
|
||||
private indicator?: ActivityIndicatorSprite;
|
||||
|
||||
override init() {
|
||||
super.init();
|
||||
if (!this.imageSprite) {
|
||||
this.imageSprite = new ImageSprite(
|
||||
images.load(Paths.sprites + "/signs/" + "default" + ".png"),
|
||||
0, 0, 32, 32
|
||||
);
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this["class"] = "default";
|
||||
}
|
||||
|
||||
override set(key: string, value: object) {
|
||||
super.set(key, value);
|
||||
if (key === "activity-indicator" && stendhal.config.getBoolean("activity-indicator")) {
|
||||
this.indicator = new ActivityIndicatorSprite();
|
||||
} else if (key === "class") {
|
||||
this.imageSprite = new ImageSprite(
|
||||
images.load(Paths.sprites + "/signs/" + this["class"] + ".png"),
|
||||
0, 0, 32, 32
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
override draw(ctx: RenderingContext2D) {
|
||||
let image = this.imageSprite?.imageRef?.image;
|
||||
let localX = this["x"] * 32;
|
||||
let localY = this["y"] * 32;
|
||||
if (image) {
|
||||
override draw(ctx: CanvasRenderingContext2D) {
|
||||
if (!this.imagePath) {
|
||||
this.imagePath = stendhal.paths.sprites + "/signs/" + this["class"] + ".png";
|
||||
}
|
||||
var image = stendhal.data.sprites.get(this.imagePath);
|
||||
if (image.height) {
|
||||
var localX = this["x"] * 32;
|
||||
var localY = this["y"] * 32;
|
||||
ctx.drawImage(image, localX, localY);
|
||||
if (this.indicator) {
|
||||
this.indicator.draw(ctx, localX, localY, image.width);
|
||||
|
|
@ -64,12 +52,7 @@ export class Sign extends Entity {
|
|||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/look.png) 1 3, auto";
|
||||
}
|
||||
|
||||
override destroy(parent: RPObject|RPZone): void {
|
||||
this.indicator?.free();
|
||||
super.destroy(parent);
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/look.png) 1 3, auto";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { Paths } from "../data/Paths";
|
||||
import { NPC } from "./NPC";
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
export class TrainingDummy extends NPC {
|
||||
|
|
@ -29,6 +29,6 @@ export class TrainingDummy extends NPC {
|
|||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/attack.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/attack.png) 1 3, auto";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
import { Entity } from "./Entity";
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
declare var marauroa: any;
|
||||
|
||||
export class UnknownEntity extends Entity {
|
||||
|
||||
|
|
|
|||
|
|
@ -9,26 +9,32 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
declare var stendhal: any;
|
||||
|
||||
import { Entity } from "./Entity";
|
||||
import { MenuItem } from "../action/MenuItem";
|
||||
import { Paths } from "../data/Paths";
|
||||
import { ImageSprite } from "sprite/image/ImageSprite";
|
||||
import { images } from "sprite/image/ImageManager";
|
||||
|
||||
|
||||
export class UseableEntity extends Entity {
|
||||
override zIndex = 3000
|
||||
action = "use";
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.sprite = {
|
||||
height: 32,
|
||||
width: 32
|
||||
};
|
||||
}
|
||||
|
||||
override set(key: string, value: any) {
|
||||
super.set(key, value);
|
||||
if (key === "class" || key === "name") {
|
||||
let filename = Paths.sprites + "/" + this["class"] + "/" + this["_name"] + ".png";
|
||||
let state = this["state"] * 32 || 0;
|
||||
this.imageSprite?.free();
|
||||
this.imageSprite = new ImageSprite(images.load(filename), 0, state, 32, 32);
|
||||
} else if (key === "state" && this.imageSprite) {
|
||||
this.imageSprite.offsetY = this["state"] * 32;
|
||||
this.sprite.filename = stendhal.paths.sprites + "/"
|
||||
+ this["class"] + "/" + this["_name"] + ".png";
|
||||
}
|
||||
if (key === "state") {
|
||||
this.sprite.offsetY = this["state"] * 32;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
import { stendhal } from "../stendhal";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
import { Entity } from "./Entity";
|
||||
import { Player } from "./Player";
|
||||
|
|
@ -33,7 +33,6 @@ import { OutfitDialog } from "../ui/dialog/outfit/OutfitDialog";
|
|||
import { FloatingWindow } from "../ui/toolkit/FloatingWindow";
|
||||
|
||||
import { Direction } from "../util/Direction";
|
||||
import { ViewPort } from "ui/ViewPort";
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -164,7 +163,7 @@ export class User extends Player {
|
|||
override onExitZone() {
|
||||
super.onExitZone();
|
||||
// speech bubbles & emojis from viewport
|
||||
ViewPort.get().onExitZone();
|
||||
stendhal.ui.gamewindow.onExitZone();
|
||||
// stop sounds & clear map sounds cache on zone change
|
||||
const msgs: string[] = [];
|
||||
const lssm = singletons.getLoopedSoundSourceManager();
|
||||
|
|
@ -226,7 +225,7 @@ export class User extends Player {
|
|||
* @param dir {util.Direction.Direction}
|
||||
* New direction to face.
|
||||
*/
|
||||
public faceTo(dir: Direction) {
|
||||
public setFacing(dir: Direction) {
|
||||
marauroa.clientFramework.sendAction({type: "face", dir: ""+dir.val});
|
||||
}
|
||||
|
||||
|
|
@ -245,7 +244,7 @@ export class User extends Player {
|
|||
return;
|
||||
}
|
||||
// in case viewport frozen from view change event
|
||||
ViewPort.get().freeze = false;
|
||||
stendhal.ui.viewport.freeze = false;
|
||||
if (cancelAutoWalk && this.autoWalkEnabled() && this.getWalkDirection() == dir) {
|
||||
// cancel auto-walk if enabled & new direction is same as current direction of movement
|
||||
marauroa.clientFramework.sendAction({type: "walk"});
|
||||
|
|
@ -281,7 +280,7 @@ export class User extends Player {
|
|||
public moveTo(x: number, y: number, zone?: string): void;
|
||||
public moveTo(p1: object|number, p2?: number, p3?:string) {
|
||||
// in case viewport frozen from view change event
|
||||
ViewPort.get().freeze = false;
|
||||
stendhal.ui.viewport.freeze = false;
|
||||
let action: any = {};
|
||||
if (typeof(p1) === "object") {
|
||||
action = p1;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2003-2026 - Stendhal *
|
||||
* (C) Copyright 2003-2023 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
|
@ -9,10 +9,9 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { images } from "sprite/image/ImageManager";
|
||||
import { Paths } from "../data/Paths";
|
||||
import { Entity } from "./Entity";
|
||||
import { ImageSprite } from "sprite/image/ImageSprite";
|
||||
|
||||
declare var stendhal: any;
|
||||
|
||||
export class VisibleEntity extends Entity {
|
||||
|
||||
|
|
@ -20,29 +19,21 @@ export class VisibleEntity extends Entity {
|
|||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
override init(): void {
|
||||
let filename = Paths.sprites + "/"
|
||||
+ (this["class"] || "") + "/"
|
||||
+ (this["subclass"] || "") + "/"
|
||||
+ (this["_name"] || "") + ".png";
|
||||
let state = this["state"] * 32 || 0;
|
||||
this.imageSprite = new ImageSprite(images.load(filename), 0, state, 32, 32);
|
||||
this.sprite = {
|
||||
height: 32,
|
||||
width: 32
|
||||
};
|
||||
}
|
||||
|
||||
override set(key: string, value: any) {
|
||||
super.set(key, value);
|
||||
if (key === "class" || key === "subclass" || key === "_name") {
|
||||
// if this was already initialized, create a new ImageSprite
|
||||
if (this.imageSprite) {
|
||||
this.imageSprite.free();
|
||||
this.init();
|
||||
}
|
||||
this.sprite.filename = stendhal.paths.sprites + "/"
|
||||
+ (this["class"] || "") + "/"
|
||||
+ (this["subclass"] || "") + "/"
|
||||
+ (this["_name"] || "") + ".png";
|
||||
} else if (key === "state") {
|
||||
if (this.imageSprite) {
|
||||
this.imageSprite.offsetY = value * 32;
|
||||
}
|
||||
this.sprite.offsetY = value * 32;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,7 +42,7 @@ export class VisibleEntity extends Entity {
|
|||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/look.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/look.png) 1 3, auto";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,9 +9,10 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { Paths } from "../data/Paths";
|
||||
import { Entity } from "./Entity";
|
||||
|
||||
declare var stendhal: any;
|
||||
|
||||
export class WalkBlocker extends Entity {
|
||||
|
||||
override zIndex = 3000;
|
||||
|
|
@ -21,7 +22,7 @@ export class WalkBlocker extends Entity {
|
|||
}
|
||||
|
||||
override getCursor(_x: number, _y: number) {
|
||||
return "url(" + Paths.sprites + "/cursor/stop.png) 1 3, auto";
|
||||
return "url(" + stendhal.paths.sprites + "/cursor/stop.png) 1 3, auto";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,12 +9,11 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
import { stendhal } from "../stendhal";
|
||||
declare var marauroa: any;
|
||||
declare var stendhal: any;
|
||||
|
||||
import { Entity } from "./Entity";
|
||||
import { Player } from "./Player";
|
||||
import { Ground } from "./Ground";
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -23,12 +22,11 @@ import { Ground } from "./Ground";
|
|||
export class Zone {
|
||||
|
||||
/** Entities found in this zone. */
|
||||
public entities: Entity[] = [];
|
||||
private entities: Entity[] = [];
|
||||
|
||||
/** Singleton instance. */
|
||||
private static instance: Zone;
|
||||
|
||||
public ground = new Ground();
|
||||
|
||||
/**
|
||||
* Retrieves singleton instance.
|
||||
|
|
@ -47,7 +45,7 @@ export class Zone {
|
|||
// do nothing
|
||||
}
|
||||
|
||||
getEntitiesAt(x: number, y: number, filter?: boolean): Entity[] {
|
||||
getEntitiesAt(x: number, y: number, filter: boolean): Entity[] {
|
||||
const xGrid = x / 32;
|
||||
const yGrid = y / 32;
|
||||
const entities = [] as Entity[];
|
||||
|
|
@ -65,14 +63,14 @@ export class Zone {
|
|||
return entities;
|
||||
}
|
||||
|
||||
entityAt(x: number, y: number, filter?: boolean): Entity {
|
||||
let res = Zone.get().ground as any;
|
||||
entityAt(x: number, y: number, filter: boolean): Entity {
|
||||
let res = stendhal.zone.ground;
|
||||
for (const obj of this.getEntitiesAt(x, y, filter)) {
|
||||
res = obj;
|
||||
}
|
||||
|
||||
// If we found an entity, return it
|
||||
if (res != Zone.get().ground) {
|
||||
if (res != stendhal.zone.ground) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2005-2026 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* 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 "marauroa"
|
||||
|
||||
export class AttackEvent extends RPEvent {
|
||||
|
||||
public damage!: string;
|
||||
public type!: string;
|
||||
public weapon!: string;
|
||||
|
||||
public execute(entity: any): void {
|
||||
let target = entity.getAttackTarget();
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
if (this.hasOwnProperty("hit")) {
|
||||
var damage = parseInt(this["damage"], 10);
|
||||
if (damage !== 0) {
|
||||
target.onDamaged(entity, damage);
|
||||
} else {
|
||||
target.onBlocked(entity);
|
||||
}
|
||||
} else {
|
||||
target.onMissed(entity);
|
||||
}
|
||||
entity.onAttackPerformed(parseInt(this["type"], 10), this.hasOwnProperty("ranged"), this["weapon"]);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -10,13 +10,13 @@
|
|||
* *
|
||||
***************************************************************************/
|
||||
|
||||
import { RPEvent } from "marauroa"
|
||||
import { RPEvent } from "./RPEvent";
|
||||
|
||||
import { ui } from "../ui/UI";
|
||||
|
||||
import { DialogContentComponent } from "../ui/toolkit/DialogContentComponent";
|
||||
|
||||
import { stendhal } from "../stendhal";
|
||||
declare var stendhal: any;
|
||||
|
||||
|
||||
export class BestiaryEvent extends RPEvent {
|
||||
|
|
@ -24,7 +24,7 @@ export class BestiaryEvent extends RPEvent {
|
|||
enemies!: string;
|
||||
|
||||
|
||||
execute(_entity: any) {
|
||||
execute(entity: any) {
|
||||
if (!this.hasOwnProperty("enemies")) {
|
||||
console.error("Event does not have \"enemies\" attribute");
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
import { Chat } from "../util/Chat";
|
||||
import { ChatOptionsDialog } from "../ui/dialog/ChatOptionsDialog";
|
||||
import { RPEvent } from "marauroa"
|
||||
import { RPEvent } from "./RPEvent";
|
||||
|
||||
import { marauroa } from "marauroa"
|
||||
declare var marauroa: any
|
||||
|
||||
/**
|
||||
* shows an image for a detail view
|
||||
|
|
|
|||
|
|
@ -1,93 +0,0 @@
|
|||
/***************************************************************************
|
||||
* (C) Copyright 2003-2026 - Stendhal *
|
||||
***************************************************************************
|
||||
* *
|
||||
* 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 { marauroa } from "marauroa"
|
||||
|
||||
import { AttackEvent } from "event/AttackEvent";
|
||||
import { BestiaryEvent } from "./BestiaryEvent";
|
||||
import { ChatOptionsEvent } from "./ChatOptionsEvent";
|
||||
import { ExamineEvent } from "./ExamineEvent";
|
||||
import { GlobalVisualEffectEvent } from "event/GlobalVisualEffectEvent";
|
||||
import { GroupChangeEvent } from "./GroupChangeEvent";
|
||||
import { GroupInviteEvent } from "./GroupInviteEvent";
|
||||
import { ImageEvent } from "event/ImageEvent";
|
||||
import { PlayerLoggedOnEvent } from "./PlayerLoggedOnEvent";
|
||||
import { PlayerLoggedOutEvent } from "./PlayerLoggedOutEvent";
|
||||
import { PrivateTextEvent } from "event/PrivateTextEvent";
|
||||
import { ProgressStatusEvent } from "./ProgressStatusEvent";
|
||||
import { ReachedAchievementEvent } from "event/ReachedAchievementEvent";
|
||||
import { ShowItemListEvent } from "./ShowItemListEvent";
|
||||
import { ShowOutfitListEvent } from "./ShowOutfitListEvent";
|
||||
import { SoundEvent } from "./SoundEvent";
|
||||
import { TextEvent } from "event/TextEvent";
|
||||
import { TradeEvent } from "./TradeEvent";
|
||||
import { TransitionGraphEvent } from "event/TransitionGraphEvent";
|
||||
import { ViewChangeEvent } from "./ViewChangeEvent";
|
||||
|
||||
|
||||
export class EventRegistry {
|
||||
|
||||
private initialized = false;
|
||||
|
||||
/** Singleton instance. */
|
||||
private static instance: EventRegistry;
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves singleton instance.
|
||||
*/
|
||||
static get(): EventRegistry {
|
||||
if (!EventRegistry.instance) {
|
||||
EventRegistry.instance = new EventRegistry();
|
||||
}
|
||||
return EventRegistry.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hidden singleton constructor.
|
||||
*/
|
||||
private constructor() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers standard events.
|
||||
*/
|
||||
init() {
|
||||
if (this.initialized) {
|
||||
console.warn("tried to re-initialize EventRegistry");
|
||||
return;
|
||||
}
|
||||
this.initialized = true;
|
||||
|
||||
marauroa.rpeventFactory.register("attack", AttackEvent);
|
||||
marauroa.rpeventFactory.register("bestiary", BestiaryEvent);
|
||||
marauroa.rpeventFactory.register("chat_options", ChatOptionsEvent);
|
||||
marauroa.rpeventFactory.register("examine", ExamineEvent);
|
||||
marauroa.rpeventFactory.register("global_visual_effect", GlobalVisualEffectEvent);
|
||||
marauroa.rpeventFactory.register("group_change_event", GroupChangeEvent);
|
||||
marauroa.rpeventFactory.register("group_invite_event", GroupInviteEvent);
|
||||
marauroa.rpeventFactory.register("image_event", ImageEvent);
|
||||
marauroa.rpeventFactory.register("player_logged_on", PlayerLoggedOnEvent);
|
||||
marauroa.rpeventFactory.register("player_logged_out", PlayerLoggedOutEvent);
|
||||
marauroa.rpeventFactory.register("private_text", PrivateTextEvent);
|
||||
marauroa.rpeventFactory.register("progress_status_event", ProgressStatusEvent);
|
||||
marauroa.rpeventFactory.register("reached_achievement", ReachedAchievementEvent);
|
||||
marauroa.rpeventFactory.register("show_item_list", ShowItemListEvent);
|
||||
marauroa.rpeventFactory.register("show_outfit_list", ShowOutfitListEvent);
|
||||
marauroa.rpeventFactory.register("sound_event", SoundEvent);
|
||||
marauroa.rpeventFactory.register("text", TextEvent);
|
||||
marauroa.rpeventFactory.register("trade_state_change_event", TradeEvent);
|
||||
marauroa.rpeventFactory.register("transition_graph", TransitionGraphEvent);
|
||||
marauroa.rpeventFactory.register("view_change", ViewChangeEvent);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue