diff --git a/.github/workflows/dev.build.yml b/.github/workflows/dev.build.yml index e773ccf089..ace75b0b28 100644 --- a/.github/workflows/dev.build.yml +++ b/.github/workflows/dev.build.yml @@ -7,39 +7,48 @@ on: env: GMC_ENABLE_ON_PUBLISH: true + GMC_DEV_URL: 'https://auronen.cokoliv.eu/gmc/' jobs: deploy: runs-on: ubuntu-latest steps: - name: Install Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: # Number of commits to fetch. 0 indicates all history. # Default: 1 # 0 is needed for the update time plugin to work properly fetch-depth: 0 - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: 3.11 + python-version: 3.12 cache: pip - - name: Cache `requirements.txt` + - name: Process Python Cache id: cache-requirements - uses: actions/cache@v3 + uses: actions/cache@v4 with: - path: '**/venv/*' - key: requirements-${{ hashFiles('**/requirements*.txt') }} - - name: Install Dependencies into `venv` + path: venv + key: requirements-${{ hashFiles('requirements*.txt') }} + - name: Install Uncached Requirements if: steps.cache-requirements.outputs.cache-hit != 'true' run: | python -m venv venv source venv/bin/activate pip install -r requirements.txt + pip install -r requirements-deploy.txt - name: Run prebuild tests run: | source venv/bin/activate python -m unittest discover tests/ -v + - name: Process MkDocs Plugins & Hooks Cache + uses: actions/cache@v4 + with: + path: .cache + key: mkdocs-${{ github.sha }} + restore-keys: | + mkdocs- - name: Build and deploy site run: | source venv/bin/activate diff --git a/.github/workflows/master.build.yml b/.github/workflows/master.build.yml index eb96c37fd4..a78e9bb751 100644 --- a/.github/workflows/master.build.yml +++ b/.github/workflows/master.build.yml @@ -13,33 +13,41 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: # Number of commits to fetch. 0 indicates all history. # Default: 1 # 0 is needed for the update time plugin to work properly fetch-depth: 0 - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: 3.11 + python-version: 3.12 cache: pip - - name: Cache `requirements.txt` + - name: Process Python Cache id: cache-requirements - uses: actions/cache@v3 + uses: actions/cache@v4 with: - path: '**/venv/*' - key: requirements-${{ hashFiles('**/requirements*.txt') }} - - name: Install Dependencies into `venv` + path: venv + key: requirements-${{ hashFiles('requirements*.txt') }} + - name: Install Uncached Requirements if: steps.cache-requirements.outputs.cache-hit != 'true' run: | python -m venv venv source venv/bin/activate pip install -r requirements.txt + pip install -r requirements-deploy.txt - name: Run prebuild tests run: | source venv/bin/activate python -m unittest discover tests/ -v + - name: Process MkDocs Plugins & Hooks Cache + uses: actions/cache@v4 + with: + path: .cache + key: mkdocs-${{ github.sha }} + restore-keys: | + mkdocs- - name: Build and deploy site run: | source venv/bin/activate diff --git a/.github/workflows/pull.request.yml b/.github/workflows/pull.request.yml index 7817fee2ff..4164073b0c 100644 --- a/.github/workflows/pull.request.yml +++ b/.github/workflows/pull.request.yml @@ -13,29 +13,30 @@ jobs: runs-on: ubuntu-latest steps: - name: Install Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: # Number of commits to fetch. 0 indicates all history. # Default: 1 # 0 is needed for the update time plugin to work properly fetch-depth: 1 - name: Install Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: 3.11 + python-version: 3.12 cache: pip - - name: Cache `requirements.txt` + - name: Process Python Cache id: cache-requirements - uses: actions/cache@v3 + uses: actions/cache@v4 with: - path: '**/venv/*' - key: requirements-${{ hashFiles('**/requirements*.txt') }} - - name: Install Dependencies into `venv` + path: venv + key: requirements-${{ hashFiles('requirements*.txt') }} + - name: Install Uncached Requirements if: steps.cache-requirements.outputs.cache-hit != 'true' run: | python -m venv venv source venv/bin/activate pip install -r requirements.txt + pip install -r requirements-deploy.txt - name: Run prebuild tests run: | source venv/bin/activate diff --git a/.gitignore b/.gitignore index f2f846fd6f..8fe757e00d 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,7 @@ __pycache__/ /drafts/ # Social Plugin image cache -.cache/ \ No newline at end of file +.cache/ + +# VS Code config files +.vscode/ \ No newline at end of file diff --git a/docs/.pages b/docs/.pages index ff39b93ddb..935044d41e 100644 --- a/docs/.pages +++ b/docs/.pages @@ -1,6 +1,7 @@ nav: - Home: - ... | index*.md + - ... | preferences*.md - zengin - genome - contribute \ No newline at end of file diff --git a/docs/contribute/index.md b/docs/contribute/index.md index 3a56d6f398..707a0c14e6 100644 --- a/docs/contribute/index.md +++ b/docs/contribute/index.md @@ -188,25 +188,25 @@ In order to work locally: #### Build preferences While working with the project, it's possible to set various environmental variables to configure it to your own preferences: -- `GMC_DEFAULT_LANG` - is a 2-character language identifier (it must be present in the `mkdocs.yml` file), it sets the default language of the site -- `GMC_ONLY_DEFAULT_LANG` - `True` or `False` value, activates the site build to be only in the default language +- `GMC_DEV_LOCALE` - is a 2-character language identifier (ex. `en`, `pl`), it sets the development language of the site. This will enforce that language to be the default and only built language. Helps to decrease build time and allows to easily change the language without modyfying the config file. **Because of changes in the `mkdocs-static-i18n` plugin, this is the only way to temporarily change the default language** +- `GMC_BUILD_ALTERNATES` - `True` or `False` value, activates the site build to also include alternate languages apart of the default language. Default behaviour is to omit alternates to decrease build time. - `GMC_ENABLE_ON_PUBLISH` - `True` or `False` value, activates all of the final build procedures, like adding of the last modified date, minifying of the resources etc. Environmental variables can be set temporarily for the currently open Terminal window: ```bash title="Linux" -export GMC_DEFAULT_LANG=en export GMC_ONLY_DEFAULT_LANG=True; mkdocs serve +export GMC_DEV_LOCALE=en export GMC_BUILD_ALTERNATES=False; mkdocs serve ``` ```powershell title="Windows Powershell" -$env:GMC_DEFAULT_LANG="en" -$env:GMC_ONLY_DEFAULT_LANG="True" +$env:GMC_DEV_LOCALE="en" +$env:GMC_BUILD_ALTERNATES="False" mkdocs serve ``` ```batch title="Windows Command Prompt (cmd)" -set GMC_DEFAULT_LANG=en -set GMC_ONLY_DEFAULT_LANG=True +set GMC_DEV_LOCALE=en +set GMC_BUILD_ALTERNATES=False mkdocs serve ``` diff --git a/docs/contribute/index.pl.md b/docs/contribute/index.pl.md index e88d2af266..e7f4c911d5 100644 --- a/docs/contribute/index.pl.md +++ b/docs/contribute/index.pl.md @@ -188,25 +188,25 @@ Aby móc pracować lokalnie: #### Preferencje budowy strony Podczas pracy z projektem można ustawić różne zmienne środowiskowe, żeby przystosować konfigurację do własnych preferencji: -- `GMC_DEFAULT_LANG` - to dwuznakowy identyfikator języka (musi być obecny w pliku `mkdocs.yml`), ustawia domyślny język strony -- `GMC_ONLY_DEFAULT_LANG` - wartość `True` albo `False`, aktywuje budowanie strony wyłącznie w domyślnym języku +- `GMC_DEV_LOCALE` - to dwuznakowy identyfikator języka (np. `en`, `pl`), ustawia język testowy. To ustawi ten języki jako domyślny oraz jedyny renderowany podczas budowy strony. Pomaga w zmniejszeniu czasu budowy strony oraz pozwala na łatwe zmienianie języka zamiast modyfikowania pliku konfiguracyjnego. **Przez zmiany w pluginie `mkdocs-static-i18n` jest to jedyny sposób na tymczasową zmianę domyślnego języka** +- `GMC_BUILD_ALTERNATES` - wartość `True` albo `False`, aktywuje budowanie strony wraz z alternatywnymi językami. Domyślnie alternatywne języki są pomijane, aby zmenijszyć czas budowy strony. - `GMC_ENABLE_ON_PUBLISH` - wartość `True` albo `False`, aktywuje wszystkie finalne procesy, jak dodanie daty ostatniej aktualizacji, minimalizacja zasobów itp. Dla otwartego okna poleceń można tymczasowo je ustawić: ```bash title="Linux" -export GMC_DEFAULT_LANG=en export GMC_ONLY_DEFAULT_LANG=True; mkdocs serve +export GMC_DEV_LOCALE=en export GMC_BUILD_ALTERNATES=False; mkdocs serve ``` ```powershell title="Windows Powershell" -$env:GMC_DEFAULT_LANG="en" -$env:GMC_ONLY_DEFAULT_LANG="True" +$env:GMC_DEV_LOCALE="en" +$env:GMC_BUILD_ALTERNATES="False" mkdocs serve ``` ```batch title="Windows Konsola Poleceń (cmd)" -set GMC_DEFAULT_LANG=en -set GMC_ONLY_DEFAULT_LANG=True +set GMC_DEV_LOCALE=en +set GMC_BUILD_ALTERNATES=False mkdocs serve ``` diff --git a/docs/genome/tools/index.md b/docs/genome/tools/index.md index 432f878d20..ccf868efcc 100644 --- a/docs/genome/tools/index.md +++ b/docs/genome/tools/index.md @@ -6,5 +6,5 @@ Piranha Bytes did not release a modkit for their Genome engine, but the modding This page is under construction, for now, only handful of links are present. ## Gothic 3 SDK -Georgeto, inspired by NiceDE's Risen SDK, has created an SDK for Gothic 3. It can be used to manipulate the engine in the similar way Union is able to manipulate ZenGin. +Georgeto, inspired by NicoDE's Risen SDK, has created an SDK for Gothic 3. It can be used to manipulate the engine in the similar way Union is able to manipulate ZenGin. [GitHub repository](https://github.com/georgeto/gothic3sdk) diff --git a/docs/preferences.md b/docs/preferences.md new file mode 100644 index 0000000000..5665708f12 --- /dev/null +++ b/docs/preferences.md @@ -0,0 +1,92 @@ +--- +preferences_i18n: + en: + page-title: "Preferences" + page-description: "This page allows to set various preferences for reading the docs:" + color-title: "Color" + color-description: "You can change the feel of the site with a color change." + color-input-accent-title: "Select accent color" + color-input-hue-title: "Select hue color" + color-button-reset: "Reset colors" + custom-title: "Custom CSS" + custom-description: "You can add custom stylesheets." + custom-textarea-title: "Input CSS" + font-title: "Font" + font-description: "You can change the font to another preset." + font-selection-title: "Select font" + font-selection-default: "Default" + font-selection-opendyslexic: "OpenDyslexic" + heading-shadows-title: "Heading shadows" + heading-shadows-description: "You can enable additional shadows for the heading to make them appear more bold." + pl: + page-title: "Preferencje" + page-description: "Ta strona pozwala ustawić różne preferencje do czytania dokumentacji:" + color-title: "Kolor" + color-description: "Możesz zmienić nastrój strony poprzez zmianę koloru." + color-input-accent-title: "Wybierz kolor akcentujący" + color-input-hue-title: "Wybierz kolor odcienia" + color-button-reset: "Zresetuj kolory" + custom-title: "Własny CSS" + custom-description: "Możesz dodać niestandardowe arkusze stylów." + custom-textarea-title: "Wprowadź CSS" + font-title: "Czcionka" + font-description: "Możesz zmienić czcionkę na predefiniowany." + font-selection-title: "Wybierz czcionkę" + font-selection-default: "Domyślna" + font-selection-opendyslexic: "OpenDyslexic" + heading-shadows-title: "Cienie nagłówków" + heading-shadows-description: "Możesz włączyć dodatkowe cienie do nagłówków żeby wyglądały bardziej pogrubione." +--- +# {{ page-title }} + +{{ page-description }} + +## {{ color-title }} + +{{ color-description }} + + + + + + + +[{{ color-button-reset }} :fontawesome-regular-circle-xmark:](#preference-color-reset){ #preference-color-reset .md-button data-extra="reset" data-option="color" title="{{ color-button-reset }}" } + +## {{ font-title }} + +{{ font-description }} + + + + +## {{ custom-title }} + +{{ custom-description }} +
+ +
+ + \ No newline at end of file diff --git a/docs/zengin/anims/events.md b/docs/zengin/anims/events.md index 6023b9dd04..272cdd000d 100644 --- a/docs/zengin/anims/events.md +++ b/docs/zengin/anims/events.md @@ -1,50 +1,878 @@ --- -title: EventBlocks +title: Events --- -## Animation event blocks -We often need to perform some other actions together with our animation, such as playing a sound effect, inserting item into NPC's hand or changing an item instance into a different one, like turning a raw steel into hot raw steel. + +!!! example "Acknowledgment" + This tutorial was possible thanks to Kerrax, VAM and their excelent articles ([MDS](https://worldofplayers.ru/threads/36653/), [EventTags](https://worldofplayers.ru/threads/37708/)) and Avallach from [theModders](http://themodders.org/index.php?topic=13214.0) who provided valuable insight. + +## Animation event block overview + +We often need to perform some other actions together with our animation, such as playing a sound effect, inserting item into NPC's hand or changing an item instance into a different one, like turning a raw steel into hot raw steel. These actions often need to be done at very **specific** moment during the animation playback, therefore they are defined using **events**(#aniamtion-events) in the event block which follows right after the animation definition. The event block is started and closed by curly brackets. Example: ```dae -ani ("s_RunL" 1 "s_RunL" 0.0 0.1 M. "Hum_RunLoop_M01.asc" F 12 31) +ani ("s_RunL" 1 "s_RunL" 0.0 0.1 M. "Hum_RunLoop_M01.asc" F 12 31) // animation +{ // event block start + + *eventSFXGrnd (12 "Run") // animation event + *eventSFXGrnd (24 "Run") // animation event + ... + *eventSFXGrnd (30 "Run") // animation event +} // event block end +``` + +!!! Warning + Each animation can define a maximum of 16 events. Should you need more, split the animation into parts and use `next_ani` to chain them together. + +## Animation events +Animation events are commands telling engine to do something. Event `*eventSFXGrnd(12 "Run")` will command the engine to play sound `Run` at the very moment (12th frame) the character lands food on the ground. So with that in mind here is the general syntax as well as each animation event in the game. + +General Syntax: +```dae + *EVENTNAME (FRAME KEYWORD "INSTANCE" [OPTIONAL] [A:VALUE] [B:VALUE]) +``` + +`FRAME` - all events specify on what frame int the animation source file `.ASC` should this event happen + +`KEYWORD` - some events expect very specific keywords. + +`"INSTANCE"` - this indicates parameter is expected to be inside quotes, usually it;s slot/bone or item/sound instance name from the scrips + +`[OPTIONAL]` - this is an example of the optional parameter. Optional parameters will be indicated by brackets `[]`, if you don't specify them, the event will use the default value defined by the engine. + +`A:VALUE` - some events that have more than one optional parameter use a prefix to know which was specified + + +`NODE_NAME` - will indicate any `NODE` should work, be it bones (`BIP01`...) or `ZS_` slots (`ZS_RIGHTHAND`) + +`SLOT` - this will indicate most likely only `ZS_` slots will work. + + +!!! Warning + Events should follow in ascending order by the frame they appear on. i. e. `*eventTag(1 ...)` must come before `*eventTag(2 ...)` + +| Event | Description | +|---------------------------------------|-------------------------------------------------------------------------------------| +| [eventCamTremor](#eventcamtremor) | camera shake | +| [eventMMStartAni](#eventmmstartani) | start morph-mesh | +| [eventPFX](#eventpfx) | create particle effect | +| [eventPFXStop](#eventpfxstop) | destroy particle effect | +| [eventSwapMesh](#eventswapmesh) | exchange item meshes between two slots | +| [eventSFX](#eventsfx) | create sound effect | +| [eventSFXGRND](#eventsfxgrnd) | create sound effect on the ground | +| [eventTag](#eventtag) | generic event, does action specified in parameters | +| Defined in engine but never used ? | | +| [eventPFXGRND](#eventpfxgrnd) | create particle effect on the ground | +| [eventSetMesh](#eventsetmesh) | ? | +| [modelTag](#modeltag) | same as eventTag, but applies to morphmesh? | + + +### eventCamTremor + +Earthquake effect (camera shake) + +Example: +```dae +*eventCamTremor (12 1000 500 2 8 ) +``` + +Syntax: +```dae +*eventCamTremor (FRAME RANGE DURATION MIN_AMPLIFIER MAX_AMPLIFIER) +``` + +`eventCamTremor` - is a keyword, for camera shake event + +Let's describe all the parameters + +`FRAME` - animation frame at which this event starts + +`RANGE` - range from which the effect will be 'felt' defined in in-game **centimeters** (1000 is 10 meters in-game) + +`DURATION` - duration of the effect in milliseconds + +`MIN_AMPLIFIER` - minimum amount of shaking in in-game centimeters + +`MAX_AMPLIFIER` - the maximum amount of shaking. + +### eventMMStartAni + +Start the animation of the morph-mesh that is attached to the specified node. Mostly used to start NPC facial animations or to animate bows/crossbows shooting. + +Example: +```dae +*eventMMStartAni (14 "T_HURT") +*eventMMStartAni (6 "S_SHOOT" "ZS_RIGHTHAND") +*eventMMStartAni (6 "S_BOOK_NEXT_PAGE" "ZS_RIGHTHAND" I:0.5 H:5) +``` + +Syntax: +```dae +*eventMMStartAni (FRAME "ANI_NAME" ["NODE_NAME"] [I:INTENSITY] [H:HOLD_TIME]) +``` + + +`FRAME` - animation frame at which animation should start + +`ANI_NAME` - name of the morph-mesh animation (specified in .MMS) file + +`NODE_NAME` - node in the hierarchy, to which morph mesh is attached. If not specified, a default value of `BIP01 HEAD` will be used. + +`I:INTENSITY` - **float** value to specify blending of morph animation with the current one ? + +`H:HOLD_TIME` - time in seconds, how long will the animation "stay" + + +Both `INTENSITY` and `HOLD_TIME` can be specified in the MMS script. All gothic morph meshes specify those values in .MMS, therefore behavior when both specified in eventMMStartAni and .MMS file is unknown/untested + +## eventPfx + +Start particle effect at the specified bone. + +Example: +```dae +*eventPFX (12 "ZMODELLANDDUST" "Bip01" ) +*eventPFX (2 1 "DEMON_ATTACK" "BIP01 R HAND" ATTACH) +``` + +Syntax: +```dae +*eventPFX (FRAME [PFX_HANDLE] "PFX_NAME" "NODE_NAME" [ATTACH]) +``` + +`FRAME` - animation frame at which particle effect starts + +`PFX_NAME` - name of the PFX instance + +`PFX_HANDLE` - an optional integer value. Specifying this creates a 'handle' and allows stop the PFX later using [eventPFXStop](#eventpfxstop) + +`NODE_NAME` - node in the hierarchy. particle effect will be spawned at the node's position. If not specified, a default value of `BIP01` will be used. + +`ATTACH` - keyword, including this keyword, will make particle effect follow the node specified, otherwise, it will stay where it spawned. + + +!!! Tip + `ATTACH` is used to create demons burning hand during the attack, while without this keyword dust particles are made to stay at the position where NPC landed after falling. + + +## eventPFXStop + +Stops particle effect previously started by [eventPfx](#eventpfx) + + +Example: +```dae +*eventPFX (2 1 "DEMON_ATTACK" "BIP01 R HAND" ATTACH) // starts pfx with handle 1 +... +*eventPFXStop (70 1) // stops pfx started above +``` + +Syntax: +```dae +*eventPFXStop (FRAME PFX_HANDLE) +``` + +`FRAME` - animation frame at which particle effect should disappear + +`PFX_HANDLE` - an integer value. *Handle* of the particle effect, that should be destroyed. Particle effect must be spawned using the same handle by [eventPfx](#eventpfx) first + + +## eventSwapMesh + +Move mesh from source `NODE` to target node. Item should be present in the node already. Only mesh of the Items is moved, engine internally still keeps a reference to items in the original slot? Never used in game? + +Example: +```dae +*eventSwapMesh (5 "ZS_CROSSBOW" "ZS_LEFTARM") +``` + +Syntax: +```dae +*eventSWAPMESH (FRAME "SOURCE_NODE_NAME" "TARGET_NODE_NAME") +``` + +`FRAME` - animation frame at which transport of the mesh should happen + +`SOURCE_NODE_NAME` - source node containing the item. + +`TARGET_NODE_NAME` - target node that the item should be moved to. + + +!!! Note + In some rare occasions duplicates item + +## eventSfx + +Play sound effect. It can be either `SFX` instance from scripts, or `.WAV` file. + +Example: +```dae +*eventSFX (0 "Drown") +*eventSFX (8 "WHOOSH" EMPTY_SLOT) +*eventSFX (8 "BAB_SIGH" R:5000 EMPTY_SLOT) +``` + +Syntax: +```dae +*eventPFX (FRAME "SFX_NAME" [R:RANGE] [EMPTY_SLOT]) +``` + +`FRAME` - animation frame at which particle effect starts + +`SFX_NAME` - name of the SFX instance or `.WAV` file + +`R:RANGE` - an optional integer value. The range from which the effect will be 'heard' defined in in-game **centimeters** (1000 is 10 meters in-game) + +`[EMPTY_SLOT]` - optional keyword. By default audio effects use a single audio channel (slot) per Model. That means every `eventSFX` request will cancel any currently playing effect. If `EMPTY_SLOT` is specified, audio will be played on the next available (empty) audio slot and other sounds will not be interrupted. + + +!!! Note + A lot of original game animations contain `EMTPY_SLOT` instead of `EMPTY_SLOT` which was probably unintended. Gothic therefore acts as no keyword was provided, which causes a lot of sound interruptions. Therefore be mindful of spelling when copying original MDS scripts + + +## eventSfxGrnd + +the same as [eventSfx](#eventsfx) with only one difference, the sound effect name is appended with the current material name. + +Example: +```dae +*eventSFXGrnd (12 "Run") +``` + +Syntax: +```dae +*eventSFXGrnd (FRAME "SFX_NAME" [R:RANGE] [EMPTY_SLOT]) +``` + +Depending on the material of the texture, the character is standing on, the game will add one of the following suffixes: + + +| Spacer Material | Suffix | Gothic 1 | Gothic 2a | +|---------------------|------------|------------|-----------| +| `UNDEF` | _Undef | ✔️ | ✔️ | +| `EARTH` | _Earth | ✔️ | ✔️ | +| `SAND` | _Sand | ✔️ | ✔️ | +| `METAL` | _Metal | ✔️ | ✔️ | +| `WATER` | _Water | ✔️ | ✔️ | +| `WOOD` | _Wood | ✔️ | ✔️ | +| `SNOW` | _Snow | ❌ | ✔️ | +| `STONE` | _Stone | ✔️ | ✔️ | +| default | _Stone | ✔️ | ✔️ | + + +NPC running on grass texture, with material set to EARTH in world editor, will play sound `Run_Earth` by using `*eventSFXGrnd (12 "Run")` in run animation. `_Earth` suffix is determined and added by the engine. + + +## eventTag + +This is a generic type of event that does different actions based on the first parameter after the frame parameter. It was probably later in development to extend MDS functionality without the need to expand parser itself. +All parameters except `FRAME` are passed inside quotes Further parameters are specific for every `EVENT_TAG_TYPE`. + +!!! Waning + eventTag contrary to other events is validated only at runtime. If parameters are wrong, it won't work or might crash the game + +Syntax: +```dae +*eventTag (FRAME "EVENT_TAG_TYPE" "PARAMETER_1" "PARAMETER_2" ... "PARAMETER_N") +``` + +`FRAME` - Frame at which the event will execute. This parameter is always first and the same for all `eventTags` + +`EVENT_TAG_TYPE` - a type of event = action that should happen. + +Here is a list of event tag types: + +| EVENT TAG TYPE | Description +|---------------------------------------------------|-------------------------------------------------------| +| [DEF_CREATE_ITEM](#def_create_item) | Creates item into slot | +| [DEF_INSERT_ITEM](#def_insert_item) | Inserts item to slot from inventory | +| [DEF_REMOVE_ITEM](#def_remove_item) | Removes item from slot to inventory | +| [DEF_DESTROY_ITEM](#def_destroy_item) | Destroys item in slot | +| [DEF_PLACE_ITEM](#def_place_item) | ~~Places item from slot into mob slot~~ Destroys item in slot | +| [DEF_EXCHANGE_ITEM](#def_exchange_item) | Removes item in slot and replaces with new item | +| [DEF_FIGHTMODE](#def_fightmode) | Sets npc into weapon stance | +| [DEF_PLACE_MUNITION](#def_place_munition) | Inserts munition into slot | +| [DEF_REMOVE_MUNITION](#def_remove_munition) | Remove munition back to inventory | +| [DEF_DRAWSOUND](#def_drawsound) | Plays weapon drawing sound based on weapon material | +| [DEF_UNDRAWSOUND](#def_undrawsound) | Plays weapon sheating sound based on weapon material | +| [DEF_SWAPMESH](#def_swapmesh) | Moves items visual to different slot visually | +| [DEF_DRAWTORCH](#def_drawtorch) | Inserts torch | +| [DEF_INV_TORCH](#def_inv_torch) | Moves torch to different slot temporarily | +| [DEF_DROP_TORCH](#def_drop_torch) | Drops torch from slot to world | +| [DEF_HIT_LIMB](#def_hit_limb) | Defines node which deals damage | +| [DEF_DIR](#def_dir) | Defines attack direction | +| [DEF_DAM_MULTIPLIER](#def_dam_multiplier) | Defines damage mutliplier | +| [DEF_PAR_FRAME](#def_par_frame) | Defines frame range for blocking | +| [DEF_OPT_FRAME](#def_opt_frame) | Defines damage frames | +| [DEF_HIT_END](#def_hit_end) | Defines last frame to continue combo | +| [DEF_WINDOW](#def_window) | Defines frame for combo continuation | + +#### DEF_CREATE_ITEM + +Creates a new item instance and inserts it into the specified slot. Item is not inserted permanently but only for the duration of interaction. + +Example: +```dae +*eventTag (4 "DEF_CREATE_ITEM" "ZS_RIGHTHAND" "ItMw_1H_Mace_L_04") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_CREATE_ITEM" "SLOT" "ITEM_INSTANCE") +``` + + +`SLOT` - a name of the `ZS_` slot, write in UPPERCASE + +`ITEM_INSTANCE` - item instance from the scripts + + +!!! Warning + This event tag most likely works only during Mob/Item interaction + +#### DEF_INSERT_ITEM + +Insert the interaction item into the specified slot. + + - during mob interaction, inserted item instance is of instance taken from **UseWithItem** mob property. + - during item interaction (i.e. drink potion) item that started the **SceneName** will be inserted. + +In the example below: `(1)` inserts `ItMiSwordrawhot` that is defined in spacer into `ZS_LEFTHAND`, then `(2)` spawns `ItMw_1H_Mace_L_04` (hammer) into `ZS_RIGHTHAND` for anvil interaction. + +Example: +```{ .dae } +ani ("t_BSANVIL_S0_2_S1" 1 "s_BSANVIL_S1" 0.0 0.0 M. "Hum_BSAnvil_Jue00.asc" F 4 9) { - *eventSFXGrnd (12 "Run") - *eventSFXGrnd (21 "Run") + *eventTag (4 "DEF_INSERT_ITEM" "ZS_LEFTHAND") // (1) + *eventTag (4 "DEF_CREATE_ITEM" "ZS_RIGHTHAND" "ItMw_1H_Mace_L_04") // (2) } ``` -The example shows the animation and its event block. We place these events into a block surrounded by curly brackets. -There are many events to choose from to choose from. Here are some examples: -Sound effects +Syntax: ```dae -*eventSFXGrnd (12 "Run") -*eventSFX (10 "Swim") +*eventTag (FRAME "DEF_INSERT_ITEM" "SLOT") +``` + + +`SLOT` - a name of the `ZS_` slot, use UPPERCASE + +`ITEM_INSTANCE` - item instance from the scripts + +!!! Warning + This event tag most likely works only during Mob/Item interaction + +!!! Note "" + The well-known Gothic bug: + + If player gets hit while drinking a potion, the effect of the potion is applied, but the potion remains in the inventory - the reason for the bug is that the potion item is inserted into hand using `DEF_INSERT_ITEM` and would be removed from the world at the end of the drinking animation, while the potion's effect (a script function that increases stats) is applied at the very beginning of the animation. When the player is hit, the drinking animation is interrupted, and the engine does not remove the item from the world. + +#### DEF_REMOVE_ITEM + +Remove an item inserted into a slot via `DEF_INSERT_ITEM` from the slot back into the **inventory**. + +Example: +```dae +*eventTag (0 "DEF_REMOVE_ITEM") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_REMOVE_ITEM") +``` + +!!! Warning + This event tag most likely works only during Mob/Item interaction + +#### DEF_DESTROY_ITEM + +Destroys an item inserted into a slot via `DEF_INSERT_ITEM`. The item is **removed** from the world. + +Example: +```dae +*eventTag (0 "DEF_DESTROY_ITEM") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_DESTROY_ITEM") +``` + +!!! Warning + This event tag most likely works only during Mob/Item interaction + +#### DEF_PLACE_ITEM + +Remove the item inserted via eventTag `DEF_INSERT_ITEM` from the slot and the world. In terms of its action, eventTag `DEF_PLACE_ITEM` is a synonym for `DEF_DESTROY_ITEM`. +Possibly fixed by SystemPack. See intended use. + +Example: +```dae +*eventTag (0 "DEF_PLACE_ITEM") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_PLACE_ITEM") +``` + +!!! Warning + This event tag most likely works only during Mob/Item interaction + +??? Example "Intended use" + Presumably, the eventTag `DEF_PLACE_ITEM` was intended to have different behavior: If an NPC interacts with a MOB that has a `ZS_SLOT` node, then move the item inserted via `DEF_INSERT_ITEM` from the NPC node into the `ZS_SLOT` node on the MOB. An example would be orc priest hearts in the Temple of the Sleeper, Gothic 1. + + ```dae + // Sleeper Portal + ani ("t_SPORTAL_Stand_2_S0" 1 "s_SPORTAL_S0" 0.0 0.0 M. "Hum_SleeperPortal_M01.asc" F 0 19) + ani ("s_SPORTAL_S0" 1 "s_SPORTAL_S0" 0.0 0.0 M. "Hum_SleeperPortal_M01.asc" F 20 20) + ani ("t_SPORTAL_S0_2_Stand" 1 "" 0.0 0.2 M. "Hum_SleeperPortal_M01.asc" R 0 19) + ani ("t_SPORTAL_S0_2_S1" 1 "s_SPORTAL_S1" 0.0 0.0 M. "Hum_SleeperPortal_M01.asc" F 21 90 FPS:10) + { + *eventTag (60 "DEF_INSERT_ITEM" "ZS_RIGHTHAND") // (1) + *eventTag (90 "DEF_PLACE_ITEM") // (2) + } + ani ("s_SPORTAL_S1" 1 "s_SPORTAL_S1" 0.0 0.0 M. "Hum_SleeperPortal_M01.asc" F 91 91) + ani ("t_SPORTAL_S1_2_Stand" 1 "" 0.0 0.2 M. "Hum_SleeperPortal_M01.asc" F 90 100) + ``` + + During animation on 60th frame,`(1)` inserts orc priest sword from the inventory, and `(2)` on 90th frame, presumably, should have left the sword inserted into the heart sticking out. There is `ZS_SLOT` present to indicate the location of the sword after insertion into the heart. + + In reality, `(2)` simply removes the sword from the world like `DEF_DESTROY_ITEM`. This was most likely an unrealized idea. In G2, eventTag `DEF_PLACE_ITEM` is not used. + +#### DEF_EXCHANGE_ITEM + +Replace an item in a slot with another item. Item present in the slot is removed from the slot and the world, new item specified in parameters is created and inserted in the same slot. + +Example: +```dae +*eventTag (37 "DEF_EXCHANGE_ITEM" "ZS_LEFTHAND" "ItMiSwordrawhot") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_EXCHANGE_ITEM" "SLOT" "ITEM_INSTANCE") ``` -Particle effects + +`SLOT` - a name of the `ZS_` slot, use UPPERCASE + +`ITEM_INSTANCE` - item instance from the scripts + +!!! Warning + This event tag most likely works only during Mob/Item interaction + +#### DEF_FIGHTMODE + +Set fight mode for the model. Used in transition animations to weapon stances like `t_1h_2_1hRun`. + +Example: ```dae -*eventPFX (12 "ZMODELLANDDUST" "Bip01") -*eventPFX (35 1 "BUBBLES" "BIP01 HEAD" ATTACH) -*eventPFXStop (45 1) +*eventTag (5 "DEF_FIGHTMODE" "FIST") ``` -Morph mesh animations -> ⚠ Heads are animated using morph meshes and whilst this feature is almost never used in the original game, Chronicles of Myrtana uses it plenty. I intend to dedicate separate section to `morphMesh` animation in the future. +Syntax: ```dae -*eventMMStartAni (14 "T_HURT") +*eventTag (FRAME "DEF_FIGHTMODE" "FIGHT_MODE") ``` -Event tags + +`FIGHT_MODE` - fight modes are defined in the engine and can be one of the following: + +- `""` - remove weapon +- `"FIST"` - fists +- `"1H"` or `"1HS"` - one-handed weapon +- `"2H"` or `"2HS"` - two-handed weapon +- `"BOW"` - bow +- `"CBOW"` - crossbow +- `"MAG"` - magic + +Example: Parameter `1H` sets fight mode for the actor (in the engine), but also exchanges sword from `ZS_SWORD` slot to the `ZS_RIGHTHAND` + +#### DEF_PLACE_MUNITION + +Place ammunition, from inventory such as an arrow into the specified slot. Used in reloading animations after a bow/crossbow shot. + +Example: ```dae -*eventTag (5 "DEF_FIGHTMODE" "") +*eventTag (9 "DEF_PLACE_MUNITION" "ZS_RIGHTHAND") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_PLACE_MUNITION" "SLOT") +``` -*eventTag (0 "DEF_HIT_LIMB" "ZS_RIGHTHAND") -*eventTag (0 "DEF_OPT_FRAME" "6") -*eventTag (0 "DEF_HIT_END" "29") -*eventTag (0 "DEF_WINDOW" "18 35") +`SLOT` - slot where the ammunition is created. There are only two valid slot names: `"ZS_LEFTHAND"` and `"ZS_RIGHTHAND"`. -*eventTa (4 "DEF_INSERT_ITEM" "ZS_LEFTHAND") -*eventTa (4 "DEF_CREATE_ITEM" "ZS_RIGHTHAND" "ItMw_1H_Sledgehammer_01") -*eventTa (9 "DEF_EXCHANGE_ITEM" "ZS_LEFTHAND" "ItMiSwordbladehot") -*eventTa (4 "DEF_REMOVE_ITEM") +Ammunition always corresponds to the equipped ranged weapon instance and its `munition` field in the `C_ITEM` instance + +```dae hl_lines="10" +instance ItRw_Sld_Bow(C_Item) +{ + name = "Лук"; + mainflag = ITEM_KAT_FF; + flags = ITEM_BOW; + material = MAT_WOOD; + value = Value_SldBogen; + damageTotal = Damage_SldBogen; + damagetype = DAM_POINT; + munition = ItRw_Arrow; + cond_atr[2] = ATR_DEXTERITY; + cond_value[2] = Condition_SldBogen; + visual = "ItRw_Sld_Bow.mms"; + description = name; + text[2] = NAME_Damage; + count[2] = damageTotal; + text[3] = NAME_Dex_needed; + count[3] = cond_value[2]; + text[5] = NAME_Value; + count[5] = value; +}; ``` +#### DEF_REMOVE_MUNITION + +Remove ammunition previously placed by [DEF_PLACE_MUNITION](#def_place_munition) event + +Example: +```dae +*eventTag (19 "DEF_REMOVE_MUNITION") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_REMOVE_MUNITION") +``` + +#### DEF_DRAWSOUND + +Play weapon drawing sound. Determined by drawn weapon `material` field in the `C_ITEM` instance + + - `“DrawSound_WO.wav”` - for MAT_WOOD; + - `"DrawSound_ME.wav"` - for MAT_METAL. + + +Example: +```dae +*eventTag (19 "DEF_DRAWSOUND") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_DRAWSOUND") +``` + +#### DEF_UNDRAWSOUND + +Play weapon sheathing sound. Determined by drawn weapon `material` field in the `C_ITEM` instance + + - `"UndrawSound_WO.wav”` - for MAT_WOOD; + - `"UndrawSound_ME.wav"` - for MAT_METAL. + + +Example: +```dae +*eventTag (19 "DEF_UNDRAWSOUND") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_UNDRAWSOUND") +``` + +#### DEF_SWAPMESH + +Swap items in the specified slots. + +Example: +```dae +*eventTag (5 "DEF_SWAPMESH" "ZS_CROSSBOW" "ZS_LEFTHAND") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_SWAPMESH" "SLOT1" "SLOT2") +``` + +`SLOT1` - name of the slot with item to be exchanged. + +`SLOT2` - name of the slot with item to be exchanged. + +!!! Warning + In case `SLOT1` or `SLOT2` is equal to `"ZS_LEFTHAND"` or `"ZS_RIGHTHAND"`, the engine will attempt to put the model into fight mode similar to [DEF_FIGHTMODE](#def_fightmode) event. This can lead to game freezing. + +!!! Tip + This event is similar to the [*eventSwapMesh](#eventswapmesh). The main difference is [*eventSwapMesh](#eventswapmesh) will swap only visuals (meshes) of the items, while [eventTag DEF_SWAPMESH](#def_swapmesh) will swap items and their slot references. + After a game reload, meshes would reset their positions if swapped using [*eventSwapMesh](#eventswapmesh). Additionally [*eventSwapMesh](#eventswapmesh) does not try to set the model into fight mode. + +#### DEF_DRAWTORCH + +Does nothing? never used. + +Example: +```dae +*eventTag (5 "DEF_DRAWTORCH") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_DRAWTORCH") +``` + +#### DEF_INV_TORCH + +Temporarily return torch into inventory, for the duration of mob/item interaction. Does nothing if a torch is not present in `ZS_LEFTHAND`. +Used before interacting with mobs like bed, or before performing eating animations that require a left hand. + + +Example: +```dae +*eventTag (5 "DEF_INV_TORCH") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_INV_TORCH") +``` + +#### DEF_DROP_TORCH + +Drop the torch onto the ground if present in `ZS_LEFTHAND`. + +Example: +```dae +*eventTag (5 "DEF_DROP_TORCH") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_DROP_TORCH") +``` + +#### DEF_HIT_LIMB + +Set which node is dealing damage to others. This node is then used in calculations for collisions. Up to four slots can be specified. + +Example: +```dae +// humans - fist attacks +*eventTag (0 "DEF_HIT_LIMB" "BIP01 R HAND") +// humans - sword attacks +*eventTag (0 "DEF_HIT_LIMB" "ZS_RIGHTHAND") +// animals +eventTag (0 "DEF_HIT_LIMB" "BIP01 HEAD") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_HIT_LIMB" "SLOT1" "SLOT2" "SLOT3" "SLOT4") +``` + +#### DEF_DIR + +Set the direction of the attack. Enemy block animation is determined by this information. Not used. + +Example: +```dae +*eventTag (0 "DEF_DIR" "O") +*eventTag (0 "DEF_DIR" "L") +*eventTag (0 "DEF_DIR" "OUOL") // combo attack - top, under, +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_DIR" "DIRECTIONS") +``` + +`DIRECTIONS` - can be up to 10 characters, each character defines one attack direction during combo attack, default is `O` - capital letter `O`, not zero `0`. Possible values are + +- `O` - (oben) from top/ over + +- `U` - (unter) from under + +- `R` - from right + +- `L` - from left + +If the enemy is trying to block an attack with a defined direction it will choose a matching animation adding a direction suffix like `t_1hParade_U` for opponent's attack direction `U` + +!!! Note + Sadly this feature was unused in Gothic 1. All attacks use `O` direction and only defined animations for blocking are for said `t_1hParade_O` But can be easily restored with a few new animations and MDS file edits. + In Gothic 2, blocking animation uses zero `0` instead of `O` which might indicate the feature no longer works. + + +#### DEF_DAM_MULTIPLIER + +Set damage multiplier. For the attack animation. The damage will be multiplied by a provided number regardless of whether the attack is a critical attack or not. + +Example: +```dae +*eventTag (0 "DEF_DAM_MULTIPLIER" "0.2") +*eventTag (0 "DEF_DAM_MULTIPLIER" "2.0") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_DAM_MULTIPLIER" "MULTIPLIER") +``` + +`MULTIPLIER` - float value inside quotes + +#### DEF_PAR_FRAME + +Set frame range during which damage is blocked. If not provided whole animation is blocking damage. + +Example: +```dae +*eventTag (0 "DEF_PAR_FRAME" "1 8") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_PAR_FRAME" "START_FRAME_END_FRAME") +``` + +`START_FRAME_END_FRAME` - Two integer numbers inside quotes. if `"0 0"` is provided, the animation will be blocking it's whole duration + +#### DEF_OPT_FRAME + +Set frames during which damage collisions should be evaluated. Damage is checked for collision with ["hit limb"](#def_hit_limb). This event usually comes in pair with eventTags [DEF_WINDOW](#def_window) and [DEF_HIT_END](#def_hit_end) + +Example: +```dae +*eventTag (0 "DEF_OPT_FRAME" "6") // on hit attack, hit on 6th frame +*eventTag (0 "DEF_OPT_FRAME" "6 30") // 2 attack combo, hit at 6th and 30th frame +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_OPT_FRAME" "HIT_FRAME1 HIT_FRAME2 ... HIT_FRAME10") +``` + +`HIT_FRAME1 HIT_FRAME2 ... HIT_FRAME10` - specify 1 and up to 10 integers separated by space inside quotes. Each number represents frame at which damage should be done. Number of provided hit frames determines number of combos (max 10 possible). + + +#### DEF_HIT_END + +Set frames at which the combo is “cut off” if you do not press the “up” key (G1) or the left mouse button (G2) during the attack. Gothic has bug that in this case we will hear all the sound effects following this frame, and the animation ends with the character’s characteristic twitching. +The number of frames specified in this entry must match the number of frames of the [eventTag DEF_OPT_FRAME](#def_opt_frame). + +Example: +```dae +*eventTag (0 "DEF_HIT_END" "32") +*eventTag (0 "DEF_HIT_END" "27 48 75") +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_HIT_END" "HIT_END1 HIT_END2 ... HIT_END10") +``` + +`HIT_END1 HIT_END2 ... HIT_END10` - specify 1 and up to 10 integers separated by space inside quotes. After this frame combo cannot be continued and model will continue animation until the current `DEF_WINDOW -` 1`. Which is usually animation returning to idle stance + +#### DEF_WINDOW + +Set a “window” in the animation - an interval of frames during which you need to press the “up” (G1) or the left mouse button (G2) to continue the combo strike. + +Example: +```dae +*eventTag (0 "DEF_WINDOW" "9 19") // one combo with window from 9-19 (can be chained) +*eventTag (0 "DEF_WINDOW" "10 23 32 41 58 70") // 3 combos with windows 10-23 then 32-41, 58-70 +``` + +Syntax: +```dae +*eventTag (FRAME "DEF_WINDOW" "HIT_1_WINDOW_START HIT_1_WINDOW_END HIT_2_WINDOW_START HIT_2_WINDOW_END ...") +``` + +`HIT_1_WINDOW_START HIT_1_WINDOW_END HIT_2_WINDOW_START HIT_2_WINDOW_END` - specify 1 and up to 20? integers separated by space inside quotes. A window consists of a start and end frame, therefore for each DEF_OPT_FRAME, you must provide 2 numbers. + +- `HIT_WINDOW_START` - First value of the pair defines frame from which attack can continue. +- `HIT_WINDOW_END` - Second value is a little confusing. It defines **START** of the next attack animation. Ability to continue combo stops at [DEF_HIT_END](#def_hit_end) frames. Usually there are few frames of animation, where characters returns to idle position. `HIT_WINDOW_END` should be one frame after characters return to idle stance, which should also be first frame of the next attack + + +#### Attack eventTags explained + +This is original attack combo from Gothic 1 + +```dae +ani ("s_1hAttack" 1 "s_1hAttack" 0.0 0.1 M. "Hum_1hAttackComboT3_M05.asc" F 1 114) +{ + *eventTag (0 "DEF_HIT_LIMB" "ZS_RIGHTHAND") + *eventTag (0 "DEF_OPT_FRAME" "4 36 73 107") + *eventTag (0 "DEF_HIT_END" "31 63 95 113") + *eventTag (0 "DEF_WINDOW" "10 33 42 65 78 97 110 113") + *eventSFX (4 "Whoosh" EMPTY_SLOT ) + *eventSFX (72 "BACK" EMPTY_SLOT ) +} + +``` + +I will edit it slightly to make it more readable. Let's focus on the DEF_OPT_FRAME, DEF_HIT_END, + +```dae +ani ("s_1hAttack" 1 "s_1hAttack" 0.0 0.1 M. "Hum_1hAttackComboT3_M05.asc" F 1 114) +{ + ... + *eventTag (0 "DEF_OPT_FRAME" "4 36 73 107 ") + *eventTag (0 "DEF_HIT_END" " 31 63 95 113") + *eventTag (0 "DEF_WINDOW" " 10 33 42 65 78 97 110 113") + ... +} +``` + +Let's focus only on the first combo. + +```dae +ani ("s_1hAttack" 1 "s_1hAttack" 0.0 0.1 M. "Hum_1hAttackComboT3_M05.asc" F 1 114) +{ + ... + *eventTag (0 "DEF_OPT_FRAME" "4 ...") + *eventTag (0 "DEF_HIT_END" " 31 ...") + *eventTag (0 "DEF_WINDOW" " 10 33 ...") + ... +} +``` + +| Frames | Animation | Description | +|---------------|-----------------------------------------------------------|-----------------------------------------------------------------------------------------------| +| 1 | animation start | | +| 1..4 | swing of the sword | | +| 4 | sword is in the front of the model | `DEF_OPT_FRAME` - test damage collisions at this frame | +| 4..10 | end of the sword swing | | +| 10 | model stands ready to start next swing | `DEF_WINDOW` - user can press key to advance combo from this frame. | +| 10..31 | slight idle 'shake' | if player continues combo, animation playback will jump to the frame 33 (`DEF_WINDOW` second pair), from the animation perspective, next attack starts from pose similar to frame 10. If perfect inputs would be provided, animation would continue perfectly. | +| 31 | | `DEF_HIT_END` - ends user input. | +| 31..32 | model returns to the idle position | | +| 32 | idle position, standing with sword in hand | animation will end here, if combo not continued (`DEF_WINDOW` second pair - 1) | +| 33 | first frame of the next attack (similar to frame 10) | `DEF_WINDOW` second pair, start of next attack | + + + + + +## eventPfxGrnd + +Not used anywhere in the original game. Could possibly spawn particle effect like [eventPfx](#eventpfx) but with an added suffix similar to how [eventSfxGrnd](#eventsfxgrnd) works. Needs to be investigated. + +Syntax: +```dae +*eventPFXGRND (FRAME) +``` + +## eventSetMesh + +Unknown + +Syntax: +```dae +*eventSETMESH (FRAME "NODE_NAME") +``` + +## modelTag + +Should work similarly to [eventTag](#eventtag), but can be defined inside aniEnum block and applies to all animations of the Model. + +Syntax: +```dae +*modelTag (FRAME "EVENT_TAG_TYPE" "PARAMETER1" "PARAMETER2" "PARAMETER3" "PARAMETER4" ... ) +``` \ No newline at end of file diff --git a/docs/zengin/general_info/object_persistence.md b/docs/zengin/general_info/object_persistence.md index 2e339b8805..d64b1cbbaa 100644 --- a/docs/zengin/general_info/object_persistence.md +++ b/docs/zengin/general_info/object_persistence.md @@ -45,7 +45,7 @@ This property might not be present in older archives. This is the most important part of the header as it specifies in which format should the data be stored. There are 4 different modes: - **ASCII** - The simplest one. It stores data in human-readable ASCII notation (not unlike JSON for example). This is usually used when saving data during development and/or testing, while the final version of said data will most likely be stored as BIN_SAFE. -- **ASCII_PROPS** - Same as ASCII except with more additional data that the developer can specify for visual clarity. In practice, it is not used anywhere and mostly serves only to prettify debug info (try typing `ZWORLD VOBPROPS` in the console and look in zSpy ;) ). +- **ASCII_PROPS** - Same as ASCII except with more additional data that the developer can specify for visual clarity. In practice, it is not used anywhere and mostly serves only to prettify debug info (try typing `ZWORLD VOBPROPS` in the console and look in [zSpy](../tools/zSpy.md) ;) ). - **BINARY** - Binary representation of the class instance, which mostly copies the data 1:1 into/from the stream. In practice, this format is only used to store savefiles (.SAV). - **BIN_SAFE** - BinSafe, short for Binary Safe, is an extended version of Binary which stores type information along with the data itself. This is meant to make error checking for invalid data easier. There are other changes which are explained below. Most, if not all world files (.ZEN), are stored in this format. diff --git a/docs/zengin/music.md b/docs/zengin/music.md index 3705bebb97..397edcc02a 100644 --- a/docs/zengin/music.md +++ b/docs/zengin/music.md @@ -18,3 +18,7 @@ The music directory contains these file types: - Patterns - fragments of tracks, that can be later merged, looped and superimposed on each other - `.sgt` - File with properly connected patterns - the final track + +## Alternative Music System + +The [zBassMusic](./union/plugins/zbassmusic.md) plugin replaces Zengin's default music library with the much newer BASS library. This allows, among other things, to play music in such formats as `.mp3` or `.ogg`, and to pack songs into `.vdf` and `.mod` archives. \ No newline at end of file diff --git a/docs/zengin/music.pl.md b/docs/zengin/music.pl.md new file mode 100644 index 0000000000..2a29ce3669 --- /dev/null +++ b/docs/zengin/music.pl.md @@ -0,0 +1,27 @@ +--- +title: Muzyka +--- +# Muzyka + +Zengin używa [DirectMusic](https://en.m.wikipedia.org/wiki/DirectMusic) do odtwarzania ścieżki dźwiękowej w grze. Aby edytować pliki muzyczne Gothica, potrzebujesz programu [Direct Music Producer](https://en.m.wikipedia.org/wiki/DirectMusic), który został wydany przez Microsoft i był dostarczany do starszych zestawów SDK DirectX. + +!!! Warning "Ostrzeżenie" + Pliki muzyczne nie mogą być spakowane do archiwów `.vdf` lub `.mod`, wszystkie takie pliki muszą znajdować się w katalogu `/_work/Data/Music`. + +## Formaty plików + +Katalog `Music` zawiera następujące typy plików: + +- `.dls` - Plik formatu [Downloadable Sound](https://en.wikipedia.org/wiki/DLS_format). Jest bazą dla wszystkich innych plików. Zawiera: + - Kolekcje wirtualnych instrumentów muzycznych. + - Pliki `.wav` używane przez instrumenty. + +- `.sty` - Plik stylu. Zawiera: + - Zespoły (Bands) - ustawienia instrumentów wirtualnych z `.dls`. + - Wzory (Patterns) - fragmenty utworów, które można później łączyć, zapętlać i nakładać na siebie. + +- `.sgt` - Plik z odpowiednio połączonymi wzorami (patternami) - końcowy utwór + +## Alternatywny System Muzyczny + +Plugin [zBassMusic](./union/plugins/zbassmusic.md) zastępuje domyślną bibliotekę muzyczną Zengina, dużo nowszą biblioteką BASS. Umożliwia to między innymi odtwarzanie muzyki w takich formatach jak `.mp3` lub `.ogg`, oraz pakownie utworów do archiwów `.vdf` i `.mod`. \ No newline at end of file diff --git a/docs/zengin/scripts/classes/c_item.md b/docs/zengin/scripts/classes/c_item.md index ea5757085b..741c1ee5b2 100644 --- a/docs/zengin/scripts/classes/c_item.md +++ b/docs/zengin/scripts/classes/c_item.md @@ -41,7 +41,7 @@ Class definition as it is defined in [`Scripts/Content/_intern/Classes.d`](https // Benötigte Attribute zum Benutzen des Items var int cond_atr[3]; // Array of NPC attributes needed to equip the item - var int cond_value[3]; // Array of values corresponding to the cond_atr arry + var int cond_value[3]; // Array of values corresponding to the cond_atr array // Attributes to be changed on equip var int change_atr[3]; // Array of attributes that will be changed on equip diff --git a/docs/zengin/scripts/classes/c_menu.md b/docs/zengin/scripts/classes/c_menu.md new file mode 100644 index 0000000000..cf75021448 --- /dev/null +++ b/docs/zengin/scripts/classes/c_menu.md @@ -0,0 +1,179 @@ +--- +title: C_MENU +--- + +# C_MENU Daedalus class + +!!! example "Acknowledgment" + Heavily inspired by the amazing documentation site [Gothic library](http://www.gothic-library.ru) + +Class `C_Menu` is responsible for the behavior and properties of the game menus (options, save etc.). +## Class definition +Class definition as it is defined in [`Scripts/System/_intern/Menu.d`](https://github.com/VaanaCZ/gothic-2-addon-scripts/blob/Unified-EN/_work/Data/Scripts/System/_intern/Menu.d) script file. + +??? "C_Menu Daedalus class" + ```dae + class C_Menu + { + var string backPic; // Menu background image + var string backWorld; // Background ZEN-world of the game menu (Not used) + var int posx; // The top left point of the menu on the screen horizontally (X-axis) + var int posy; // The top left point of the menu on the screen vertically (Y-axis) + var int dimx; // Menu width in virtual coordinates + var int dimy; // Menu height in virtual coordinates + var int alpha; // Menu transparency + var string musicTheme; // Music track of the menu + var int eventTimerMSec; // trigger time for the event EVENT_TIMER + var string items[150]; // Menu items + var int flags; // Menu flags + var int defaultOutGame; // Menu item highlighted by default when the game is not running + var int defaultInGame; // Menu item highlighted by default when the game is running + }; + ``` + +## Class members + +| Variable | Type | Description | +|-----------------------------------|--------|-------------------------------------------------------------------------------------| +| [backPic](#backpic) | string | Menu background image | +| [backWorld](#backworld) | string | Background ZEN-world of the game menu (Not used) | +| [posx](#posx) | int | The top left point of the menu on the screen horizontally (X-axis) | +| [posy](#posy) | int | The top left point of the menu on the screen vertically (Y-axis) | +| [dimx](#dimx) | int | Menu width in virtual coordinates | +| [dimy](#dimy) | int | Menu height in virtual coordinates | +| [alpha](#alpha) | int | Menu transparency | +| [musicTheme](#musictheme) | string | Music track of the menu | +| [eventTimerMSec](#eventtimermsec) | int | The timer that triggered the event in seconds | +| [items](#items) | string | Menu items | +| [flags](#flags) | int | Menu flags | +| [defaultOutGame](#defaultoutgame) | int | Menu item highlighted by default when the game is not running | +| [defaultInGame](#defaultingame) | int | Menu item highlighted by default when the game is running | + + +## Class member overview +Description of the class member variables. + +### backPic +`backPic` is just a name of background image of the menu in `.tga` format. + +### backWorld +!!! Warning "Deprecated setting" + The background world of the game menu in `.ZEN` format. + +### posx +The horizontal position of the top left point of the menu on the screen, in virtual coordinates. + +### posy +The vertical position of the top left point of the menu on the screen, in virtual coordinates. + +### dimx +Menu width in virtual coordinates. + +### dimy +Menu height in virtual coordinates. + +### alpha +Menu transparency. Accepts values from 0 to 255. Without the `backPic` property specified, the value of this parameter is ignored. + +!!! Note + Texture transparency can only be adjusted if the texture has an alpha channel. + +### musicTheme +Music theme of the menu. +```dae +instance MENU_MAIN(C_MENU_DEF) +{ + ... + musictheme = "SYS_Menu"; + ... +}; +``` +All instances of musical themes are stored in a file [`Scripts/System/Music/MusicInst.d`](https://github.com/VaanaCZ/gothic-2-addon-scripts/blob/Unified-EN/_work/Data/Scripts/System/Music/MusicInst.d) + +### eventTimerMSec +Defines the trigger time for the event `EVENT_TIMER` in seconds. + +The list of constants for all menu events is described in the file [`Scripts/System/_intern/Menu.d`](https://github.com/VaanaCZ/gothic-2-addon-scripts/blob/Unified-EN/_work/Data/Scripts/System/_intern/Menu.d#L51) + +```dae +const int EVENT_UNDEF = 0; // Undefined +const int EVENT_EXECUTE = 1; // Process start event +const int EVENT_CHANGED = 2; // Menu parameter change event +const int EVENT_LEAVE = 3; // Menu item focus loss event +const int EVENT_TIMER = 4; // Timer fire event +const int EVENT_CLOSE = 5; // Menu close event +const int EVENT_INIT = 6; // Initialization event +const int EVENT_SEL_PREV = 7; // Select event of the previous menu item +const int EVENT_SEL_NEXT = 8; // Select event of the next menu item +``` + +### items +An array of items belonging to this menu. It is possible to use up to 150 items in one menu. The same elements can be used for different menus. The element instance is specified as the value. + +```dae +// Menu +instance MENU_MAIN(C_MENU_DEF) +{ + ... + items[0] = "MENUITEM_MAIN_HEADLINE"; + items[1] = "MENUITEM_MAIN_HEADLINE2"; + items[2] = "MENUITEM_MAIN_NEWGAME"; + ... +}; + +// Menu elements: labels, checkboxes, sliders, etc. + +instance MENUITEM_MAIN_HEADLINE(C_MENU_ITEM_DEF) +{ + ... +}; + +instance MENUITEM_MAIN_HEADLINE2(C_MENU_ITEM_DEF) +{ + ... +}; + +instance MENUITEM_MAIN_NEWGAME(C_MENU_ITEM_DEF) +{ + ... +}; +``` + +### flags +Menu flags. + +The list of flag constants can be found in the file [`Scripts/System/_intern/Menu.d`](https://github.com/VaanaCZ/gothic-2-addon-scripts/blob/Unified-EN/_work/Data/Scripts/System/_intern/Menu.d#L43) + + +```dae +const int MENU_OVERTOP = 1; // Show menu over previous menu or in game +const int MENU_EXCLUSIVE = 2; // Close all previous menus. Only the active menu is displayed +const int MENU_NOANI = 4; // No animation +const int MENU_DONTSCALE_DIM = 8; // Don't Scale Menu Sizes +const int MENU_DONTSCALE_POS = 16; // Empty flag +const int MENU_ALIGN_CENTER = 32; // Center Align Menu +const int MENU_SHOW_INFO = 64; // Display information at the bottom of the description menu from menu items text[1] +``` + +- **MENU_OVERTOP** - Flag to display the menu over the previous menu. It is not advisable to use with a transparent menu. +- **MENU_EXCLUSIVE** - Hide all menus except the active one. When closed, the previous menu is restored. +- **MENU_NOANI** - Animation of minimizing and maximizing windows. The game is mainly used for dialogue windows. You can't enable or disable the animation of dialog windows through scripts. This is done using the `animatedWindows` setting in the Gothic.ini file. +- **MENU_DONTSCALE_DIM** - Scale the menu to fit 640x480 resolution. +- **MENU_DONTSCALE_POS** - Empty flag. Not used. +- **MENU_ALIGN_CENTER** - Align the menu to the center of the screen. +- **MENU_SHOW_INFO** - Display information at the bottom of menu description from menu item `text[1]`. + +### defaultOutGame +The menu item that is highlighted by default when the game is not running. + +A value of -1 enables automatic selection of the first selectable element. + +Items with the `~IT_SELECTABLE` flag are not selected. + +### defaultInGame +Menu item highlighted by default when the game is running. + +A value of -1 enables automatic selection of the first selectable element. + +Items with the `~IT_SELECTABLE` flag are not selected. + diff --git a/docs/zengin/scripts/classes/c_menuitem.md b/docs/zengin/scripts/classes/c_menuitem.md new file mode 100644 index 0000000000..a8b04deb25 --- /dev/null +++ b/docs/zengin/scripts/classes/c_menuitem.md @@ -0,0 +1,765 @@ +--- +title: C_MENU_ITEM +--- + +# C_MENU_ITEM Daedalus class + +!!! example "Acknowledgment" + Heavily inspired by the amazing documentation site [Gothic library](http://www.gothic-library.ru) + +Class `C_Menu_Item` describes the elements of the game menu (sliders, checkboxes, buttons, etc.) . +## Class definition +Class definition as it is defined in [`Scripts/System/_intern/Menu.d`](https://github.com/VaanaCZ/gothic-2-addon-scripts/blob/Unified-EN/_work/Data/Scripts/System/_intern/Menu.d) script file. + +??? "C_Menu_Item Daedalus class" + ```dae + CONST INT MAX_USERSTRINGS = 10; + CONST INT MAX_ITEMS = 150; + CONST INT MAX_EVENTS = 10; + CONST INT MAX_SEL_ACTIONS = 5; + CONST INT MAX_USERVARS = 4; + + class C_Menu_Item + { + var string fontName; // Font of the menu item. + var string text[MAX_USERSTRINGS]; // Text of the interface element. + var string backPic; // Background image of menu items. + var string alphaMode; // Transparency blending mode of menu items. + var int alpha; // Transparency of the menu item. + var int type; // Type of the interface element. + var int onSelAction[MAX_SEL_ACTIONS]; // Array of commands executed when selecting the menu item. + var string onSelAction_S[MAX_SEL_ACTIONS]; // Arguments for commands specified in the onSelAction property. + var string onChgSetOption; // Gothic.ini file parameter modified by this menu item. + var string onChgSetOptionSection; // Section of the Gothic.ini file where the modified parameter is located. + var func onEventAction[MAX_EVENTS]; // Call the required function by a constant identifier. + var int posx; // Top-left point of the menu item on the screen horizontally (X-axis). + var int posy; // Top-left point of the menu item on the screen vertically (Y-axis). + var int dimx; // Width of the menu item in virtual coordinates. + var int dimy; // Height of the menu item in virtual coordinates. + var float sizeStartScale; // Initial size of the item. Not used. + var int flags; // Flags of the menu item. + var float openDelayTime; // Delay before opening the item. Not used. + var float openDuration; // Opening time. Not used. + var float userFloat[MAX_USERVARS]; // Digital settings of menu items. + var string userString[MAX_USERVARS]; // String settings of menu items. + var int frameSizeX; // Text offset inside the frame on the X-axis. + var int frameSizeY; // Text offset inside the frame on the Y-axis. + var string hideIfOptionSectionSet; // Section of Gothic.ini file where the option determining the display of this menu item is located. + var string hideIfOptionSet; // Gothic.ini file parameter determining the display of this menu item. + var int hideOnValue; // Value of the Gothic.ini file parameter at which this interface element is not displayed. + }; + ``` + +## Class members + +| Property | Type | Description | +|---------------------------------|--------|-------------------------------------------------------------------------| +| [fontName](#fontname) | string | Font of the menu item. | +| [text](#text) | string | Text of the interface element. | +| [backPic](#backpic) | string | Background image of menu items. | +| [alphaMode](#alphamode) | string | Transparency blending mode of menu items. | +| [alpha](#alpha) | int | Transparency of the menu item. | +| [type](#type) | int | Type of the interface element. | +| [onSelAction](#onselaction) | int | Array of commands executed when selecting the menu item. | +| [onSelAction_S](#onselaction_s) | string | Arguments for commands specified in the onSelAction property. | +| [onChgSetOption](#onchgsetoption) | string | Gothic.ini file parameter modified by this menu item. | +| [onChgSetOptionSection](#onchgsetoptionsection) | string | Section of the Gothic.ini file where the modified parameter is located. | +| [onEventAction](#oneventaction) | Func | Call the required function by a constant identifier. | +| [posx](#posx) | int | Top-left point of the menu item on the screen horizontally (X-axis). | +| [posy](#posy) | int | Top-left point of the menu item on the screen vertically (Y-axis). | +| [dimx](#dimx) | int | Width of the menu item in virtual coordinates. | +| [dimy](#dimy) | int | Height of the menu item in virtual coordinates. | +| [sizeStartScale](#sizestartscale) | float | Initial size of the item. Not used. | +| [flags](#flags) | int | Flags of the menu item. | +| [openDelayTime](#opendelaytime) | float | Delay before opening the item. Not used. | +| [openDuration](#openduration) | float | Opening time. Not used. | +| [userFloat](#userfloat) | float | Digital settings of menu items. | +| [userString](#userstring) | string | String settings of menu items. | +| [frameSizeX](#framesizex) | int | Text offset inside the frame on the X-axis. | +| [frameSizeY](#framesizey) | int | Text offset inside the frame on the Y-axis. | +| [hideIfOptionSectionSet](#hideifoptionsectionset) | string | Section of Gothic.ini file where the option determining the display of this menu item is located. | +| [hideIfOptionSet](#hideifoptionset) | string | Gothic.ini file parameter determining the display of this menu item. | +| [hideOnValue](#hideonvalue) | int | Value of the Gothic.ini file parameter at which this interface element is not displayed. | + +## Class member overview + +Description of the class member variables. + +### fontName +`*.TGA` file defining the font of the displayed text of the menu item. + +To create a color change effect, two fonts are needed: + + - The first font is specified in the `fontName` field and is used by default. + - The second font with the suffix `_Hi` is used to replace the text on the active (selected) element. + +This creates a highlighting effect. + +### text +Text inside a menu item. + +Used to determine possible values for game settings. See [onChgSetOptionSection](#onchgsetoptionsection). + +Also used to display hints about the item at the bottom of the menu when the `MENU_SHOW_INFO` [flag](#flags) is set. + +```dae +// Text displayed in the element + +text[0] = "New Game"; + +// Text in the interface element responsible for game settings +// One of the presented options is displayed + +text[0] = "off|on"; + +// Tooltip for the selected element +// Index 1 is used for tooltips, not 0 + +text[1] = "Start a new adventure"; +``` + +### backPic +Background image of the menu item in `*.TGA` format. + +```dae +instance MENUITEM_MAIN_NEWGAME(C_MENU_ITEM_DEF) +{ + backpic = "Inv_Slot_Highlighted.tga"; +} +``` + +### alphaMode +Texture transparency blending mode. Used in conjunction with the [alpha](#alpha) property. This parameter's value is ignored if the [backPic](#backpic) property is not specified. + +**Supported modes:** + +- `MAT_DEFAULT` + Uses the standard texture. If the material has an alpha channel, it will be transparent; otherwise, it will be opaque. + +- `NONE` + Transparency is not used unless the texture itself is transparent. + +- `BLEND` + Blends the alpha channel of the texture with the background. + +- `ADD` + Adds the alpha channel of the texture to the background. + +- `SUB` + Subtracts the alpha channel of the texture from the background. + +- `MUL` and `MUL2` + Multiplies the alpha channel of the texture by the background. + +### alpha +Menu element transparency. Accepts values from 0 to 255. Without specifying the [backPic](#backpic) property, the value of this parameter is ignored. + +The alpha channel rendering mode is determined using the [alphaMode](#alphamode) property. + +### type +Interface element type. Some interface elements have their own settings determined by the [userFloat](#userfloat) and [userString](#userstring) properties. + +Constants for menu item types are described in the file [`Scripts/System/_intern/Menu.d`](https://github.com/VaanaCZ/gothic-2-addon-scripts/blob/Unified-EN/_work/Data/Scripts/System/_intern/Menu.d#L18-L25). + +```dae +CONST INT MENU_ITEM_UNDEF = 0; // Undefined +CONST INT MENU_ITEM_TEXT = 1; // Text +CONST INT MENU_ITEM_SLIDER = 2; // Slider +CONST INT MENU_ITEM_INPUT = 3; // Input field +CONST INT MENU_ITEM_CURSOR = 4; +CONST INT MENU_ITEM_CHOICEBOX = 5; // Checkbox +CONST INT MENU_ITEM_BUTTON = 6; // Button +CONST INT MENU_ITEM_LISTBOX = 7; // Frame +``` + +- `MENU_ITEM_UNDEF` + Undefined element type. Not used in scripts. + +- `MENU_ITEM_TEXT` + Menu item type "Text". Text can be multiline by setting the `IT_MULTILINE` [flag](#flags). + +- `MENU_ITEM_SLIDER` + Menu item type "Slider". Additional settings are provided for the slider. + - [`userFloat[0]`](#userfloat) property determines the number of divisions for the slider. + - [`userFloat[1]`](#userfloat) property determines the width of the slider. + - [`userString[0]`](#userstring) property determines the background image for the slider thumb. + + ```dae + INSTANCE MENUITEM_AUDIO_MUSICVOL_SLIDER(C_MENU_ITEM_DEF) + { + backPic = MENU_SLIDER_BACK_PIC; + type = MENU_ITEM_SLIDER; // Type: Slider + // [...] + onChgSetOption = "musicVolume"; // INI file parameter + onChgSetOptionSection = "SOUND"; // INI file section + userFloat[0] = 15; // Number of slider positions + userString[0] = MENU_SLIDER_POS_PIC; // Background image of the slider + // [...] + }; + ``` + +- `MENU_ITEM_INPUT` + This type of element is intended for entering control keys during configuration, as well as for entering the name of the save in the corresponding menu. + +- `MENU_ITEM_CURSOR` + Deprecated element type. Not used in scripts. + +- `MENU_ITEM_CHOICEBOX` + "SELECT" type allowing the selection of one of the available values. + +- `MENU_ITEM_BUTTON` + Button. Not used in scripts. + - The [`userString[0]`](#userstring) property determines which image will be used for the disabled button. The [backPic](#backpic) property is responsible for the background image of the enabled button. + +- `MENU_ITEM_LISTBOX` + Menu item type used in the "Quest Log" menu. + - The [`userString[0]`](#userstring) property determines which task list will be displayed in this element. + + ```dae + userstring[0] = "CURRENTMISSIONS"; + userstring[0] = "OLDMISSIONS"; + userstring[0] = "FAILEDMISSIONS"; + userstring[0] = "LOG"; + ``` + +### onSelAction +Array of commands executed when selecting the menu item. + +Each command receives parameters in the [`onSelAction_S`](#onselaction_s) property. + +Constants are described in the file [`Scripts/System/_intern/Menu.d`](https://github.com/VaanaCZ/gothic-2-addon-scripts/blob/Unified-EN/_work/Data/Scripts/System/_intern/Menu.d#L8-L15). + +```dae +CONST INT SEL_ACTION_UNDEF = 0; // No action. Used when setting game parameters, calling functions... +CONST INT SEL_ACTION_BACK = 1; // Return to the previous menu or game +CONST INT SEL_ACTION_STARTMENU = 2; // Open a menu +CONST INT SEL_ACTION_STARTITEM = 3; // Special command for save slots +CONST INT SEL_ACTION_CLOSE = 4; // Close menu or game +CONST INT SEL_ACTION_CONCOMMANDS = 5; // Execute console command +CONST INT SEL_ACTION_PLAY_SOUND = 6; // Play sound from C_SFX instance +CONST INT SEL_ACTION_EXECCOMMANDS = 7; // Execute command specified in the onSelAction_S field using RUN or EFFECT commands +``` + +### onSelAction_S +Arguments for commands specified in the [`onSelAction`](#onselaction) property. + +Below are commands and their arguments: + +- `SEL_ACTION_UNDEF` + This command has no arguments and is mostly used in options and for calling script functions. + + ```dae + instance MENUITEM_MAIN_CREDITS(C_MENU_ITEM_DEF) + { + text[0] = "Credits"; + // [...] + onselaction[0] = SEL_ACTION_UNDEF; + oneventaction[1] = showcredits; + }; + + func int showcredits() + { + PlayVideo("credits.bik"); + PlayVideo("credits2.bik"); + return 1; + }; + ``` + +- `SEL_ACTION_BACK` + This command has no arguments. It returns to the previous menu or the game. + + ```dae + instance MENUITEM_MAIN_RESUME(C_MENU_ITEM_DEF) + { + text[0] = "Resume"; + text[1] = "Resume the current game"; + // [...] + onselaction[0] = SEL_ACTION_BACK; + }; + ``` + +- `SEL_ACTION_STARTMENU` + The argument for this command is the menu instance. The specified menu will be displayed. + + ```dae + instance MENUITEM_MAIN_EXIT(C_MENU_ITEM_DEF) + { + text[0] = "Quit Game"; + text[1] = "Leave the world of Gothic II"; + onselaction[0] = SEL_ACTION_STARTMENU; + onselaction_s[0] = "MENU_LEAVE_GAME"; + // [...] + }; + + instance MENU_LEAVE_GAME(C_MENU_DEF) + { + // [...] + }; + ``` + +- `SEL_ACTION_STARTITEM` + The argument is an interface element serving as a slot for saving the game. + + ```dae + INSTANCE MENUITEM_SAVE_SLOT1(C_MENU_ITEM_DEF) + { + // [...] + onSelAction[0] = SEL_ACTION_STARTITEM; + onSelAction_S[0]= "MENUITEM_SAVE_SLOT1"; + onSelAction[1] = SEL_ACTION_CLOSE; + onSelAction_S[1]= "SAVEGAME_SAVE"; + }; + ``` + +- `SEL_ACTION_CLOSE` + The closing menu command supports the following arguments: + + - `NEW_GAME` + Start a new game. + + ```dae + instance MENUITEM_MAIN_NEWGAME(C_MENU_ITEM_DEF) + { + // [...] + text[0] = "New Game"; + text[1] = "Start a new adventure"; + onSelAction[0] = SEL_ACTION_CLOSE; + onSelAction_S[0]= "NEW_GAME"; + }; + ``` + + - `LEAVE_GAME` + Exit the game. + + ```dae + INSTANCE MENUITEM_LEAVE_GAME_YES(C_MENU_ITEM_DEF) + { + // [...] + text[0] = "Yes."; + text[1] = "Yes, I'll be back!"; + onSelAction[0] = SEL_ACTION_CLOSE; + onSelAction_S[0]= "LEAVE_GAME"; + }; + ``` + + - `SAVEGAME_SAVE` + Save the game to the selected slot and return to the game. + + ```dae + INSTANCE MENUITEM_SAVE_SLOT1(C_MENU_ITEM_DEF) + { + // [...] + onSelAction[0] = SEL_ACTION_STARTITEM; + onSelAction_S[0]= "MENUITEM_SAVE_SLOT1"; + onSelAction[1] = SEL_ACTION_CLOSE; + onSelAction_S[1]= "SAVEGAME_SAVE"; + }; + ``` + + - `SAVEGAME_LOAD` + Load the game from the selected slot and return to the game. + + ```dae + INSTANCE MENUITEM_LOAD_SLOT1(C_MENU_ITEM_DEF) + { + // [...] + onSelAction[0] = SEL_ACTION_CLOSE; + onSelAction_S[0]= "SAVEGAME_LOAD"; + }; + ``` + +- `SEL_ACTION_CONCOMMANDS` + The argument is a console commands. + + ```dae + INSTANCE MENUITEM_EXAMPLE_1(C_MENU_ITEM_DEF) + { + // [...] + onSelAction[1] = SEL_ACTION_CONCOMMANDS; + onSelAction_S[1]= "goto pos 0 0 0"; + }; + ``` + +- `SEL_ACTION_PLAY_SOUND` + The argument is an C_SFX class instance. + + ```dae + INSTANCE MENUITEM_EXAMPLE_1(C_MENU_ITEM_DEF) + { + // [...] + onSelAction[1] = SEL_ACTION_PLAY_SOUND; + onSelAction_S[1]= "LevelUp"; + }; + ``` + +- `SEL_ACTION_EXECCOMMANDS` + There are two supported executable commands: `RUN` and `EFFECTS`. + + - `RUN` + Indicates the instance of the menu element that is used to select the key. + + ```dae + INSTANCE MENU_ITEM_KEY_UP(C_MENU_ITEM_DEF) + { + // [...] + text[0] = "Forward"; + text[1] = "press DEL key to empty slot and RETURN to define"; + onSelAction[0] = SEL_ACTION_EXECCOMMANDS; + onSelAction_S[0]= "RUN MENU_ITEM_INP_UP"; + }; + + INSTANCE MENU_ITEM_INP_UP(C_MENU_ITEM_DEF) + { + // [...] + text[1] = "Please press the desired key for this action."; + type = MENU_ITEM_INPUT; + onChgSetOption = "keyUp"; + onChgSetOptionSection = "KEYS"; + }; + ``` + + - `EFFECTS` + Specifies the menu item instance to which the focus switches. + + ```dae + INSTANCE MENU_ITEM_SEL_MISSIONS_ACT(C_MENU_ITEM_DEF) + { + text[0] = "Current\nQuests"; + // [...] + onSelAction[0] = SEL_ACTION_EXECCOMMANDS; + onSelAction_S[0]= "EFFECTS MENU_ITEM_LIST_MISSIONS_ACT"; + }; + + instance MENU_ITEM_LIST_MISSIONS_ACT(C_MENU_ITEM_DEF) + { + type = MENU_ITEM_LISTBOX; + text[0] = "Act Missions"; + // [...] + userString[0] = "CURRENTMISSIONS"; + }; + ``` + + There are also two commands, `SETDEFAULT` and `SETALTERNATIVE`, which set control settings. The first restores default settings, and the second uses alternative character control settings. + +### onChgSetOption + +Parameter of the `Gothic.ini` file that will be modified by this menu item. + +```dae +instance MENUITEM_GAME_FIGHTFOCUS_CHOICE(C_MENU_ITEM_DEF) +{ + text[0] = "none|box|lighten|both"; + // [...] + onChgSetOption = "highlightMeleeFocus"; // INI parameter + onChgSetOptionSection = "GAME"; // INI section + // [...] +}; +``` + +The `text[0]` property of such an element usually specifies possible values of the modified parameter. Values are listed using the `|` symbol. + +Make sure that the number of parameter options in the menu corresponds to the number of options in the `Gothic.ini` file. + +```ini +highlightMeleeFocus=2 +; ... here you can turn on an optional focus highlight effect during fighting +``` + +### onChgSetOptionSection +The section of the Gothic.ini file in which the parameter being changed is located. + +See [onChgSetOption](#onchgsetoption) above. + +### onEventAction +Allows a user to call a function on a specified event. + +The list of constants is described in the file [`Scripts/System/_intern/Menu.d`](https://github.com/VaanaCZ/gothic-2-addon-scripts/blob/Unified-EN/_work/Data/Scripts/System/_intern/Menu.d#L51-L59). + +```dae +const int EVENT_UNDEF = 0; // Undefined +const int EVENT_EXECUTE = 1; // Process start event +const int EVENT_CHANGED = 2; // Menu parameter change event +const int EVENT_LEAVE = 3; // Menu item focus loss event +const int EVENT_TIMER = 4; // Timer fire event +const int EVENT_CLOSE = 5; // Menu close event +const int EVENT_INIT = 6; // Initialization event +const int EVENT_SEL_PREV = 7; // Select event of the previous menu item +const int EVENT_SEL_NEXT = 8; // Select event of the next menu item +``` + +For example, you can use the function associated with the constant `EVENT_EXECUTE` to call a script function. + +```dae +instance MENUITEM_MAIN_INTRO(C_MENU_ITEM_DEF) +{ + text[0] = "Play Intro"; + text[1] = "Play introduction sequence"; + // [...] + onEventAction[EVENT_EXECUTE] = ShowIntro; +}; + +func int ShowIntro() +{ + PlayVideo("intro.bik"); + return 1; +}; +``` + +### posx +The horizontal position of the top left point of the menu on the screen, measured in virtual coordinates. + +!!! Example "Virtual coordinates" + Virtual coordinates divide the menu into 8192 parts (`0 - 8191`) horizontally and vertically. The position of the menu item is calculated based on these values. + +### posy +The vertical position of the top left point of the menu on the screen, measured in virtual coordinates. + +### dimx +The width of the menu item in virtual coordinates. + +!!! Tip + To automatically determine the width, enter `-1`. In this case, the width is calculated based on the text contained in the element. + +### dimy + +The height of the menu item in virtual coordinates. + +!!! Tip + To automatically determine the element's height, enter a value of `-1`. In this case, the height is calculated taking into account the text contained in the element. + +### sizeStartScale + +!!! Warning "Deprecated setting" + Size of the menu item at the beginning. + + +### flags +Flags of the menu item. + +Constants for all flags are described in the file [`Scripts/System/_intern/Menu.d`](https://github.com/VaanaCZ/gothic-2-addon-scripts/blob/Unified-EN/_work/Data/Scripts/System/_intern/Menu.d#L27-L41). + +```dae +const int IT_CHROMAKEYED = 1; +const int IT_TRANSPARENT = 2; +const int IT_SELECTABLE = 4; // Element can be selected +const int IT_MOVEABLE = 8; +const int IT_TXT_CENTER = 16; // Align text to center +const int IT_DISABLED = 32; // Interactive item +const int IT_FADE = 64; +const int IT_EFFECTS_NEXT = 128; // Flag for influencing an adjacent menu item +const int IT_ONLY_OUT_GAME = 256; // Element available only outside the game +const int IT_ONLY_IN_GAME = 512; // Element available only in-game +const int IT_PERF_OPTION = 1 << 10; // Option responsible for performance +const int IT_MULTILINE = 1 << 11; // Multi-line text element +const int IT_NEEDS_APPLY = 1 << 12; // Need to apply a settings. Used when changing screen resolution +const int IT_NEEDS_RESTART = 1 << 13; // The game need to be restarted +const int IT_EXTENDED_MENU = 1 << 14; // Advanced menu flag +``` + +- `IT_CHROMAKEYED` + Empty flag. Not used. + +- `IT_TRANSPARENT` + Empty flag. Not used. + +- `IT_SELECTABLE` + Items marked with this flag can be selected. + +- `IT_MOVEABLE` + Empty flag. Not used. + + ??? Example "Intended use" + In early engine versions, the initial position of the element could be specified using the `startPosX` and `startPosY` properties. The element moved from these coordinates to the desired position. + + At the beginning of the video below, it can be seen that the elements slides into the screen. That was probably done using this flag and mentioned parameters. + + ![type:video](https://www.youtube.com/embed/mfJag6fkfH8) + +- `IT_TXT_CENTER` + Aligns the text in the element to the center. + +- `IT_DISABLED` + The menu item becomes inactive. + + ```dae + instance MENUITEM_MAIN_NEWGAME(C_MENU_ITEM_DEF) + { + text[0] = "New Game"; + text[1] = "Start a new adventure"; + flags = flags | IT_TXT_CENTER | IT_DISABLED; + // [...] + }; + ``` + +- `IT_FADE` + Empty flag. Not used. + +- `IT_EFFECTS_NEXT` + This flag affects the next neighboring element, i.e., the element specified in the [`items`](./c_menu.md#items) list of the [`C_MENU`](./c_menu.md) class. + + ```dae + instance MENU_OPT_GAME(C_MENU_DEF) + { + // [...] + items[1] = "MENUITEM_GAME_SUB_TITLES"; + items[2] = "MENUITEM_GAME_SUB_TITLES_CHOICE"; + // [...] + }; + ``` + + In this case, the element affecting (MENUITEM_GAME_SUB_TITLES_CHOICE) is usually made non-selectable. + + ```dae + instance MENUITEM_GAME_SUB_TITLES(C_MENU_ITEM_DEF) + { + // [...] + text[0] = "Subtitles"; + text[1] = "Subtitles on/off"; + flags = flags | IT_EFFECTS_NEXT; + // [...] + }; + + instance MENUITEM_GAME_SUB_TITLES_CHOICE(C_MENU_ITEM_DEF) + { + // [...] + text[0] = "no|yes"; + flags = flags & ~IT_SELECTABLE; + // [...] + }; + ``` + + This flag is mainly used for options and for managing checkboxes, sliders, and enumerations. + +- `IT_ONLY_OUT_GAME` + This flag determines that the menu item is only available before starting the game. Once you start the game, the menu item becomes unavailable. + +- `IT_ONLY_IN_GAME` + This flag determines that the menu item is only available in the running game. Until the game is started, the element remains unavailable. + +- `IT_PERF_OPTION` + A special flag for options. Settings affecting the game's performance are marked with this flag. + +- `IT_MULTILINE` + Flag for multiline text. The text of such elements can be moved to a new line using the newline escape sequence `\n`. + +- `IT_NEEDS_APPLY` + Flag indicating the need to apply settings. Used when changing the game resolution. + +- `IT_NEEDS_RESTART` + Flag indicating that the game needs to be restarted for the settings to take effect. + +- `IT_EXTENDED_MENU` + Flag indicating that this element is part of the "Extended Menu." It is displayed only if the `extendedMenu` parameter in the `Gothic.ini` file is set to `1`. + +### openDelayTime + +!!! Warning "Deprecated setting" + Delay before opening a menu item. + +### openDuration + +!!! Warning "Deprecated setting" + The time the menu item was opened. + +### userFloat + +Numerical settings of the interface element. Depending on the interface element, the purpose of the property changes. See [type](#type). + +### userString + +String settings of the interface element. The purpose of the property changes depending on the interface element. See [type](#type)`. + +### frameSizeX + +Indentation of text inside the frame along the X axis. This applies the padding to both sides of the frame. Measured in virtual coordinates from 0 to 4095. + +Frames are a special tool designed to work with the log of tasks and quests. + +Used for elements of [type](#type) `MENU_ITEM_LISTBOX`. + +```dae +instance MENU_ITEM_LIST_MISSIONS_ACT(C_MENU_ITEM_DEF) +{ + backpic = "NW_Misc_CaveWall_01.tga"; + type = MENU_ITEM_LISTBOX; + text[0] = "Act Missions"; + // [...] + userstring[0] = "CURRENTMISSIONS"; + framesizex = 2000; + framesizey = 2000; +}; +``` + +As a result, we get the following frame (Source: [Gothic-Library](http://www.gothic-library.ru/publ/class_c_menu_item/1-1-0-37#frameSizeX)): + +![](../../../assets/images/c_menu_item_farmesize.png) + +And the width and height of the frame are set, as for all elements, by the [dimx](#dimx) and [dimy](#dimy) properties. + +### frameSizeY + +Indentation of text inside the frame along the Y axis. In this case, the indentation is applied at the top and bottom of the frame. Measured in virtual coordinates from 0 to 4095. + +See [frameSizeX](#framesizex) above. + + +### hideIfOptionSectionSet +The section of the `Gothic.ini` file with the option which value of determines the display of this menu item. + +This property works together with the [`hideIfOptionSet`](#hideifoptionset) and [`hideOnValue`](#hideonvalue) properties. + +In the example below, the interface element will not be displayed until the `useGothic1Controls` parameter in the GAME section is set to 1, i.e., enabled. + +```dae +instance MENU_ITEM_NEXTMENU(C_MENU_ITEM_DEF) +{ + text[0] = "More keys..."; + text[1] = "Configure further control keys"; + // [...] + hideifoptionsectionset = "GAME"; + hideifoptionset = "useGothic1Controls"; + hideonvalue = 1; +}; +``` + +!!! Tip + `Gothic.ini` settings can also be changed through the main menu. See [`onChgSetOption`](#onchgsetoption) and [`onChgSetOptionSection`](#onchgsetoptionsection). + +### hideIfOptionSet +The `Gothic.ini` file parameter, the value of which determines the display of this menu item. + +See [hideIfOptionSectionSet](#hideifoptionsectionset). + +### hideOnValue +The value of the `Gothic.ini` file parameter at which this interface element is not displayed. + +See [hideIfOptionSectionSet](#hideifoptionsectionset). + +## Predefined instances +There are a lot of predefined class instances in the menu `C_MENU_ITEM` performing a strictly defined function. They cannot be renamed, but they can be configured to a certain extent. + +| Instance | Description | +|---------------------------------------|------------------------------------------------------------| +| MENUITEM_LOADSAVE_THUMBPIC | Save picture in the Save/Load menu. | +| MENUITEM_LOADSAVE_LEVELNAME_VALUE | The name of the level of the selected Save/Load menu item. | +| MENUITEM_LOADSAVE_DATETIME_VALUE | The date the selected Save/Load menu item was saved. | +| MENUITEM_LOADSAVE_GAMETIME_VALUE | Game time for saving the selected Save/Load menu item. | +| MENUITEM_LOADSAVE_PLAYTIME_VALUE | Total play time of the selected Save/Load menu item. | +| MENUITEM_SAVE_SLOT1 - MENUITEM_SAVE_SLOT20 | Save menu slots. | +| MENUITEM_LOAD_SLOT1 - MENUITEM_LOAD_SLOT20 | Load menu slots. | +| MENU_ITEM_LIST_MISSIONS_ACT | Frame with a list of current tasks in the journal. | +| MENU_ITEM_LIST_MISSIONS_FAILED | Frame with a list of failed tasks in the log. | +| MENU_ITEM_LIST_MISSIONS_OLD | Frame with a list of old tasks in the journal. | +| MENU_ITEM_LIST_LOG | Frame of general information in the task log. | +| MENU_ITEM_CONTENT_VIEWER | Job log window. | +| MENU_ITEM_DAY | Current day in the quest log window. | +| MENU_ITEM_TIME | Current time in the task log window. | +| MENU_ITEM_PLAYERGUILD | Character's guild in the statistics window. | +| MENU_ITEM_TALENT_0_TITLE - MENU_ITEM_TALENT_16_TITLE | The name of the character's talent. Array indexes are used `TXT_TALENTS` from the `Text.d` file. There may be more elements, depending on the talents realized in the game. | +| MENU_ITEM_TALENT_0_SKILL - MENU_ITEM_TALENT_16_SKILL | Character's talent level. Array indexes are used `TXT_TALENTS_SKILLS` from the `Text.d` file. | +| MENU_ITEM_EXP | The character's current experience value in the statistics window. | +| MENU_ITEM_LEVEL | Current character level in the statistics window. | +| MENU_ITEM_LEVEL_NEXT | The amount of experience required to obtain the next level in the statistics window. | +| MENU_ITEM_LEARN | The number of available training points in the statistics window. | +| MENU_ITEM_ATTRIBUTE_1 - MENU_ITEM_ATTRIBUTE_4 | Character attributes in the statistics window. | +| MENU_ITEM_ARMOR_1 - MENU_ITEM_ARMOR_4 | Character protection in the statistics window. | diff --git a/docs/zengin/scripts/classes/c_musicsys_cfg.md b/docs/zengin/scripts/classes/c_musicsys_cfg.md new file mode 100644 index 0000000000..a0d8fd84b6 --- /dev/null +++ b/docs/zengin/scripts/classes/c_musicsys_cfg.md @@ -0,0 +1,59 @@ +--- +title: C_MUSICSYS_CFG +--- + +# C_MUSICSYS_CFG Daedalus class + +!!! example "Acknowledgment" + Heavily inspired by the amazing documentation site [Gothic library](http://www.gothic-library.ru) + + +Class `C_MusicSys_CFG` defines the global settings for the game's music. + +An instance of this class is declared only once. +## Class definition +Class definition as it is defined in [`Scripts/System/_intern/Music.d`](https://github.com/VaanaCZ/gothic-2-addon-scripts/blob/Unified-EN/_work/Data/Scripts/System/_intern/Music.d#L40) script file. + +??? "C_MusicSys_CFG Daedalus class" + ```dae + class C_MusicSys_CFG + { + var float volume; // Music volume + var int bitResolution; // Sound quality + var int globalReverbEnabled; // Enable global reverb + var int sampleRate; // Frequency + var int numChannels; // Sound channels + var int reverbBufferSize; // Reverb buffer size + }; + ``` +## Class members + +| Variable | Type | Description | +|---------------------------------------------|--------|--------------------------------------------------------------| +| [volume](#volume) | float | Overall game music volume | +| [bitResolution](#bitresolution) | int | Sound quality | +| [globalReverbEnabled](#globalreverbenabled) | int | Enable global reverb | +| [sampleRate](#samplerate) | int | Frequency | +| [numChannels](#numchannels) | int | Number of sound chanells | +| [reverbBufferSize](#reverbbuffersize) | int | The size of reverb buffer | + +## Class member overview +Description of the class member variables. + +### volume +The overall volume of the background music (soundtrack). From 0.0 to 1.0. + +### bitResolution +Sound quality. 8 or 16 bit. + +### globalReverbEnabled +Enable global reverb. + +### sampleRate +Frequency. From 11050 to 44100. + +### numChannels +Number of sound channels. From 16 to 32. + +### reverbBufferSize +The size of the reverb buffer. \ No newline at end of file diff --git a/docs/zengin/scripts/classes/c_musictheme.md b/docs/zengin/scripts/classes/c_musictheme.md new file mode 100644 index 0000000000..ab04f13c8f --- /dev/null +++ b/docs/zengin/scripts/classes/c_musictheme.md @@ -0,0 +1,115 @@ +--- +title: C_MUSICTHEME +--- + +# C_MUSICTHEME Daedalus class + +!!! example "Acknowledgment" + Heavily inspired by the amazing documentation site [Gothic library](http://www.gothic-library.ru) + +Class `C_MusicTheme` describes musical themes. +## Class definition +Class definition as it is defined in [`Scripts/System/_intern/Music.d`](https://github.com/VaanaCZ/gothic-2-addon-scripts/blob/Unified-EN/_work/Data/Scripts/System/_intern/Music.d#L52) script file. + +??? "C_MusicTheme Daedalus class" + ```dae + class C_MusicTheme + { + var string file; // Sound file in DirectMusic `.sgt` format + var float vol; // Sound volume + var int loop; // Enable cycle + var float reverbMix; // Reverb mixing + var float reverbTime; // Reverb time + var int transType; // Type of transition to the next theme + var int transSubType; // Subtype of transition to the next theme song + }; + ``` +## Class members + +| Variable | Type | Description | +|-----------------------------------|--------|-------------------------------------------------------------------------------------| +| [file](#file) | string | Sound file in DirectMusic `.sgt` format | +| [vol](#vol) | float | Sound volume | +| [loop](#loop) | int | Enable/disable cycle | +| [reverbMix](#reverbmix) | float | Reverb mixing | +| [reverbTime](#reverbtime) | float | Reverb time | +| [transType](#transtype) | int | The type of transition to the next theme song | +| [transSubType](#transsubtype) | int | The subtype of transition to the next theme song | + +## Class member overview +Description of the class member variables. + +### file +DirectMusic sound in *.sgt format or MIDI file. + +### vol +The volume of the theme song. From 0.0 to 1.0. + +### loop +Enable/disable theme music looping. Disabled = 0. Enabled = 1. + +### reverbMix +Reverb mixing. Measured in decibels. + +### reverbTime +Reverberation time in milliseconds. + +### transType +The type of transition to the next theme song. + +The list of constants for all transitions types is described in the file [`Scripts/System/_intern/Music.d`](https://github.com/VaanaCZ/gothic-2-addon-scripts/blob/Unified-EN/_work/Data/Scripts/System/_intern/Music.d#L24) + +```dae +const int TRANSITION_TYPE_NONE = 1; // No transition +const int TRANSITION_TYPE_GROOVE = 2; // Ripple +const int TRANSITION_TYPE_FILL = 3; // Padding +const int TRANSITION_TYPE_BREAK = 4; // Break +const int TRANSITION_TYPE_INTRO = 5; // Introductory +const int TRANSITION_TYPE_END = 6; // End topic +const int TRANSITION_TYPE_ENDANDINTRO = 7; // End and start new +``` + +### transSubType +The subtype of transition to the next theme song. + +The list of constants for all transitions subtypes is described in the file [`Scripts/System/_intern/Music.d`](https://github.com/VaanaCZ/gothic-2-addon-scripts/blob/Unified-EN/_work/Data/Scripts/System/_intern/Music.d#L33) + +```dae +const INT TRANSITION_SUB_TYPE_IMMEDIATE = 1; // Instant transition +const INT TRANSITION_SUB_TYPE_BEAT = 2; // Rhythmic transition +const INT TRANSITION_SUB_TYPE_MEASURE = 3; // Gradual transition +``` + +## Name features +The musical themes of the game are played depending on the game situation. By default, the theme with the `_STD` (standard) suffix is played. In case of a threat, the `_THR` (threat) theme will be played. During the combat the `_FGT` (fight) theme plays. + +```dae +instance WOO_DAY_STD(C_MUSICTHEME_STANDARD) +{ + file = "woo_daystd.sgt"; +}; + +instance WOO_DAY_THR(C_MUSICTHEME_THREAT) +{ + file = "woo_daythr.sgt"; +}; + +instance WOO_DAY_FGT(C_MUSICTHEME_FIGHT) +{ + file = "woo_dayfgt.sgt"; +}; +``` +In addition, the suffix `_DAY_` and `_NGT_` determines whether the theme should be played on day or night. +```dae +instance OWD_DAY_FGT(C_MUSICTHEME_FIGHT) +{ + file = "owp_dayfgt.sgt"; +}; + +instance OWD_NGT_STD(C_MUSICTHEME_STANDARD) +{ + file = "owd_daystd.sgt"; +}; +``` +!!! Tip + In G2 the `C_MUSICTHEME_STANDARD`, `C_MUSICTHEME_THREAT` and `C_MUSICTHEME_FIGHT` prototypes are used by default. \ No newline at end of file diff --git a/docs/zengin/scripts/extenders/ikarus/constants.md b/docs/zengin/scripts/extenders/ikarus/constants.md new file mode 100644 index 0000000000..26ffb254f4 --- /dev/null +++ b/docs/zengin/scripts/extenders/ikarus/constants.md @@ -0,0 +1,46 @@ +--- +title: Constants +--- + +# Ikarus User Constants + +In the Constants file, you'll find user variables that control various aspects, including the debug output of Ikarus. You can customize these variables to suit your needs. + + +## MEM-Helper + +- `#!dae const string MEM_FARFARAWAY` + Waypoint where the Mem-Helper is spawned (default: `"TOT"`) +- `#!dae const string MEM_HELPER_NAME` + Name of the Mem-Helper (default: `"MEMHLP"`) + +## Debug + +- `#!dae const int zERR_ErrorBoxOnlyForFirst` + Controls whether only the first error should trigger an error box (default: `1`). +- `#!dae const int zERR_StackTraceOnlyForFirst` + Determines if stack traces should be displayed only for the first error (default: `0`). + +### MEM_Debug + +The [`MEM_Debug`](functions/debug.md#mem_debug) function allows you to set up a custom message channel for debugging purposes. You can adjust the following variables to configure this channel: + +- `#!dae const string zERR_DEBUG_PREFIX` + Specifies a prefix to be added to each debug message (default: `"Debug: "`). +- `#!dae const int zERR_DEBUG_TOSPY` + Controls whether `MEM_Debug` messages should be sent to [zSpy](../../../tools/zSpy.md) (default: `1`). +- `#!dae const int zERR_DEBUG_TYPE` + Specifies the [message type](#error-message-types) for `MEM_Debug` messages when sent to [zSpy](../../../tools/zSpy.md) (default: `zERR_TYPE_INFO`). +- `#!dae const int zERR_DEBUG_TOSCREEN` + Determines whether `MEM_Debug` messages should be printed to the screen (default: `0`). +- `#!dae const int zERR_DEBUG_ERRORBOX` + Allows you to display an error box for `MEM_Debug` messages (default: `0`). + +### Error message types +```dae +const int zERR_TYPE_OK = 0; /* [ungenutzt] */ +const int zERR_TYPE_INFO = 1; /* MEM_Info */ +const int zERR_TYPE_WARN = 2; /* MEM_Warn */ +const int zERR_TYPE_FAULT = 3; /* MEM_Error */ +const int zERR_TYPE_FATAL = 4; /* [ungenutzt] */ +``` \ No newline at end of file diff --git a/docs/zengin/scripts/extenders/ikarus/floats.md b/docs/zengin/scripts/extenders/ikarus/floats.md new file mode 100644 index 0000000000..d9fc9e25fd --- /dev/null +++ b/docs/zengin/scripts/extenders/ikarus/floats.md @@ -0,0 +1,360 @@ +# Floats +This part of ikarus implements support for 32 bit IEEE 754 floats in Daedalus. The script was originally created to edit `zFLOAT` and `zREAL` variables, but can also be used to arithmetic operations on real float values (not to be confused with Daedalus floats). + +## Initialization +The best way to initialize all Ikarus functions is to call `MEM_InitAll()` in the `Init_Global()` initialization function. +!!! warning + If you want to use Ikarus in Gothic 1, it is best to define your own `Init_Global()` function and call it from every world initialization function. + +```dae +MEM_InitAll(); +``` + +## Implementation +[:material-github: float.d on GitHub](https://github.com/Lehona/Ikarus/blob/master/float.d) + +## Functions +!!! Danger + Ikarus floats are saved as int but it doesn't mean that you can use arithmetic operators on them. All operations on floats must be done with functions listed below. + +### `mkf` +(make float) Converts the input integer x to a float value. +```dae +func int mkf(var int x) +``` +**Parameters** + +- `#!dae var int x` + The input integer + +**Return value** + +The function returns the float representation of the input integer x. + +### `truncf` +(truncate float) Truncates the decimal part of the input float x. +```dae +func int truncf(var int x) +``` +**Parameters** + +- `#!dae var int x` + The input float + +**Return value** + +The function returns the integer part of the input float x by discarding the decimal part. + +### `roundf` +(round float) Rounds the input float x to the nearest integer value. +```dae +func int roundf(var int x) +``` +**Parameters** + +- `#!dae var int x` + The input float + +**Return value** + +The function returns the nearest integer value to the input float x. If the decimal part is exactly halfway between two integers, the function rounds to the nearest even integer. + +### `addf` +(add floats) Adds two ikarus floats together. +```dae +func int addf(var int x, var int y) +``` +**Parameters** + +- `#!dae var int x` + The first float +- `#!dae var int y` + The second float + +**Return value** + +The function returns the sum of the input floats `x` and `y`. (x + y) + +### `subf` +(subtract floats) Subtracts the second float from the first float. +```dae +func int subf(var int x, var int y) +``` +**Parameters** + +- `#!dae var int x` + The first float +- `#!dae var int y` + The second float + +**Return value** + +The function returns the difference between the first float `x` and the second float `y`. (x - y) + +### `negf` +(negate float) Negates the input float. +```dae +func int negf(var int x) +``` +**Parameters** + +- `#!dae var int x` + The input float + +**Return value** + +The function returns the negation of the input float `x`. + +### `mulf` +(multiply floats) Multiplies two ikarus floats. +```dae +func int mulf(var int x, var int y) +``` +**Parameters** + +- `#!dae var int x` + The first float +- `#!dae var int y` + The second float + +**Return value** + +The function returns the product of multiplying the input floats x and y. (x * y) + +### `divf` +(divide floats) Divides two ikarus floats. +```dae +func int divf(var int x, var int y) +``` +**Parameters** + +- `#!dae var int x` + The dividend float +- `#!dae var int y` + The divisor float + +**Return value** + +The function returns the quotient of dividing the input float x by y. (x / y) + +### `invf` +(inverse float) Computes the inverse of the input float. +```dae +func int invf(var int x) +``` +**Parameters** + +- `#!dae var int x` + The input float + +**Return value** + +The function returns the inverse of the `x`, calculated as `1/x`. + +### `gf` +(greater) Checks if the first float is greater than the second float. +```dae +func int gf(var int x, var int y) +``` +**Parameters** + +- `#!dae var int x` + The first float +- `#!dae var int y` + The second float + + + +**Return value** + +The function returns `TRUE` if `x` is greater than `y`, `FALSE` is returned otherwise. + +### `gef` +(greater or equal) Checks if the first float is greater than or equal to the second float. +```dae +func int gef(var int x, var int y) +``` +**Parameters** + +- `#!dae var int x` + The first float +- `#!dae var int y` + The second float + +**Return value** + +The function returns `TRUE` if `x` is greater than or equal to `y`, `FALSE` is returned otherwise. + +### `lf` +(lower) Checks if the first float is less than the second float. +```dae +func int lf(var int x, var int y) +``` +**Parameters** + +- `#!dae var int x` + The first float +- `#!dae var int y` + The second float + +**Return value** + +The function returns `TRUE` if `x` is less than `y`, `FALSE` is returned otherwise. + +### `lef` +(lower or equal) Checks if the first float is less than or equal to the second float. +```dae +func int lef(var int x, var int y) +``` +**Parameters** + +- `#!dae var int x` + The first float +- `#!dae var int y` + The second float + +**Return value** + +The function returns `TRUE` if `x` is less than or equal to `y`, `FALSE` is returned otherwise. + +### `sqrf` +(square float) Calculates the square of the float. +```dae +func int sqrf(var int x) +``` +**Parameters** + +- `#!dae var int x` + The input float + +**Return value** + +The function returns the square of the input float `x`, computed as `x * x`. + +### `sqrtf` +(square root float) Calculates the square root of the float. +```dae +func int sqrtf(var int x) +``` +**Parameters** + +- `#!dae var int x` + The input float + +**Return value** + +The function returns the square root of the input float `x`. + +### `sqrtf_approx` +Calculates the approximate square root of a float. +```dae +func int sqrtf_approx(var int f) +``` +**Parameters** + +- `#!dae var int f` + The input float + +**Return value** + +The function returns the approximate square root of the input float as an ikarus float. + +### `absf` +(absolute value) Computes the absolute value of a float. +```dae +func int absf(var int x) +``` +**Parameters** + +- `#!dae var int x` + The input float + +**Return value** + +The function returns the absolute value of the input float `x`, which is the value without the negative sign (if present). + +### `fracf` +(fraction) Computes the fraction of two integers p and q. +```dae +func int fracf(var int p, var int q) +``` +**Parameters** + +- `#!dae var int p` + Numerator +- `#!dae var int q` + Denominator + +**Return value** + +The function returns the fraction of `p` divided by `q` as an ikarus float. + +### `castFromIntf` +Converts an ikarus float to a Daedalus float. +```dae +func float castFromIntf(var int f) +``` +**Parameters** + +- `#!dae var int f` + Ikarus float + +**Return Value** + +The function returns the value `f` as a Daedalus float. + +### `castToIntf` +Converts a Daedalus float to an ikarus float. +```dae +func int castToIntf(var float f) +``` +**Parameters** + +- `#!dae var float f` + Daedalus float + +**Return Value** + +The function returns the value `f` as an ikarus float. + +### `toStringf` +Converts a float value to its string representation. +```dae +func string toStringf(var int x) +``` +**Parameters** + +- `#!dae var int x` + Input float value + +**Return value** + +The function returns a string representation of the input float value. + +### `printf` +(print float) Prints the float on screen using `Print()`. +```dae +func void printf(var int x) +``` +**Parameters** + +- `#!dae var int x` + The printed float + +## Examples + +### Simple operations +```dae +var int float1; float1 = mkf(5); // Create an Ikarus float with value 5 +var int float2; float2 = mkf(2); // Create an Ikarus float with value 2 + +var int addResult; addResluts = addf(float1, float2); // Add float1 and float2 +var int subResult; subResults = subf(float1, float2); // Subtract float2 from float1 +var int mulResult; mulRelsults = mulf(float1, float2); // Multiply float1 by float2 +var int divResult; divResults = divf(float1, float2); // Divide float1 by float2 + +printf(addResult); // Output: 7 +printf(subResult); // Output: 3 +printf(mulResult); // Output: 10 +printf(divResult); // Output: 2.5 +``` \ No newline at end of file diff --git a/docs/zengin/scripts/extenders/ikarus/functions/arrays.md b/docs/zengin/scripts/extenders/ikarus/functions/arrays.md new file mode 100644 index 0000000000..fc91d9d9f1 --- /dev/null +++ b/docs/zengin/scripts/extenders/ikarus/functions/arrays.md @@ -0,0 +1,227 @@ +# Arrays (zCArray) +Set of function for working with ZenGin's `zCArray` data structure. + +## Initialization +The best way to initialize all Ikarus functions is to call `MEM_InitAll()` in the `Init_Global()` initialization function. +!!! warning + If you want to use Ikarus in Gothic 1, it is best to define your own `Init_Global()` function and call it from every world initialization function. + +```dae +MEM_InitAll(); +``` + +## Implementation +[:material-github: Ikarus.d on GitHub](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L2017-L2338) + +## Functions + +### `MEM_ArrayCreate` +Creates an empty `zCArray` (allocates memory) and returns a pointer to it. +```dae +func int MEM_ArrayCreate() +``` +**Return value** + +The function returns a pointer to the created `zCArray`. + +### `MEM_ArrayFree` +Frees the memory allocated for a `zCArray` and its data. +```dae +func void MEM_ArrayFree(var int zCArray_ptr) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` to be freed + +### `MEM_ArrayClear` +Clears the data of a `zCArray`, freeing the memory used by its elements. The array becomes empty. +```dae +func void MEM_ArrayClear (var int zCArray_ptr) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` to be cleared + +### `MEM_ArraySize` +Returns the size (number of elements) of an array. +```dae +func int MEM_ArraySize(var int zCArray_ptr) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` + +**Return value** + +The function returns a number of a `zCArray` elements. + +### `MEM_ArrayWrite` +Writes a value at a specific position in the `zCArray`. +```dae +func void MEM_ArrayWrite(var int zCArray_ptr, var int pos, var int value) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` +- `#!dae var int pos` + Position in the array where the value will be written +- `#!dae var int value` + Value to be written + +### `MEM_ArrayRead` +Reads the value at a specific position in the `zCArray`. +```dae +func int MEM_ArrayRead(var int zCArray_ptr, var int pos) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` +- `#!dae var int pos` + Position in the array from which the value will be read + +**Return value** + +The function returns the value at a specific position in the `zCArray`. + +### `MEM_ArrayInsert` +Appends a value to the end of the `zCArray`. The array is automatically resized if it is too small. +```dae +func void MEM_ArrayInsert (var int zCArray_ptr, var int value) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` +- `#!dae var int value` + Value to be inserted + +### `MEM_ArrayPush` +Alias for [`MEM_ArrayInsert`](#mem_arrayinsert), inserts a value at the end of the `zCArray`. +```dae +func void MEM_ArrayPush (var int zCArray_ptr, var int value) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` +- `#!dae var int value` + Value to be inserted + +### `MEM_ArrayPop` +Removes and returns the last element from the `zCArray`. +```dae +func int MEM_ArrayPop(var int zCArray_ptr) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` + +**Return value** + +The function returns the element removed from the end of an array. + +### `MEM_ArrayTop` +Returns the last element of the `zCArray` without removing it. +```dae +func int MEM_ArrayTop(var int zCArray_ptr) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` + +**Return value** + +The function returns the last element of an array. + +### `MEM_ArrayIndexOf` +Searches the `zCArray` for the first occurrence of a `value` and returns its index. +```dae +func int MEM_ArrayIndexOf(var int zCArray_ptr, var int value) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` +- `#!dae var int value` + Value to search for + +**Return value** + +The function returns the index of a first occurrence of a `value`. If not found `-1` is returned. + +### `MEM_ArrayRemoveIndex` +Removes the element at a specific index from the `zCArray`. +```dae +func void MEM_ArrayRemoveIndex (var int zCArray_ptr, var int index) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` +- `#!dae var int index` + Index of the element to be removed + +### `MEM_ArrayRemoveValue` +Removes all occurrences of a value from the `zCArray`. +```dae +func void MEM_ArrayRemoveValue (var int zCArray_ptr, var int value) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` +- `#!dae var int value` + Value to be removed + +### `MEM_ArrayRemoveValueOnce` +Removes the first occurrence of a value from the `zCArray`. If value is not found, a warning is issued. +```dae +func void MEM_ArrayRemoveValueOnce (var int zCArray_ptr, var int value) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` +- `#!dae var int value` + Value to be removed + +### `MEM_ArraySort` +Sorts the elements of the `zCArray` in ascending order. +```dae +func void MEM_ArraySort(var int zCArray_ptr) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` + +### `MEM_ArrayUnique` +Removes duplicate elements from the `zCArray`. +```dae +func void MEM_ArrayUnique(var int zCArray_ptr) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` + +### `MEM_ArrayToString` +Converts the `zCArray` to a string representation. +```dae +func string MEM_ArrayToString (var int zCArray_ptr) +``` +**Parameters** + +- `#!dae var int zCArray_ptr` + Pointer to the `zCArray` + +**Return value** + +The function returns a string representation of a given array. \ No newline at end of file diff --git a/docs/zengin/scripts/extenders/ikarus/functions/asm.md b/docs/zengin/scripts/extenders/ikarus/functions/asm.md new file mode 100644 index 0000000000..137db0caa3 --- /dev/null +++ b/docs/zengin/scripts/extenders/ikarus/functions/asm.md @@ -0,0 +1,225 @@ +--- +title: ASM +--- +# Ikarus Machine Code Implementation (ASM) + +Machine code refers to a program or program segment written in machine language, which can be directly executed by a processor without further translation steps. The relevant machine language for us is that belonging to the x86 processor architecture. All machine instructions, what they do, and how they are encoded in machine language can be found in the [Intel Manuals](http://www.intel.com/products/processor/manuals/index.htm). + +In practice, dealing with (abstract) machine instructions and manually translating them into (concrete) machine code is rarely necessary due to its complexity. + +However, machine code can be useful for performing technical tasks that cannot be expressed in Daedalus directly. For example, the CALL package use the ASM function set as a basis. + +!!! Note + The functions in this chapter have the `ASM_` prefix for Assembly (language). Assembly language is a human-readable language with one-to-one correspondences to machine language. Strictly speaking, the `ASM_` prefix is misleading here, as it pertains to machine code rather than assembly language. However, conceptually, the two are closely related. + +## Initialization +The best way to initialize all Ikarus functions is to call `MEM_InitAll()` in the `Init_Global()` initialization function. +!!! warning + If you want to use Ikarus in Gothic 1, it is best to define your own `Init_Global()` function and call it from every world initialization function. + +```dae +MEM_InitAll(); +``` + +## Implementation +[:material-github: Ikarus.d on GitHub](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L1064-L1267) + + +## Opcodes + +The code defines several constants that represent different machine code instructions. Each constant is assigned a hexadecimal value and corresponds to a specific machine code instruction. [Here](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L1070-L1111) is a link to all instructions. + + +## Internal Stack + +The code includes an internal stack implementation, allowing the storage of data. The stack is already used at two points: + +- When calling an engine function, the address of the current run is stored in the internal stack. +- When nesting the use of the CALL package, a push and pop operation is performed to manage the context. + +The internal stack is implemented using an array, and the following functions are provided: + +### `ASMINT_Push` +Pushes the specified `data` onto the internal stack. +```dae +func void ASMINT_Push(var int data) +``` +**Parameters** + +- `#!dae var int data` + Data pushed onto internal stack + +### `ASMINT_Pop` +Pops and returns the topmost data from the internal stack. +```dae +func int ASMINT_Pop() +``` +**Return value** + +The function returns a data popped form the internal stack. + +## Functions (Core) + +The ASM core functionality provides a framework for assembling machine code instructions and executing them. The following functions are included: + +### `ASMINT_Init` +Initializes the ASM system by creating an internal stack and finding function addresses. +```dae +func void ASMINT_Init() +``` + +!!! Tip + It's worth noting that `ASMINT_Ini` is also invoked by the `MEM_InitAll` function. + +### `ASM_Open` +Changes the size of the memory allocated at the start o the dictation + +The memory in which the machine code is stored is allocated at the beginning of the dictation. If this function isn't called a default size (see **Constant** below) is allocated by [`ASM`](#asm) or [`ASM_Here`](#ams_here) function. The 256 bytes is often sufficient for simple applications, but if more memory is required, this function must be called at the beginning of the dictation. +```dae +func void ASM_Open(var int space) +``` +**Parameters** + +- `#!dae var int space` + Space allocated for machine code (in bytes) + +**Constant** + +`ASM_StandardStreamLength` constant defines the default space available for an Assembler sequence (in bytes). + +```dae +const int ASM_StandardStreamLength = 256; +``` + +### `ASM` +Writes machine code instructions to the stream. + +Using this function it is possible to dictate machine code little by little. The `data` bytes of the `length` (maximum 4!) are appended to the previously dictated part. This creates a program piece by piece that can be executed by the processor. +```dae +func void ASM(var int data, var int length) +``` +**Parameters** + +- `#!dae var int data` + The machine code instruction or its part +- `#!dae var int length` + Length of the `data` (max 4 bytes) + + +=== "ASM_1" + ### `ASM_1` + [`ASM`](#asm) with `length` parameter hardcoded to 1. Writes one byte machine code instructions to the stream. + ```dae + func void ASM_1(var int data) + ``` + **Parameters** + + - `#!dae var int data` + One byte machine code instruction or its part + +=== "ASM_2" + ### `ASM_2` + [`ASM`](#asm) with `length` parameter hardcoded to 2. Writes two bytes machine code instructions to the stream. + ```dae + func void ASM_1(var int data) + ``` + **Parameters** + + - `#!dae var int data` + Two bytes machine code instruction or its part + +=== "ASM_3" + ### `ASM_3` + [`ASM`](#asm) with `length` parameter hardcoded to 3. Writes three bytes machine code instructions to the stream. + ```dae + func void ASM_1(var int data) + ``` + **Parameters** + + - `#!dae var int data` + Three bytes machine code instruction or its part + +=== "ASM_4" + ### `ASM_4` + [`ASM`](#asm) with `length` parameter hardcoded to 4. Writes four bytes machine code instructions to the stream. + ```dae + func void ASM_1(var int data) + ``` + **Parameters** + + - `#!dae var int data` + Four bytes machine code instruction or its part + +### `ASM_Here` +Provides, the address of the cursor, i.e., the address of the location that will be described next by a call to [`ASM`](#asm). It is guaranteed that the location where the code is written is also the location where it will be executed. +```dae +func int ASM_Here() +``` + +**Return value** + +The function returns an address that is the current position in the machine code stream. + +### `ASM_Close` +Finalizes the stream by adding a return instruction and returns the starting address of the stream. This pointer can now be passed to at any time and any number of times to execute the machine code. + +!!! Warning + The memory area obtained by `ASM_Close` must be released manually using [`MEM_Free`](mem_utility.md#mem_free) to avoid memory leaks. It is probably sufficient for almost all practical purposes. +```dae +func int ASM_Close() +``` +**Return value** + +The function returns a starting address of the stream (pointer to the stream). + + +### `ASM_Run` +Executes a machine code (stream) from a pointer. + +!!! Note + `ASM_Run` can also be used to call engine functions with no parameters and no relevant return value. In this case `ptr` would simply have to point to the function to be executed in the code segment. +```dae +func void ASM_Run(var int ptr) +``` +**Parameters** + +- `#!dae var int ptr` + Pointer to the executed code (returned form [`ASM_Close`](#asm_close)) + +### `ASM_RunOnce` +Executes the code dictated up to that point, similar to how an external function is executed. After that the code is released, and new code can be dictated. +```dae +func void ASM_RunOnce() +``` + +## Example +The following function sets the NPC passed as slf as the player, as if you had pressed **O** in Marvin mode with this NPC in focus. This is so short because there is already a function for this exact purpose, it's just not normally accessible from the scripts. It is therefore sufficient to write assembly code that pushes the parameter of the function (the `this` pointer) into the appropriate register and then calls the function. +```dae +func void SetAsPlayer(var C_NPC slf) { /* Address of the function */ + const int oCNpc__SetAsPlayer = 7612064; //0x7426A0 (Gothic2.exe) + + var int slfPtr; + slfPtr = MEM_InstToPtr (slf); + + //mov ecx slfPtr + ASM_1(ASMINT_OP_movImToECX); /* move a value to ecx */ + ASM_4(slfPtr); /* a value */ + + //call oCNpc__SetAsPlayer + ASM_1(ASMINT_OP_call); + ASM_4(oCNpc__SetAsPlayer - ASM_Here() - 4); + + ASM_RunOnce(); /* return will be added automatically */ +}; +``` + +!!! Note + Call targets are specified relative to the instruction that would have been executed after the actual call instruction. Therefore, both ASM_Here() and the subtraction of 4 in the call parameter are necessary. + +The above example describes, among other things, [`CALL__thiscall`](#) function form the [CALL Package](call.md) that can be also used to implement `SetAsPlayer`. +```dae +func void SetAsPlayer(var C_NPC slf) { + const int oCNpc__SetAsPlayer = 7612064; + CALL__thiscall(MEM_InstToPtr(slf), oCNpc__SetAsPlayer); +}; +``` \ No newline at end of file diff --git a/docs/zengin/scripts/extenders/ikarus/functions/call.md b/docs/zengin/scripts/extenders/ikarus/functions/call.md new file mode 100644 index 0000000000..abf742c1af --- /dev/null +++ b/docs/zengin/scripts/extenders/ikarus/functions/call.md @@ -0,0 +1,409 @@ +# CALL Package +This part of Ikarus makes possible to call engine functions directly from scripts. + +In order to be able to invoke an engine function, you must know some of its properties. This includes the number and types of parameters, the type of return value, address of function and calling convention. + +Knowledge about engine functions can be obtained using tools like IDA, which can analyze and convert GothicMod.exe / Gothic2.exe into a more human-readable format. + +!!! Info + In fact, [machine code execution (ASM)](asm.md) is part of the CALL package, but due to its complexity, this functionality is discussed in a separate article. + +## Initialization +The best way to initialize all Ikarus functions is to call `MEM_InitAll()` in the `Init_Global()` initialization function. +!!! warning + If you want to use Ikarus in Gothic 1, it is best to define your own `Init_Global()` function and call it from every world initialization function. + +```dae +MEM_InitAll(); +``` + +## Implementation +[:material-github: Ikarus.d on GitHub](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L1268-L1654) + +## Call modes +There are two modes: + +### Disposable +The simple mode that produces a disposable call that is used only once. All parameters are hardcoded. + +```dae +func int hero_GetAssessEnemy() { + const int oCNpc__GetPerceptionFunc = 7726080; //0x75E400 + + CALL_IntParam(_@(PERC_ASSESSENEMY)); + CALL_PutRetValTo(_@(funcID)); + CALL__thiscall(_@(hero), oCNpc__GetPerceptionFunc); + + var int funcID; + return +funcID; +}; +``` + +### Recyclable +The second version produces code that can be used more than once. Instead of the parameters the user specifies the address where the parameters are to be taken from. In addition to executing the code, the user will receive an address that he can use to repeat the call. This is much faster than rebuilding the call from scratch. + +```dae +func int Npc_GetPercFunc(var C_Npc npc, var int type) { + const int oCNpc__GetPerceptionFunc = 7726080; //0x75E400 + + var int npcPtr; npcPtr = _@(npc); + + const int call = 0; + if (CALL_Begin(call)) { + CALL_IntParam(_@(type)); + CALL_PutRetValTo(_@(funcID)); + CALL__thiscall(_@(npcPtr), oCNpc__GetPerceptionFunc); + call = CALL_End(); + }; + + var int funcID; + return +funcID; +}; +``` +> Receives a pointer. In case the pointer is non-zero, the code at this position is executed and 0 is returned. In case pointer is zero, the current mode is changed into recyclable mode, this means that the call functions expect instructions to build a recyclable call. This mode will continue until `CALL_End()`. This allows code like this: + +## Start and End + +### `CALL_Open` +Initializes a Recyclable call mode. +```dae +func void CALL_Open() +``` + +### `CALL_Begin` +A practical wrapper for `CALL_Open`. Makes a call if it had been already created, initializes it otherwise. +```dae +func int CALL_Begin(var int ptr) +``` +**Parameters** + +- `#!dae var int ptr` + Zero if you need to create a new recyclable function to be called (usually, before first use). In this case `CALL_Open` is called and `CALL_Begin` returns `1`. + +**Return Value** + +The function returns `1` if the new call has been created, `0` is returned otherwise. + +### `CALL_Close` +Finalizes a function call in recyclable mode, restoring the previous execution context. +```dae +func int CALL_Close() +``` + +### `CALL_End` +Finalizes a function call, pushes the pointer onto the stack, and runs the associated assembly code (makes an actual call). +```dae +func int CALL_End() +``` + +**Return Value** + +The function returns a pointer that could be used to repeat the call. + + +!!! Tip + `CALL_Close` only finalizes the function call, returning the pointer, while `CALL_End` additionally handles pushing the pointer onto the stack and running associated assembly code. + + + +## Passing parameters + +Parameters must be arranged on the machine stack from right to left i.e. from the parameter on the far right to the parameter on the far left. These functions generate machine code that will place parameters on the machine stack when executed. + +!!! Note + These functions do not impose any parameters on the Machine stack. Exactly it should say: You create the machine code that will put parameters on the machine stack when it is executed. And it is only carried out in the second step with the announcement of the calling convention. + +### `CALL_IntParam` +Passes an integer (`int32`) as a parameter to the called function. +```dae +func void CALL_IntParam(var int param) +``` +**Parameters** + +- `#!dae var int param` + Address of an integer to be passed + +### `CALL_FloatParam` +Passes an IEEE 7554 floating-point number (`single` / `zREAL`) as a parameter to the called function. +```dae +func void CALL_FloatParam(var int param) +``` +**Parameters** + +- `#!dae var int param` + Address of a float to be passed + +### `CALL_PtrParam` +Passes a pointer (`void*`) as a parameter to the called function. +```dae +func void CALL_PtrParam(var int param) +``` +**Parameters** + +- `#!dae var int param` + Pointer to be passed + +### `CALL_zStringPtrParam` +Passes a string (`zString*`) as a parameter to the called function. +```dae +func void CALL_zStringPtrParam(var string param) +``` +**Parameters** + +- `#!dae var string param` + String to be passed + +!!! Warning + This function only works when writing a disposable call! + +### `CALL_cStringPtrParam` +Passes a char array (`char **`) as a parameter to the called function. +```dae +func void CALL_cStringPtrParam(var string param) +``` +**Parameters** + +- `#!dae var string param` + String to be passed as character array` + +!!! Warning + This function only works when writing a disposable call! + +### `CALL_StructParam` +Passes a structure (struct) as a parameter to the called function. +```dae +func void CALL_StructParam(var int ptr, var int words) +``` +**Parameters** + +- `#!dae var int param` + Pointer to the object +- `#!dae var int words` + Size of a structure (1 word = 32 bits) + +!!! Note + `CALL_IntParam`, `CALL_FloatParam`, and `CALL_PtrParam` are functionally identical and are differentiated for code readability. + +## The call +The calling convention determines how the function's parameters are passed. IDA or another disassembler can be used to identify the convention used by a specific engine function. + +The announcement of the calling convention, i.e. the call of one of the four functions below is also the time of calling the function. In particular, all parameters must already be specified at this point. + +### `CALL__stdcall` +Calls a function with [`__stdcall`](https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170) (Standard Call) calling convention. +```dae +func void CALL__stdcall(var int adr) +``` +**Parameters** + +- `#!dae var int adr` + Address of a function + +### `CALL__thiscall` +Calls a function with [`__thiscall`](https://learn.microsoft.com/en-us/cpp/cpp/thiscall?view=msvc-170) calling convention. Used with a member functions. +```dae +func void CALL__thiscall(var int this, var int adr) +``` +**Parameters** + +- `#!dae var int this` + Pointer to the owner class object passed as a `this` parameter +- `#!dae var int adr` + Address of a function + +### `CALL__cdecl` +Calls a function with [`__cdecl`](https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170) calling convention. Used with non-Windows API and non-class functions. +```dae +func void CALL__cdecl (var int adr) +``` +**Parameters** + +- `#!dae var int adr` + Address of a function + + +### `CALL__fastcall` +Calls a function with [`__fastcall`](https://learn.microsoft.com/en-us/cpp/cpp/fastcall?view=msvc-170) calling convention. +```dae +func void CALL__fastcall(var int ecx, var int edx, var int adr) +``` +**Parameters** + +- `#!dae var int ecx` + First parameter of a function +- `#!dae var int edx` + Second parameter of a function +- `#!dae var int adr` + Address of a function + +## Return Value +As soon as the function call has taken place, i.e. after step 2, the return value can be queried. The following functions interpret the return value (usually this is the content of EAX immediately after the call) in the manner suggested in the function name. The result is then returned in a manner usable in Daedalus. + +!!! Note + Some return values are not stored in the EAX. In that case the call of the special function `RetValIs` is required to get the return value. + + Following functions are provided: [`CALL_RetValIsFloat`](#call_retvalisfloat), [`CALL_RetValIszString`](#call_retvaliszstring), [`CALL_RetValIsStruct`](#call_retvalisstruct). + +### `CALL_PutRetValTo` +Simply places the return value to the given address (mostly the address of a daedalus integer). Must be called before [The Call](#the-call) function. +```dae +func void CALL_PutRetValTo(var int adr) +``` +**Parameters** + +- `#!dae var int adr` + Destination address of the return value + + +### `CALL_RetValAsInt` +Retrieves an integer returned by the called function. +```dae +func int CALL_RetValAsInt() +``` +**Return value** + +The function returns an integer returned by the previously called engine function. + +### `CALL_RetValIsFloat` +Specifies that the return value is a float. Must be called before [The Call](#the-call) function to allow getting the return value with [`CALL_RetValAsFloat`](#call_retvalasfloat). +```dae +func void CALL_RetValIsFloat() +``` + +### `CALL_RetValAsFloat` +Retrieves a float returned by the called function. +```dae +func int CALL_RetValAsFloat() +``` +**Return value** + +The function returns a float returned by the previously called engine function. + +### `CALL_RetValAsPtr` +Retrieves a pointer (`void*`) returned by the called function. +```dae +func int CALL_RetValAsPtr() +``` +**Return value** + +The function returns a pointer returned by the previously called engine function. + +### `CALL_RetValIsStruct` +Specifies that the return value is a Structure. Must be called before [The Call](#the-call) function to allow getting the return value with [`CALL_RetValAsStructPtr`](#call_retvalasstructptr). +```dae +func void CALL_RetValIsStruct(var int size) +``` +**Parameters** + +- `#!dae var int size` + Size of the returned structure in bytes + +!!! Danger + If the return value is a structure with a size larger than 32 bit, the space for the return value has to be allocated by the caller (this is us).The address to the allocated memory is expected on the stack as an additional parameter (pushed last). + +!!! Warning + It is in your responsibility to free the structure memory, when the return value is not needed any more. + + +### `CALL_RetValAsStructPtr` +Retrieves a pointer to the structure returned by the called function and converts it to the instance. Can be used to make an assignment to an instance, for example an assignment to a `var zCVob` if the return value is a pointer to a `zCVob`. +```dae +func MEMINT_HelperClass CALL_RetValAsStructPtr() +``` +**Return value** + +The function returns an instance returned by the previously called engine function. + +### `CALL_RetValIszString` +Specifies that the return value is a `zString` (20 bytes structure). Must be called before [The Call](#the-call) function to allow getting the return value with [`CALL_RetValAszStringPtr`](#call_retvalasstructptr) and [`CALL_RetValAszString`](#call_retvalaszstring). +```dae +func string CALL_RetValAszString() +``` + +!!! Note + `CALL_RetValAszStringPtr` and `CALL_RetValAszString` are quite different and should not be confused. Using `CALL_RetValAszString` frees up memory that may still be needed. In a reverse with `CALL_RetValAszStringPtr` memory that is no longer needed is not freed and can cause memory leak. + +### `CALL_RetValAszStringPtr` +Retrieves a `zString` pointer and converts it to the daedalus string. (don't frees the memory) +```dae +func string CALL_RetValAszStringPtr() +``` +**Return value** + +The function returns a daedalus string form a `zString` returned by the previously called engine function. + + +### `CALL_RetValAszString` +Retrieves a `zString` pointer and converts it to the daedalus string. (frees the memory) +```dae +func string CALL_RetValAszString() +``` +**Return value** + +The function returns a daedalus string form a `zString` returned by the previously called engine function. + +??? Trivia "Function author note" + > A `zString` is merely a special case of a structure, with the difference, + that it is used as a primitive datatype. Nobody will be willing + to use it as a pointer to some memory or an instance in Daedalus. + This function copies the contents of the `zString` into a + daedalus string and frees the `zString` afterwards. + +## Examples + +### Apply overlay (Disposable) +```dae +// .text:0072D2C0:int __thiscall oCNpc::ApplyOverlay(class zSTRING const &) + +func void example1(){ + const int oCNpc__ApplyOverlay = 7525056; //0x72D2C0 (G2A) + CALL_zStringPtrParam ("HUMANS_MILITIA.MDS"); + CALL__thiscall (MEM_InstToPtr (hero), oCNpc__ApplyOverlay); + //We are not interested in the return value here. +}; +``` + +### Get time as string (Disposable) +e.g. `"7:30"` for half past seven in the morning +```dae +// .text:00780EC0:class zSTRING __thiscall oCWorldTimer::GetTimeString(void) + +func void example2(){ + const int oCWorldTimer__GetTimeString = 7868096; //780EC0 (G2A) + CALL_RetValIszString(); + CALL__thiscall (MEM_InstToPtr (MEM_WorldTimer), oCWorldTimer__GetTimeString ); + PrintDebug (CALL_RetValAszString()); +}; +``` + +### Get the "sky time" (Disposable) +Sky time is a floating point value between 0 and 1 that jumps back from 1 to 0 at noon. +```dae +// .text:00781240:float __thiscall oCWorldTimer::GetSkyTime(void) + +func int GetSkyTime() { + const int oCWorldTimer__GetSkyTime = 7868992; //0x781240 + CALL_RetValIsFloat(); + CALL__thiscall (MEM_InstToPtr (MEM_WorldTimer), + oCWorldTimer__GetSkyTime); + + return CALL_RetValAsFloat(); +}; +``` + +### Delete Vob (Recyclable) +Call of the `oCWorld.RemoveVob`. [`MEM_DeleteVob`](objects.md#mem_deletevob) is an ikarus built-in function. +```dae +func void MEM_DeleteVob(var int vobPtr) { + var int world; world = MEM_Game._zCSession_world; + + const int call = 0; + if (CALL_Begin(call)) { + /* oCWorld.RemoveVob */ + CALL_IntParam(_@(vobPtr)); + CALL__thiscall(_@(world), MEMINT_SwitchG1G2(7171824, 7864512)); + + call = CALL_End(); + }; +}; +``` \ No newline at end of file diff --git a/docs/zengin/scripts/extenders/ikarus/functions/debug.md b/docs/zengin/scripts/extenders/ikarus/functions/debug.md new file mode 100644 index 0000000000..c12b920418 --- /dev/null +++ b/docs/zengin/scripts/extenders/ikarus/functions/debug.md @@ -0,0 +1,139 @@ +# Debug +A set of debugging and error-handling functions for mod development with Ikarus. + +## Initialization +The best way to initialize all Ikarus functions is to call `MEM_InitAll()` in the `Init_Global()` initialization function. +!!! warning + If you want to use Ikarus in Gothic 1, it is best to define your own `Init_Global()` function and call it from every world initialization function. + +```dae +MEM_InitAll(); +``` + +## Implementation +[:material-github: Ikarus.d on GitHub](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L135-L327) + +## Functions + +### `MEM_CheckVersion` +Checks if the version of Ikarus is the specified version or newer. +```dae +func int MEM_CheckVersion(var int base, var int major, var int minor) +``` +**Parameters** + +- `#!dae var int base` + Base version number +- `#!dae var int major` + Major revision number +- `#!dae var int minor` + Minor revision number + +**Return value** + +The function returns `TRUE` if the version of Ikarus is the specified version or newer, `FALSE` is returned otherwise. + + +### `MEM_SetShowDebug` +Sets the variable that is also toggled by the `toggle debug` command. As a result, messages outputted by `PrintDebug` are directed to the [zSpy](../../../../tools/zSpy.md) +```dae +func void MEM_SetShowDebug(var int on) +``` +**Parameters** + +- `#!dae var int on` + Specifies whether to turn on (`TRUE`) or off (`FALSE`) debug information. + +### `MEM_SendToSpy` +Sends a message to the debugging console. +```dae +func void MEM_SendToSpy(var int errorType, var string text) +``` +**Parameters** + +- `#!dae var int errorType` + Type of error (e.g., `zERR_TYPE_FAULT`, `zERR_TYPE_WARN`, `zERR_TYPE_INFO`) +- `#!dae var string text` + The message to be sent. + +### `MEM_ErrorBox` +Displays an error message in a message box. +```dae +func void MEM_ErrorBox(var string text) +``` +**Parameters** + +- `#!dae var string text` + The error message to be displayed. + +### `MEM_PrintStackTrace` +Prints the stack trace. +```dae +func void MEM_PrintStackTrace() +``` + +### `MEM_Error` +Handles a fatal error, displaying the error message and printing the stack trace. +```dae +func void MEM_Error(var string error) +``` +**Parameters** + +- `#!dae var string error` + The error message. + +### `MEM_Warn` +Handles a warning, displaying the warning message and printing the stack trace. +```dae +func void MEM_Warn(var string warn) +``` +**Parameters** + +- `#!dae var string warn` + The warning message. + +### `MEM_Info` +Handles an information message, printing it if enabled in the settings. +```dae +func void MEM_Info(var string info) +``` +**Parameters** + +- `#!dae var string info` + The information message. + +### `MEM_AssertFail` +Handles an assertion failure, reporting the error message as a fatal error. +```dae +func void MEM_AssertFail(var string assertFailText) +``` +**Parameters** + +- `#!dae var string assertFailText` + The assertion failure message. + +### `MEM_Debug` +Freely configurable debug channel. See how to setup it in the [Constants](../constants.md#mem_debug) article. +```dae +func void MEM_Debug(var string message) +``` +**Parameters** + +- `#!dae var string message` + The debug message. + +### `MEMINT_SwitchG1G2` +Switches between values based on the game version. Used mainly to change addresses in multi-platform hooks or function calls. +```dae +func int MEMINT_SwitchG1G2(var int g1Val, var int g2Val) +``` +**Parameters** + +- `#!dae var int g1Val` + The value to return if the game version is Gothic 1. +- `#!dae var int g2Val` + The value to return if the game version is Gothic 2. + +**Return value** + +The function returns an appropriate value based on the game version. \ No newline at end of file diff --git a/docs/zengin/scripts/extenders/ikarus/functions/ini_access.md b/docs/zengin/scripts/extenders/ikarus/functions/ini_access.md index 2821037b19..04e115bdbc 100644 --- a/docs/zengin/scripts/extenders/ikarus/functions/ini_access.md +++ b/docs/zengin/scripts/extenders/ikarus/functions/ini_access.md @@ -18,6 +18,17 @@ MEM_InitAll(); ## Read functions +### `MEM_GetCommandLine` +Returns the contents of the command line passed to Gothic. +```dae +func string MEM_GetCommandLine() +``` +**Return value** + +The function returns contents of the command line passed to Gothic. This could, for example, look like this: + +`"-TIME:7:35 -GAME:TEST_IKARUS.INI -ZREPARSE -ZWINDOW -ZLOG:5,S -DEVMODE -ZMAXFRAMERATE:30"` + ### `MEM_GetGothOpt` Searches the `Gothic.ini` for an option. ```dae diff --git a/docs/zengin/scripts/extenders/ikarus/functions/ini_access.pl.md b/docs/zengin/scripts/extenders/ikarus/functions/ini_access.pl.md index c3ec2b5138..92b42c74cd 100644 --- a/docs/zengin/scripts/extenders/ikarus/functions/ini_access.pl.md +++ b/docs/zengin/scripts/extenders/ikarus/functions/ini_access.pl.md @@ -1,3 +1,6 @@ +--- +title: Ini File Access +--- # Dostęp do plików konfiguracyjnych Ta część Ikarusa umożliwia dostęp do `Gothic.ini` i pliku konfiguracyjnego załadowanej modyfikacji. @@ -15,6 +18,17 @@ MEM_InitAll(); ## Funkcje odczytu +### `MEM_GetCommandLine` +Zwraca zawartość linii poleceń przekazaną do Gothica. +```dae +func string MEM_GetCommandLine() +``` +**Zwracana wartość** + +Funkcja zwraca zawartość linii poleceń przekazaną do Gothica. Może to wyglądać na przykład tak: + +`"-TIME:7:35 -GAME:TEST_IKARUS.INI -ZREPARSE -ZWINDOW -ZLOG:5,S -DEVMODE -ZMAXFRAMERATE:30"` + ### `MEM_GetGothOpt` Przeszukuje `Gothic.ini` w poszukiwaniu opcji ```dae @@ -29,7 +43,7 @@ func string MEM_GetGothOpt(var string sectionname, var string optionname) **Zwracana wartość** -Funkcja zwraca wartość opcji w postaci łańcucha znaków, albo pustą zmienną, gdy opcja nie istnieje w danej sekcji. +Funkcja zwraca wartość opcji w postaci ciągu znaków, albo pustą zmienną, gdy opcja nie istnieje w danej sekcji. ### `MEM_GetModOpt` Przeszukuje ini załadowanej modyfikacji w poszukiwaniu opcji. @@ -45,7 +59,7 @@ func void MEM_GetModOpt(var string sectionname, var string optionname) **Zwracana wartość** -Funkcja zwraca wartość opcji w postaci łańcucha znaków, albo pustą zmienną, gdy opcja nie istnieje w danej sekcji. +Funkcja zwraca wartość opcji w postaci ciągu znaków, albo pustą zmienną, gdy opcja nie istnieje w danej sekcji. ### `MEM_GothOptSectionExists` Sprawdza, czy dana sekcja istnieje w `Gothic.ini` @@ -178,7 +192,7 @@ func void MEM_SetKeys(var string name, var int primary, var int secondary) - `#!dae var int primary` Podstawowy klawisz do przypisania, można go pobrać z pliku [Ikarus_Const_G1](https://github.com/Lehona/Ikarus/blob/master/Ikarus_Const_G1.d) / [Ikarus_Const_G2](https://github.com/Lehona/Ikarus/blob/master/Ikarus_Const_G2.d). - `#!dae var int secondary` - Zapasowy klawisz do przypisania, można go pobrać z pliku[Ikarus_Const_G1](https://github.com/Lehona/Ikarus/blob/master/Ikarus_Const_G1.d) / [Ikarus_Const_G2](https://github.com/Lehona/Ikarus/blob/master/Ikarus_Const_G2.d). + Zapasowy klawisz do przypisania, można go pobrać z pliku [Ikarus_Const_G1](https://github.com/Lehona/Ikarus/blob/master/Ikarus_Const_G1.d) / [Ikarus_Const_G2](https://github.com/Lehona/Ikarus/blob/master/Ikarus_Const_G2.d). ### `MEM_SetKey` Ustawia podstawowy klawisz klawiatury dla klawisza logicznego. diff --git a/docs/zengin/scripts/extenders/ikarus/functions/jumps_loops.md b/docs/zengin/scripts/extenders/ikarus/functions/jumps_loops.md new file mode 100644 index 0000000000..abb34e0d59 --- /dev/null +++ b/docs/zengin/scripts/extenders/ikarus/functions/jumps_loops.md @@ -0,0 +1,458 @@ +# Jumps and Loops + +## Jumps + +Jumps in Ikarus are implemented by direct manipulation of the stack pointer, achieved with two lines of code. These lines enable the change of the current position within the parser stack, representing machine-level code generated during script compilation. By querying and setting this position, the execution flow can be redirected to a new location in the code. + +### Initialization + +To ensure the correct functioning of this jump mechanism, it is crucial to execute the `MEM_InitLabels()` function once after loading a saved game. The recommended practice is to integrate this initialization function within `INIT_GLOBAL`. It's only after `MEM_InitLabels()` has been called that accessing `MEM_StackPos.position` becomes valid. + +```dae +func void MEM_InitLabels() +``` +!!! Tip + It's worth noting that `MEM_InitLabels` is also invoked by the `MEM_InitAll` function. + +### Usage +- **Label Initialization** + Before attempting a jump, it's important to initialize the label to which the jump is intended. Forward jumps, where the jump point is encountered before the jump target, can be challenging. Label initialization looks like that: + ```dae + // [...] + var int label; + label = MEM_StackPos.position; + // [...] + ``` +- **Actual jump** + After initializing the label you could simply jump to it by setting `MEM_StackPos.position` to the label. + ```dae + // [...] + MEM_StackPos.position = label; + // [...] + ``` + +**Jump flowchart** + ```mermaid + flowchart TD + A(Start) --> B["var int label; \n label = MEM_StackPos.position;"]; + B --> C{Your code} + C -->D["MEM_StackPos.position = label;"]; + C --> E(End) + D --> |Jump| B; + ``` +### Notes and warnings + +- **Validity of Labels** + Labels become invalid after saving and loading. Consequently, labels should be used immediately, and there is generally no reason to persist them for an extended period. + +- **Caution with Jumping** + Jumping between different functions without a clear understanding of the code structure can lead to unexpected issues. Similarly, using labels without a thorough comprehension of their purpose may result in undesired consequences. It's crucial to exercise caution, especially when making assignments involving labels. + + +### Examples + +=== "Simple jump 'loop'" + The following code outputs the numbers from 0 to 42: + + ```dae + func void foo() { + /* Initialization */ + MEM_InitLabels(); + var int count; count = 0; + + /* Record the execution position in label. */ + var int label; + label = MEM_StackPos.position; + /* <---- label now points here, + * i.e. to the position AFTER the assignment of label. */ + + Print (ConcatStrings ("COUNT: ", IntToString (count))); + count += 1; + + if (count <= 42) { + /* Replace the execution position, + * with the "<-----" the system then continues */ + MEM_StackPos.position = label; + }; + + /* Once 43 is reached, the “loop” is exited. */ + }; + ``` +=== "Nested jump 'loop'" + The following code should enumerate all pairs (x,y) with `0 <= x < max_x`, `0 <= y < max_y` + ```dae + func void printpairs(var int max_x, var int max_y) + { + // Initialize labels + MEM_InitLabels(); + // PrintDebug should be used, i.e. activate debug output + MEM_SetShowDebug (1); + + var int x; var int y; x = 0; + + // while (x < max_x) + var int x_loop; x_loop = MEM_StackPos.position; + if (x < max_x) + { + y = 0; + // while (y < max_y) + var int y_loop; y_loop = MEM_StackPos.position; + if (y < max_y) + { + var string out; out = "("; + out = ConcatStrings (out, IntToString (x)); + out = ConcatStrings (out, ", "); + out = ConcatStrings (out, IntToString (y)); + out = ConcatStrings (out, ")"); + PrintDebug (out); + y += 1; + + // continue y_loop + MEM_StackPos.position = y_loop; + }; + x += 1; + // continue x_loop + MEM_StackPos.position = x_loop; + }; + }; + + /* + Output of a call printpairs(4,2) would then be: + 00:36 Info: 5 U: Skript: (0, 0) .... + 00:36 Info: 5 U: Skript: (0, 1) .... + 00:36 Info: 5 U: Skript: (1, 0) .... + 00:36 Info: 5 U: Skript: (1, 1) .... + 00:36 Info: 5 U: Skript: (2, 0) .... + 00:36 Info: 5 U: Skript: (2, 1) .... + 00:36 Info: 5 U: Skript: (3, 0) .... + 00:36 Info: 5 U: Skript: (3, 1) .... + */ + ``` + +## Label and Goto + +Besides the normal [jumps](#jumps) Ikarus implements `MEM_Label` and `MEM_Goto` functions. They work similar to the stack manipulation with `var int label` but the interface is much more user-friendly and defining new variables is not needed. + +### `MEM_Label` +Function that works like a `label = MEM_StackPos.position;`. You could jump to it with [`MEM_Goto`](#mem_goto). +```dae +func void MEM_Label(var int lbl) +``` +**Parameters** + +- `#!dae var int lbl` + Number of the label, used for nested loop or multiple loops within one function + +### `MEM_Goto` +Function that works like a `MEM_StackPos.position = label;`. Executes a jump to a [`MEM_Label`](#mem_label) with specified number. +```dae +func void MEM_Goto(var int lbl) +``` +**Parameters** + +- `#!dae var int lbl` + Number of the label, the function will jump to + +### Usage +Usage of Label and Goto is probably self-explanatory, since it is same as in the regular Ikarus Jump. But before using it reading the [Notes and warnings](#notes-and-warnings) of the Jumps is recommended. + +**Label-Goto loop flowchart** + ```mermaid + flowchart TD + A(Start) --> B["MEM_Label(0);"]; + B --> C{Your code} + C -->D["MEM_Goto(0);"]; + C --> E(End) + D --> |Jump| B; + ``` + +```dae title="Label-Goto loop" +func void LabelGoto_test() { + var int i; + MEM_Label(0); + MEM_Debug(IntToString(i)); + i = i + 1; + if(i >= 4) + { + return; + }; + MEM_Goto(0); +}; + +// Results: +// Info: 0 Q: Debug: 0 +// Info: 0 Q: Debug: 1 +// Info: 0 Q: Debug: 2 +// Info: 0 Q: Debug: 3 +``` + +### Examples + +=== "Simple Label-Goto 'loop'" + The following code outputs the numbers from 0 to 42: + + ```dae + func void foo() { + var int count; count = 0; + + MEM_Label(0); + /* <---- label now points here, + * i.e. to the position AFTER the assignment of label. */ + + Print (ConcatStrings ("COUNT: ", IntToString (count))); + count += 1; + + if (count <= 42) { + // Jump to the MEM_Label + MEM_Goto(0); + }; + + /* Once 43 is reached, the “loop” is exited. */ + }; + ``` +=== "Nested Label-Goto 'loop'" + The following code should enumerate all pairs (x,y) with `0 <= x < max_x`, `0 <= y < max_y` + ```dae + func void printpairs(var int max_x, var int max_y) + { + // PrintDebug should be used, i.e. activate debug output + MEM_SetShowDebug (1); + + var int x; var int y; x = 0; + + // while (x < max_x) + MEM_Label(0); + if (x < max_x) + { + y = 0; + // while (y < max_y) + MEM_Label(1); + if (y < max_y) + { + var string out; out = "("; + out = ConcatStrings (out, IntToString (x)); + out = ConcatStrings (out, ", "); + out = ConcatStrings (out, IntToString (y)); + out = ConcatStrings (out, ")"); + PrintDebug (out); + y += 1; + + MEM_Goto(1); + }; + x += 1; + MEM_Goto(0); + }; + }; + + /* + Output of a call printpairs(4,2) would then be: + 00:36 Info: 5 U: Skript: (0, 0) .... + 00:36 Info: 5 U: Skript: (0, 1) .... + 00:36 Info: 5 U: Skript: (1, 0) .... + 00:36 Info: 5 U: Skript: (1, 1) .... + 00:36 Info: 5 U: Skript: (2, 0) .... + 00:36 Info: 5 U: Skript: (2, 1) .... + 00:36 Info: 5 U: Skript: (3, 0) .... + 00:36 Info: 5 U: Skript: (3, 1) .... + */ + ``` + +## While loop + +Ikarus also implements a while loop. Its syntax isn't as good as the loop from [zParserExtender](../../zparserextender/syntax_extensions/while.md), due to the daedalus limitations, but it works as a normal while loop that can be found in many programming languages. + +### Syntax +The Ikarus while loop consist of three things: + +- **while function** +That works like a while statement and start of the brace `while(var int b){`. +```dae +func void while(var int b) +``` + +- **end constant** +That works like an ending brace `}`. +```dae +const int end = -72; +``` + +- **break and continue constant** +These two constants works like a regular `break` and `continue` statements in C. +```dae +const int break = -42; +const int continue = -23; +``` + +```dae title="while loop" +func void while_test() { + var int value; value = 10; + while(value > 0); //{ + + if (value == 8) + { + continue; + }; + + if (value == 2) + { + break; + }; + end; //} +}; +``` + +### Examples + +=== "Simple while loop" + The following code outputs the numbers from 0 to 42: + + ```dae + func void foo() { + var int count; count = 0; + while(count <= 42); //{ + Print (ConcatStrings ("COUNT: ", IntToString (count))); + count += 1; + end; //} + + /* Once 43 is reached, the loop is exited. */ + }; + ``` +=== "Nested while loop" + The following code should enumerate all pairs (x,y) with `0 <= x < max_x`, `0 <= y < max_y` + ```dae + func void printpairs(var int max_x, var int max_y) + { + // PrintDebug should be used, i.e. activate debug output + MEM_SetShowDebug (1); + + var int x; var int y; x = 0; + + while(x < max_x); //{ + y = 0; + while(y < max_y); //{ + var string out; out = "("; + out = ConcatStrings (out, IntToString (x)); + out = ConcatStrings (out, ", "); + out = ConcatStrings (out, IntToString (y)); + out = ConcatStrings (out, ")"); + PrintDebug (out); + y += 1; + end; //} + x += 1; + end; //} + }; + + /* + Output of a call printpairs(4,2) would then be: + 00:36 Info: 5 U: Skript: (0, 0) .... + 00:36 Info: 5 U: Skript: (0, 1) .... + 00:36 Info: 5 U: Skript: (1, 0) .... + 00:36 Info: 5 U: Skript: (1, 1) .... + 00:36 Info: 5 U: Skript: (2, 0) .... + 00:36 Info: 5 U: Skript: (2, 1) .... + 00:36 Info: 5 U: Skript: (3, 0) .... + 00:36 Info: 5 U: Skript: (3, 1) .... + */ + ``` + +## Repeat loop + +In addition Ikarus implements something called **Repeat loop**. + +### Initialization + +To use Repeat loop you must first call `MEM_InitRepeat()` function once after loading a saved game. The recommended practice is to integrate this initialization function within `INIT_GLOBAL`. + +```dae +func void MEM_InitRepeat() +``` +!!! Tip + It's worth noting that `MEM_InitRepeat` is also invoked by the `MEM_InitAll` function. + + +### Syntax +Repeat loop has a syntax very similar to the [while loop](#syntax). It also uses `end` constant as an ending brace. `break` and `continue` statements can be used within it as well. The main difference is the main loop function `Repeat` that has following properties: + +```dae +func void Repeat(var int variable, var int limit) +``` + +- `#!dae var int variable` + A variable that increase with every loop iteration. +- `#!dae var int limit` + A variable that defines the number of loop iterations. If `variable >= limit` the loop is exited. + +**Repeat loop flowchart** +```mermaid +flowchart TD + A(Start) --> B["Repeat(i, limit)"] + B --> C{i < limit} + C -->|true| D[Command] + D --> |i = i + 1| B + C --> |false| E(End) +``` + + +```dae title="Repeat loop" +func void Repeat_test() { + Repeat(i, 4); var int i; //{ + MEM_Debug(IntToString(i)); + end; //} +}; + +// Results: +// Info: 0 Q: Debug: 0 +// Info: 0 Q: Debug: 1 +// Info: 0 Q: Debug: 2 +// Info: 0 Q: Debug: 3 +``` + +### Examples + +=== "Simple Repeat loop" + The following code outputs the numbers from 0 to 42: + + ```dae + func void foo() { + Repeat(count, 43); var int count; //{ + Print (ConcatStrings ("COUNT: ", IntToString (count))); + end; //} + + /* Once 43 is reached, the loop is exited. */ + }; + ``` +=== "Nested Repeat loop" + The following code should enumerate all pairs (x,y) with `0 <= x < max_x`, `0 <= y < max_y` + ```dae + func void printpairs(var int max_x, var int max_y) + { + // PrintDebug should be used, i.e. activate debug output + MEM_SetShowDebug (1); + + var int x; var int y; x = 0; + + Repeat(x, max_x); //{ + y = 0; + Repeat(y, max_y); //{ + var string out; out = "("; + out = ConcatStrings (out, IntToString (x)); + out = ConcatStrings (out, ", "); + out = ConcatStrings (out, IntToString (y)); + out = ConcatStrings (out, ")"); + PrintDebug (out); + end; //} + end; //} + }; + + /* + Output of a call printpairs(4,2) would then be: + 00:36 Info: 5 U: Skript: (0, 0) .... + 00:36 Info: 5 U: Skript: (0, 1) .... + 00:36 Info: 5 U: Skript: (1, 0) .... + 00:36 Info: 5 U: Skript: (1, 1) .... + 00:36 Info: 5 U: Skript: (2, 0) .... + 00:36 Info: 5 U: Skript: (2, 1) .... + 00:36 Info: 5 U: Skript: (3, 0) .... + 00:36 Info: 5 U: Skript: (3, 1) .... + */ + ``` \ No newline at end of file diff --git a/docs/zengin/scripts/extenders/ikarus/functions/keyboard.md b/docs/zengin/scripts/extenders/ikarus/functions/keyboard.md index 82f4d20d47..0239eb9318 100644 --- a/docs/zengin/scripts/extenders/ikarus/functions/keyboard.md +++ b/docs/zengin/scripts/extenders/ikarus/functions/keyboard.md @@ -4,6 +4,9 @@ title: Keyboard # Keyboard interaction This part of Ikarus implements function that make interaction with keyboard possible. +!!! Info + Keyboard interaction is also implemented with [gameKeyEvents.d](../../standalone/gameKeyEvents.md) + ## Initialization The best way to initialize all Ikarus functions is to call `MEM_InitAll()` in the `Init_Global()` initialization function. !!! warning @@ -14,11 +17,26 @@ MEM_InitAll(); ``` ## Implementation -[:material-github: Ikarus.d on GitHub](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L4198) +[:material-github: Ikarus.d on GitHub](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L4198-L4292) ## Functions !!! Tip Different players use different keys for specific actions! However, it is possible to get key assigned to the action from Gothic.ini. See [Ini access](ini_access.md#key-functions). + +### `MEM_KeyPressed` +Checks if the key is hold right at the moment of function call. +```dae +func int MEM_KeyPressed(var int key) +``` +**Parameters** + +- `#!dae var int key` + Checked key + +**Return value** + +The function returns `TRUE` if the key is hold, `FALSE` is returned otherwise. + ### `MEM_KeyState` Returns the state of the `key`. ```dae diff --git a/docs/zengin/scripts/extenders/ikarus/functions/mem_access.md b/docs/zengin/scripts/extenders/ikarus/functions/mem_access.md index 07e248c476..717703ee01 100644 --- a/docs/zengin/scripts/extenders/ikarus/functions/mem_access.md +++ b/docs/zengin/scripts/extenders/ikarus/functions/mem_access.md @@ -82,7 +82,7 @@ The function returns integer value from the array if the address is correct. ### `MEM_ReadStringArray` !!! Info - `MEM_ReadStringArray` has been already moved to the LeGo PermMem package. + `MEM_ReadStringArray` has been already moved to the LeGo [PermMem](../../lego/tools/permmem.md#mem_readstringarray) package. ### `MEM_ReadByteArray` Reads byte from the array at the `arrayAddress`. @@ -114,7 +114,7 @@ func void MEM_WriteInt(var int address, var int value) - `#!dae var int value` Integer value to write -??? abstract "Examples" +??? abstract "Example" An example of using this function is the following Ikarus function, which turns debugging messages on and off: ```dae func void MEM_SetShowDebug(var int on) diff --git a/docs/zengin/scripts/extenders/ikarus/functions/mem_utility.md b/docs/zengin/scripts/extenders/ikarus/functions/mem_utility.md new file mode 100644 index 0000000000..22bc428e00 --- /dev/null +++ b/docs/zengin/scripts/extenders/ikarus/functions/mem_utility.md @@ -0,0 +1,231 @@ +# Memory utility +Ikarus utility functions, for memory management and manipulation. + +## Initialization +The best way to initialize all Ikarus functions is to call `MEM_InitAll()` in the `Init_Global()` initialization function. +!!! warning + If you want to use Ikarus in Gothic 1, it is best to define your own `Init_Global()` function and call it from every world initialization function. + +```dae +MEM_InitAll(); +``` + +## Implementation +[:material-github: Ikarus.d on GitHub](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L1655-L1838) + +## Functions + +### `MEM_Alloc` +Allocates a specified amount of memory and returns a pointer to the allocated memory area. + +!!! Danger + Gothic does not and cannot retain a reference to this memory area or release it, even when destroying the session. Therefore, memory should only be reserved under certain conditions: + + - It is guaranteed to exist and can be released again with [`MEM_Free`](#mem_free) after loading a save game. + - Gothic is aware of this memory area and independently releases it. + +It might be possible to create new objects with this function and permanently integrate them into the object structure of Gothic. However, extreme caution is advised, as object structures cannot be used, and manual handling is required. + +This function is well-suited for building small elements like list items and integrating them into existing lists. The memory allocated by this function is always initialized to zero. +```dae +func int MEM_Alloc(var int amount) +``` +**Parameters** + +- `#!dae var int amount` + The amount of bytes to allocate + +**Return value** + +The function returns a pointer to the allocated memory area. + +### `MEM_Realloc` +Allocates a memory area of size `newsize` and returns a pointer to this memory area. The memory area from location `ptr` is released. + +If `newsize >= oldsize`, the first `oldsize` bytes from the old memory area are transferred to the new one. The additional memory is initialized with zero. + +If `newsize <= oldsize`, all bytes of the new memory area are initialized with the corresponding values of the old memory area. + +This function is intended to create an allocated memory area enlarge or reduce. Existing data remains naturally way received. +```dae +func int MEM_Realloc(var int ptr, var int oldsize, var int newsize) +``` +**Parameters** + +- `#!dae var int ptr` + The original pointer to the memory block +- `#!dae var int oldsize` + The size of the original memory block +- `#!dae var int newsize` + The size of the new memory block + +**Return value** + +The function returns a pointer to the modified memory area. + +### `MEM_Free` +Releases an allocated memory area. + +!!! Danger + Great caution is advised, especially when attempting to destroy engine objects, as no destructors are called! + +Releasing small things such as list elements can be done easily. +```dae +func void MEM_Free(var int ptr) +``` +**Parameters** + +- `#!dae var int ptr` + Pointer to the released memory block + +### `MEM_Copy` +Copies a specified number of words from the source address to the destination address. +```dae +func void MEM_Copy(var int src, var int dst, var int wordcount) +``` +**Parameters** + +- `#!dae var int src` + The source address to copy from +- `#!dae var int dst` + The destination address to copy to +- `#!dae var int wordCount` + The number of words to copy + +### `MEM_CopyWords` +Alias to [`MEM_Copy`](#mem_copy). Copies a specified number of words from the source address to the destination address. +```dae +func void MEM_CopyWords(var int src, var int dst, var int wordcount) +``` +**Parameters** + +- `#!dae var int src` + The source address to copy from +- `#!dae var int dst` + The destination address to copy to +- `#!dae var int wordCount` + The number of words to copy + +### `MEM_CopyBytes` +Copies a specified number of bytes from the source address to the destination address +```dae +func void MEM_CopyBytes(var int src, var int dst, var int byteCount) +``` +**Parameters** + +- `#!dae var int src` + The source address to copy from +- `#!dae var int dst` + The destination address to copy to +- `#!dae var int byteCount` + The number of bytes to copy + +### `MEM_Swap` +Swaps a specified number of words between the source address and the destination address. +```dae +func void MEM_Swap(var int src, var int dst, var int wordCount) +``` +**Parameters** + +- `#!dae var int src` + The source address to swap from +- `#!dae var int dst` + The destination address to swap to +- `#!dae var int wordCount` + The number of words to swap + +### `MEM_SwapWords` +Alias to [`MEM_Swap`](#mem_swap). Swaps a specified number of words between the source address and the destination address. +```dae +func void MEM_SwapWords(var int src, var int dst, var int wordCount) +``` +**Parameters** + +- `#!dae var int src` + The source address to swap from +- `#!dae var int dst` + The destination address to swap to +- `#!dae var int wordCount` + The number of words to swap + +### `MEM_SwapBytes` +Swaps a specified number of bytes between the source address and the destination address. +```dae +func void MEM_SwapBytes(var int src, var int dst, var int byteCount) +``` +**Parameters** + +- `#!dae var int src` + The source address to swap from +- `#!dae var int dst` + The destination address to swap to +- `#!dae var int byteCount` + The number of bytes to swap + + +### `MEM_Clear` +Sets a specified number of bytes in memory to zero. +```dae +func void MEM_Clear(var int ptr, var int size) +``` +**Parameters** + +- `#!dae var int ptr` + The memory address to start clearing from +- `#!dae var int size` + The number of bytes to clear + +### `MEM_Compare` +Compares a specified number of words between two memory blocks. +```dae +func int MEM_Compare(var int ptr0, var int ptr1, var int wordCount) +``` +**Parameters** + +- `#!dae var int ptr0` + The first memory block to compare +- `#!dae var int ptr1` + The second memory block to compare +- `#!dae var int wordCount` + The number of words to compare + +**Return value** + +The function returns `TRUE` if the memory blocks are equal, `FALSE` is returned otherwise. + + +### `MEM_CompareWords` +Alias to [`MEM_Compare`](#mem_compare). Compares a specified number of words between two memory blocks. +```dae +func int MEM_CompareWords(var int ptr0, var int ptr1, var int wordCount) +``` +**Parameters** + +- `#!dae var int ptr0` + The first memory block to compare +- `#!dae var int ptr1` + The second memory block to compare +- `#!dae var int wordCount` + The number of words to compare + +**Return value** + +The function returns `TRUE` if the memory blocks are equal, `FALSE` is returned otherwise. + +### `MEM_CompareBytes` +Compares a specified number of bytes between two memory blocks. +```dae +func int MEM_CompareBytes(var int ptr1, var int ptr2, var int byteCount) +``` +**Parameters** + +- `#!dae var int ptr0` + The first memory block to compare +- `#!dae var int ptr1` + The second memory block to compare +- `#!dae var int wordCount` + The number of bytes to compare + +**Return value** + +The function returns `TRUE` if the memory blocks are equal, `FALSE` is returned otherwise. diff --git a/docs/zengin/scripts/extenders/ikarus/functions/objects.md b/docs/zengin/scripts/extenders/ikarus/functions/objects.md new file mode 100644 index 0000000000..0b11fa1422 --- /dev/null +++ b/docs/zengin/scripts/extenders/ikarus/functions/objects.md @@ -0,0 +1,301 @@ +# zCObjects + +Set of functions for working with `zCObject` and its subclasses instances. + +## Initialization +The best way to initialize all Ikarus functions is to call `MEM_InitAll()` in the `Init_Global()` initialization function. +!!! warning + If you want to use Ikarus in Gothic 1, it is best to define your own `Init_Global()` function and call it from every world initialization function. + +```dae +MEM_InitAll(); +``` + +## Implementation +[:material-github: Ikarus.d on GitHub](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L3755-L4197) + +## Global instances +Ikarus package introduces the following instances: + +```dae +instance MEM_Game (oCGame); +instance MEM_World(oWorld); +instance MEM_Timer(zCTimer); +instance MEM_WorldTimer(oCWorldTimer); +instance MEM_Vobtree(zCTree); +instance MEM_InfoMan(oCInfoManager); +instance MEM_InformationMan (oCInformationManager); +instance MEM_Waynet(zCWaynet); +instance MEM_Camera(zCCamera); +instance MEM_SkyController(zCSkyController_Outdoor); +instance MEM_SpawnManager (oCSpawnManager); +instance MEM_GameMananger (CGameManager); +instance MEM_GameManager (CGameManager); +instance MEM_Parser(zCParser); +``` + +The classes used here all have one thing in common: there is a maximum of one object of them at the same time (e.g. there is not two worlds or two sky at the same time). + +[`MEM_InitGlobalInst`](#mem_initglobalinst) function sets the offsets of these instances to the corresponding unique object. While it has been called, all of the above instances can be used. + +### `MEM_InitGlobalInst` +Initializes global instances of commonly used objects in the game (is called by the `MEM_InitAll` function). +```dae +func void MEM_InitGlobalInst() +``` + +!!! Warning + `MEM_InitGlobalInst` must be executed once after loading a savegame. The easiest way is do it is to call this function from `INIT_GLOBAL`. + +## Functions + +??? Trivia "About zCClassDef" + For every class (derived from `zCObject`) there is an "administrative object" of type `zCClassDef`. This encapsulates some useful information about all objects in this class. + + ```dae + class zCClassDef { + var string className; //zSTRING + var string baseClassName; //zSTRING + var string scriptClassName; //zSTRING + var int baseClassDef; //zCClassDef* + var int createNewInstance; //zCObject* ( *) (void) + var int createNewInstanceBackup; //zCObject* ( *) (void) + var int classFlags; //zDWORD + var int classSize; //zDWORD + var int numLivingObjects; + var int numCtorCalled; + var int hashTable; //zCObject** + var int objectList_array; //zCObject** + var int objectList_numAlloc; //int + var int objectList_numInArray; //int + var int bitfield; + }; + ``` + + Full Ikarus definition of this class, with members description can be found in [`Misc.d`](https://github.com/Lehona/Ikarus/blob/master/EngineClasses_G1/Misc.d#L490-L537) file. The class is same for G1 and G2A engines. + +### `MEM_GetClassDef` +Returns a pointer to the `zCClassDef` of the object. For more info see the **About zCClassDef** section above. + +Passing these functions a pointer that does not point to a zCObject will most likely result in a crash +lead. + +```dae +func int MEM_GetClassDef(var int objPtr) +``` +**Parameters** + +- `#!dae var int objPtr` + A pointer to the object whose class definition is to be retrieved + +**Return value** + +The function returns a pointer to the `zCClassDef` of the object. + +??? abstract "Example" + This would return a pointer to the `zCClassDef` object that belongs to the `oCNpc` class. + ```dae + func int example1 + { + var int her; her = MEM_InstToPtr(hero); + return MEM_GetClassDef(her); + }; + ``` + + +### `MEM_GetClassName` +This function returns the name of the class to which an object belongs. +```dae +func string MEM_GetClassName(var int objPtr) +``` +**Parameters** + +- `#!dae var int objPtr` + A pointer to the object whose class name is to be retrieved + +**Return value** + +The function returns the objects class name as a string, if the object is invalid an empty string is returned. + +??? abstract "Example" + This would return a name of the `oCNpc` class as a string. + ```dae + func string example2 + { + var int her; her = MEM_InstToPtr(hero); + return MEM_GetClassName(her); + }; + // return: "oCNpc" + ``` + +### `MEM_CheckInheritance` +Checks if an object is derived from a specific class definition. +```dae +func int MEM_CheckInheritance(var int objPtr, var int classDef) +``` +**Parameters** + +- `#!dae var int objPtr` + A pointer to the object to be checked +- `#!dae var int classDef` + A pointer to the class definition to check against + +**Return value** + +The function returns `TRUE` if the object is derived from the specified class definition, `FALSE` is returned otherwise. + +#### `Hlp_Is_*` +In addition [`MEM_CheckInheritance`](#mem_checkinheritance) function has some overloads with hardcoded `classDef` parameter. + +```dae +func int Hlp_Is_oCMobFire(var int ptr){}; +func int Hlp_Is_zCMover(var int ptr){}; +func int Hlp_Is_oCMob(var int ptr){}; +func int Hlp_Is_oCMobInter(var int ptr){}; +func int Hlp_Is_oCMobLockable(var int ptr){}; +func int Hlp_Is_oCMobContainer(var int ptr){}; +func int Hlp_Is_oCMobDoor(var int ptr){}; +func int Hlp_Is_oCMobBed(var int ptr){}; +func int Hlp_Is_oCMobSwitch(var int ptr){}; +func int Hlp_Is_oCMobWheel(var int ptr){}; +func int Hlp_Is_oCMobLadder(var int ptr){}; +func int Hlp_Is_oCNpc(var int ptr){}; +func int Hlp_Is_oCItem(var int ptr){}; +func int Hlp_Is_zCVobLight(var int ptr){}; +``` + +The usage of these functions is probably obvious, they checks if the given object belongs to class given in the function name. + + +### `MEM_InsertVob` +Inserts a Vob with the visual `vis` at the waypoint `wp`. If the visual or waypoint does not exist, this is the behaviour this function undefined. + +!!! Note + The inserted Vob is even an `oCMob`, so it can be given a focus name, for example. But you can treat it like a [`zCVob`](../../../../worlds/Classes/zCVob.md)), if you don't need the additional properties. +```dae +func int MEM_InsertVob(var string vis, var string wp) +``` +**Parameters** + +- `#!dae var string vis` + Name of the inserted Vob visual (`"FAKESCROLL.3DS"`, `"FIRE.PFX"`, `"SNA_BODY.ASC"`, `"CHESTSMALL_NW_POOR_LOCKED.MDS"`, `"ADD_PIRATEFLAG.MMS"` etc.) +- `#!dae var string wp` + Name of the waypoint to insert Vob on + +**Return value** + +The function returns a pointer to the created object. + +### `MEM_DeleteVob` +Deletes a specific Vob form world. +```dae +func void MEM_DeleteVob(var int vobPtr) +``` +**Parameters** + +- `#!dae var int vobPtr` + Pointer to a [`zCVob`](../../../../worlds/Classes/zCVob.md) object to be deleted + +### `MEM_RenameVob` +Renames the passed Vob to the `newName` that is also passed. + +The object becomes this first removed from the Vob-hashtable, then unnamed and then again inserted into the Vob-hashtable under a new name. +```dae +func void MEM_RenameVob(var int vobPtr, var string newName) +``` +**Parameters** + +- `#!dae var int vobPtr` + Pointer to a [`zCVob`](../../../../worlds/Classes/zCVob.md) object to be renamed +- `#!dae var string newName` + The new Name of the Vob + +=== "MEM_TriggerVob" + + ### `MEM_TriggerVob` + Sends a trigger message to the Vob. + ```dae + func void MEM_TriggerVob(var int vobPtr) + ``` + **Parameters** + + - `#!dae var int vobPtr` + Pointer to a triggered [`zCVob`](../../../../worlds/Classes/zCVob.md) + + !!! Danger + If triggering the Vob has immediate effects (even before MEM_TriggerVob is exited), the name of the Vob is corrupted during this time. It is not advisable to rename, trigger again or destroy the object at this moment, the behavior in such cases is untested. +=== "MEM_UntriggerVob" + + ### `MEM_UntriggerVob` + Sends an untrigger message to the Vob. + ```dae + func void MEM_TriggerVob(var int vobPtr) + ``` + **Parameters** + + - `#!dae var int vobPtr` + Pointer to an untriggered [`zCVob`](../../../../worlds/Classes/zCVob.md) + + !!! Danger + If untriggering the Vob has immediate effects (even before MEM_TriggerVob is exited), the name of the Vob is corrupted during this time. It is not advisable to rename, trigger again or destroy the object at this moment, the behavior in such cases is untested. + +### `MEM_SearchVobByName` +Returns the address of a [`zCVob`](../../../../worlds/Classes/zCVob.md) named `str` if such a Vob exists. +```dae +func int MEM_SearchVobByName(var string str) +``` +**Parameters** + +- `#!dae var string str` + Name of searched [`zCVob`](../../../../worlds/Classes/zCVob.md) + +**Return value** + +The function returns a pointer to the [`zCVob`](../../../../worlds/Classes/zCVob.md) if the object with the given name exist. `0` is returned otherwise. + + +### `MEM_SearchAllVobsByName` +Variation of [`MEM_SearchVobByName`](#mem_searchvobbyname). Creates a `zCArray` in which all pointers are to Vobs with the name `str`. If no Vob with the name exists, an empty `zCArray` is created. A pointer to the created `zCArray` is then returned. This can be evaluated, but should be released again with `MEM_ArrayFree` before the end of the frame (before the player can load) to avoid memory leaks. +```dae +func int MEM_SearchAllVobsByName(var string str) +``` +**Parameters** + +- `#!dae var string str` + Name of searched [`zCVob`](../../../../worlds/Classes/zCVob.md) + +**Return value** + +The function returns a pointer to the created `zCArray`, that contains pointers to the all Vobs with the specified name. + +### `MEM_GetBufferCRC32` +Calculates the CRC32 hash value from a byte array starting at the address specified by `buf` and having a length of `buflen`. +```dae +func int MEM_GetBufferCRC32(var int buf, var int buflen) +``` +**Parameters** + +- `#!dae var int buf` + Address of a byte array, the hash calculation will begin from + +- `#!dae var int buflen` + The length of the byte array starting from the address specified by `buf` + +**Return value** + +The function returns the calculated CRC32 hash value. + + +### `MEM_GetStringHash` +Calculates the CRC32 hash value for a string. +```dae +func int MEM_GetStringHash(var string str) +``` +**Parameters** + +- `#!dae var string str` + A string for which the hash value is to be calculated + +**Return value** + +The function returns an integer representing the calculated hash value for the input string. \ No newline at end of file diff --git a/docs/zengin/scripts/extenders/ikarus/functions/parser.md b/docs/zengin/scripts/extenders/ikarus/functions/parser.md new file mode 100644 index 0000000000..b0140fa9bb --- /dev/null +++ b/docs/zengin/scripts/extenders/ikarus/functions/parser.md @@ -0,0 +1,597 @@ +--- +title: Parser stuff +--- +# `zCParser` related functions +This Ikarus part provides some useful functions to work with parser, its instances, symbols and stack. + +!!! Danger + Remember to always assign an instance to a correct class. If you assign an `oCNpc` pointer to `oCItem` class you won't be able to read any data from it. + +## Implementation +[:material-github: Ikarus.d on GitHub](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L513) + +## Initialization +The best way to initialize all Ikarus functions is to call `MEM_InitAll()` in the `Init_Global()` initialization function. +!!! Warning + If you want to use Ikarus in Gothic 1, it is best to define your own `Init_Global()` function and call it from every world initialization function. + +```dae +MEM_InitAll(); +``` + +### `MEM_ReinitParser` +Parser operations are initialized with this function. +```dae +func void MEM_ReinitParser() +``` + +!!! Tip + It's worth noting that `MEM_ReinitParser` is also invoked by the `MEM_InitAll` function. + + +## Pointers and instances + +### `MEM_PtrToInst` +Returns an instance pointed to by the pointer. If the pointer is null an error is thrown. +```dae +func MEMINT_HelperClass MEM_PtrToInst(var int ptr) +``` +**Parameters** + +- `#!dae var int ptr` + Pointer to return an instance from + +**Shortcut** + +In addition there is a function **`_^`** with the same signature and functionality as `MEM_PtrToInst`. It is used as a shortcut, since the converting pointer to instance is commonly used while working with Ikarus. + +```dae +func MEMINT_HelperClass _^ (var int ptr) +``` + +??? abstract "Example" + Following code + ```dae + var oCNpc her; her = MEM_PtrToInst(heroPtr); + ``` + is equivalent to + ```dae + var oCNpc her; her = _^(heroPtr); + ``` + + +### `MEM_NullToInst` +Returns an instance from a null pointer. +```dae +func MEMINT_HelperClass MEM_NullToInst() +``` + +### `MEM_AssignInst` +Takes an instance from a pointer and assigns it to a given instance. If the pointer is null an error is thrown. +```dae +func void MEM_AssignInst(var int inst, var int ptr) +``` +**Parameters** + +- `#!dae var int ptr` + Pointer to assign an instance from +- `#!dae var int inst` + Instance to which the pointer will be assigned + +??? abstract "Example" + Following code + ```dae + var oCNpc inst; + MEM_AssignInst (inst, ptr); + ``` + is equivalent to + ```dae + var oCNpc inst; + inst = MEM_PtrToInst(ptr); + ``` + +### `MEM_AssignInstNull` +Assigns null pointer to a given instance. +```dae +func void MEM_AssignInstNull(var int inst) +``` +**Parameters** + +- `#!dae var int inst` + Instance to which the null pointer will be assigned + +### `MEM_InstToPtr` +Returns a pointer to given instance. +```dae +func int MEM_InstToPtr(var int inst) +``` +**Parameters** + +- `#!dae var int inst` + The instance to which the pointer is returned + +### `MEM_InstGetOffset` +Alias to `MEM_InstToPtr`. Returns a pointer to given instance. +```dae +func int MEM_InstGetOffset(var int inst) +``` +**Parameters** + +- `#!dae var int inst` + The instance to which the pointer is returned + +### `MEM_CpyInst` +Returns a copy of a given instance +```dae +func MEMINT_HelperClass MEM_CpyInst(var int inst) +``` +**Parameters** + +- `#!dae var int inst` + Instance to copy + +??? abstract "example" + Following code + ```dae + selfCopy = MEM_CpyInst (self); + ``` + is equivalent to + ```dae + selfCopy = MEM_PtrToInst (MEM_InstToPtr (self)); + ``` +## Call function +You don't always know at compile time when you want to call which function. For example, if you want to call the condition function of a mob that the player has in focus, you are at a loss at compile time because you have no idea which mob the player will choose. Ikarus provides a way to call functions based on their name or symbol index. In the example of the mob, the name of the condition function can simply be looked up in the mob. + +!!! Note + The functions below also work for externals without any restrictions. + +### Passing Parameters +If the function to be called has parameters, these must first be placed on the data stack. The parameters must be pushed in the correct order, from left to right. + +#### `MEM_PushIntParam` +Passes an integer as a parameter to the called function. +```dae +func void MEM_PushIntParam (var int param) +``` +**Parameters** + +- `#!dae var int param` + Integer to pass as a function parameter + +#### `MEM_PushInstParam` +Passes an instance as a parameter to the called function. +```dae +func void MEM_PushInstParam (var int inst) +``` +**Parameters** + +- `#!dae var int inst` + Instance to pass as a function parameter + +#### `MEM_PushStringParam` +Passes a string as a parameter to the called function. +```dae +func void MEM_PushStringParam (var string str) +``` +**Parameters** + +- `#!dae var string str` + String to pass as a function parameter + +### The call + +#### `MEM_Call` +Calls a function. +```dae +func void MEM_Call(var func fnc) +``` +**Parameters** + +- `#!dae var func fnc` + Function to be called + +#### `MEM_CallByID` +Calls a function by its ID. +```dae +func void MEM_CallByID (var int symbID) +``` +**Parameters** + +- `#!dae var int symbID` + The ID of the function to be called + +#### `MEM_CallByPtr` +Calls a function by its pointer. +```dae +func void MEM_CallByPtr(var int ptr) +``` +**Parameters** + +- `#!dae var int ptr` + The pointer of the function to be called + +#### `MEM_CallByOffset` +Calls a function by its offset. +```dae +func void MEM_CallByOffset(var int offset) +``` +**Parameters** + +- `#!dae var int offset` + The offset of the function to be called + +#### `MEM_CallByString` +Calls a function by its name. +```dae +func void MEM_CallByString (var string fnc) +``` +**Parameters** + +- `#!dae var string fnc` + The name of the function IN CAPITAL LETTERS. + +### Return value +If a function has a return value, it should be fetched from the data stack after it is called, otherwise stack overflows can occur under unfavorable circumstances (aside from that, you may simply want the return value because it contains important information). + +#### `MEM_PopIntResult` +Retrieves an integer returned by the called function. +```dae +func int MEM_PopIntResult() +``` +**Return value** + +The function returns an integer returned by the previously called script function. + +#### `MEM_PopStringResult` +Retrieves a daedalus string returned by the called function. +```dae +func string MEM_PopStringResult() +``` +**Return value** + +The function returns a string returned by the previously called script function. + +#### `MEM_PopInstResult` +Retrieves an instance returned by the called function. +```dae +func MEMINT_HelperClass MEM_PopInstResult() +``` +**Return value** + +The function returns an instance returned by the previously called script function. + +## Function stuff +### `MEM_GetFuncID` +Returns the ID of the given function. +```dae +func int MEM_GetFuncID(var func fnc) +``` +**Parameters** + +- `#!dae var func fnc` + The function whose ID is returned + +### `MEM_GetFuncPtr` +Returns the pointer of the given function. +```dae +func int MEM_GetFuncPtr(var func fnc) +``` +**Parameters** + +- `#!dae var func fnc` + The function whose pointer is returned + +### `MEM_GetFuncOffset` +Returns the offset of the given function. +```dae +func int MEM_GetFuncOffset(var func fnc) +``` +**Parameters** + +- `#!dae var func fnc` + The function whose offset is returned + +### `MEM_GetFuncIDByOffset` +[`MEM_GetFuncID`](#mem_getfuncid), but with an offset as a parameter. +```dae +func int MEM_GetFuncIDByOffset(var int offset) +``` +**Parameters** + +- `#!dae var int offset` + Offset of a function whose ID is returned + +**Return value** + +The function returns an ID of a function with a given offset. + +### `MEM_ReplaceFunc` +Replaces the `f1` function with `f2` function so if you call the first function, the second function is called. +```dae +func void MEM_ReplaceFunc(var func f1, var func f2) +``` +**Parameters** + +- `#!dae var func f1` + Function to replace +- `#!dae var func f2` + Function called instead of `f1` + +## Parser stack + +### `MEM_GetFrameBoundary` +Returns the address/pointer to the boundary of a stack frame (ESP). +```dae +func int MEM_GetFrameBoundary() +``` +### `MEM_GetCallerStackPos` +Retrieves the stack position (pop position) of the caller's caller (look at the example for better understanding). +```dae +func int MEM_GetCallerStackPos() +``` +**Return value** + +The function returns an integer representing the stack position of the caller's caller. + +??? abstract "Example" + After calling `B()` from within `A()`, when `MEM_GetCallerStackPos()` is invoked in function `B()`, it retrieves the stack position of the caller's caller, which is function `A()` in this case. Therefore, the variable `adr` will contain the stack position of function `A()`. + ```dae + func void A(){ + B(); + }; + + func void B(){ + int adr; adr = MEM_GetCallerStackPos(); + // Now, 'adr' will contain the stack position of A. + }; + ``` + +### `MEM_SetCallerStackPos` +Sets the stack position (pop position) of the caller's caller. +```dae +func void MEM_SetCallerStackPos(var int popPos) +``` +**Parameters** + +- `#!dae var int popPos` + An integer parameter representing the new stack position of the caller's caller + +## Get address + +### `MEM_GetAddress_Init` +Initializes the `MEM_GetIntAddress`, `MEM_GetFloatAddress` and `MEM_GetStringAddress` functions. +```dae +func void MEM_GetAddress_Init() +``` + +!!! Tip + It's worth noting that `MEM_GetAddress_Init` is also invoked by the `MEM_InitAll` function. + +### `MEM_GetIntAddress` +Returns an address of a given integer. +```dae +func int MEM_GetIntAddress(var int i) +``` +**Parameters** + +- `#!dae var int i` + Integer whose address is returned + +**Shortcut** + +In addition there is a function **`_@`** with the same signature and functionality as `MEM_GetIntAddress`. + +```dae +func int _@(var int i) +``` + +### `MEM_GetFloatAddress` +Returns an address of a given daedalus float. +```dae +func int MEM_GetFloatAddress(var float f) +``` +**Parameters** + +- `#!dae var float f` + Float whose address is returned + +**Shortcut** + +In addition there is a function **`_@f`** with the same signature and functionality as `MEM_GetFloatAddress`. + +```dae +func int _@s(var string s) +``` + +### `MEM_GetStringAddress` +Returns an address of a given string. +```dae +func int MEM_GetStringAddress(var string s) +``` +**Parameters** + +- `#!dae var string s` + String whose address is returned + +**Shortcut** + +In addition there is a function **`_@s`** with the same signature and functionality as `MEM_GetStringAddress`. + +```dae +func int _@s(var string s) +``` + +### `STR_GetAddressInit` +Alias to [`MEM_GetAddress_Init`](#mem_getaddress_init), kept for downward compatibility. +```dae +func void STR_GetAddressInit() +``` + +### `STR_GetAddress` +Function similar to `MEM_GetStringAddress`. There is a guarantee, that this function works initialized i.e. invokes [`MEM_GetAddress_Init`](#mem_getaddress_init), but the first time may only return an address of a copy of the string. +```dae +func int STR_GetAddress(var string str) +``` + +## Static arrays +Accessing static arrays like this below is very tedious in Daedalus. +```dae +var int myStaticArray[42]; +``` +It is not possible to access `myStaticArray[i]` with a variable index i, but only with a constant. This changes with the following functions. + +!!! Danger + Neither function performs any kind of validity check. If the value passed is not an array or offsets are beyond the boundaries of the array passed, the behavior is undefined. + +### `MEM_InitStatArrs` +Initializes static arrays read and write functions. +```dae +func void MEM_InitStatArrs() +``` + +### `MEM_WriteStatArr` +Changes the value at the `offset` of a static integer-array. +```dae +func void MEM_WriteStatArr (var int array, var int offset, var int value) +``` +**Parameters** + +- `#!dae var int array` + Array which will be edited +- `#!dae var int offset` + Array index at which value will be edited +- `#!dae var int value` + The new value + +### `MEM_ReadStatArr` +Reads the value at the specific offset of a static integer-array. +```dae +func int MEM_ReadStatArr (var int array, var int offset) +``` +**Parameters** + +- `#!dae var int array` + Array to get a value from +- `#!dae var int offset` + Array index of the value to return + +**Return value** + +The function returns an integer value from the `offset` of a given static array. + +### `MEM_WriteStatStringArr` +Changes the value at the `offset` of a static string-array. +```dae +func void MEM_WriteStatStringArr(var string array, var int offset, var string value) +``` +**Parameters** + +- `#!dae var string array` + Array which will be edited +- `#!dae var int offset` + Array index at which value will be edited +- `#!dae var string value` + The new value + +### `MEM_ReadStatStringArr` +Reads the value at the specific offset of a static string-array. +```dae +func string MEM_ReadStatStringArr(var string array, var int offset) +``` +**Parameters** + +- `#!dae var string array` + Array to get a value from +- `#!dae var int offset` + Array index of the value to return + +**Return value** + +The function returns a string form the `offset` of a given static array. + +## Parser symbol +### `MEM_SetCurrParserSymb` +Makes [`currParserSymb`](#currparsersymb) point to the symbol of the specified instance. +```dae +func void MEM_SetCurrParserSymb (var int inst) +``` +**Parameters** + +- `#!dae var int inst` + Instance to whose symbol `currParserSymb` will be set + +#### `currParserSymb` +An instance representing current parser symbol. +```dae +INSTANCE currParserSymb (zCPar_Symbol); +``` + +### `MEM_FindParserSymbol` +Returns the index of the parser symbol with name `inst` if such a symbol exists. +```dae +func int MEM_FindParserSymbol(var string inst) +``` +**Parameters** + +- `#!dae var string inst` + Name of the symbol to be found + +**Return value** + +The function returns the index of the parser symbol with name `inst` if such a symbol exists. If non exists, a warning is issued and `-1` is returned. + +### `MEM_GetSymbolIndex` +Alias to [`MEM_FindParserSymbol`](#mem_findparsersymbol). Returns the index of the parser symbol with name `inst` if such a symbol exists. +```dae +func int MEM_GetSymbolIndex(var string inst) +``` +**Parameters** + +- `#!dae var string inst` + Name of the symbol to be found + +**Return value** + +The function returns the index of the parser symbol with name `inst` if such a symbol exists. If non exists, a warning is issued and `-1` is returned. + +### `MEM_GetParserSymbol` +Looks for the parser symbol with the name `inst` and returns a pointer to the appropriate `zCPar_Symbol` structure. +```dae +func int MEM_GetParserSymbol (var string inst) +``` +**Parameters** + +- `#!dae var string inst` + Name of the symbol to be found + +**Return value** + +The function returns the appropriate `zCPar_Symbol` structure of the parser symbol with name `inst` if such a symbol exists. If non exists, a warning is issued and `0` is returned. + +### `MEM_GetSymbol` +Alias to [`MEM_GetParserSymbol`](#mem_getparsersymbol). Looks for the parser symbol with the name `inst` and returns a pointer to the appropriate `zCPar_Symbol` structure. +```dae +func int MEM_GetSymbol(var string inst) +``` +**Parameters** + +- `#!dae var string inst` + Name of the symbol to be found + +**Return value** + +The function returns the appropriate `zCPar_Symbol` structure of the parser symbol with name `inst` if such a symbol exists. If non exists, a warning is issued and `0` is returned. + +### `MEM_GetSymbolByIndex` +[`MEM_GetParserSymbol`](#mem_getparsersymbol), but with ID (index) as a parameter. +```dae +func int MEM_GetSymbolByIndex(var int id) +``` +**Parameters** + +- `#!dae var string inst` + ID (index) of the symbol to be found + +**Return value** + +The function returns the appropriate `zCPar_Symbol` structure of the parser symbol with name `inst` if such a symbol exists. If non exists, a warning is issued and `0` is returned. \ No newline at end of file diff --git a/docs/zengin/scripts/extenders/ikarus/functions/string.md b/docs/zengin/scripts/extenders/ikarus/functions/string.md new file mode 100644 index 0000000000..fbcfebc76f --- /dev/null +++ b/docs/zengin/scripts/extenders/ikarus/functions/string.md @@ -0,0 +1,291 @@ +# String operations +Collection of Ikarus functions to manipulate and format strings. + +## Initialization +The best way to initialize all Ikarus functions is to call `MEM_InitAll()` in the `Init_Global()` initialization function. +!!! warning + If you want to use Ikarus in Gothic 1, it is best to define your own `Init_Global()` function and call it from every world initialization function. + +```dae +MEM_InitAll(); +``` + +## Implementation +[:material-github: Ikarus.d on GitHub](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L2341) + +## Functions + +### `STR_GetCharAt` +Returns the ASCII value of a character at a specific position in a string. +```dae +func int STR_GetCharAt (var string str, var int pos) +``` +**Parameters** + +- `#!dae var string str` + The input string +- `#!dae var int pos` + The position of the character + +**Return value** + +The function returns the ASCII value of the character at the specified position. + +### `STR_Len` +Returns the length of a string. +```dae +func int STR_Len (var string str) +``` +**Parameters** + +- `#!dae var string str` + The input string + +**Return value** + +The function returns the length of the string in characters. + +### `STR_toChar` +Converts a string to a pointer to its character array. +```dae +func int STR_toChar (var string str) +``` +**Parameters** + +- `#!dae var string str` + The input string + +**Return value** + +The function returns a pointer to the character array representing the input string `str` + +### `STR_FromChar` +Converts a character array to a string. +```dae +func string STR_FromChar(var int char) +``` +**Parameters** + +- `#!dae var int char` + Pointer to the character array + +**Return value** + +The function returns a string representation of the character array. + +### `STR_SubStr` +Extracts a substring from a given string. +```dae +func string STR_SubStr (var string str, var int start, var int count) +``` +**Parameters** + +- `#!dae var string str` + The input string +- `#!dae var int start` + The starting position of the substring +- `#!dae var int count` + The length of the substring + +**Return value** + +The function returns a substring, if the starting position is invalid an empty string is returned. + + +### `STR_Prefix` +Extracts a prefix of a given string, similar to [`STR_SubStr`](#str_substr), but with the starting position set to the first character of the string. +```dae +func string STR_Prefix (var string str, var int len) +``` +**Parameters** + +- `#!dae var string str` + The input string +- `#!dae var int count` + The length of the prefix + +**Return value** + +The function returns a prefix of the input string with the specified length. + +### `STR_Compare` +Compares two strings lexicographically and returns a result indicating their relative order. +```dae +func int STR_Compare(var string str1, var string str2) +``` +**Parameters** + +- `#!dae var string str1` + The first string to compare +- `#!dae var string str2` + The second string to compare + +**Return Value** + +The function returns an integer value representing the result of the comparison: + +- `STR_GREATER` (1): If `str1` comes lexicographically after `str2`. +- `STR_EQUAL` (0): If `str1` is lexicographically equal to `str2`. +- `STR_SMALLER` (-1): If `str1` comes lexicographically before `str2`. + +??? abstract "Examples" + The comparison is based on lexicographic order, which is the order of characters as they appear in the ASCII table. Uppercase letters come before lowercase letters. + + ```dae + int result1 = STR_Compare("A", "B"); + // The 'result1' variable now contains STR_SMALLER + + int result2 = STR_Compare("ABC", "ABC"); + // The 'result2' variable now contains STR_EQUAL + + int result3 = STR_Compare("AA", "A"); + // The 'result3' variable now contains STR_GREATER + + int result4 = STR_Compare("BA", "BB"); + // The 'result4' variable now contains STR_SMALLER + + int result5 = STR_Compare("B", "a"); + // The 'result5' variable now contains STR_SMALLER + + int result6 = STR_Compare("A", ""); + // The 'result6' variable now contains STR_GREATER + ``` + +### `STR_ToInt` +Converts a string to an integer. +```dae +func int STR_ToInt (var string str) +``` +**Parameters** + +- `#!dae var string str` + The input string + +**Return Value** + +The function returns an integer value of the string, if a string is invalid (doesn't contain an integer) zero is returned. + +### `STR_IndexOf` +Searches for a substring `tok` within a given string and returns the index of the first occurrence of `tok`, taking into account upper and lower case letters. +```dae +func int STR_IndexOf(var string str, var string tok) +``` +**Parameters** + +- `#!dae var string str` + The string in which to search for `tok`. +- `#!dae var string tok` + The substring to search for within `str`. + +**Return Value** + +The function returns the index at which the first occurrence of `tok` begins within `str`. If `tok` is not found in `str`, the function returns -1. + +??? abstract "Examples" + + ```dae + int index1 = STR_IndexOf("Hello World!", "Hell"); + // The 'index1' variable now contains 0 + + int index2 = STR_IndexOf("Hello World!", "World"); + // The 'index2' variable now contains 6 + + int index3 = STR_IndexOf("Hello World!", "Cake"); + // The 'index3' variable now contains -1 + + int index4 = STR_IndexOf("Hello World!", ""); + // The 'index4' variable now contains 0 + + int index5 = STR_IndexOf("Hello", "Hello World!"); + // The 'index5' variable now contains -1 + + int index6 = STR_IndexOf("hello Hell!", "Hell"); + // The 'index6' variable now contains 6 + + int index7 = STR_IndexOf("", ""); + // The 'index7' variable now contains 0 + ``` + +### `STR_SplitCount` +Counts the number of parts a string splits into when using a specified separator. +```dae +func int STR_SplitCount(var string str, var string separator) +``` +**Parameters** + +- `#!dae var string str` + The input string to be split. +- `#!dae var string separator` + The separator character or string used to split the input string. + +**Return Value** + +The function returns a number of parts the input string splits into when using the specified separator. + +??? abstract "Example" + + ```dae + string inputStr = "This is a sentence."; + int count = STR_SplitCount(inputStr, " "); + // The 'count' variable now contains 4 + ``` + +### `STR_Split` +Splits a string into multiple substrings based on a specified separator and returns the substring at a specified offset. +```dae +func string STR_Split(var string str, var string separator, var int offset) +``` + +**Parameters** + +- `#!dae var string str ` + The input string to be split. +- `#!dae var string separator` + The separator character or string used to split the input string. +- `#!dae var int offset` + The index of the substring to be returned after splitting. The index is zero-based. + +**Return Value** + +The function returns a substring at the specified offset after splitting the input string. If the offset is greater than or equal to the number of parts generated by splitting, an empty string is returned. + +??? abstract "Example" + + ```dae + func void foo() { + string inputStr = "This is a sentence."; + string tok1 = STR_Split(inputStr, " ", 0); // This + string tok2 = STR_Split(inputStr, " ", 1); // is + string tok3 = STR_Split(inputStr, " ", 2); // a + string tok4 = STR_Split(inputStr, " ", 3); // sentence + }; + ``` + At the end of the function, `tok1` contains "This", `tok2` contains "is", `tok3` contains "a", and `tok4` contains "sentence.". + +### `STR_Upper` +Converts a string to uppercase. +```dae +func string STR_Upper(var string str) +``` +**Parameters** + +- `#!dae var string str` + The input string + +**Return Value** + +The function returns a copy of `str` with all uppercase letters converted to their corresponding uppercase letters. + +### `STR_Lower` +Converts a string to lowercase. +```dae +func string STR_Lower(var string str) +``` +**Parameters** + +- `#!dae var string str` + The input string + +**Return Value** + +The function returns a copy of `str` with all lowercase letters converted to their corresponding uppercase letters. diff --git a/docs/zengin/scripts/extenders/ikarus/functions/time_benchmark.md b/docs/zengin/scripts/extenders/ikarus/functions/time_benchmark.md new file mode 100644 index 0000000000..eb281fd746 --- /dev/null +++ b/docs/zengin/scripts/extenders/ikarus/functions/time_benchmark.md @@ -0,0 +1,146 @@ +# Time and Benchmark +Set of functions to time measurement and Benchmark. + +## Initialization +The best way to initialize all Ikarus functions is to call `MEM_InitAll()` in the `Init_Global()` initialization function. +!!! warning + If you want to use Ikarus in Gothic 1, it is best to define your own `Init_Global()` function and call it from every world initialization function. + +```dae +MEM_InitAll(); +``` + +## Implementation +[:material-github: Ikarus.d on GitHub](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L4596-L4714) + +## Time functions + +### `MEM_GetSystemTime` +Returns the elapsed time since Gothic started. +```dae +func int MEM_GetSystemTime() +``` +**Return value** + +The function returns the elapsed time since the start of Gothic in milliseconds. This value is used for timing measurements, in the `BenchmarkMS` functions. + +### `MEM_GetPerformanceCounter` +Call to the WinAPI [`QueryPerformanceCounter`](https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter) function. +```dae +func int MEM_GetPerformanceCounter() +``` +**Return value** + +The function returns a value representing the number of elapsed ticks since the system was started. This value is used for timing measurements, in the `BenchmarkPC` functions. + +## Benchmark functions + +!!! Tip + For reliable results, avoid measuring a single run of a function; instead, measure the total duration of multiple runs (e.g., 1000). This is crucial, especially for very fast functions, as a single run can distort the measurement. Use `_N` benchmark functions to include a parameter specifying the number of runs for function `f`. + + Choose the parameter `n` to ensure meaningful results. If `n` executions take less than a millisecond, obtaining a return value in milliseconds has no sense. For very fast functions, the time spent in the benchmark function, not in `f`, significantly affects the measurement, falsifying the result. Reliable measurements are achievable only for functions with sufficient slowness. + + For reference, here is a timing for some operations (in nanoseconds, i.e., billionths of a second): + ``` + - Function call (jumping back and forth): 30ns + - Elementary calculation (e.g., i = i + 1): 130ns + - Wld_IsTime: 200ns + - MEM_ReadInt, MEM_WriteInt: 350ns + - Hlp_StrCmp("Hello", "Hello"): 500ns + - MEM_InstToPtr: 1400ns + - (small) Allocate and free memory: 9700ns + - CALL__stdcall (in empty function): 29000ns + - MEM_GetParserSymb: 280000ns + + - Iteration of the benchmark function: 300ns + ``` + +### `MEM_BenchmarkMS` +Benchmark of the execution time for a specified function. (Milliseconds) +```dae +func int MEM_BenchmarkMS(var func f) +``` +**Parameters** + +- `#!dae var func f` + Function to benchmark + +**Return value** + +The function returns the duration of a function execution in milliseconds. + +### `MEM_BenchmarkMMS` +Benchmark of the execution time for a specified function. (microseconds) +```dae +func int MEM_BenchmarkMMS(var func f) +``` +**Parameters** + +- `#!dae var func f` + Function to benchmark + +**Return value** + +The function returns the duration of a function execution in microseconds. + +### `MEM_BenchmarkPC` +Benchmark of the execution time for a specified function, using the [Performancecounter](#mem_getperformancecounter). +```dae +func int MEM_BenchmarkMS(var func f) +``` +**Parameters** + +- `#!dae var func f` + Function to benchmark + +**Return value** + +The function returns the number of [Performancecounter](#mem_getperformancecounter) ticks the function needs. + +### `MEM_BenchmarkMS_N` +[`MEM_BenchmarkMS`](#mem_benchmarkms), but with the parameter to specify the number of function runs. +```dae +func int MEM_BenchmarkMS_N(var func f, var int n) +``` +**Parameters** + +- `#!dae var func f` + Function to benchmark +- `#!dae var int n` + Number of runs + +**Return value** + +The function returns a summed duration of multiple (`n`) runs of the function in milliseconds. + +### `MEM_BenchmarkMMS_N` +[`MEM_BenchmarkMMS`](#mem_benchmarkmms), but with the parameter to specify the number of function runs. +```dae +func int MEM_BenchmarkMMS_N(var func f, var int n) +``` +**Parameters** + +- `#!dae var func f` + Function to benchmark +- `#!dae var int n` + Number of runs + +**Return value** + +The function returns a summed duration of multiple (`n`) runs of the function in microseconds. + +### `MEM_BenchmarkPC_N` +[`MEM_BenchmarkPC`](#mem_benchmarkpc), but with the parameter to specify the number of function runs. +```dae +func int MEM_BenchmarkPC_N(var func f, var int n) +``` +**Parameters** + +- `#!dae var func f` + Function to benchmark +- `#!dae var int n` + Number of runs + +**Return value** + +The function returns a summed number of [Performancecounter](#mem_getperformancecounter) ticks needed to execute function multiple (`n`) times. \ No newline at end of file diff --git a/docs/zengin/scripts/extenders/ikarus/functions/win_utilities.md b/docs/zengin/scripts/extenders/ikarus/functions/win_utilities.md index 74597a9ff8..fc384f4c94 100644 --- a/docs/zengin/scripts/extenders/ikarus/functions/win_utilities.md +++ b/docs/zengin/scripts/extenders/ikarus/functions/win_utilities.md @@ -70,7 +70,7 @@ func int VirtualProtect(var int lpAddress, var int dwSize, var int flNewProtect) - `#!dae var int dwSize` The size of the region whose access protection attributes are to be changed, in bytes. - `#!dae var int flNewProtect` - The memory protection option. All options can be found [here](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L1908). + The memory protection option. All options can be found [here](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L1907-L1919). **Return value** @@ -103,7 +103,7 @@ func int MEM_MessageBox(var string txt, var string caption, var int type) - `#!dae var string caption` Header of MessageBox. - `#!dae var int type` - Type of MessageBox. All types listed [here](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L1957). + Type of MessageBox. All types listed [here](https://github.com/Lehona/Ikarus/blob/master/Ikarus.d#L1956-L1992). ### `MEM_InfoBox` Alias to `MEM_MessageBox` with "Information:" header and `MB_OK | MB_ICONINFORMATION` type. diff --git a/docs/zengin/scripts/extenders/ikarus/index.md b/docs/zengin/scripts/extenders/ikarus/index.md index 474a9274c8..d9bcdd48d0 100644 --- a/docs/zengin/scripts/extenders/ikarus/index.md +++ b/docs/zengin/scripts/extenders/ikarus/index.md @@ -7,5 +7,16 @@ Ikarus is a Daedalus library for Gothic. It exploits the interpreter to allow ar | GitHub | [:material-github: Ikarus](https://github.com/Lehona/Ikarus) | | Forum | [:material-forum: Ikarus](https://forum.worldofplayers.de/forum/threads/1299679-Skriptpaket-Ikarus-4) | +!!! Trivia "Author Note (by Sektenspinner)" + This script package is not called **Ikarus** for nothing: + + One can leave the boundaries of Daedalus behind, but may also crash and burn. For instance, reading from invalid addresses won't trigger a [zSpy](../../../tools/zSpy.md) warning but will result in a desktop crash with an Access Violation. This is not a reason to panic but requires a tolerance for frustration (which can be useful for scripters in general). + + Of course, such spectacular-looking errors can be fixed, and with focused and systematic work, something sensible can be achieved. + + In short: Extra care is needed! A bug that leads to a crash is not something you want in the release version. But if you work cleanly and test extensively, it's not such a big deal. + + A good friend in debugging crashes is undoubtedly `PrintDebug`. It allows sending messages to [zSpy](../../../tools/zSpy.md) (for example, to narrow down where the crash is occurring). It's worth enabling debug messages by [`MEM_SetShowDebug`](functions/debug.md#mem_setshowdebug) and the text filter (Options -> Textfilter) in [zSpy](../../../tools/zSpy.md#configuration). + !!! Note Ikarus is hosted on [GitHub](https://github.com/Lehona/Ikarus) and the documentation is [built in](https://github.com/Lehona/Ikarus/blob/master/Ikarus_Doc.d). The translation is planned. diff --git a/docs/zengin/scripts/extenders/ikarus/index.pl.md b/docs/zengin/scripts/extenders/ikarus/index.pl.md index 204d188dc4..6d1f1af0b7 100644 --- a/docs/zengin/scripts/extenders/ikarus/index.pl.md +++ b/docs/zengin/scripts/extenders/ikarus/index.pl.md @@ -7,5 +7,16 @@ Ikarus jest biblioteką Daedalusa - języka skryptowego Gothica. Wykorzystuje in | GitHub | [:material-github: Ikarus](https://github.com/Lehona/Ikarus) | | Forum | [:material-forum: Ikarus](https://forum.worldofplayers.de/forum/threads/1299679-Skriptpaket-Ikarus-4) | +!!! Trivia "Notatka autora (Sektenspinner)" + Ten pakiet skryptów nie bez powodu nazywa się **Ikarus**: + + Można opuścić granice Dedala, ale można też rozbić się i spalić. Na przykład odczyt z nieprawidłowych adresów nie wywoła ostrzeżenia [zSpy](../../../tools/zSpy.md), ale spowoduje wyjście do pulpitu wraz z Access Violation. Nie jest to powód do paniki, ale wymaga tolerancji na frustrację (co może być ogólnie przydatne dla skrypterów). + + Oczywiście tak spektakularnie wyglądające błędy można naprawić, a przy systematycznej pracy w skupieniu można osiągnąć coś sensownego. + + W skrócie: wymagana jest dodatkowa ostrożność! Błąd prowadzący do awarii nie jest czymś, czego chciałbyś w wydanej wersji. Ale jeśli pracujesz czysto i intensywnie testujesz, nie jest to taka wielka sprawa. + + Dobrym przyjacielem w debugowaniu awarii jest niewątpliwie `PrintDebug`. Umożliwia wysyłanie wiadomości do [zSpy](../../../tools/zSpy.md) (na przykład w celu zawężenia miejsca wystąpienia awarii). Warto włączyć komunikaty debugowania za pomocą [`MEM_SetShowDebug`](functions/debug.md#mem_setshowdebug) i filtr tekstowy (Opcje -> Textfilter) w [zSpy](../../../tools/zSpy.md#configuration). + !!! Note Ikarus jest hostowany na [GitHubie](https://github.com/Lehona/Ikarus) i posiada wbudowaną [dokumentacje](https://github.com/Lehona/Ikarus/blob/master/Ikarus_Doc.d). Jej tłumaczenie jest w planach. diff --git a/docs/zengin/scripts/extenders/ikarus/setup.md b/docs/zengin/scripts/extenders/ikarus/setup.md new file mode 100644 index 0000000000..75b4af15cb --- /dev/null +++ b/docs/zengin/scripts/extenders/ikarus/setup.md @@ -0,0 +1,123 @@ +--- +title: Setup +--- + +# Ikarus Setup + +## Download +First you need to download ikarus from the [official github repository](https://github.com/Lehona/Ikarus). We recommend using the master branch as it contains the latest and most up-to-date version of Ikarus. However, you can also download a specific release if needed. + +## File location +Before unpacking the downloaded archive it's needed to create a dedicated folder in `