|
-
NPC soll alle Opfer in der Nähe plündern
Ich habe für unsere Jäger ein Skript geschrieben, das sie die getöteten Viecher plündern lässt. Das funktioniert auch, allerdings plündern sie immer nur eins und ignorieren die anderen. Nun habe ich schon selbst ein bisschen herumprobiert und auch schon im Forum gesucht, aber nichts gefunden, das mir bei meinem Problem wirklich weiterhilft.
Das Skript sieht so aus:
Code:
// *************************************
// ZS_RansackDeadMonster
// --------------
// wird am Ende von ZS_Attack aufgerufen
// *************************************
func void ZS_RansackDeadMonster ()
{
Perception_Set_Normal();
};
func int ZS_RansackDeadMonster_Loop ()
{
AI_StandUp (self);
// ------ zum Body gehen ------
AI_GotoNpc (self, other);
// ------ zum Body drehen ------
B_TurnToNpc (self, other);
// ------ Durchsuchen-Ani ------
AI_PlayAni (self, "T_PLUNDER");
B_TransferInventory(other, self);
return LOOP_END;
};
func void ZS_RansackDeadMonster_End ()
{
// ------ NSC heilt sich ------
if (self.attribute[ATR_HITPOINTS] < (self.attribute[ATR_HITPOINTS_MAX]/2))
{
AI_StartState (self, ZS_HealSelf, 0, "");
return;
};
};
Und wird in der ZS_Attack_End aufgerufen:
Code:
if (C_NpcIsDown(other))
&& (other.aivar[AIV_DEADMONSTERRANSACKED] == FALSE)
&& (Npc_GetDistToNpc(self, other) < PERC_DIST_INTERMEDIAT)
&& (other.aivar[AIV_MM_REAL_ID] != ID_GOBBO_BLACK)
&& (other.aivar[AIV_MM_REAL_ID] != ID_GOBBO_GREEN)
&& (other.aivar[AIV_MM_REAL_ID] != ID_GOBBO_SKELETON)
&& (other.aivar[AIV_MM_REAL_ID] != ID_SKELETON)
&& (other.aivar[AIV_MM_REAL_ID] != ID_DRAGONSNAPPER)
&& (other.aivar[AIV_MM_REAL_ID] != ID_MINECRAWLER)
&& (other.aivar[AIV_MM_REAL_ID] != ID_MINECRAWLERWARRIOR)
&& (other.aivar[AIV_MM_REAL_ID] != ID_SHADOWBEAST)
&& (other.aivar[AIV_MM_REAL_ID] != ID_STONEGOLEM)
&& (other.aivar[AIV_MM_REAL_ID] != ID_SWAMPSHARK)
&& (other.aivar[AIV_MM_REAL_ID] != ID_TROLL_BLACK)
&& (other.aivar[AIV_MM_REAL_ID] != ID_DEMON)
&& (other.aivar[AIV_MM_REAL_ID] != ID_DEMON_LORD)
&& (other.aivar[AIV_MM_REAL_ID] != ID_SHEEP)
{
if (other.guild > GIL_SEPERATOR_HUM) && (self.guild == GIL_DJG)
{
other.aivar[AIV_DEADMONSTERRANSACKED] = TRUE;
AI_StartState (self, ZS_RansackDeadMonster, 0, "");
return;
};
};
-
Dein Skriptablauf ist zurzeit in etwa:
Wenn Kampf vorbei:
> Ist der umgehauene Gegner von der Art welche ich plündern möchte? und noch nicht fürs plündern markiert?
-->Falls Ja: markiere diesen Gegner als geplündert und starte Zustand ZS_RansackDeadMonster
Im Zustand ZS_RansackDeadMonster:
gehe zu other, plündere ihn und beende die Schleife(Verlasse den Zustand und gehe eventuell in ZS_HealSelf)
Deiner Beschreibung nach möchtest du so etwas:
Wenn Kampf vorbei: starte Zustand ZS_RansackDeadMonster
Im Zustand ZS_RansackDeadMonster: Schaue nach ob in der nähe mindestens ein umgehauener Gegner von der Art herumliegt welche ich plündern möchte und noch nicht fürs plündern markiert ist.
->Falls ja: markiere und plündere einen. Wiederhole das ganze(ZS_RansackDeadMonster neu starten).
->Falls nein: Verlasse den Zustand und gehe eventuell in ZS_HealSelf.
-
Zitat von Cryp18Struct
Dein Skriptablauf ist zurzeit in etwa:
Wenn Kampf vorbei:
> Ist der umgehauene Gegner von der Art welche ich plündern möchte? und noch nicht fürs plündern markiert?
-->Falls Ja: markiere diesen Gegner als geplündert und starte Zustand ZS_RansackDeadMonster
Im Zustand ZS_RansackDeadMonster:
gehe zu other, plündere ihn und beende die Schleife(Verlasse den Zustand und gehe eventuell in ZS_HealSelf)
Deiner Beschreibung nach möchtest du so etwas:
Wenn Kampf vorbei: starte Zustand ZS_RansackDeadMonster
Im Zustand ZS_RansackDeadMonster: Schaue nach ob in der nähe mindestens ein umgehauener Gegner von der Art herumliegt welche ich plündern möchte und noch nicht fürs plündern markiert ist.
->Falls ja: markiere und plündere einen. Wiederhole das ganze(ZS_RansackDeadMonster neu starten).
->Falls nein: Verlasse den Zustand und gehe eventuell in ZS_HealSelf.
So ist es. Eigentlich müsste ich im ZS ja nur abfragen, ob in der Nähe noch mehr Gegner liegen und dann den ZS so oft wiederholen, bis alle geplündert sind. Nur wie mache ich das?
-
Code für alle npc in der nähe des Spielers ausführen geht bequem mit dieser Funktion von Sektenspinner:
https://forum.worldofplayers.de/foru...1#post17232705
Oder du iterierst halt direkt durch die active vob List(kannst du dir auch in Sektenspinners Script abschauen)
Code:
if (sphereOnly) {
/* to speed things up (and do the filtering)
* we only search the (small) active Vob List */
var int i; i = 0;
var int loop; loop = MEM_StackPos.position;
if (i < MEM_World.activeVobList_numInArray) {
var int vob;
vob = MEM_ReadIntArray(MEM_World.activeVobList_array, i);
if (Hlp_Is_oCNpc(vob)) {
var C_NPC npc;
npc = MEM_PtrToInst(vob);
// mach was
};
i += 1;
MEM_StackPos.position = loop;
};
}
-
Kann dir nicht sagen, ob es funktioniert, da ich gerade keine Möglichkeit zum Testen habe, aber ich würde es so versuchen:
Code:
// *************************************
// ZS_RansackDeadMonster
// --------------
// wird am Ende von ZS_Attack aufgerufen
// *************************************
func void ZS_RansackDeadMonster ()
{
Perception_Set_Normal();
};
func int ZS_RansackDeadMonster_Loop ()
{
AI_StandUp (self);
// ------ zum Body gehen ------
AI_GotoNpc (self, other);
// ------ zum Body drehen ------
B_TurnToNpc (self, other);
// ------ Durchsuchen-Ani ------
AI_PlayAni (self, "T_PLUNDER");
B_TransferInventory(other, self);
if (//hier abfragen ob keine toten Viecher mehr in der Nähe des NPC sind)
{
return LOOP_END;
}
//falls das nicht der Fall ist -> Loop neu starten
return LOOP_CONTINUE;
};
func void ZS_RansackDeadMonster_End ()
{
// ------ NSC heilt sich ------
if (self.attribute[ATR_HITPOINTS] < (self.attribute[ATR_HITPOINTS_MAX]/2))
{
AI_StartState (self, ZS_HealSelf, 0, "");
return;
};
};
Edit: Ich würde mir vielleicht noch eine Funktion schreiben, die deine Abfragen in der ZS_Dead_End (Npc_IsDown(...)) zusammenfasst und diese als Abfrage an meiner markierten Stelle benutzen, so prüfst du am Ende jeden Loops noch einmal alle (Monster-)Gilden und deren Ransacked-Flag um den NPC um damit den Loop wieder von vorne zu beginnen.
Diese könnte vielleicht so aussehen:
Code:
func int C_CanRansackLoop(var c_npc oth)
{
if (C_NpcIsDown(oth))
&& (other.aivar[AIV_DEADMONSTERRANSACKED] == FALSE)
&& (Npc_GetDistToNpc(self, other) < PERC_DIST_INTERMEDIAT)
&& (other.aivar[AIV_MM_REAL_ID] != ID_GOBBO_BLACK)
&& (other.aivar[AIV_MM_REAL_ID] != ID_GOBBO_GREEN)
&& (other.aivar[AIV_MM_REAL_ID] != ID_GOBBO_SKELETON)
&& (other.aivar[AIV_MM_REAL_ID] != ID_SKELETON)
&& (other.aivar[AIV_MM_REAL_ID] != ID_DRAGONSNAPPER)
&& (other.aivar[AIV_MM_REAL_ID] != ID_MINECRAWLER)
&& (other.aivar[AIV_MM_REAL_ID] != ID_MINECRAWLERWARRIOR)
&& (other.aivar[AIV_MM_REAL_ID] != ID_SHADOWBEAST)
&& (other.aivar[AIV_MM_REAL_ID] != ID_STONEGOLEM)
&& (other.aivar[AIV_MM_REAL_ID] != ID_SWAMPSHARK)
&& (other.aivar[AIV_MM_REAL_ID] != ID_TROLL_BLACK)
&& (other.aivar[AIV_MM_REAL_ID] != ID_DEMON)
&& (other.aivar[AIV_MM_REAL_ID] != ID_DEMON_LORD)
&& (other.aivar[AIV_MM_REAL_ID] != ID_SHEEP)
{
return TRUE;
};
return FALSE;
};
EDIT 2: other.aivar[AIV_DEADMONSTERRANSACKED] = TRUE; würde ich auch eher in deine ZS schreiben, damit auch für jedes geplünderte Viech das Flag gesetzt wird. Ansonsten wird das Flag evtl. nur für den zuletzt besiegten Gegner gesetzt, da dort der ZS_Attack ja endet.
Geändert von GenerationLost (26.07.2017 um 12:48 Uhr)
-
Vielen Dank euch beiden. Ich hatte es gestern schon geschafft, aber keine große Lust mehr zu schreiben. ^^
Mit diesem Skript funktioniert es:
Code:
// *************************************
// ZS_RansackDeadMonster
// ---------------------
// wird am Ende von ZS_Attack aufgerufen
// *************************************
var int DeadMonsterWithLootNearMe;
func void CheckDeadMonstersNearMe (var C_NPC Monster)
{
if (C_NpcIsDown(Monster))
&& (Npc_GetDistToNpc(self, Monster) < PERC_DIST_INTERMEDIAT)
&& (Monster.aivar[AIV_DEADMONSTERRANSACKED] == FALSE)
&& (Npc_GetInvItemBySlot (Monster, 0, 0) > 0)
// --- FOLGENDE MONSTER WERDEN !NICHT! GEPLÜNDERT ---
&& (Monster.aivar[AIV_MM_REAL_ID] != ID_GOBBO_BLACK)
&& (Monster.aivar[AIV_MM_REAL_ID] != ID_GOBBO_GREEN)
&& (Monster.aivar[AIV_MM_REAL_ID] != ID_GOBBO_SKELETON)
&& (Monster.aivar[AIV_MM_REAL_ID] != ID_SKELETON)
&& (Monster.aivar[AIV_MM_REAL_ID] != ID_DRAGONSNAPPER)
&& (Monster.aivar[AIV_MM_REAL_ID] != ID_MINECRAWLER)
&& (Monster.aivar[AIV_MM_REAL_ID] != ID_MINECRAWLERWARRIOR)
&& (Monster.aivar[AIV_MM_REAL_ID] != ID_SHADOWBEAST)
&& (Monster.aivar[AIV_MM_REAL_ID] != ID_STONEGOLEM)
&& (Monster.aivar[AIV_MM_REAL_ID] != ID_SWAMPSHARK)
&& (Monster.aivar[AIV_MM_REAL_ID] != ID_TROLL_BLACK)
&& (Monster.aivar[AIV_MM_REAL_ID] != ID_DEMON)
&& (Monster.aivar[AIV_MM_REAL_ID] != ID_DEMON_LORD)
&& (Monster.aivar[AIV_MM_REAL_ID] != ID_SHEEP)
{
DeadMonsterWithLootNearMe = TRUE;
Monster.aivar[AIV_DEADMONSTERRANSACKED] = TRUE;
AI_StandUp (self);
AI_GotoNpc (self, Monster);
B_TurnToNpc (self, Monster);
AI_PlayAni (self, "T_PLUNDER");
B_TransverInventory (Monster, self);
} else {
DeadMonsterWithLootNearMe = FALSE;
};
};
func void ZS_RansackDeadMonster ()
{
Perception_Set_Normal();
self.aivar[AIV_RANSACKDEADMONSTER] = TRUE;
};
func int ZS_RansackDeadMonster_Loop ()
{
DoForSphere (CheckDeadMonstersNearMe);
if (DeadMonsterWithLootNearMe == FALSE)
{
self.aivar[AIV_RANSACKDEADMONSTER] = FALSE;
return LOOP_END;
};
};
func void ZS_RansackDeadMonster_End ()
{
// ------ NSC heilt sich ------
if (self.attribute[ATR_HITPOINTS] < (self.attribute[ATR_HITPOINTS_MAX]/2))
{
AI_StartState (self, ZS_HealSelf, 0, "");
return;
};
AI_ContinueRoutine (self);
};
Benötigt wird https://forum.worldofplayers.de/forum/threads/775333-Script-Broadcasts?p=17232705&viewfull=1#post17232705 und auch dieses Skript https://forum.worldofplayers.de/forum/threads/199081-npc-soll-anderen-npc-ausbeuten?p=3146927#post3146927, wenn man die Funktion B_TransverInventory verwenden will. Die Aivars AIV_RANSACKDEADMONSTER und AIV_DEADMONSTERRANSACKED müssen auch in die AI_Constants eingetragen werden.
In die ZS_Attack muss unter AI_RemoveWeapon noch das:
Code:
if (other.guild > GIL_SEPERATOR_HUM) && (self.guild == GIL_DJG)
{
AI_StartState (self, ZS_RansackDeadMonster, 0, "");
};
Diese Funktion sollte man aber noch anpassen, da vermutlich nicht jeder will, dass alle NPCs mit der Gilde "Drachenjäger" tote Monster ausnehmen.
Geändert von Bloodfly91 (26.07.2017 um 14:42 Uhr)
Berechtigungen
- Neue Themen erstellen: Nein
- Themen beantworten: Nein
- Anhänge hochladen: Nein
- Beiträge bearbeiten: Nein
|
|