• Herzlich Willkommen!

    Nach der Schließung von inDiablo.de wurden die Inhalte und eure Accounts in dieses Forum konvertiert. Ihr könnt euch hier mit eurem alten Account weiterhin einloggen, müsst euch dafür allerdings über die "Passwort vergessen" Funktion ein neues Passwort setzen lassen.

    Solltet ihr keinen Zugriff mehr auf die mit eurem Account verknüpfte Emailadresse haben, so könnt ihr euch unter Angabe eures Accountnamens, eurer alten Emailadresse sowie eurer gewünschten neuen Emailadresse an einen Administrator wenden.

[Guide] Formel-Berechnungen in den txt-Dateien

RedHavoc

Well-known member
Ex-Staffmember
Registriert
6 April 2002
Beiträge
2.144
Punkte Reaktionen
0
Hiho allerseits,

ich hab mich mal wieder dazu aufgerafft einen kleinen Guide zu schreiben. In letzter Zeit gab es einige Anfragen, die in Richtung dieses Themas gehen und ich hab auch in den PK Foren bisher keine befriedigende Erläuterung gefunden (auf die ich dann einfach verlinken könnte :D ). Es geht um einen Aspekt, der in allen Pre-LoD Versionen meist versteckt in den DLLs ablief, mit 1.10 und der modding-freundlichen Struktur der .txt Dateien nun aber in voller Bandbreite zu Tage tritt: Formeln.
Ich werd hier mangels Zeit erstmal die wichtigsten Sachen posten und später dann noch andere ergänzen.

Worum geht´s genau? Nunja, wer schonmal einen Blick in die skills.txt, skilldesc.txt oder auch missiles.txt geworfen hat, wird dort mit mehr oder weniger Verblüffung in einigen Zellen Ausdrücke wie die folgenden gesehen haben:

100-dm34
ln12
edxs*par5/256
skill('Prayer'.edmn)

oder gar gaaanz furchtbare Dinger wie:

min((lvl+skill('Dopplezon'.blvl))*par7,85)
ln34+(skill('Frozen Armor'.blvl)+skill('Shiver Armor'.blvl))*par7
((lvl < 5) ? 0 : ((lvl-4) * par4) )+skill('Sacrifice'.blvl)*par8

Wat dat denn nu :confused: ?!? Nun, das sind genau die Dinge, über die ich hier gerne ein bissel Klarheit verschaffen will: Formeln.
Hauptsächlich kommen diese netten Teil in den drei oben genannten Dateien zum Einsatz (wobei es Gerüchte gibt, dass auch andere Dateien Formeln akzeptieren) und sorgen dort meist für heftig Verwirrung - aber keine Angst. Mir ging es zu Beginn nicht anders, aber wenn ihr den Dreh erstmal raus habt werdet ihr sie lieben, eröffnen sie doch jedem Modder vorher ungeahnte Möglichkeiten in Sachen Skills und Missiles.

Was genau sind denn diese Formeln?
Nun, in 1.09 und früheren Versionen enthielten die meisten Spalten in der skills.txt und missiles.txt nur einfache Zahlen, während die zugrundeliegenden Berechnungen, etwa für Boni von Skills (Schaden, Lebenspunkte, Dauer etc.) versteckt im Hintergrund abliefen. Alles was man tun konnte war die Zahlen zu verändern und das war oftmals nicht gerade viel.
In 1.10 sind die meisten dieser Berechnungen nun softcodet, sprich, die Berechnungsfunktionen lassen sich direkt in den .txt Dateien anschauen und ändern. An vielen Stellen kann man sich selbst Funktionen schreiben, die so genau die Skillboni hervorbringen, die man sich wünscht - vorausgesetzt natürlich man weiß weiß mit den Formeln umzugehen.
Im Grunde sind Formeln (bzw. Funktionen, man möge mir ein Vermischen der mathematischen Termini verzeihen ;) ) nichts anderes als das, was man in der Schule lernt - eine Abfolge mathematischer Grundoperationen (Addition, Subtraktion, Multiplikation, Division), die auf einige Eingabewerte angewendet werden um einen Funktionswert zu bestimmen. Blizzard hat diese sehr weit gefasste Definition nun etwas beschränkt, dahingehen dass man nur eine bestimmte Anzahl Eingabeparameter verwenden und auf einige Standard-Eingabevariablen zurückgreifen kann. Ferner sind eine ganze Reihe von Funktionen, die man für häufige typische Berechnungen braucht bereits vordefiniert und lassen sich mit einem Kürzel schnell in jede Formel einbauen. Dieses Kürzel enthält häufig auch schon Angaben darüber, welche Eingabevariablen verwendet werden, bzw. woher diese genommen werden. Prinzipiell kann man sich aber auch seine eigenen Funktionen schreiben, wenn unter den vordefinierten keine passende zu finden ist, allerdings kann man dann keine eigenen Kürzel dafür definieren.
Fast alle vordefinierten Funktionen und Variablen findet man in der skillcalc.txt (für die skills.txt und skilldesc.txt) bzw. der misscalc.txt (für die missiles.txt). Es sein jedoch darauf hingewiesen, dass die skillcalc.txt viele Fehler enthält und einige wichtige Funktionen komplett fehlen. Ich werde hier auf das meiste eingehen und das hoffentlich auch korrekterweise. :)

Schauen wir uns also zunächst mal an, welche Eingabeparameter wir in Formeln nutzen können:


----
parX
----
Dies ist der wohl einfachste Eingabeparameter, denn er tut nichts anders als Werte aus den Param-Spalten zu repräsentieren. Diese Spalten existieren sowohl in der skills.txt (Param1-8), als auch in der missiles.txt (Param1-5). Logischerweise bezieht sich die parX Variable in einer Formel in der missiles.txt auch auf die ParamX Spalten der missiles.txt. Dito für ParX in der skills.txt, einzig für die skilldesc.txt sein angemerkt, dass sie die Werte auch aus der skills.txt bezieht.
Betrachten wir als Beispiel mal den Totenbeschwörer-Skill Corpse Explosion. In der Skills.txt finden wir in den Spalten Param1 und Param2 die Werte für den minimalen und den maximalen Prozentsatz der Leichen-Lebenspunkte, die bei der Explosion in Schaden umgewandelt werden. Scrollen wir nun zurück nach links in die Spalten calc1 und calc2, so finden wir dort bei "% target hp min damage" den Wert par1 und bei "% target hp max damage" den Wert par2. Für die Schadensbestimmung werden also einfach die in den Param1 und Param2 Spalten definierten Werte ohne weitere Umrechnung in die calc Spalten übertragen, wo der eigentliche Explosionsschaden bestimmt wird (dass das für CE gerade dort geschieht ist hardgecodet).
Nun werfen wir auch noch einen Blick in die skilldesc.txt, denn dort werden diese Werte mit den gleichen Eingabevariablen für die Anzeige in den Skillbeschreibungen verwendet. In der Zeile corpse explosion scrollen wir zur Spalte dsc2line1. Ohne jetzt zu sehr auf die Funktionsweise der skilldesc.txt einzugehen: Die 38 ist eine Zahl, die das Format der Anzeige in der Skillbeschreibung bestimmt und das sieht hier so aus:

<Beschreibungstext A> <Beschreibungsformel A in %> - <Beschreibungsformel B in %> <Beschreibungstext B>

Die Beschreibungstexte erhält man aus den .tbl Dateien (einfach den angegebenen Key suchen), während die Beschreibungsformeln, in diesem Fall par1 und par2 direkt aus der skills.txt kommen. Setzen wir alles zusammen erhalten wir die Anzeige wie im Spiel:

Schaden: 60% - 100% der Leichen-Lebenspunkte

Die parX Variable greift also in der skilldesc.txt auf die ParamX-Einträge der skills.txt zurück.



-----------------
lvl | blvl | ulvl
-----------------
Diese Eingabewerte werden sehr häufig verwendet und beziehen sich auf verschiedene Level des Charakters bzw. des Skills. Die Variablen vergibt das Spiel von alleine, es gibt keine Spalte dafür.

lvl in der skills.txt/skilldesc.txt bezeichnet das tatsächliche Skill-Level eines Skills einschließlich aller Boni durch Items, Schreine oder Fertigkeiten. In der missiles.txt bezeichnet es das Level der jeweiligen Missile, welches allerdings gleich dem Level des Skills ist, der die Missile erzeugt hat.

blvl bezeichnet das Basislevel des Skills, also jenes Level, was nur durch fest vergebene Fertigkeitspunkte zustande kommt. Jegliche Skillboni sind im blvl ausgenommen.

ulvl ist das Level desjenigen, der den Skill ausführt. Dies wird in den meisten Fällen der Charakter selbst sein, aber auch Söldner, Minions und natürlich Monster sind imstande Skills zu verwenden.


---------------------------------
skill('<Skill>'.<Formel o. Variable>)
---------------------------------
Mit dieser Variablen kann man Werte von beliebigen Skills an die Funktion übergeben. In der Regel werden Werte von anderen Skills als denen, für den die Formel gilt übergeben, bei Synergien beispielweise das Basis-Skilllevel des entsprechenden Synergie-Skills. Die Syntax ist immer ähnlich:

skill('<Skill>'.<Übergabewert>)

Die Anführungsstriche, die um den Skillnamen gesetzt sind, sind die von der #-Taste (zumindest auf den normalen deutschen Tastaturen). Als <Skill> wird der Name des Skills eingetragen, so wie es in der allerersten Spalte in der skills.txt steht. Die korrekte Schreibweise ist hier wichtig, am besten also direkt aus der entsprechenden Zelle kopieren. Der Übergabewert kann ein einfacher Eingabeparameter sein, oder aber eine Formel. In beiden Fällen werden die Werte von der Fertigkeit bezogen, die in <Skill> steht.
Nehmen wir zwei Beispiele, damit es verständlicher wird. Zunächst gehen wir in der skills.txt in die Zeile der Paladin-Aura "Resist Cold" und scrollen vor zur Spalte aurastat2. Dort steht eine Eigenschaft (Stat) des Paladins, die durch die Aura erhöht wird, in diesem Fall also die maximale Kälteresistenz. In der darauffolgenden Spalte aurastatcalc2 steht die Berechnung für diesen Bonus:

skill('Resist Cold'.blvl)

Dies bedeutet nun nichts anderes, als dass die Erhöhung des maximalen Kältewiderstandes durch "Resist Cold" gleich dessem Basis-Skilllevel entspricht. Wenn man 11 Fertigkeitenpunkte in "Resist Cold" investiert hat, dann liefert die Variable "skill('Resist Cold'.blvl)" einen Wert von 11. Dementsprechend steigt die maximale Kälteresistenz bei aktivierter Aura von 75% auf 86% an.

Als zweites betrachten wir mal eine etwas kompliziertere Formel: Die für die Anzahl geworfener Blitzsterne bei der Assasinen-Fertigkeit Schocknetz. Die Berechnung dieser Anzahl erfolgt in der Spalte prgcalc1 in Zeile "Shock Field". Dort steht:

par1 + lvl/par2 + skill('FireTrauma'.blvl)/3

Nehmen wir es mal auseinander. par1 bezieht sich auf Spalte Param1 (Number of missiles) der gleichen Zeile. Grundsätzlich werden also immer schonmal 6 Sterne geworfen. Im nächsten Summanden steht lvl für das tatsächliche Skill-Level von Schocknetz und par2 für Param2 (Levels per missile). Da das Spiel immer abrundet, erhalten wir durch diesen Term alle vier Skill-Level von Schocknetz einen Blitzstern extra, den ersten bei Skill-Level 4, den nächsten bei 8 usw. Der letzte Summand bezieht die Synergie durch Feuer-Stoß mit ein. skill('Fire Trauma'.blvl) übergibt das Basis-Level von Feuer-Stoß, dieses wird anschließend durch 3 geteilt. Da das Spiel hier erneut immer abrundet, erhalten wir bei Feuer-Stoß auf Basislevel 3 +1 extra Blitzstern, bei Basislevel 6 +2 extra Blitzsterne dazu usw.


Die skill() Variable kann in allen drei Dateien skills.txt, skilldesc.txt und missiles.txt verwendet werden.


-------------------
stat('<Stat>'.accr)
-------------------
Dieser Eingabeparameter ist was Feines, denn mit ihm kann man beliebige Stats des Charakters in die Formel einbeziehen. Unter Stat ist dabei so ziemlich alles zu verstehen, was in der itemstatcost.txt aufgeführt ist, also z.B. Stärke, Energie, Ausdauer, Maximalschaden, Manaregeneration, Resistenzen oder das am Mann getragene Gold. Wie schon bei der skill() Variable wird der Wert des jeweiligen Stats direkt in die Formel übernommen. Die Syntax ist denkbar einfach:

stat('<Stat>'.accr)

Als <Stat> wird der Name des Stats eingetragen wie er in der itemstatcost.txt in der ersten Spalte aufgeführt ist. Die Anführungsstriche um den Statnamen sind erneut die von der #-Taste.
Die stat() Variable wird bisher nur bei Hydra verwendet und dort auf eine etwas undurchsichtige Art und Weise. Als Beispiel suchen wir uns deshalb mal was aus, wo man das Ergebnis richtig gut sieht - wir modifizieren die Formel für die Anzahl abgeschossener Zähne beim Necro-Skill Teeth derart, dass sie nicht vom Skill-Level sondern dem Energie-Wert abhängt. Dazu gehen wir in der skills.txt in der Zeile für den Teeth-Skill zur Spalte calc1 (# Missiles). Die Formel dort löschen wir und schreiben dafür folgendes:

stat('energy'.accr)/10 + 1

Diese Formel verwendet als Eingabevariable den Wert des Stats Energie und teilt ihn durch 10. Das Ergebnis wird abgerundet und es wird +1 hinzuaddiert. Wenn wir das Ganze dann im Spiel checken:

3 Zähne bei 25 Energie
8 Zähne bei 70 Energie
375 Energie - nur echt mit 38 Zähnen!

Soweit so gut, aber die Anzeige in der Skillbeschreibung rechnet noch nach Skill-Leveln - also auf in die skilldesc.txt und die entsprechende Formel geändert. Diese finden wir unter der Spalte desccalca3, also löschen wir dort den bestehenden Eintrag erneut und schreiben die gleiche Formel wie in der skills.txt hinein. Nun sollte unsere Anzeige im Spiel die richtigen Werte anzeigen. :)



Dies wäre es erstmal zu den wichtigsten Eingabevariablen, es existieren allerdings exklusiv für die missiles.txt einige weitere Abarten der parX Variablen, die ich hier auch erwähnen möchte. Die missiles.txt enthält Spalten für viele verschiedene Parameter (server, client, server hit, client hit, damage) und zu jeder gibt es eine Variante:

----
cpaX
----
Diese Variable funktioniert genauso wie die parX Variable, verwendet allerdings die CltParam1-5 Spalten in der missiles.txt.

----
hpaX
----
Diese Variable funktioniert genauso wie die parX Variable, verwendet allerdings die sHitPar1-3 Spalten in der missiles.txt.

----
chpX
----
Diese Variable funktioniert genauso wie die parX Variable, verwendet allerdings die cHitPar1-3 Spalten in der missiles.txt.

----
dpaX
----
Diese Variable funktioniert genauso wie die parX Variable, verwendet allerdings die dParam1-2 Spalten in der missiles.txt.



Als nächstes schauen wir uns mal an, was Blizzard uns für Funktionen zum Herumspielen eingebaut hat. :) Auf den ersten Blick existieren erstmal sehr viele, verwendet werden im Spiel aber längst nicht alle, sondern vielmehr nur eine Reihe von Funktionen, die man immer wieder braucht. Der Rest ist verfügbar und kann eingesetzt werden, wenn man dafür ne sinnvolle Anwendung hat.


----
lnXY
----
Dies ist die lineare Standard-Berechnungsfunktion (ln = linear) für alle Werte, die auf Slvl 1 mit einem Basiswert beginnen und sich mit jedem zusätzlichen Skill-Level um einen festgelegten Betrag erhöhen. Die mathematische Formel hinter lnXY ist wie folgt (Aufgepasst: Die Formel in der skillcalc.txt ist verkehrt!):

lnXY = X+(lvl-1)*Y

lvl steht dabei für das Skill-Level. X und Y sind unsere Eingabevariablen und die wiederum kommen aus den Spalten ParamX und ParamY in der skills.txt. Somit ist auch klar, warum wir die lnXY Funktion in vierfacher Ausführung haben:

ln12 verwendet Param1 und Param2
ln34 verwendet Param3 und Param4
ln56 verwendet Param5 und Param6
ln78 verwendet Param7 und Param8

Betrachten wir noch ein kleines Beispiel dazu: Der Barbaren-Skill Whirlwind verwendet zur Schadensboni-Berechnung die Funktion ln12 (siehe Spalte calc1). In der Param1-Spalte (Damage percent per attack) steht ein Wert von -50, in der Param2-Spalte (Damage percent per level) der Wert 8. Gemäß der Funktion ln12 erhält der Barbar also für ein Slvl1 Whirlwind einen Schadensmalus von -50%, zu dem jedoch für jedes weitere Skill-Level +8% hinzukommen.


----
slXY
clXY
shl1
chl1
dl12

----
Die lnXY Funktion gilt nur für Berechnungen in der skills.txt und skilldesc.txt, die missiles.txt verwendet ihre eigenen linearen Funktionen. Da es dort mehrere verschiedene Parameter-Spalten gibt, gibt´s auch verschieden benannte Funktionen. Diese sind in der misscalc.txt aufgeführt und da sogar richtig. Die Funktionen verwenden die folgenden Eingabeparameter:

slXY verwendet die Spalten Param1-4
clXY verwendet die Spalten CltParam1-4
shl1 verwendet die Spalten sHitPar1-2
chl1 verwendet die Spalten cHitParam1-2
dl12 verwendet die Spalten dParam1-2

Im Grunde sind nur die Eingabevariablen anders, die Berechnung erfolgt genauso wie bei lnXY.


----
dmXY
----
Wer sich schon immer gefragt hat, wie zum Henker eigentlich die nicht-linearen Erhöhungen bei Skills wie Dodge, Natural Resistance oder Weapon Block berechnet werden, in dieser Funktion liegt der Schlüssel dazu. dm steht für diminishing, was zu deutsch etwa das gleiche wie vermindern, abnehmen, verkleinern heißt. Damit ist der Zuwachs des Funktionswertes gemeint, der in der Tat mit höherem Slvl immer geringer ausfällt. Die eigentliche Funktion sieht zwar nicht auf den ersten Blick danach aus, sie tut aber genau das:

dmXY = { (Y-X) * [110*lvl / ( lvl + 6 )] / 100 } + X

lvl steht erneut für das Skill-Level und mit den Eingabeparametern X und Y ist´s das gleiche Spiel wie schon zuvor: Die beiden bezeichnen die Werte der ParamX und ParamY Spalten in der skills.txt und wir haben erneut 4 dm-Funktionen zur Verfügung:

dm12 verwendet Param1 und Param2
dm34 verwendet Param3 und Param4
dm56 verwendet Param5 und Param6
dm78 verwendet Param7 und Param8

Ein Hinweis an dieser Stelle: Die Funktionen, die in der skillcalc.txt und missiles.txt aufgeführt sind, sind inkorrekt. Zwar kann man sie auf den ersten Blick in genau die hier angegebene Formel umformen, da das Spiel jedoch mit der oben genannten Formel rechnet und während der Rechnungen rundet, ergeben sich in manchen Fällen Differenzen zwischen beiden Formeln. Ruvanal hat das Ganze in diesem Thread näher erläutert, wer also stets exakt rechnen möchte, sollte lieber die obige Formel benutzen. Dabei gilt es, die Rechenweise des Computers zu beachten. Dieser kann komplexe Gleichungen wie die oben nur dadurch lösen, dass er sie schrittweise durch Grundrechnenoperationen auflöst und die jeweiligen Zwischenergebnisse als ganze Zahlen abspeichert. Sind die Zahlen gebrochen, rundet der PC sie ab.

Erst vor zwei Tagen hatten gautcho und ich nen Problem gehabt, wo die vertrakte Rechenweise des PCs voll zum Zuge kam. Nehmen wir das Beispiel mal erneut zur Hand. Gegeben seinen folgende Werte:

X = 10
Y = 80
lvl = 1

Einsetzen in die Formel liefert nach normaler (durchschnittsmenschlicher) Rechenweise (heh!... wer zieht da den Taschenrechner? :no: ):

{(80-10) * [(110 * 1)/(1 + 6)]}/100 + 10
= (70 * 110 / 7) / 100 + 10
= (10 * 110) / 100 + 10
= 110 / 10 + 10
= 11 + 10
= 21

Unser lieber Rechner ist mit den höheren Künsten der Mathematik (Ausklammern und Kürzen) aber hoffnungslos überfordert, rechnet folglich stur in Einzelschritten und rundet dabei. Und man beachte folgendes erstaunliches Resultat:

{(80-10) * [(110 * 1)/(1 + 6)]/100 + 10
= [70 * (110 / 7)] / 100 + 10
= (70 * 15) / 100 + 10
= 1050 / 100 + 10
= 10 + 10
= 20

Die gelben Werte sind durch Abrunden des Rechners entstanden. In Abhängigkeit von den Parametern X und Y können da durchaus auch größere Differenzen auftreten, etwa bei Schadensberechnung pro Frame. Wer also wert auf Exaktheit legt, sollte lieber immer mal nachrechnen. ;)


Ich habe zur Veranschaulichung die Funktion mal von MathCAD zeichnen lassen und man erkennt recht gut den abnehmenden Charakter. Im Bild sind als Minimalwert 1 gesetzt, als Maximalwert 100 (siehe Y-Achse), und das Ganze mal über einen Bereich von 40 Skillleveln (siehe X-Achse) betrachtet. Man sieht, dass auf Slvl 1 nicht der Minimalwert aus den Spalten in der .txt vorherrscht, sondern bereits ein etwas höherer Wert (der Minimalwert stellt sich eigentlich auf Slvl0 ein). Umgekehrt erreicht man den Maximalwert auch bei noch so vielen Skillpunkten niemals ganz. Stattdessen sind nach 20 Skillpunkten in etwa 80% des Höchstwertes erreicht, alles da drüber ist dann wirklich nur noch was für Perfektionisten.

Einige Worte noch an die Modder: Wenn man diese Funktionen bei Skills verwenden will steht man immer vor dem Problem, dass man zwar weiß in welchem Wertebereich die Funktion verlaufen soll, die in den ParamX-Spalten einzutragenden Minimal- und Maximal-Werte aber nicht genau kennt. Da die dmXY Funktion nun 4 Unbekannte enthält (X, Y, lvl und Funktionswert), von denen maximal 2 bekannt sein können (Funktionswert auf einem bestimmten lvl), ist das mit der Berechnung natürlich ein bisserl kompliziert.
Unter der Vorraussetzung, dass man sich die Werte der Funktion für Slvl1 und Slvl20 festsetzt kann man den Minimal- und Maximalwert mit den folgenden beiden Formeln berechnen:

X = 140/114 * <Wert auf Slvl1> - 26/114 * <Wert auf Slvl20>

Y = 70/11 * <Wert auf Slvl1> - 59/11 * X

Bei Fragen wie man drauf kommt bitte PM.

Mit den beiden Formeln kann man zumindest recht gut in die Nähe der gewünschten Werte, eventuelle Abweichungen kommen dann erneut durch die Rechnung des PCs zustande. Wer Mathe nicht mag oder sich im Taschenrechner immer vertippt, kann natürlich auch mit Trial&Error auf die gewünschten Werte kommen. :clown:

Abschließend noch nen Beispiel: Critical Strike der Amazone hat als Minimum 5 (Param1) und als Maximum 80 (Param2) und die Funktion dm12 (passivecalc1) berechnet die Chance auf kritischen Treffer. Für Skill-Level 2 ergibt sich dann ein Wert von 25 abrundet.


----
sdXY
cdXY
shd1
chd1
dd12

----
Wie schon bei der lnXY-Funktion hat die missiles.txt ihre eigenen Funktionen, da sie mehrere verschiedene Param-Spalten besitzt.

sdXY - dmXY-Funktion, die die Param1-4 Spalten verwendet
cdXY - dmXY-Funktion, die die CltParam1-4 Spalten verwendet
shd1 - dmXY-Funktion, die die sHitPar1-2 Spalten verwendet
chd1 - dmXY-Funktion, die die cHitParam1-2 Spalten verwendet
dd12 - dmXY-Funktion, die die dParam1-2 Spalten verwendet

Die Berechnungsformel ist die gleiche wie die der Funktionen in der skills.txt.


----
edmn
edmx
edns
edxs
edln

----
Diese Funktionen berechnen gestaffelte Erhöhungen basierend auf dem Skill-Level und verwenden dabei die EMin/EMax und EMinLev1-5/EMaxLev1-5 Spalten der skills.txt bzw. missiles.txt. Auch wenn die Spalten andeuten als würden sie grundsätzlich erstmal Schaden berechnen, ist dies nicht ausschließlich so. Man kann mit diesen Funktionen Werte für alles mögliche berechnen lassen, wenn man sie an den richtigen Stellen einsetzt. Wir werden uns dies bei den Beispielen anschauen.

edmn steht für elemental damage minimum, heißt also soviel wie Elementar-Minimal-Schaden. edmx dagegen bedeutet elemental damage maximum und somit Elementar-Maximalschaden. Beide Funktionen werden zumeist zur Berechnung von elementarem Schaden verwendet, wie oben angedeutet kann man sie aber auch für andere Berechnungen nutzen. Die Berechnungen sind abhängig von Skill-Level des betreffenden Skills und laufen wie folgt ab (am Beispiel edmn):

Slvl 1 => min. Schaden ist gleich dem Wert der Spalte MinDam
Slvl 2 - 8 => min. Schaden erhöht sich für jedes Slvl um den Betrag in der MinLevDam1 Spalte
Slvl 9 - 16 => min. Schaden erhöht sich für jedes Slvl um den Betrag in der MinLevDam2 Spalte
Slvl 17 - 22 => min. Schaden erhöht sich für jedes Slvl um den Betrag in der MinLevDam3 Spalte
Slvl 23 - 28 => min. Schaden erhöht sich für jedes Slvl um den Betrag in der MinLevDam4 Spalte
Slvl 29+ => min. Schaden erhöht sich für jedes Slvl um den Betrag in der MinLevDam5 Spalte

Die gleiche Berechnung läuft für die Funktion edmx ab, nur werden dort logischerweise die Max Spalten verwendet.

Betrachten wir einige Beispiele dazu: Der Zauberinnen-Skill Lightning. Welchen Schaden macht der wohl auf Slvl 18? Schauen wir uns zunächst mal den Minimalschaden an, der nach der Funktion edmn berechnet wird. Die für uns relevanten Werte sind:

EMin = 1
EMinLev1 = 0
EMinLev2 = 0
EMinLev3 = 0

Wie unschwer zu erkennen ist, bleibt der Minimalschaden immer 1. Auf Slvl 1 gilt der EMin-Wert und für alle weiteren Slvl kommt immer nur 0 dazu. Wie schaut´s nun mit dem maximalen Blitz-Schaden aus? Dort haben wir:

EMax = 40
EMaxLev1 = 8
EMaxLev2 = 12
EMaxLev3 = 20

Wir beginnen also mit einem Grundschaden von 40. Dazu kommt für die Slvl 2 - 8 insgesamt 7mal der Wert 8 hinzu, also 56. Damit wäre der Maximalschaden 96 auf Slvl8. Für die Slvl 9-16 kommen 7 * 12 dazu, womit wir auf Slvl16 dann bei 180 wären. Nun noch die 2 Erhöhungen auf Slvl17 und Slvl18, die jeweils +20 draufaddieren. Final wären wir also bei eine Gesamtschaden von:

40 + 7*8 + 7*12 + 2*20 = 40 + 56 + 84 + 40 = 220

Oben hatte ich mehrfach erwähnt, dass man diese Spalten auch zur Berechnung anderer Werte nutzen kann. Schauen wir einmal in die Zeile des Amazonen-Skills Inner Sight und dort in die Spalte aurastatcalc1. Dort wird der AC-Abzug der Gegner berechnet und der lautet in dem Falle:

-edmn

Das bedeutet, dass mit den Werten des elementaren Minimalschadens der AC-Abzug berechnet wird. Der eigentliche "Schaden" entspricht dabei dem AC-Wert, der betroffenen Monstern abgezogen wird.



Nun gibt´s noch die Funktionen edns und edxs und die sind etwas merkwürdig. Sie tun genau das gleiche wie die edmn und edmx Funktionen, nur dass jeweils nochmal ein Faktor von 256 dazukommt. Man kann quasi sagen dass:

edns = edmn * 256
edxs = edmx * 256

sind. Wozu das Ganze?
Nunja, ich bin mir nicht 100% sicher, aber ich erinnere mich daran, dass Ruvanal mal irgendwo gepostet hat, dass einige Skills bei der Berechnung zuerst mit 256 multipliziert werden und bei Abschluss der Rechnung wieder durch 256 geteilt werden. Im Hinblick auf das Rundungsverhalten des Rechners macht dies durchaus Sinn. Nehmen wir mal an wir haben eine Schadensberechnung pro Frame und die sähe durch diverse Hitshifts etc. so aus:

Schaden pro Frame = 3 * 0,25 + 1,25 * 0,625 + 6 * 0,15

Genosse Taschenrechner liefern uns ein Ergebnis von 2,43125 was auf 2 abgerundet wird. Was aber tut der Rechenknecht? Der arbeitet stur alles nach Priorität der mathematischen Operationen ab und rundet dabei fröhlich vor sich hin:

3 * 0,25 = 0,75 -> auf 0 abrunden
1,25 * 0,625 = 0,78125 -> auf 0 abrunden
6 * 0,15 = 0,9 -> auf 0 abrunden

Stolzes Ergebnis: Schaden pro Frame = 0 * 0 * 0 = 0
Na Prost! :clown:

Was passiert, wenn wir zuvor alles mit 256 multiplizieren und das Endergebnis wieder durch 256 teilen?

(3 * 0,25 * 256 + 1,25 * 0,625 * 256 + 6 * 0,15 * 256) / 256
= (192 + 200 + 230) / 256
= 622 / 256
= 2,429688
= 2

Man beachte die geringe Abweichung zum tatsächlich richtigen Ergebnis.

Von dieser Warte aus betrachtet machen die Funktionen edns und edxs also durchaus Sinn, wenn man mit kleinen Werten rechnen muss, oder wenn man etwas genauer rechnen möchte als mit den Standard-Funktionen.



Zuguterletzt haben wir noch die edln Funktion. Diese berechnet ebenfalls gestaffelte Erhöhungen basierend auf dem Skill-Level und wird üblicherweise für die Bestimmung der Länge bestimmter Effekte genutzt: Kälte, Gift und Stun. Sie verwendet dabei die Spalten ELen, sowie ELevLen1-3, die es sowohl in der skills.txt als auch in der missiles.txt gibt. Die Berechnung läuft wie folgt:

Slvl 1 => Länge des Effektes in Frames gleich dem Wert in ELen
Slvl 2-8 => Bonus auf Länge gleich dem Wert in ELevLen1
Slvl 9-16 => Bonus auf Länge gleich dem Wert in ELevLen2
Slvl 17+ => Bonus auf Länge gleich dem Wert in ELevLen3

Natürlich kann man auch hier diese Funktionen für andere Sachen als die Dauer verwenden.


EDIT 1:

-----------
rand(X,Y)
-----------
Der Name dieser Funktion rand ist abgeleitet von "randomize", was soviel wie "zufällig/willkürlich bestimmen" heißt. Die Funktion ermittelt einen beliebigen (ganzzahligen) Wert zwischen den beiden Werten X und Y, wobei diese in der Menge der möglichen Ergebnisse enthalten sind. Wenn beispielsweise die Funktion heißt:

rand(2,5)

dann können als Ergebnis die Werte 2, 3, 4 oder 5 auftreten.
Erfreulicherweise wird immer wieder ein neuer Zufallswert bestimmt, wenn man den Skill ausführt, bzw. die Missile aktiviert wird. Dadurch ergeben sich zahlreiche Möglichkeiten, die ansonsten sehr unflexiblen Skills durch das Element Zufall etwas aufzulockern. Beispielsweise könnte man durch Verwenden einer Funktion der Form:

lnXY + (rand(0,1) * parZ)

für die Schadensberechnung ganze Schadensanteile zufällig ein- oder ausschalten - ergibt die rand()-Funktion 0, so verschwindet der hintere Anteil der Formel, ist das Ergebnis aber 1 so trägt er zum Gesamtergebnis mit bei. Dadurch könnte man dann z.B. einen Skill realisieren, der mal nur sehr wenig Schaden anrichtet, oder aber sehr viel. Und durch Kombinieren mehrerer rand()-Funktionen hintereinander kann man dann sogar die Wahrscheinlichkeiten zwischen beiden Fällen einstellen.
Vorhin hatten wir das schöne Beispiel mit der Anzahl Zähne beim Necro-Skill Teeth und da es sich hier wieder gut anbietet, machen wir es gleich nochmal. In die Spalte calc1 in der Zeile von Teeth in der skills.txt ändern wir den Eintrag auf

rand(2,4)

um. Somit feuert der Skill bei jeder Ausführung willkürlich zwischen 2 und 4 Zähnen ab. (Beispiel-Screenie). Wie in den meisten anderen Funktionen können auch bei rand()
die Argumente selber Funktionen sein. Tragen wir zum Beispiel:

rand(2,ln12)

bei Teeth ein, so werden willkürlich zwischen 2 und der Maximalanzahl Zähne für das jeweilige Skill-Level abgeschossen.



--------
min(X,Y)
max(Y,X)

--------
Diese beiden Funktionen sind sehr praktisch, denn mit ihnen kann man Limits für Funktionswerte realisieren. In beiden Fällen werden die zwei Eingangswerte X und Y miteinander verglichen und dann entweder immer der kleinere oder der größeren Wert von beiden genommen. Man kann sich quasi folgendes merken:

min(X,Y) vergleicht die Werte der beiden Variablen X und Y und nimmt immer den kleineren von beiden. Wenn eine der beiden einen festen Wert hat, entspricht das Verhalten der min()-Funktion einem Maximallimit - übersteigt nämlich der Wert der einen Variablen den der festgesetzten, so wird immer letzterer genommen.

max(X,Y) vergleicht beide Werte X und Y und wählt immer den größeren von beiden aus. Ist einer der beiden auf einen festen Wert eingestellt, so erzeugt die max()-Funktion einen Minimalwert, unter den der letztendliche Funktionswert nicht sinken kann.

X und Y können dabei sowohl feste Werte, als auch selbst Funktionen sein.
Schauen wir uns ein Beispiel an, wie das Ganze in natura funktioniert. Zuerst gehen wir zur Spalte calc1 in der Zeile des Amazonen-Skills Multiple Shot. Dort wird die Anzahl maximal verschossener Pfeile berechnet, die Formel dazu lautet:

min(24,ln12)

Par1 hat einen Wert von 2 und Par2 einen Wert von 1. Die min() Funktion tut nun nichts anderes, als den Wert 24 mit dem durch ln12 berechneten Wert zu vergleichen und dabei stets den kleineren zu nehmen. Anfangs wird das zweifellos immer der durch ln12 berechnete sein und somit steigt mit jedem Skilllevel die Anzahl abgefeuerter Pfeile um eins an. Auf Slvl 24 ergibt dann allerdings ln12 einen Wert von 25 und nun ist der erste Wert der kleinere und wird verwendet. Wenn wir Multiple Shot auf noch höhere Levels bringen, so bleibt die 24 nach wie vor der kleinere Wert und wird immer verwendet - ergo ist die maximale Anzahl durch MS verschießbare Pfeile gleich 24 und auf Slvl 25 erreicht. Ändern wir die Funktion nun wie folgt um:

max(5,(lvl/2))

Wie verhält es sich nun? Solange lvl/2 kleiner als der Wert 5 bleibt, verschiesst die Ama immer 5 Pfeile. Auf Slvl 12 (Runden des Rechners beachten!) erreicht dann lvl/2 den Wert 6, ist somit größer als 5 und folglich verschiesst die Ama dann auch 6 Pfeile. Bei noch höherem Slvl verballert sie entsprechend mehr, wir bemerken allerdings, dass mindestens immer 5 Pfeile verschossen werden.



--------
<X> ? <Y> : <Z>
--------
Dieses Konstrukt schaut auf den ersten Blick sehr merkwürdig aus, dahinter verbirgt sich allerdings auch eine Funktion - und zwar sogar eine sehr nützliche. Diejenigen, die schonmal was mit Programmieren zu tun hatte, kennen gewiss die if-then-else Anweisung. Genau das Gleiche tut diese Funktion.

<X> ? <Y> : <Z>

bedeutet nichts anderes als:

falls <X> wahr ist, dann <Y>; ansonsten <Z>

<X> wird dabei immer irgendeine Abfrage oder ein Test sein, bei den bereits in LoD verwendeten Funktionen ist es immer eine Überprüfung auf "größer als..." oder "kleiner als...". <Y> und <Z> sind dann anschließend die Ergebnisse, von denen eines in Abhängigkeit vom Test <X> eintritt.
Was genau ist unter "falls <X> wahr ist..." zu verstehen? Nun dazu am besten ein kleines Zahlenbeispiel:

(5 > 2) ? 6 : 7

Vor dem Fragezeichen steht die Abfrage, in diesem Fall also der Test, ob 5 größer als 2 ist. Das Ergebnis ist wahr, denn 5 ist größer als 2. Wie schaut es aus, wenn die Formel wie folgt lautet:

(5 < 2) ? 6 : 7

In diesem Fall ist das Ergebnis des Testes unwahr, denn 5 ist nicht größer als 2.
Und wie ist das nun mit den unterschiedlichen Ergebnissen, wann tritt welches ein? Um bei den obigen Beispielen zu bleiben, die obere Formel liefert das Ergebnis 6, weil die Formel ja bedeutet:

Wenn (5 > 2) ist, dann 6; ansonsten 7

Bei der zweiten Formel ist das Ergebnis, das die Formel ausspuckt 7, denn der Test ergibt unwahr und somit wird die Alternative gewählt:

Wenn (5 < 2) ist, dann 6; ansonsten 7

Untermauern wir die trockene Theorie mal nochmal mit etwas praktischer Anwendung aus den txt-Dateien. In der skills.txt finden wir in der Zeile des Skills "Raise Skeleton" unter petmax die maximale Anzahl beschwörbarer Skelette. Die Formel dort lautet wie folgt:

(lvl < 4) ? lvl : (2 + lvl/3)

Die erste Klammer führt einen Check durch, ob das Slvl von Raise Skeleton kleiner als 4 ist. Bis Slvl 3 ist das immer der Fall, also entspricht dort dann die Anzahl beschwörbarer Skelette dem Slvl. Sind wir bei Skill-Leveln über 3, so ergibt der Test das Ergebnis unwahr und die Anzahl Skelette wird dann nach dem zweiten Term berechnet, folglich erhalten wir über Slvl 3 nur alle 3 weitere Skill-Levels ein weiteres Skelett dazu.

Ein anderes schönes Beispiel wäre die Schadensberechnung beim Paladin-Skill Zeal, wo der Schadensbonus des Skills erst ab einem bestimmten Slvl einsetzt. Auch hier kommt die Funktion zum Einsatz: Zeile Zeal, Spalte calc2 in der skills.txt.

((lvl < 5) ? 0 : ((lvl-4) * par4) )+skill('Sacrifice'.blvl)*par8

Zugegebenermaßen sieht das Teil böse aus, aber wenn man es auseinander nimmt, ist es ganz einfach. Betrachten wir mal nur den ersten Summanden, der lautet:

(lvl < 5) ? 0 : ((lvl-4) * par4)

Der erste Teil ist eine Überprüfung, ob das Skill-Level kleiner als 5 ist. Wenn ja, dann liefert die Formel das Ergebnis 0. Ist die Bedingung unwahr, also das Slvl gleich oder größer als 5, so wird die Alternative verwendet und der Schadensbonus wird nach der angegebenen Formel berechnet. Der zweite Summand ist dann nur noch der hinzukommende Synergie-Bonus durch Sacrifice, der in dieser Form oben schonmal behandelt wurde.


In diesem Sinne:
(verstanden = ja) ? l33t : n00b
:D
 
:eek:

Wow, sowas lob ich mir :top:

Gute Erklärung der Parameter :keks:

Kann ich wieder nen Mod-Guide konvertieren, wenn ich mit den Charguides fertig bin :cool:
 
echt super :top: :top: :top:

nur eine frage habe ich noch: wie schaut das mit der hydra genau aus (bei der statabhängigkeit)? :D
 
Die Hydras sind eigentlich Summons, quasi eigene Monster nmit eigenen Stats - man findet sie auch in der monstats.txt aufgelistet. Die stat(<...>.accr) Einträge in der skills.txt sorgen dafür, dass die Hydras die Eigenschaften passive_fire_mastery(Feuerschadenerhöhung durch Mastery) und passive_fire_pierce (Senkung der Feuerresistenz bei Gegnern) von den Werten der Zauberin übernimmt.
Da die Hydra nen eigenständiges Monster darstellt, hätte es diese Fähigkeiten normalerweise nicht - ohne die Einträge in der skills.txt würden sich Mastery und FR-Senkung folglich nicht auf den Schaden der Hydra-Feuerbälle auswirken.

Ähnlich läuft es mit der Übertragung der Skills Dodge, Avoid und Evade bei der Walküre - die übernimmt die auch analog von der Ama, da sie diese Fertigkeiten nicht defaultmäßig besitzt.
 
Gibts das ganze auch für 1.09 (inkl. Offsets bitte) :D
Ne ernsthaft... sieht gut aus :top:
 
jo hamma Red Havoc, weil das wollte ich genau wissen, den Schaden und so ändern, wußte garnicht wie ich das anstellen sollte ! Echt top :top:
Mir fallen die Augen raus :eek:
Danke für diese Hilfe!
 
Hier ist ja von missels und skills die rede.. kann man die formeln, oder zum. die werte auch irgendwie in affixe packen?
 
In einigen anderen Dateien und dort in ganz bestimmten Spalten sollen sie angeblich funktionieren... ich hab aber keine Liste davon. :(

Im Zweifelsfall - ausprobieren! :D

[EDIT] Is mir grad noch eingefallen... ich glaub in den calc-Spalten in der misc.txt funktionieren sie. Bin mir aber nicht 100%ig sicher.
 
Mir gehts halt um sowas wie Schwert dessen Schaden von der aktuellen Lebensenergie abhängt z.B. (sowas kenn ich noch aus FF6/7)
 
Nicht über Formeln, aber über neue Attribute geht es. Ist allerdings buggy, weil der Schaden dann nur beim An- bzw. Ablegen des Items auf den aktuellen Lebenswert aktualisiert wird. :(
 
So, wieder ne Ergänzung mehr... das müssten dann die wirklich wichtigen Formeln gewesen sein. :) Es gibt noch ne ganze Reihe weiterer Formeln, die sind aber im Wesentlichen nur noch Abwandlungen der oben beschriebenen und mit der skillcalc.txt bzw. misscalc.txt kann man sich recht gut zusammenreimen, was die machen. Eventuell ergänze ich die nochmal irgendwann, aber man brauch die eh weitaus seltener. ;)

Was noch kommt is ne Übersicht im reservierten Post, damit man die Funktionen schneller findet und nicht jedesmal den langen Post durchsuchen muss, sowie ein paar Hinweise, die man beim Basteln mit Funktionen berücksichtigen sollte. :)
 
mich würde mal interessiern wie man die dt1mask (fragt mich jetzt nicht in welcher txt-file die ist :D ) errechnet
 
Wow, nie so einen kompletten guide dafuer gesehen ;).

Allerdings gibts noch zwei hilfreiche Sachen... Wenn Ihr nicht wollt, dass die Leute die Energie, um z.b. mehr Teeth zu bekommen (wie im Beispiel), über +energy items reinholen, koennt ihr statt

stat('energy'.accr)

stat('energy'.base)

nehmen. Das liefert nur den Basis-Wert zurueck. Es gibt auch etwas, das den Teil zurueckliefert, der durch Items kommt, also
stat('energy'.accr) - stat('energy'.base)

Soweit ich weiss, heisst das dann

stat('energy'.bonus)

aber da bin ich nicht ganz sicher.

Beispiel: Character hat 310 Energy, davon 60 durch Items oder andere Skills oder woher auch immer (Basiswert 250).

-> stat('energy'.accr) = 310
-> stat('energy'.base) = 250
-> stat('energy'.bonus) = 60

hoffe, das hilft irgendwem ;).
 
Hoi Henning, schön dich hier auch mal zu sehen. :hy:

Der Formel-Guide ist auch schon etwas älter, da gibt´s gewiss noch ne ganze Menge anderer Sachen, wo man etwas mehr zu sagen könnte oder wo was verbessert werden müsste.
Mal gucken, wenn ich meine Diplomarbeit rum hab, sind eh nen paar Updates vorgesehen, vielleicht guck ich hier auch nochmal durch... :read:
 
Zurück
Oben