Es fliegen so viele nützliche Scripte (klein bis groß) hier im Forum herum, in denen teilweise sehr viel Aufwand steckt, dass es Schade ist, dass sie hier im Forum mehr oder weniger untergehen: Im Endeffekt sind sie nur über die Signaturen der Ersteller zu finden, wenn die denn noch aktiv sind. Vergangene Versuche, irgendwelche Listen von "interessanten Scripten" zu führen, sind auch immer wieder fehlgeschlagen (nicht mehr aktuell und nur größere Scripte). Die kürzeren Scripte, die teilweise auf Nachfrage in Threads angefertigt werden, verschwinden komplett von der Bildfläche: Es gibt keine Links, die dort hinführen und wenn man den Thread nicht zufällig gelesen hat, gibt es keine Chance, sie zu finden.
Daher habe ich eine wilde Sammlung von Scripten, den ScriptBin, zusammengestellt. Das soll einerseits eine zentrale Ressource sein, durch die man stöbern und eventuell einen Nutzen ziehen kann, andererseits eine nützliche Basis für weitere Scripte, die jemand der Öffentlichkeit bereitstellen möchte. Es gab schon öfter Posts, in denen jemand ein Script gepostet hat, um Vobs zu bewegen. Jedesmal musste man entweder auf einen alten Post von Sekti verweisen oder die dafür nötigen Funktionen (SetPositionWorldVec, VobPositionUpdated, ...) selber zum Post hinzufügen - und das ist sicherlich nur eines von vielen Beispielen. Es gibt eine einfache Lösung für ein Problem, die die Broadcasts von Sektenspinner benutzt? Dann muss man erstmal den Link rauskramen, wenn man so eine Lösung posten möchte.
Ein weiterer Anreiz (vor allem für Neulinge) sollte die einfache Installation sein: Hat man die .zip-Datei entpackt, muss man nur noch einen einzigen Eintrag in der Gothic.src vornehmen. Vor allem die Installation von Ikarus* hat einige da sicherlich verwirrt.
Vorneweg: Keine der Scripte in dieser Sammlung machen irgendetwas, wenn sie nicht aufgerufen werden. Wenn ihr nur eine einzige Funktion benutzt, werden euch also auch keine anderen Funktionen irgendwie dazwischenfunken (z.B. bei Crash bei Weltwechsel oder was auch immer). Kurzum: Es geht nichts kaputt, wenn ihr den ScriptBin installiert.
Wer kein Ikarus benutzen möchte hat es auch nicht weiter schwierig, die Ordnerstruktur trennt zwischen "normalen" Scripten und Scripten, die Ikarus benötigen.
Mal ein paar Beispiele, was für Scripte bisher enthalten sind und welche "Umfang" sie haben:
Spoiler:(zum lesen bitte Text markieren)
Code:
// Banale Scripte, die kaum mehr als ein Einzeiler sind:
func int max(var int i, var int j) {
if (i > j) {
return i;
};
return j;
};
func int max3(var int i1, var int i2, var int i3) {
return max(max(i1, i2), i3);
};
func int max4(var int i1, var int i2, var int i3, var int i4) {
return max(max3(i1, i2, i3), i4);
};
func string i2s(var int i) {
return IntToString(i);
};
func string cs2 (var string s1, var string s2) {
return ConcatStrings (s1, s2);
};
func string cs3 (var string s1, var string s2, var string s3) {
return cs2 (cs2 (s1, s2), s3);
};
Code:
//Schon interessanter
func int Log_GetTopicStatus(var string name) {
const int logMan = 11191608; //0xaac538
var zCList list; list = _^(logMan);
while(list.next);
list = _^(list.next);
if (list.data) {
if (Hlp_StrCmp(MEM_ReadString(list.data), name)) {
return MEM_ReadInt(list.data + 24);
};
};
end;
return -1;
};
Außerdem habe ich auch größere Scripte, die inhaltlich in dieses Paket passen, hinzugefügt, wie z.B. die Broadcasts von Sektenspinner oder die "Insert Anything"-Scripte von mud-freak. In diesem Fall wurden jeweils die Autoren genannt und es gibt einen Link zum dazugehörigen Thread/Post. Da die Scripte bereits frei verfügbar waren, hoffe ich, dass das im Sinne der Autoren ist
Natürlich konnte ich nicht alle Posts sichten, die hier im Editing gepostet wurden. Bisher sind also vor allem Scripte enthalten, an die ich mich selber noch erinnern konnte plus einige wenige, die noch bei mir auf der Platte rumflogen. Sollte es hier eine positive Rückmeldung geben, würde ich mich freuen, wenn ihr weitere Scripte postet, die gut dazu passen könnten: Entweder fällt euch noch ein Post hier im Forum ein oder ihr habt eigene Ideen, die einfach nicht "groß genug" für einen eigenen Thread waren?
Aber ans Hauptsächliche: Hier ist der Link. Ihr könnt einfach oben rechts auf "Download" klicken, dann solltet ihr eine .zip-Datei herunterladen. Die einfach in den Scripts\Content-Ordner entpacken und die ScriptBin.src in der Gothic.src eintragen (für ein paar weitere Informationen siehe ReadMe.txt).
Vielleicht können wir es zusammen den Anfängern ein bisschen einfacher und übersichtlicher machen
*Ikarus ist ebenfalls im ScriptBin enthalten. Normalerweise nicht so elegant, aber Sektenspinner ist schon lange inaktiv, also ist es unwahrscheinlich, dass er noch aktiv daran arbeiten wird in der Zukunft. Ich bin mir sicher, diese Sammlung von Scripten ist in seinem Interesse.
Ich find die Idee gut. Vielleicht könntest du im Einleitungspost noch eine Liste der enthaltenen Skripte aufnehmen, damit man direkt einen Überblick hat.
Wäre nicht verkehrt, wenn diese Skript-Collection eine Art Standard wird.
Das SearchWaypointByName ist etwas "veraltet". Hier hatte ich eine simplere Variante vorgeschlagen. Als Funktion könnte man das dann so aufnehmen (Code ungetestet):
Code:
func int SearchWaypointByName(var string waypoint) {
const int zCWayNet__GetWaypoint = 8061744; //0x7B0330
var int waynetPtr; waynetPtr = _@(MEM_Waynet);
var int wpNamePtr; wpNamePtr = _@s(waypoint);
const int call = 0;
if (Call_Begin(call)) {
CALL__fastcall(_@(waynetPtr), _@(wpNamePtr), zCWayNet__GetWaypoint);
call = CALL_End();
};
return CALL_RetValAsInt();
};
Wenn du magst, kannst du auch hier einige sinnvolle Skripte entnehmen.
Wie bist du auf ScriptBin gekommen? Bin hat mich erstmal an binary erinnert, oder meinst du den Papierkorb?
Gute Idee.
Wenn man erst so wilde Ideen wie "daedalus - all you may need" -> "DAYMN" hat, klingt Script-Papierkorb gar nicht mal so schlecht
Außerdem sollte es keinen "Namen" (wie Ikarus oder LeGo) bekommen, weil es eben kein, uhm, "Produkt" von mir ist. Nur eine Sammlung.
Der Sinn der Sache ist es, noch weiter zu wachsen. Bisher ist es ja nur eine sehr kleine Ansammlung.
Dokumentation müsste natürlich auch noch geschrieben werden...
Because i finished work in Ikarus and now i'm using AST(Agama Script Tools) i decided to share my scripts
Some Engine scripts:
Code:
func void SetAsPlayer (var C_NPC slf)
{
const int oCNpc__SetAsPlayer = 7612064;
CALL__thiscall (MEM_InstToPtr (slf), oCNpc__SetAsPlayer);
};
func int Menu_ReadInt(var string category, var string name) //int
{
var string value; value = Mem_GetGothOpt(category, name);
return STR_ToInt(value);
};
func void Menu_WriteInt(var string category, var string name, var int value)
{
MEM_SetGothOpt(category,name, IntToString(value));
};
func int oCNpc_GetModel(var int npc) //zCModel*
{
const int oCNpc__GetModel = 7571232;
CALL__thiscall(MEM_InstToPtr(npc), oCNpc__GetModel);
return CALL_RetValAsInt();
};
func int AniIsActive(var c_npc slf, var string aniname) //BOOL
{
var int ptr; ptr = oCNpc_GetModel(slf);
const int zCModel_AniIsActive = 5727888;//0x00576690
CALL_zStringPtrParam(Str_Upper(aniname));
CALL__thiscall(ptr,zCModel_AniIsActive);
return CALL_RetValAsInt();
};
func int zCVisual_LoadVisual(var string vis) //zCVisual*
{
const int zCVisual__LoadVisual = 6318800; //0x00606AD0
CALL_zStringPtrParam(STR_Upper(vis));
CALL__cdecl(zCVisual__LoadVisual);
return CALL_RetValAsInt();
};
func int StringIsEmpty(var string str) //BOOL
{
if(STR_Len(str)>=1)
{
return true;
};
return false;
};
func void Set_ItemVisual(var int itm, var string vis)
{
const int oCItem__SetVisual = 7411984; //0x00711910
CALL_PtrParam(zCVisual_LoadVisual(vis));
CALL__thiscall(MEM_InstToPtr(itm),oCItem__SetVisual);
};
func int zCModel_SearchNode(var int model, var string node) //zCModelNodeInst*
{
CALL_zStringPtrParam(Str_Upper(node));
CALL__thiscall(model, zCModel__SearchNode);
return CALL_RetValAsInt();
};
func void Ext_PutInSlot(var int pnpc, var string node, var string visual)
{
const int zCModel__SetNodeVisual = 5739168;
var int model; model = oCNpc_GetModel(pnpc);
var int vis; vis = zCVisual_LoadVisual(visual);
var int nde; nde = zCModel_SearchNode(model,node);
CALL_IntParam(1); //3 param
CALL_PtrParam(vis); //2 param - vis
CALL_PtrParam(nde); //1 param get node
CALL__thiscall(model, zCModel__SetNodeVisual);
};
func void Ext_PutInSlot2(var int pnpc, var string node, var int vob) //Used to mounts system (hero, "NODE", her.focus_vob)
{
var int model; model = oCNpc_GetModel(pnpc);
var int nde; nde = zCModel_SearchNode(model,node);
CALL_PtrParam(1); //1 param get node
var int vb; vb = MEM_InstGetOffset(vob);
CALL_PtrParam(MEM_ReadInt(vb+200)); //2 param - vis
CALL_PtrParam(nde); //1 param get node
CALL__thiscall(model, zCModel__SetNodeVisual);
};
func int Get_AniIDFromAniName(var int slf, var string aniName) //int
{
const int zCModel__AniIDFromAniName = 6365296; //0x00612070
var int model; model = oCNpc_GetModel(slf);
CALL_zStringPtrParam(Str_Upper(aniName));
CALL__thiscall(model,zCModel__AniIDFromAniName);
return CALL_RetValAsInt();
};
func int GetAniFromAniID(var c_npc slf, var string aniName) //zCModelAni*
{
const int zCModel__GetAniFromAniID = 4665168; //0x00472F50
var int model; model = oCNpc_GetModel(slf);
var int ani; ani = Get_AniIDFromAniName(slf,aniName);
CALL_PtrParam(ani);
CALL__thiscall(model,zCModel__GetAniFromAniID);
return CALL_RetValAsInt();
};
func void Set_AniFPS(var c_npc slf, var string aniName, var int FPS)
{
var int ptr;
ptr = GetAniFromAniID(slf, aniName);
MEM_WriteInt(ptr+176, mkf(FPS));
};
func int GetNodeBBox3D(var int slf, var string bone) //Get Node BBox - Hitboxes or Check collision
{
var int model; model = oCNpc_GetModel(slf);
var int node; node = zCModel_SearchNode(model,bone);
CALL_PtrParam(node);
CALL_RetValIsStruct(24); //6*4
CALL__thiscall(model,zCModel__GetBBox3DNodeWorld);
return CALL_RetValAsPtr();
};
func oCItem Hlp_GetItem(var int inst) //oCItem*
{
var zCPar_Symbol symb; symb = _^(MEM_GetSymbolByIndex(inst));
_^(symb.offset);
};
Fade Screen
Code:
/********************
EXAMPLE TO USE:
func void fade()
{
//SetColor
FadeScreen_Color_R = 71;
FadeScreen_Color_G = 71;
FadeScreen_Color_B = 71;
FadeScreen_Color_Over = 1; //??? I don't remember xD
//SetStatus and multipler
FadeScreen_Multipler = 5; //1-10
Fade_Status = 1;
};
********************/
var int FadeScreen_Color_R;
var int FadeScreen_Color_G;
var int FadeScreen_Color_B;
var int FadeScreen_Color_A;
var int FadeScreen_Color_Over;
var int Fade_Status;
var int FadeScreen_Multipler;
func void FadeScreen_Function() //PerFrame
{
MEM_InitGlobalInst();
MEM_GAME.array_view_visible[0] = true;
MEM_GAME.array_view_enabled[0] = true;
MEM_CAMERA.screenFadeEnabled = true;
MEM_CAMERA.screenFadeColor = RGBA(FadeScreen_Color_R, FadeScreen_Color_G, FadeScreen_Color_B, FadeScreen_Color_A);
var zCView ptr; ptr = _^(MEM_GAME.array_view[0]);
ptr.alphafunc = FadeScreen_Color_Over;
if(Fade_Status == 1)
{
if(FadeScreen_Color_A<255)
{
FadeScreen_Color_A += FadeScreen_Multipler;
}
else if (FadeScreen_Color_A>=255)
{
FadeScreen_Color_A = 255;
Fade_Status =2;
};
}
else if (Fade_Status == 2)
{
if(FadeScreen_Color_A >= FadeScreen_Multipler)
{
FadeScreen_Color_A -= FadeScreen_Multipler;
}
else if (FadeScreen_Color_A <= FadeScreen_Multipler)
{
FadeScreen_Color_A= 0;
Fade_Status =0;
};
};
};
This is all at this time. (I couldn't found my next scripts :/ )
Regards Siemekk.
Fisk2033 told me that you are interested in features presented on my YouTube channel. Most of them I never published, because it was made for polish mod - Dziedzictwo (Legacy in english). Unfortunately our team leader Kaczka (Duck in english) died in car accident 2 months ago. All materials and scenario he had and not proper to asking his familly in mourning for files of some game. I can share some scripts, but a lot of them are unfinished yet like quickslot bar (which uses LeGo quickslot bar texture) or melee weapon damage system which allows attack any npc, dual wielding, armor wearing like in The Elders Scrolls (yes, it's possible with script packets). Some scripts (like cursor) are only "sketch" to check whether it is possible to do, so it don't make sense now.
Here is cinema scope script partly made by OrcWarrior. Call FF_ApplyOnce (CinemaScope); in INIT_Global.
Schon immer hat mich an Wld_PlayEffect genervt, dass man Effekte nicht verlässlich stoppen kann. Wld_StopEffect beendet nur den erst gefundenen Effekt mit dem Namen, was häufig dazu geführt hat, dass Effekte in der Welt hängen geblieben sind. Ausserdem gibt es in Gothic 1 gar kein Wld_StopEffect, wodurch man gestartete Effekte gar nicht erst beenden konnte.
Ich möchte hier Wld_StopEffect_Ext vorstellen. Ein Skript, mit dem man genau bestimmen kann welcher Effekt beendet werden soll (und ob nur einer oder alle übereinstimmenden). Das ganze kompatibel mit Gothic 2 und Gothic 1. Die Funktion tut haargenau das, was Wld_StopEffect in der Engine tut, nur mit erweiterter Funktionalität.
Genauer:
Es gibt drei zusätzliche Funktionsparamenter und einen Rückgabewert:
func int Wld_StopEffect_Ext(string effect, int origin, int target, int stopAll)
Parameter zwei und drei sind Ursprungsobjekt und Zielobjekt (so wie man das von Wld_PlayEffect kennt). Übergeben wird jeweils eine Instanz. So kann mal sowohl NPCs und Items, als auch jegliche andere Instanz übergeben, die von der Klasse zCVob erbt. Diese Parameter können auch null sein, wenn sie nicht festgelegt werden sollen.
Der vierte Parameter lässt entscheiden, ob nur der erst gefundene Effekt gestoppt werden soll (0), so wie bei Wld_StopEffect, oder alle Effekte gestoppt werden sollen, die mit den Voraussetzungen übereinstimmen (1).
Der Rückgabewert gibt an, wie viele Effekte gestoppt wurden. Null bedeutet, dass entweder keine passenden Effekte gefunden wurden, oder die Argumente fehlerhaft waren. Mit diesem Rückgabewert hat man aus der Skripten nun auch mehr Kontrolle über was geschieht.
Beispiel:
Code:
var C_NPC Diego; Diego = Hlp_GetNpc(PC_ThiefOW);
Wld_PlayEffect("SPELLFX_SLEEPER_FIREBALL", self, Diego, 2, 150, DAM_FIRE, TRUE);
Wld_PlayEffect("SPELLFX_SLEEPER_FIREBALL", self, hero, 2, 150, DAM_FIRE, TRUE);
Wld_StopEffect_Ext("SPELLFX_SLEEPER_FIREBALL", 0, Diego, 0); // Stops exactly and only the first effect
Aufgrund der vielen Speicheradressen für sowohl Gothic 1, als auch Gothic 2, wirkt das Skript enorm lang, ist aber eigentlich ziemlich kurz und simpel.
Ich habe das Skript schon in die Form der übrigen Skripte aus dem ScriptBin gebracht (Kopfzeile im Skript), kann also direkt so übernommen werden.
Code:
// Extended functionality for Wld_StopEffect()
// See https://forum.worldofplayers.de/forum/threads/1495001-Scriptsammlung-ScriptBin?p=25548652&viewfull=1#post25548652
// Made by mud-freak (@szapp) 2017-08-05 (modified 2017-08-09)
//
// Compatible with Gothic 1 and Gothic 2
// Requirements: Ikarus 1.2
/*
* Check the inheritance of a zCObject against a zCClassDef. Emulating zCObject::CheckInheritance() at 0x476E30 in G2.
* This function is used in Wld_StopEffect_Ext().
*/
func int objCheckInheritance(var int objPtr, var int classDef){
if (!objPtr) || (!classDef){
return 0;
};
const int zCClassDef_baseClassDef_offset = 60; //0x003C
// Iterate over base classes
var int curClassDef; curClassDef = MEM_GetClassDef(objPtr);
while((curClassDef) && (curClassDef != classDef));
curClassDef = MEM_ReadInt(curClassDef+zCClassDef_baseClassDef_offset);
end;
return (curClassDef == classDef);
};
/*
* Emulate the Gothic 2 external function Wld_StopEffect(), with additional settings: Usually it is not clear which
* effect will be stopped, leading to effects getting "stuck". Here, Wld_StopEffect is extended with additional checks
* for origin and/or target vob and whether to stop all matching FX or only the first one found (like in Wld_StopEffect)
* The function returns the number of stopped effects, or zero if none was found or an error occurred.
* Compatible with Gothic 1 and Gothic 2. This means there is finally the possibility to stop effects in Gothic 1!
*
* Examples:
* var C_NPC Diego; Diego = Hlp_GetNpc(PC_ThiefOW);
* Wld_PlayEffect("SPELLFX_SLEEPER_FIREBALL", self, Diego, 2, 150, DAM_FIRE, TRUE);
* Wld_PlayEffect("SPELLFX_SLEEPER_FIREBALL", self, hero, 2, 150, DAM_FIRE, TRUE);
* Wld_StopEffect_Ext("SPELLFX_SLEEPER_FIREBALL", 0, Diego, 0); // Stops only the first effect
*
* Calling Wld_StopEffect("EFFECT_1") corresponds to Wld_StopEffect_Ext("EFFECT_1", 0, 0, 0).
*
* Big parts if this function are taken from Wld_StopEffect. Gothic 2: sub_006E32B0() 0x6E32B0
*/
func int Wld_StopEffect_Ext(var string effectName, var int originInst, var int targetInst, var int all){// Gothic 1 addresses and offsets
const int zCVob__classDef_G1 = 9269976; //0x8D72D8
const int zCWorld__SearchVobListByClass_G1 = 6249792; //0x5F5D40
const int oCVisualFX__classDef_G1 = 8822272; //0x869E00
const int oCVisualFX__Stop_G1 = 4766512; //0x48BB30
const int oCVisualFX_originVob_offset_G1 = 1112; //0x0458
const int oCVisualFX_targetVob_offset_G1 = 1120; //0x0460
const int oCVisualFX_instanceName_offset_G1 = 1140; //0x0474
// Gothic 2 addresses and offsets
const int zCVob__classDef_G2 = 10106072; //0x9A34D8
const int zCWorld__SearchVobListByClass_G2 = 6439504; //0x624250
const int oCVisualFX__classDef_G2 = 9234008; //0x8CE658
const int oCVisualFX__Stop_G2 = 4799456; //0x493BE0
const int oCVisualFX_originVob_offset_G2 = 1192; //0x04A8
const int oCVisualFX_targetVob_offset_G2 = 1200; //0x04B0
const int oCVisualFX_instanceName_offset_G2 = 1220; //0x04C4
var int zCVob__classDef;
var int zCWorld__SearchVobListByClass;
var int oCVisualFX__classDef;
var int oCVisualFX__Stop;
var int oCVisualFX_originVob_offset;
var int oCVisualFX_targetVob_offset;
var int oCVisualFX_instanceName_offset;
zCVob__classDef = MEMINT_SwitchG1G2(zCVob__classDef_G1,
zCVob__classDef_G2);
zCWorld__SearchVobListByClass = MEMINT_SwitchG1G2(zCWorld__SearchVobListByClass_G1,
zCWorld__SearchVobListByClass_G2);
oCVisualFX__classDef = MEMINT_SwitchG1G2(oCVisualFX__classDef_G1,
oCVisualFX__classDef_G2);
oCVisualFX__Stop = MEMINT_SwitchG1G2(oCVisualFX__Stop_G1,
oCVisualFX__Stop_G2);
oCVisualFX_originVob_offset = MEMINT_SwitchG1G2(oCVisualFX_originVob_offset_G1,
oCVisualFX_originVob_offset_G2);
oCVisualFX_targetVob_offset = MEMINT_SwitchG1G2(oCVisualFX_targetVob_offset_G1,
oCVisualFX_targetVob_offset_G2);
oCVisualFX_instanceName_offset = MEMINT_SwitchG1G2(oCVisualFX_instanceName_offset_G1,
oCVisualFX_instanceName_offset_G2);
var int worldPtr; worldPtr = _@(MEM_World);
if (!worldPtr){
return 0;
};
// Create array from all oCVisualFX vobs
var int vobArrayPtr; vobArrayPtr = MEM_ArrayCreate();
var zCArray vobArray; vobArray = _^(vobArrayPtr);
const int call = 0; var int zero;
if (CALL_Begin(call)){
CALL_PtrParam(_@(zero)); // Vob tree (0 == globalVobTree)
CALL_PtrParam(_@(vobArrayPtr)); // Array to store found vobs in
CALL_PtrParam(_@(oCVisualFX__classDef)); // Class definition
CALL__thiscall(_@(worldPtr), zCWorld__SearchVobListByClass);
call = CALL_End();
};
if (!vobArray.numInArray){
MEM_ArrayFree(vobArrayPtr);
return 0;
};
effectName = STR_Upper(effectName);
var zCPar_Symbol symb;
// Validate origin vob instance
if (originInst){// Get pointer from instance symbol
if (originInst > 0) && (originInst < MEM_Parser.symtab_table_numInArray){
symb = _^(MEM_ReadIntArray(contentSymbolTableAddress, originInst));
originInst = symb.offset;
} else {
originInst = 0;
};
if (!objCheckInheritance(originInst, zCVob__classDef)){
MEM_Warn("Wld_StopEffect_Ext: Origin is not a valid vob");
return 0;
};
};
// Validate target vob instance
if (targetInst){// Get pointer from instance symbol
if (targetInst > 0) && (targetInst < MEM_Parser.symtab_table_numInArray){
symb = _^(MEM_ReadIntArray(contentSymbolTableAddress, targetInst));
targetInst = symb.offset;
} else {
targetInst = 0;
};
if (!objCheckInheritance(targetInst, zCVob__classDef)){
MEM_Warn("Wld_StopEffect_Ext: Target is not a valid vob");
return 0;
};
};
// Search all vobs for the matching name
var int stopped; stopped = 0; // Number of FX stopped
repeat(i, vobArray.numInArray); var int i;
var int vobPtr; vobPtr = MEM_ArrayRead(vobArrayPtr, i);
if (!vobPtr){
continue;
};
// Search for FX with matching name
if (!Hlp_StrCmp(effectName, "")){
var string effectInst; effectInst = MEM_ReadString(vobPtr+oCVisualFX_instanceName_offset);
if (!Hlp_StrCmp(effectInst, effectName)){
continue;
};
};
// Search for a specific origin vob
if (originInst){
var int originVob; originVob = MEM_ReadInt(vobPtr+oCVisualFX_originVob_offset);
if (originVob != originInst){
continue;
};
};
// Search for a specific target vob
if (targetInst){
var int targetVob; targetVob = MEM_ReadInt(vobPtr+oCVisualFX_targetVob_offset);
if (targetVob != targetInst){
continue;
};
};
// Stop the oCVisualFX
const int call2 = 0; const int one = 1;
if (CALL_Begin(call2)){
CALL_PtrParam(_@(one));
CALL__thiscall(_@(vobPtr), oCVisualFX__Stop);
call2 = CALL_End();
};
stopped += 1;
if (!all){
break;
};
end;
MEM_ArrayFree(vobArrayPtr);
return stopped;
};
Was haltet ihr eigentlich davon, diesen Thread mal anzupinnen?
Geändert von mud-freak (13.11.2017 um 09:02 Uhr)
Grund: Code aktualisiert: Erlaubt alle Effekte eines Vobs zu löschen; Code korrigiert: _hat und _at ersetzt durch _^ und _@, siehe Post #27
Bei der Verwendung von Wld_StopEffect sollte der Anwender sich darüber im Klaren sein, dass beim Vergleich des Namens die Groß-/Kleinschreibung beachtet wird (ist auch bei der ZenGin-Implementierung so - die Namen sollten also immer groß geschrieben werden) und der Name des Effekts vom Level abhängen kann (Wld_PlayEffect("FOO", NULL, NULL, 42, 0, 0, 0) erzeugt einen Effekt mit dem Namen "FOO_L42" wenn auch eine Skriptinstanz mit diesem Namen existiert).
"Unter diesen schwierigen Umständen bin ich mir sicher, daß diese guten Menschen meinen augenblicklichen Bedarf an deren Gold verstehen werden." -- Connor
Bei der Verwendung von Wld_StopEffect sollte der Anwender sich darüber im Klaren sein, dass beim Vergleich des Namens die Groß-/Kleinschreibung beachtet wird (ist auch bei der ZenGin-Implementierung so - die Namen sollten also immer groß geschrieben werden) und der Name des Effekts vom Level abhängen kann (Wld_PlayEffect("FOO", NULL, NULL, 42, 0, 0, 0) erzeugt einen Effekt mit dem Namen "FOO_L42" wenn auch eine Skriptinstanz mit diesem Namen existiert).
Ich weiss nicht, ob ich dich falsch verstehe, aber da muss ich widersprechen. Alle Effektnamen werden von der Engine immer in Grossbuchstaben umgewandelt (auch wenn man sie als Wld_PlayEffect("foO", ...) o.Ä. startet, werden sie als "FOO" erstellt).
In der Funktion oben wird dann der übergebene Effektname in Grossbuchstaben umgewandelt (effectName = STR_Upper(effectName);), sodass ein Vergleich immer funktioniert.
Wo du aber Recht hast ist, dass ich das Effektlevel im Skript nicht berücksichtigt habe.
In der Funktion oben wird dann der übergebene Effektname in Grossbuchstaben umgewandelt (effectName = STR_Upper(effectName);), sodass ein Vergleich immer funktioniert.
Die ZenGin-External macht das nicht.
Deswegen müssen Skripter den Effektnamen immer groß schreiben, damit das Spiel den Effekt findet.
(ps: meine Dokumentation ist noch fehlerhaft, es wird, wie du schon geschrieben hast, nur der erste gefundene Effekt beendet)
Zitat von mud-freak
Wo du aber Recht hast ist, dass ich das Effektlevel im Skript nicht berücksichtigt habe.
Das müssen die Skripter selbst wissen und ist automatisch kaum zu erkennen, bzw. lohnt sich eine Umsetzung kaum (zumal die ZenGin-External das auch nicht macht). Im Zweifelsfall führen sie die Funktion mit allen Stufen aus, welche sie verwenden/kennen. Ich bin nicht sicher ob das Feature für visuelle Effekte überhaupt verwendet wurde und wollte nur darauf hinweisen, dass (wenn beide Skriptinstanzen existieren) die stufenspezifische Instanz bevorzugt und als Name verwendet wird.
"Unter diesen schwierigen Umständen bin ich mir sicher, daß diese guten Menschen meinen augenblicklichen Bedarf an deren Gold verstehen werden." -- Connor
Da ist mir noch eine Verbesserungsmöglichkeit gekommen. Man kann auch Effekte stoppen nur anhand des Upsprungs- und/oder Zielobjekts. So lassen sich auch ganz einfach alle Effekte stoppen die etwas mit einem bestimmten Objekt zu tun haben:
Code:
var C_NPC Diego; Diego = Hlp_GetNpc(PC_ThiefOW);
Wld_PlayEffect("SPELLFX_SLEEPER_FIREBALL", self, Diego, 2, 150, DAM_FIRE, TRUE);
Wld_PlayEffect("SPELLFX_HEALSHRINE", Diego, Diego, 0, 0, 0, FALSE);
// Stop all effects involving Diego
Wld_StopEffect_Ext("", Diego, 0, 1); // Stops all effects with Diego as origin
Wld_StopEffect_Ext("", 0, Diego, 1); // Stops all effects with Diego as target
Was mich an Gothic 2 immer gestört hat ist, dass die Menu-Musik weiterläuft, wenn zu Spielstart das Intro startet. (In Gothic 1 ist das nicht der Fall). Ich habe eine Funktion geschrieben, die alle aktiven Sounds sofort stoppt (Musik ist nicht betroffen, die Menu-Musik ist ein "Sound", keine Musik). Man kann die Funktion also aus der Startup kurz vor starten des Intro-Videos aufrufen, um das Problem zu beheben und einem Intro vernünftig zu lauschen:
Beispiel:
Code:
// ------ World -------
FUNC VOID STARTUP_NewWorld(){// ------ StartUps der Unter-Parts ------
STARTUP_NewWorld_Part_Forest_01();
STARTUP_NewWorld_Part_Pass_To_OW_01();
// ------ INTRO - muss ganz am Ende der Startup stehen ------
Kapitel = 1; //Joly: Kann hier stehen bleiben!
stopAllSounds();PlayVideo("INTRO.BIK");
PlayVideo("Addon_Title.BIK");
};
Auch wenn das Problem nicht bei Gothic 1 auftaucht, der Vollständigkeit halber mit Adressen für Gothic 1 und Gothic 2.
Code:
func void stopAllSounds(){
MEM_InitAll();
const int zsound_G1 = 9236044; //0x8CEE4C
const int zsound_G2 = 10072124; //0x99B03C
const int zCSndSys_MSS__RemoveAllActiveSounds_G1 = 5112224; //0x4E01A0
const int zCSndSys_MSS__RemoveAllActiveSounds_G2 = 5167008; //0x4ED7A0
var int zsoundPtr; zsoundPtr = MEMINT_SwitchG1G2(MEM_ReadInt(zsound_G1), MEM_ReadInt(zsound_G2));
const int call = 0;
if (CALL_Begin(call)){
CALL__thiscall(_@(zsoundPtr), MEMINT_SwitchG1G2(zCSndSys_MSS__RemoveAllActiveSounds_G1,
zCSndSys_MSS__RemoveAllActiveSounds_G2));
call = CALL_End();
};
};
Zitat von Lehona
Wenn man diesen Befehl (einmal pro Session) mit false aufruft, regnet es nicht mehr durch Vobs hindurch:
Code:
func void rainThroughVobs(var int bool) {
OverrideMemoryProtection(6169210, 4);
if (!bool) {
// bool == false -> Es regnet nicht mehr durch
MEM_WriteByte(6169210, 224);
} else {
MEM_WriteByte(6169210, 226);
};
Der Dank geht an Showdown, ich hab das ganze nur nach Daedalus übersetzt.
Ebenfalls könnte man folgenden BugFix fürs MultiBook einbauen:
Zitat von TheEternal
Kleiner, aber hässlicher Bug beim Multibook hier. Wenn man das Buch mit Rechtsklick schließt statt mit Escape, dann spinnt alles rum....
habe die Funktion angepasst.
Code:
func int ZS_MultiPageBooks_Loop() { // Wichtig, damit eine Taste nicht mehrmals aufgerufen wird
AI_Wait (self, 0.1);
// Die nächste Seite aufrufen?
if (UpdatePage == TRUE)
{
MEM_CallByString(CurrentBook);
UpdatePage = FALSE;
};
// Tasten
var int LeftKey; LeftKey = MEM_KeyState(KEY_LEFTARROW);
var int RightKey; RightKey = MEM_KeyState(KEY_RIGHTARROW);
var int EscKey; EscKey = MEM_KeyState(KEY_ESCAPE);
var int MouseRightKey; MouseRightKey = MEM_KeyState(MOUSE_BUTTONRIGHT);
// Pfeil-Links gedrückt
if (LeftKey == KEY_PRESSED) {
// Ende des Buches noch nicht erreicht
if (CurrentPage > 0)
{
CurrentPage -= 2;
MEM_InsertKeyEvent (KEY_ESCAPE);
MEM_InsertKeyEvent (MOUSE_BUTTONRIGHT);
UpdatePage = TRUE;
return LOOP_CONTINUE;
}
// Ende des Buches erreicht, aber Loop ist eingeschaltet
else if (CurrentBookLoopable) {
CurrentPage = CurrentBookMaxPage - (CurrentBookMaxPage%2);
MEM_InsertKeyEvent (KEY_ESCAPE);
MEM_InsertKeyEvent (MOUSE_BUTTONRIGHT);
UpdatePage = TRUE;
return LOOP_CONTINUE;
};
};
// Pfeil-Rechts gedrückt
if (RightKey == KEY_PRESSED) {
// Ende des Buches noch nicht erreicht
if (CurrentPage < CurrentBookMaxPage-2)
{
CurrentPage += 2;
MEM_InsertKeyEvent (KEY_ESCAPE);
MEM_InsertKeyEvent (MOUSE_BUTTONRIGHT);
UpdatePage = TRUE;
return LOOP_CONTINUE;
}
// Ende des Buches erreicht, aber Loop ist eingeschaltet
else if (CurrentBookLoopable) {
CurrentPage = 0;
MEM_InsertKeyEvent (KEY_ESCAPE);
MEM_InsertKeyEvent (MOUSE_BUTTONRIGHT);
UpdatePage = TRUE;
return LOOP_CONTINUE;
};
};
// Wenn Escape gedrückt, Loop verlassen und Buch schließen
if (EscKey == KEY_PRESSED || MouseRightKey == KEY_PRESSED)
{
return LOOP_END;
};
};
Wer noch Seitenzahlen in dem Multibook haben will, hier sind paar funktionen zum automatischen generieren via nDoc_SetPagenumbers()
Code:
func void mDoc_SetPagenumbersLayout(var int DocID){ mDoc_SetMargins (DocID, LEFT_PAGE, 375, 453, 30, 20, 1); mDoc_SetMargins (DocID, RIGHT_PAGE, 160, 453, 30, 20, 1);};func void mDoc_CreatePageNumbers(var int DocID, var int Pagenumber){ if Pagenumber > 0 { mDoc_PrintLines (DocID, Pagenumber - 1, IntToString(Pagenumber)); mDoc_CreatePageNumbers(DocID, Pagenumber - 1); };};func void mDoc_SetPagenumbers(var int DocID, var int Pagenumbers){ mDoc_SetPagenumbersLayout(DocID); mDoc_CreatePageNumbers(DocID, Pagenumbers);};
Just added few LeGo functions to obtain coloured texts in views
Interface.d
Code:
func int Print_ColoredTextField(var int x, var int y, var string text, var string font, var int height, var int color)
{
var int cnt; cnt = STR_SplitCount(text, Print_LineSeperator);
var int i; i = 1;
var int ptr; ptr = Print_CreateTextPtrColored(STR_Split(text, Print_LineSeperator, 0), font, color);
var zCViewText txt; txt = _^(ptr);
txt.posx = x;
txt.posy = y;
var int list; list = List_Create(Ptr);
var int pos; pos = MEM_StackPos.position;
if (i >= cnt) {
return list;
};
ptr = Print_CreateTextPtrColored(STR_Split(text, Print_LineSeperator, i), font, color);
txt = _^(ptr);
txt.posx = x;
txt.posy = y+(height*i);
List_Add(list, ptr);
i+=1;
MEM_StackPos.position = pos;
};
View.d
Code:
func void ViewPtr_AddTextColored(var int ptr, var int x, var int y, var string text, var string font, var int color)
{
var zCView v; v = _^(ptr);
var int field; field = Print_ColoredTextField(x, y, text, font, Print_ToVirtual(Print_GetFontHeight(font), v.pposy+v.psizey), color);
if(v.textLines_next)
{
List_Concat(v.textLines_next, field);
}
else
{
v.textLines_next = field;
};
};
func void View_AddTextColored(var int hndl, var int x, var int y, var string text, var string font, var int color) {
ViewPtr_AddTextColored(getPtr(hndl), x, y, text, font, color);
};
More aivars.
const int Aivars_Max = 50;
const int Aivars_Data = 99;
Code:
class CAivar
{
var int Data[Aivars_Max];
};
INSTANCE CAivar@(CAivar);
func void Npc_SetAivar(var c_npc slf, var int offset , var int value)
{
if(!Hlp_IsValidHandle(slf.aivar[Aivars_Data]))
{
slf.aivar[Aivars_Data] = new(CAivar@);
};
if(!Hlp_IsValidHandle(slf.aivar[Aivars_Data]))
{
return;
};
var CAivar a; a = get(slf.aivar[Aivars_Data]);
MEM_WriteStatArr(a.data, offset, value);
};
func int Npc_GetAivar(var c_npc slf, var int offset)
{
if(Hlp_IsValidHandle(slf.aivar[Aivars_Data]))
{
var CAivar a; a = get(slf.aivar[Aivars_Data]);
return MEM_ReadStatArr(a.data, offset);
};
};
func void Npc_ClearAivars(var c_npc slf)
{
if(Hlp_IsValidHandle(slf.aivar[Aivars_Data]))
{
var int i; i = 0;
repeat(i, Aivars_Max);
Npc_SetAivar(slf, i, 0);
end;
};
};
Ich find die Idee gut. Vielleicht könntest du im Einleitungspost noch eine Liste der enthaltenen Skripte aufnehmen, damit man direkt einen Überblick hat.
Wäre nicht verkehrt, wenn diese Skript-Collection eine Art Standard wird.
Das SearchWaypointByName ist etwas "veraltet". Hier hatte ich eine simplere Variante vorgeschlagen. Als Funktion könnte man das dann so aufnehmen (Code ungetestet):
Code:
...
Merke ich mir, aber nicht bevor ich es nicht getestet habe
Zitat von Siemekk
Because i finished work in Ikarus and now i'm using AST(Agama Script Tools) i decided to share my scripts
Some Engine scripts:
Code:
...
Fade Screen
Code:
...
This is all at this time. (I couldn't found my next scripts :/ )
Regards Siemekk.
Some of those miscellaneous functions sound good!
A fadescreen function should definitely be included, but your implementation is somewhat clunky and produces different results on different systems (because you don't account for FPS). I made a really short one (like below 20 lines) a while back which is easier to configure, I will add it once I have tested it.
Zitat von Fisk2033
Evtl. passt es ja in die Sammlung.
CinemaScope ist eine nette Idee, aber der Code ist ein komplettes Mysterium (ständig wird an irgendwelche undurchsichtigen Pointer geschrieben). Etwas vorzeigbares wäre sicherlich besser! Solange es funktioniert aber ein Anfang.
Das Anti-Cheat-Script ist auch gut, aber ich würde es eigentlich ungern so verfügbar machen - im Endeffekt stellt sich sowieso meistens raus, dass es ein Fehler war, die Cheats auszuschalten Wer selber so ein Script schreibt oder danach sucht hat (hoffentlich) etwas mehr darüber nachgedacht, wann es Sinn macht.
Das Dodge-Script ist ebenfalls gut, aber die Prints nehme ich mal lieber raus :P
Zitat von mud-freak
[Wld_StopEffectEx]
Ist drin
Zitat von Fisk2033
Falls das ScriptBin nochmal geupdated wird....
das muss unbedingt mit rein.
Ebenfalls könnte man folgenden BugFix fürs MultiBook einbauen:
Natürlich wird es! Aber ein alter Mann ist nunmal kein D-Zug.
Hab die beiden Funktionen eingebaut und das MultiPage-Book Script angepasst.
Zitat von Frank-95
Just added few LeGo functions to obtain coloured texts in views
Sounds nice but it looks like they'd belong in LeGo (where I will add them later ).
Cinemascope was wrote by OrcWarriorPL many years ago. I just ordered it, because script was practically illegible. Bottom part of script (strange formula) is for moving choice box bellow black bar when resolution is set at 1024x768 or lower. It's not necessary, because hardly anyone plays at these resolutions yet :P I think it may be written simplier, but I'm lazy xD
Btw. Some time ago I wrote script of temporary regeneration for my personal use, as alternative of Buffs. You can set delay and ticks. Usage is very easy. Just call fuction RE_CastEffects per frame. Example:
Code:
RE_AddEffect (self, ATR_HITPOINTS, 120, 8, 1000);
Code:
Code:
class RegenerationEffect
{
var int instance;
var int attribute;
var int value;
var int cycles;
var int cycles_current;
var int delay;
var int time;
};
instance RegenerationEffect@ (RegenerationEffect);
func void RE_AddEffect (var c_npc slf, var int attribute, var int value, var int cycles, var int delayMS)
{
var int hndl; hndl = new (RegenerationEffect@);
var RegenerationEffect effect; effect = get (hndl);
effect.instance = Hlp_GetInstanceID (slf);
effect.attribute = attribute;
effect.value = value;
effect.cycles = cycles;
effect.cycles_current = cycles;
effect.delay = delayMS;
effect.time = MEM_Timer.totalTime;
};
func void RE_CastEffect (var int hndl)
{
var RegenerationEffect effect; effect = get (hndl);
if (MEM_Timer.totalTime - effect.time < effect.delay || MEM_Game.singleStep == true)
{
return;
};
if (effect.cycles_current > 0)
{
var c_npc slf; slf = Hlp_GetNpc (effect.instance);
var int value; value = roundf (divf (mkf (effect.value), mkf (effect.cycles)));
effect.cycles_current -= 1;
effect.time = MEM_Timer.totalTime;
if (effect.cycles_current == 0 && effect.value - (value*effect.cycles) > 0)
{
value += effect.value - (value*effect.cycles);
};
if (slf.attribute[ATR_HITPOINTS] > 0)
{
Npc_ChangeAttribute (slf, effect.attribute, value);
};
};
if (effect.cycles_current == 0 || slf.attribute[ATR_HITPOINTS] == 0)
{
delete (hndl);
};
};
func void RE_CastEffects ()
{
foreachHndl (RegenerationEffect@, RE_CastEffect);
};
We use cookies to offer you a better browsing experience, personalise content and ads, to provide social media features and to analyse our traffic. Read about how we use cookies and how you can control them by clicking Cookie Settings. You consent to our cookies if you continue to use this website.