Ergebnis 1 bis 20 von 1418

Thema: Technik-Sammelthread für Probleme und Antworten

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Hai!

    Ich bräuchte Hilfe bei einem Skript.
    Folgende Situation:
    Ich habe in der Spielwelt verschiedene Arten von Pflanzen, die der Spieler aufsammeln kann, diese sollen je nach Art zu einer bestimmten Zeit respawnen.
    Der Timer wird durch eine Variabel Uhr gesteuert. Nachdem eine Pflanze aufgesammelt wurde, darf sie natürlich nicht wieder sammelbar sein bis der
    Befehl vom respawntimer kommt.

    Mein Problem: Gibt es eine Möglichkeit obiges zu erzielen, ohne für jede einzelne Pflanze einen Switch zu setzen, um sie bis zum respawnen der Pflanzenart "auszuschalten"?
    Irgendwie komme ich auf keinen grünen Zweig.

    Bin auch für alternative Ideen und Vorschläge offen^^

    Danke!

  2. #2
    Dieser Code geht davon aus dass 5000 die höchste verwendete Variablen-ID ist. Solltest du höhere Variablen verwenden, musst du die Zahl "5000" im Code entsprechend ändern.
    Für die anderen Variablen habe ich keine ID angegeben, da kannst du beliebige nehmen.

    Es wird ein assoziatives Array implementiert, in Variablen NACH DEM ENDE DER DEFINIERTEN, also wenn z.B. 5000 die höchste eingestellte Variable ist, werden Variablen ab #5001 verwendet. Diese erscheinen NICHT im F9-Menü!

    Es werden Daten in je 2 Variablen gespeichert, einmal ein Schlüssel, einmal ein Wert. Das Ende der Liste wird durch Schlüssel 0 signalisiert.

    Dieses Skript kodiert Map ID und Event ID in einem Schlüssel. In dem assoziativen Array speichert jedes Pflanzenevent den Zeitpunkt an dem es respawnt wird, oder 0 wenn es gerade sichtbar und aktiv ist. Es gibt ein Common Event was den Timer verwaltet und bei Bedarf Events respawnt oder beim Mapwechsel erneut deaktiviert, je nach Bedarf.

    Auf diese Weise kann man Pflanzen einfach kopieren. Pflanzen haben 3 Eventseiten, Eventseite 1 dient dazu, eine Pflanze zu respawnen, während Eventseite 2 sie deaktiviert. Dies passiert nach außen rein über die Eventgrafik (leer = deaktiviert). Eventseite 3 ist die, die beim Enterdruck ausgeführt wird. Da wird u.a. die Respawnzeit der Pflanze festgelegt sowie was genau passieren soll wenn man eine aktive Pflanze anspricht.

    Das Skript geht von maximal 1000 Events auf einer Map aus, obwohl der Maker afaik 9999 erlaubt, sowie maximal 9999 Maps (ich gehe davon aus du verwendest den 2k3, sonst wären es 999 Maps). Solltest du tatsächlich mehr verwenden, musst du die Zahl "1000" im Code ändern, allerdings je mehr Events du erlaubst, desto weniger Maps sind möglich. 1000 sollte also normalerweise gut passen.

    WARNUNG: Das ganze entstand gerade hier aus meinem Kopf. Ich habe es nicht getestet!

    Common Event "GetAssocValue":
    <> Comment: Dieses CE dient dazu, einen Wert anhand eines Schlüssels aus unserem assoziativen Array zu lesen.
    <> Comment: Skript erwartet Schlüssel in Variable [AKey] und liefert Ergebnis in Variable [AValue] oder 0 wenn Schlüssel nicht vorhanden
    <> Comment: Alle Elemente des assoziativen Arrays werden abgeklappert.
    <> Change Variable [AIndexCounter] = 5000
    <> Comment: Standardwert ist 0.
    <> Change Variable [AValue] = 0
    <> Label: 1
    <> Change Variable [AIndexCounter] += 1
    <> Change Variable [ATempKey] = V[V[AIndexCounter]]
    <> Comment: Ist der Schlüssel 0, wäre das Ende der Liste erreicht.
    <> Fork Condition: If V[ATempKey] != 0
    ....<> Change Variable [AIndexCounter] += 1
    ....<> Fork Condition: If V[ATempKey] != V[AKey]
    ........<> Comment: Weitersuchen
    ........<> Go To Label: 1
    ........<>
    ....: Else Case
    ........<> Comment: Schlüssel gefunden, Wert einlesen
    ........<> Change Variable [AValue] = V[V[AIndexCounter]]
    ........<>
    ....: End Case
    ....<>
    : End Case

    Common Event "SetAssocValue":
    <> Comment: Dieses CE dient dazu, einen Wert anhand eines Schlüssels in unserem assoziativen Array zu speichern.
    <> Comment: Skript erwartet Schlüssel in Variable [AKey] und Wert in Variable [AValue]
    <> Comment: Alle Elemente des assoziativen Arrays werden abgeklappert.
    <> Change Variable [AIndexCounter] = 5000
    <> Label: 1
    <> Change Variable [AIndexCounter] += 1
    <> Change Variable [ATempKey] = V[V[AIndexCounter]]
    <> Comment: Wenn der Schlüssel nicht 0 ist, ist der Slot schon belegt.
    <> Fork Condition: If V[ATempKey] != 0
    ....<> Comment: In diesem Fall stellen wir sicher, dass wir den gesuchten Schlüssel gefunden haben.
    ....<> Fork Condition: If V[ATempKey] != V[AKey]
    ........<> Comment: Weitersuchen
    ........<> Change Variable [AIndexCounter] += 1
    ........<> Go To Label: 1
    ........<>
    ....: End Case
    ....<>
    : Else Case
    ....<> Comment: Der Schlüssel ist 0, d.h. der Slot ist frei (Ende der Liste erreicht), wir legen hier also den neuen Schlüssel fest.
    ....<> Change Variable [V[AIndexCounter]] = V[AKey]
    ....<>
    : End Case
    <> Comment: Wert wird gesetzt.
    <> Change Variable [AIndexCounter] += 1
    <> Change Variable [V[AIndexCounter]] = V[AValue]

    Pflanzenevent Seite 1 (keine Startbedingungen, On Key Press):
    <> Comment: Diese Eventseite wird gecallt wenn das Event respawnt wird
    <> Move Event: This Event => Change Event Graphic (Die Grafik die die Pflanze im Normalfall haben soll)

    Pflanzenevent Seite 2 (keine Startbedingungen, On Key Press):
    <> Comment: Diese Eventseite wird gecallt wenn das Event deaktiviert wird
    <> Move Event: This Event => Change Event Graphic (Leeres Tile im Upper Layer oben links)

    Pflanzenevent Seite 3 (keine Startbedingungen, On Key Press):
    <> Comment: Diese Eventseite wird im Normalfall gecallt (wenn der Spieler das Event anspricht)
    <> Comment: Hier wird der Schlüssel zusammengebaut. Er besteht aus Map ID * 1000 + Event ID, also z.B. 34009 für Map 34, Event 9
    <> Change Variable [AKey] = Map ID of This Event
    <> Change Variable [AKey] *= 1000
    <> Change Variable [X] = X of This Event
    <> Change Variable [Y] = Y of This Event
    <> Get Event ID (V[X], V[Y]) => [EventID]
    <> Change Variable [AKey] += V[EventID]
    <> Comment: Der aktuell gespeicherte Wert für dieses Event wird aus dem assoziativen Array gelesen. Ist er 0, heißt das, das Event ist aktiv!
    <> Call Common Event: GetAssocValue
    <> Fork Condition: If V[AValue] == 0
    ....<> *********************************** HIER CODE EINFÜGEN DER BEIM ANSPRECHEN DES AKTIVEN (!) EVENTS PASSIEREN SOLL, z.B. "Du hast die Pflanze gepflückt" o.ä.
    ....<> Comment: Das Event wird jetzt deaktiviert.
    ....<> Change Variable [PageID] = 2
    ....<> Call Map Event: ID V[EventID], Page V[PageID]
    ....<> Change Variable [AValue] = V[GlobalTimer]
    ....<> Comment: ***** HIER DIE DAUER IN SEKUNDEN EINSTELLEN DIE DAS EVENT ZUM RESPAWNEN BRAUCHT! *****
    ....<> Change Variable [AValue] += 300
    ....<> Comment: Der Zeitpunkt, zu der das Event respawnt werden soll, wird im assoziativen Array gespeichert.
    ....<> Call Common Event: SetAssocValue
    ....<>
    : End Case

    Parallel Process Common Event: "TimerUpdate"
    <> Comment: Dieses Common Event updatet den Timer und sorgt dafür dass deaktivierte Events beim Mapwechsel automatisch wieder deaktiviert werden.
    <> Label: 1
    <> Change Variable [TMapID] = Map ID of Hero
    <> Comment: In FrameCounter wird die Anzahl Frames seit der letzten Sekundenzählung gespeichert. Eine Sekunde hat 60 Frames.
    <> Comment: GlobalTimer enthält die Anzahl Sekunden seit Beginn des Spiels. Ist FrameCounter 0, gilt eine Sekunde als abgelaufen und GlobalTimer erhöht.
    <> Comment: Zu Beginn des Spiels ist FrameCounter 0, GlobalTimer wird also sofort um 1 erhöht, dadurch ist es nie 0 (was wir ja als "Event aktiv" verwenden).
    <> Fork Condition: If V[FrameCounter] == 0
    ....<> Change Variable [GlobalTimer] += 1
    ....<> Comment: Alle Elemente des assoziativen Arrays werden abgeklappert.
    ....<> Change Variable [TIndexCounter] = 5000
    ....<> Label: 2
    ....<> Change Variable [TIndexCounter] += 1
    ....<> Change Variable [TTempKey] = V[V[TIndexCounter]]
    ....<> Comment: Ist der Schlüssel 0, wäre das Ende der Liste erreicht.
    ....<> Fork Condition: If V[TTempKey] != 0
    ........<> Change Variable [TIndexCounter] += 1
    ........<> Change Variable [TTempMapID] = V[TTempKey]
    ........<> Change Variable [TTempMapID] /= 1000
    ........<> Comment: Nur Events auf der aktuellen Map werden berücksichtigt.
    ........<> Fork Condition: If V[TTempMapID] == V[TMapID]
    ............<> Change Variable [TTempValue] = V[V[TIndexCounter]]
    ............<> Comment: Ist das Event bereits aktiv, weitersuchen
    ............<> Fork Condition: If V[TTempValue] == 0
    ................<> Go To Label: 2
    ................<>
    ............: End Case
    ............<> Comment: Ist der Respawnzeitpunkt erreicht oder überschritten, wird das Event respawnt.
    ............<> Fork Condition: If V[TTempValue] < V[GlobalTimer]
    ................<> Comment: Wert wird auf 0 für "Event aktiv" gesetzt und Eventseite 1 aufgerufen (wo die Grafik auf Normalgrafik geändert wird).
    ................<> Change Variable V[V[TIndexCounter]] = 0
    ................<> Change Variable [TTempKey] Mod= 1000
    ................<> Change Variable [TPageID] = 1
    ................<> Call Map Event: ID V[TTempKey], Page V[TPageID]
    ................<>
    ............: End Case
    ............<>
    ........: End Case
    ........<> Go To Label: 2
    ........<>
    ....: End Case
    ....<>
    : End Case
    <> Comment: Wenn die Map gewechselt wurde, werden alle Events auf der neuen Map bei Bedarf deaktiviert, wenn sie nicht aktiv sein sollen
    <> Fork Condition: If V[TMapID] != V[TLastMapID]
    ....<> Change Variable [TLastMapID] = V[TMapID]
    ....<> Comment: Alle Elemente des assoziativen Arrays werden abgeklappert.
    ....<> Change Variable [TIndexCounter] = 5000
    ....<> Label: 3
    ....<> Change Variable [TIndexCounter] += 1
    ....<> Change Variable [TTempKey] = V[V[TIndexCounter]]
    ....<> Comment: Ist der Schlüssel 0, wäre das Ende der Liste erreicht.
    ....<> Fork Condition: If V[TTempKey] != 0
    ........<> Change Variable [TIndexCounter] += 1
    ........<> Change Variable [TTempMapID] = V[TTempKey]
    ........<> Change Variable [TTempMapID] /= 1000
    ........<> Comment: Nur Events auf der aktuellen Map werden berücksichtigt.
    ........<> Fork Condition: If V[TTempMapID] == V[TMapID]
    ............<> Change Variable [TTempValue] = V[V[TIndexCounter]]
    ............<> Comment: Nur deaktivierte Events werden berücksichtigt.
    ............<> Fork Condition: If V[TTempValue] != 0
    ................<> Comment. Eventseite 2 wird aufgerufen damit das Event unsichtbar (und durchgängig) wird.
    ................<> Change Variable [TTempKey] Mod= 1000
    ................<> Change Variable [TPageID] = 2
    ................<> Call Map Event: ID V[TTempKey], Page V[TPageID]
    ................<>
    ............: End Case
    ............<>
    ........: End Case
    ........<> Go To Label: 3
    ........<>
    ....: End Case
    ....<>
    : End Case
    <> Comment: Eigentlich ist am Ende eines PP automatisch ein 1-Frame-Wait, aber um auf Nummer sicher zu gehen, machen wir das Wait selber und verwenden Label 1 als Loop.
    <> Wait 0.0s
    <> Comment: FrameCounter wird erhöht und wenn er 60 wäre, auf 0 gesetzt.
    <> Change Variable: [FrameCounter] += 1
    <> Change Variable: [FrameCounter] Mod= 60
    <> Go To Label: 1

    Geändert von Cherry (14.08.2012 um 15:41 Uhr)

  3. #3
    Wow, danke für die Mühe!

    Habe das Skript so umgesetzt, aber das Spiel stürzt ab sobald ich es starte mit der Meldung: "Eventscript referenced an event that does not exist."
    Das bezieht sich auf den ersten Call Map Event Befehl im Update Timer CE: ................<> Call Map Event: ID V[TTempKey], Page V[TPageID]
    Wenn der weg ist, stürzt das Spiel zwar nicht ab, aber es stockt für einige Sekunden, danach gehts kurz weiter, aber dann wieder Pause.

    Was genau muss ich eigentlich bei: ....<> Comment: ***** HIER DIE DAUER IN SEKUNDEN EINSTELLEN DIE DAS EVENT ZUM RESPAWNEN BRAUCHT! *****
    eingeben? Eine fork condition, die die GlobalTimer Variable abfragt?

  4. #4
    Zuerst hab ich noch einen kleinen Fehler gefunden (bzw. das macht es halt suboptimal):
    Vor der Zeile "<> Comment: Ist der Respawnzeitpunkt erreicht oder überschritten, wird das Event respawnt." muss folgendes eingefügt werden:

    ............<> Comment: Ist das Event bereits aktiv, weitersuchen
    ............<> Fork Condition: If V[TTempValue] == 0
    ................<> Go To Label: 2
    ................<>
    ............: End Case

    Zu deinem ersten Problem: Ich vermute mal, du hast irgendwas falsch nachgebaut. Ich verwende hier C-Notation für Forks, d.h. "==" heißt equal, "!=" heißt not equal. Es schaut für mich aus als wenn du bei "<> Fork Condition: If V[TTempKey] != 0" statt "not equal" "equal" eingestellt hättest... Außerdem stelle sicher, dass V[...] und V[V[...]] richtig eingestellt ist (das erste ist "Variable", das zweite "Variable No.").

    Zu deiner zweiten Frage: Das bezieht sich auf die Zeile drunter, "<> Change Variable [AValue] += 300". Ich hab da im Moment 300 eingestellt, das wären 5 Minuten.

  5. #5
    Dass "!=" not equal heißt wusste ich in der Tat nicht. Jetzt ruckelt und stürzt auch nichts ab. Aber das Respawnen scheint nicht zu funktionieren bzw. wenn die Map verlassen wird und dann gleich wieder betreten wird ist die Pflanze wieder sichtbar, egal auf was die Variable [AValue] an der betreffenden Stelle gesetzt wurde.

  6. #6
    Schick mir doch mal das Projekt oder zumindest die Database und die Map-Datei, dann muss ich das Skript nicht selber auch noch nachbauen um es zu testen!

  7. #7
    Der grüne Schleim ist die Pflanze.
    Angehängte Dateien Angehängte Dateien

  8. #8
    Sry, war zum Teil mein Fehler.

    Dein Fehler war: du hattest noch zweimal "equal" statt "not equal" drin und einmal "Modulus" statt "Divide".

    Mein Fehler war dass ich einmal "TMapID" und einmal "MapID" in TimerUpdate verwendet habe, obwohl es dieselbe Variable sein sollte. Ich hab jetzt überall TMapID verwendet.
    Außerdem hab ich bemerkt dass "<> Change Variable [TMapID] = Map ID of Hero" in TimerUpdate am besten direkt unter "<> Label: 1" gehört und noch ein paar andere Kleinigkeiten korrigiert...

    Ich hab jetzt alles korrigiert, es läuft jetzt. Ich hab gleich 4 Pflanzen-Schleime hingepackt und statt 5 Minuten 5 Sekunden eingestellt sodass man den Effekt gut testen kann.
    http://share.cherrytree.at/showfile-...st_projekt.rar

    Verstehst du eigentlich, wie das Skript funktioniert?

  9. #9
    Zitat Zitat von Cherry Beitrag anzeigen
    Dein Fehler war: du hattest noch zweimal "equal" statt "not equal" drin und einmal "Modulus" statt "Divide".
    Ach Mann, dabei hab ich alles nochmal gründlich durchgeguckt -.- Tut mir Leid. ^^"


    Zitat Zitat von Cherry Beitrag anzeigen
    Verstehst du eigentlich, wie das Skript funktioniert?
    Ja, ehh, nein... nicht ganz. Wie die Funktionsweise dahinter ist schon, aber im Detail nicht so richtig. ^^"

    Mir ist aufgefallen, dass es vorkommen kann, dass man eine Pflanze mehrmals ansprechen kann nachdem sie verschwunden ist
    und somit natürlich zum Ausnutzen verleitet falls jemand ausversehen noch einmal Enter drückt. Also ein Bug

    Ich weiß nicht welchem Muster das folgt, aber ich glaube die ersten Pflanzen sind nicht betroffen, sondern welche die danach respawnen während man noch auf der Map ist.
    Bin mir aber da auch nicht ganz sicher.

    Du sagtest man kann 1000 solcher Events pro Map haben? Oder insgesamt? Das heißt es gibt keine bestimmte Gesamtzahl, die nicht überschritten werden darf, also global?
    Die einzige Grenze stellt also das Map Limit dar? Und wieviele Maps sind jetzt noch möglich? Werden die bis zu 1000 Events vom 9999 Map Limit subtrahiert?

  10. #10
    Ich glaube mein Fehler war in GetAssocValue:

    Statt:


    <> Fork Condition: If V[ATempKey] != 0
    ....<> Fork Condition: If V[ATempKey] != V[AKey]
    ........<> Comment: Weitersuchen
    ........<> Go To Label: 1
    ........<>
    ....: Else Case
    ........<> Comment: Schlüssel gefunden, Wert einlesen
    ........<> Change Variable [AIndexCounter] += 1
    ........<> Change Variable [AValue] = V[V[AIndexCounter]]


    ...gehört:

    <> Fork Condition: If V[ATempKey] != 0
    ....<> Change Variable [AIndexCounter] += 1
    ....<> Fork Condition: If V[ATempKey] != V[AKey]
    ........<> Comment: Weitersuchen
    ........<> Go To Label: 1
    ........<>
    ....: Else Case
    ........<> Comment: Schlüssel gefunden, Wert einlesen
    ........<> Change Variable [AValue] = V[V[AIndexCounter]]


    Das Limit ist übrigens so gemeint, dass keine Event ID einer Pflanze je höher als 1000 sein darf. Insgesamt ist es aber egal wie viele Pflanzen zu pflanzt.

    Das Limit entsteht aus dem Variableninhaltslimit des RM2k3. Eine Variable kann von -9999999 bis +9999999 gehen. Das Skript kodiert eine Pflanzen-ID als "Map-ID * 1000 + Event-ID", also z.B. 147092 wenn die Map-ID 147 und die Event-ID 92 ist, und so entsteht das Limit. Wenn man tatsächlich mehr als 1000 Events auf einer Map haben sollte (was mich wundern würde), kann man die Zahl "1000" in den Skripts ändern sodass er dann z.B. "Map-ID * 2000 + Event-ID" rechnet, was natürlich dann die maximale Anzahl Maps halbiert.

    Geändert von Cherry (14.08.2012 um 15:46 Uhr)

  11. #11
    Okay, jetzt funktioniert alles! Vielen vielen Dank für deine Hilfe!

    Gut, das mit dem Limit hab ich jetzt auch verstanden.

    Mhhh... Habe jetzt irgendwie noch ein Problem mit den Conditions:
    Wenn ein Monster einen Status mit "No Action Allowed" (sowas wie z.B: Schlaf) hat, dann blinkt es trotzdem auf, der Enemy Attack Sound kommt und Punch A wird ausgeführt aber nicht gezeigt, nur der Sound (also die drei Hit sounds). Wenn ich Punch A von den Animations lösche kommt letzteres natürlich nicht mehr. Die Monster greifen nicht an, und machen auch sonst nichts außer das was ich genannt habe, wenn sie den Status haben. Meine Monster besitzen keine Standard Attacke sondern nutzen immer Skills als "standard" Attacken.

    Ich benutze ja DynRPG. Ist das vielleicht so gewollt oder auch im standard normal?

    Dann habe ich noch ein Problem und zwar:
    Ich habe diesen Zustand (Schlaf) darauf eingestellt, dass er weggeht wenn der Betreffende Schaden nimmt, Rundenanzahl auf 0 und Chance auf Heilung in jeder Runde auf 0% (auch mal auf 999 und 100%). Aber es scheint, dass einer meiner Charaktere bei manchen Angriffen egal ob er Schaden macht oder nicht, das Monster nicht aufwecken kann. Durch welche Art Schaden geht der Status weg und durch welchen nicht? Der andere Charakter kann Angreifen und Skills benutzen, beides führt zum verschwinden des Status beim Gegner, sofern er Schaden macht.

  12. #12
    Zitat Zitat von Chili Beitrag anzeigen
    Mhhh... Habe jetzt irgendwie noch ein Problem mit den Conditions:
    Wenn ein Monster einen Status mit "No Action Allowed" (sowas wie z.B: Schlaf) hat, dann blinkt es trotzdem auf, der Enemy Attack Sound kommt und Punch A wird ausgeführt aber nicht gezeigt, nur der Sound (also die drei Hit sounds). Wenn ich Punch A von den Animations lösche kommt letzteres natürlich nicht mehr. Die Monster greifen nicht an, und machen auch sonst nichts außer das was ich genannt habe, wenn sie den Status haben. Meine Monster besitzen keine Standard Attacke sondern nutzen immer Skills als "standard" Attacken.
    Das ist ungewöhnlich, ich kann mir nicht erinnern das schonmal gehört zu haben. Ich schreibs aber auf die Bug-Überprüfungsliste (normal ist es nicht)...

  13. #13
    Zum Standardangriff:
    Es gibt wenig bis nichts, was davon abhält, einen Skill zu bauen, der einfach 100% AP + 0 Basic Effect enthält und 0 Mana kostet, das wäre dann ein Ersatz-Standardangriff. Dadurch ist man das Problem los mit Animation 0 und dem Sound aus der DB und mit einem Arbeitsaufwand von weniger als 25 Sekunden pro Skill kann man Monstern Standardangriffe geben, die zu ihnen passen zB einen Schwertangriff für den Schwertkämpfer und einen Pfeilangriff für den Bogenschützen statt einem Knüppelangriff für den Schwertkämpfer, einem Knüppelangriff für den Bogenschützen, einem Knüppelangriff für den Magier, einem Knüppelangriff für den Drachen. You get it i guess ;-)

    Zum Sound in der DB:
    Stell den Standard-Attacksound mal auf einen anderen weniger penetranten Sound ;-) Ich hatte mal den Bug irgendwo, dass sich der Maker einen Sound "gemerkt" hat, obwohl der in der DB nicht mehr gewählt ist.

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •