Not logged inClonkspot Forum
Forum Home Help Search Register Login
Up Topic Deutsch / Hilfestellung / [Gelöst] "AddLight" abändern, weil sonst Gebäude
1 2 Previous Next  
- - By Serpens66 (More than 200 posts.) Date 14.09.2014 11:00 Edited 01.10.2014 12:53
Hi,
die Gebäude aus CognitionAlliance bzw. Space Launch haben ja so eine coole Lichtfunktion, welche ich nun auch schon für andere Objekte übernommen habe, um für mehr Licht zu sorgen.
Die Funktionen im Skript dafür sind ziemlich einfach, zusätzlich kann man halt noch selbst in einer weiteren Funktion bestimmen, wann das Licht ausgelöst werden soll:

private func TurnLightOn()
{
  var iColor;
  iColor = RGBa(235,150,10,50);
  mlight = AddLight(1000, iColor, this());
  return(1);
}

private func TurnLightOff()
{
  if (mlight) RemoveObject(mlight);
  return(1);
}


Erstmal die Frage:
Ist dieser "AddLight" Befehl ein fester befehl in der Engine? Ich vermute mal ja, weil im Skript dieser Befehl nirgends definiert ist und es auch keine Verweise zu anderen Skripten gibt.

Nun ist aber das Problem, dass dieses Licht offensichtlich als Gebäude gewertet wird. Da ich aber Funktionen wie "reparieren" und Gebäude abreißen" verwende, wird auch das Licht als mögliches Ziel ausgegeben. Das ist natürlich quatsch und muss ich irgendwie abstellen.

Eigentlich dachte ich mir, ich ändere beim Licht entweder, dass es kein Gebäude mehr ist, oder ich füge eine Eigenschaft hinzu, die ich dann beim reparieren/abreißen ausschließe.
Aber bei dem Befehl "AddLight" wüsste ich nicht, wie ich rausfinde, welche Eigenschaften daraus folgen und ob/wie ich das ändern kann.
Parent - - By Zapper (More than 500 posts.) Date 14.09.2014 11:05

>Ist dieser "AddLight" Befehl ein fester befehl in der Engine? Ich vermute mal ja, weil im Skript dieser Befehl nirgends definiert ist und es auch keine Verweise zu anderen Skripten gibt.


Ich glaube, der kommt aus dem Hazardpack.

PS: Es gibt die Funktion "LocateFunc" um rauszufinden, wo eine andere Funktion definiert wird. Kannst ja mal im Spiel LocateFunc("AddLight") eintippen und gucken was rauskommt.
Parent - - By Serpens66 (More than 200 posts.) Date 14.09.2014 11:36
okay, guter Hinweis, danke :)

wo tippe ich das denn ein? In ein Script und dann ein Testspiel starten, oder wie mache ich das?
Wenn wir schon bei Suchfunktion sind, gibt es eine Möglichkeit eine ID zu finden? Also z.b wenn ich über ein script stolpere, welches z.b. "DSFK" verwendet, wie finde ich dieses Objekt dann möglichst effektiv?
Parent - - By Luchs (More than 1000 posts.) Date 14.09.2014 11:51
Wenn du im Entwickler-Modus startest (Kommandozeilenargument `/console`), dann ist direkt im Hauptfenster ein Eingabefeld.

Zum ID suchen kannst du bei entpackten Paketen eine einfache Textinhaltsuche auf DefCore.txt-Dateien machen (z.B. mit grep).
Parent - - By Serpens66 (More than 200 posts.) Date 14.09.2014 12:07 Edited 14.09.2014 12:10
Danke für den Hinweis mit dem entpackten Dateien, das ist natürlich eine gute idee. Nur leider funktioniert das entpacken großer Objektpakete selten. Es dauert einige Minuten und danach funktionieren viele Dinge nicht mehr (weil fehlerhaft entpackt) -.-  zum Glück sichere ich die Dateien immer, bevor ich das entpacken versuche, sodass ich es rückgängig machen kann.  Das heißt entpacken kann ich nur kleinere Pakete fehlerfrei, aber auch das mache ich wenn möglich immer wieder rückgängig, um fehler zu vermeiden.

Was meint ihr mit "entwickler Modus" ?  Soweit ich sehe gibt es doch nur das Spiel und den Editor. Ist der Editor nicht automatisch im Entwicklermodus?
Beim Editor ist unten ein Eingabefeld. Soll ich da was reinschreiben? Wenn ich "LocateFunc("AddLight")" reinschreibe und Enter drücke, wird automatisch die Clonk.exe vorgeschoben und das Spiel startet, also ist das wohl nicht das richtige feld?

Danke auch an Gecko für die Funktion, ich brauch aber halt den Ort selbst. wenn eine ID fehlt, dann merke ich das meistens auch im Testspiel selbst, wenn die entsprechene Fehlermeldung kommt.

EDIT: achso, also ein Spiel aus dem Editor aus starten und dann in diesem Engine Fenster die Funnktion LocateFunc("AddLight") eingeben. mache ich jetzt mal, und editere dann hier.
Edit2: hab den Ort nun gefunden, Space Empire.c4d\Hazard.c4d\Effects.c4d\Light.c4d\Script.c:98     dann schau ich dort mal rein :) danke.
Parent - By Luchs (More than 1000 posts.) Date 14.09.2014 18:10

>Nur leider funktioniert das entpacken großer Objektpakete selten. Es dauert einige Minuten und danach funktionieren viele Dinge nicht mehr (weil fehlerhaft entpackt) -.-


Huh. Du könntest vielleicht mal versuchen, direkt mit c4group zu entpacken. Also über die Kommandozeile `c4group foo.c4d -x`
Parent - By Gecko (More than 500 posts.) Date 14.09.2014 11:52
Du kannst in der Commandozeile der Engine (.. wenn du aus dem Entwicklermodus startest) jeden Script eingeben.
Also das Fenster, wo man auch den Pinsel zum Kartenzeichnen hat. Dieses Texteingabefeld im unteren Bereich.

Man kann sich relativ schnell eine Funktion schreiben, zum Testen.

func TestForID(id tid){

var pIDTest = CreateObject(tid,0,0,-1);

if(pIDTest){
   RemoveObject(pIDTest);
   return true;
} else {
   return false;
}
}


Aber vermutlich entsteht schon bei CreateObject ein Fehler, falls die ID nicht existent ist. Von daher sollte auch einfach CreateObject() reichen. :D

EDIT:
Ach so, es wird natürlich keine Auskunft über den Ort geben, hab ich irgendwie überlesen.. Aber du weißt dann wenigstens, ob das Object in den Vorgaben vorhanden ist..
Parent - By Zapper (More than 500 posts.) Date 14.09.2014 12:02
Wie Luchs meinte: Einfach irgendein Szenario im Entwicklermodus starten.

Du bekommst den Namen zu einer ID per GetName, also zB GetName(0, DSFK). Den Rest musst du raten :)
- - By Serpens66 (More than 200 posts.) Date 14.09.2014 13:21
So....

im Skript vom Lichtobjekt mit der ID LIGH steht unter anderem:
global func AddLight(int iSize, int iColor, object pTarget) {
  if(!pTarget)
    if(!(pTarget = this()))
      return();
 
  return(CreateLight(LIGH, iSize, iColor, pTarget));
}


die Category in der Defcore vom Objekt LIGH , ist "C4D_Foreground|C4D_MouseIgnore|C4D_Vehicle".

So, die Funktionsweise von "abreißen" ist in einem Clonk appendto so gergelt:

/* Gebäude-Abriss */

public func ContextDestruction()
{
  [Abreißen|Image=SYF1|Condition=BackAnything]
  var obj = BackAnything();
  if (!obj) return(1);
  CreateMenu(SYF1);
  AddMenuItem("%s abreißen","DoDestruction",GetID(obj),0,0,obj);
  AddMenuItem("Zurück","NoDestruction",SYCC);
}

private func BackBuilding()
{
  var obj;
  while (obj = FindObjectOwner(0,GetOwner(), -1,+9,0,0, OCF_Exclusive(), 0,0,obj))
//    if (GetCategory(obj) & C4D_Structure())
//      if (GetCon(obj) >= 100)
        if (!FindObject(DSTR,0,0,0,0,0,"Destruct",obj))
          return(obj);
  return(0);
}

private func BackConstruct()
{
  var obj;
  while (obj = FindObjectOwner(0,GetOwner(), -20,+8,40,5, OCF_Construct(), 0,0,obj))
//   if (GetCategory(obj) & C4D_Structure())
      if (!FindObject(DSTR,0,0,0,0,0,"Destruct",obj))
        return(obj);
  obj = 0;
  while (obj = FindObjectOwner(0,GetOwner(), -1,+9,0,0, OCF_Construct(), 0,0,obj))
//    if (GetCategory(obj) & C4D_Structure())
      if (!FindObject(DSTR,0,0,0,0,0,"Destruct",obj))
        return(obj);
  return(0);
}

private func BackAnything()
{
  var obj = BackBuilding();
  if (obj) return(obj);
  return(BackConstruct());
}

private func DoDestruction(par0, target)
{
  CreateObject(DSTR)->DoDestruction(target);
}

private func NoDestruction() {}


genauer ist das dann unter SpaceEmpire bzw. StarEmpire /Genereal/Structures/Destruction geregelt, aber das ist hierfür unwichtig.

In dem oben genannten Skript wird recht lang beschrieben, was abgerissen werden kann.
Ich kenn mich wie ihr wisst noch nicht so gut aus, habe aber das Gefühl, dass man das besser lösen kann.  Das Problem ist nämlich, dass hier definiert wird, dass nur Dinge die im DefCore "Exclusive" stehen haben, abgerissen werden können.  Das ist aber nicht gut, weil dann Dinge wie ein Amboss und ähnliche kleine Objekte nicht abgerissen werden können.  Deswegen habe ich den Eintrag "OCF_Exclusive()"  durch "(GetCategory(obj) & C4D_Structure())" erstetzt.  Danach können auch der Amboss und CO abgerissen werden. Nur dummerweise sorgt dies auch dafür, dass Lichter abgerissen werden können, was ich nicht ganz verstehe, da das "LIGH" Objekt kein Gebäude ist...

Also woran liegt es und/oder wie könnte man das Skript fürs abreißen abändern, sodass alle Gebäude abgerissen werden können, aber nicht die Lichter... Ich hatte an einen Befehl gedacht, der prüft, ob in der defCore "Construction=1" steht, aber sowas gibt es leider nicht =/  http://crdocs.clonkspot.org/de/sdk/definition/ocf.html
Alternativ könnte ich natürlich auch irgendwie das Licht verändern, wenn ihr da Ideen zu habt... aber ich will da natürlich auch nichts kaputtmachen =/
Parent - - By Luchs (More than 1000 posts.) Date 14.09.2014 16:07

>Ich hatte an einen Befehl gedacht, der prüft, ob in der defCore "Construction=1" steht, aber sowas gibt es leider nicht =/


Doch: http://crdocs.clonkspot.org/de/sdk/script/fn/GetDefCoreVal.html
Parent - - By Serpens66 (More than 200 posts.) Date 14.09.2014 21:47
danke, das kannte ich noch nicht, werde ich morgen mal testen, ob ich das damit schaffe. Falls nicht melde ich mich nochmal :)

die Seiten der Entwickler Dokumentation sind ziemlich unübersichtlich und ich hab das Gefühl, dass man sich nur von Begriff zu Begriff hangeln kann...
ich meine, wenn ich etwas noch nicht kenne, wie jetzt z.b den Befehl zu "GetDefcoreVal" oder auch die von mir zuvor geposteten "Object Character Flags", wie finde ich sowas dann vernünftig? Ich speicher mir schon für alles wichtige Lesezeichen ab.. hatte aber z.b für die "Object Character Flags" noch eine richtige Liste gefunden gehabt, die ich nun nicht mehr wiederfinde =/
Parent - By Pyrit (More than 200 posts.) Date 14.09.2014 22:03
ich finde "Funktionen nach Kategorie" hier eigentlich ganz ok.
Parent - - By Clonkonaut (More than 200 posts.) Date 15.09.2014 07:31

> auch die von mir zuvor geposteten "Object Character Flags", wie finde ich sowas dann vernünftig?


Irgendwie muss die Doku sortiert sein. Alle Funktionen findest du am besten "nach Kategorie" (in "Script"), alles was nicht Funktion ist (also z.B. OCF, das sind nur benannte Konstanten), ist möglichst nach Logik einsortiert: OCF betrifft Objekte (Object Character Flag), daher Objektdefinitionen aufklappen. OCF ergeben sich auf DefCore und dem Spielstatus, darum DefCore aufklappen. Und da sind OCF eingeordnet. Ansonsten ist diese Inhaltsübersicht auch nicht so riesig verschachtelt, als dass man nicht alles mal durchklicken könnte. Mit Doppelklick kannst du alles auf einmal aufklappen.
Parent - - By Serpens66 (More than 200 posts.) Date 15.09.2014 11:34
okay, danke an dich und Pyrit.

ist ein bisschen unglücklich gemacht, dass man nicht auf die schrift von "Funktionen nach Kategorie" klicken kann, um es zu öffnen. So habe ich es tatsächlich übersehen, weil ich dachte es funktioniert nicht.
Parent - By Luchs (More than 1000 posts.) Date 15.09.2014 13:36
Das ist, weil die Überschriften in einigen Fällen auch eigene Übersichtsseiten haben.
Parent - - By Serpens66 (More than 200 posts.) Date 16.09.2014 00:34 Edited 16.09.2014 00:55
so ich komm nicht weiter =/
ist das hier denn richtig? :
GetDefCoreVal("Construction", "DefCore");

ich wollte prüfen, ob das der richtige Wert ist, also ob 0 oder 1 dabei rauskommt, wenn die Funktion in der es steht aufgerufen wird, aber selbst das hab ich nicht hinbekommen =( (habe es in die Funktion Backbuilding eingetragen)
Wollte es mit "Log()" machen. Aber ich wieß nicht, was ich da dann eintragen muss.
Habe es dann mit

var con;
con = GetDefCoreVal("Construction", "DefCore");
Log(con);


probiert, aber das spuckt nichts aus. Dann dachte ich mir, vllt ist ja iwas falsch und es gibt keinen Wert, deshalb wollte ich dann den Variablen Wert mit dem Wort "test" zusammen als Lognachricht haben, aber keeeeine ahnug, wie das geht, ständig gab es nur syntaxfehler...  Wenn ich Log("con") schreibe, dann gibt er mir das Wort "con" aus, aber ich will ja den Wert der Variablen haben.

Ach und ich würde es dann eigentlich wie folgt schreiben:
private func BackBuilding()
{
  var obj;
  while (obj = FindObjectOwner(0,GetOwner(), -1,+9,0,0, OCF_Exclusive(), 0,0,obj))
//    if (GetCategory(obj) & C4D_Structure())
//      if (GetCon(obj) >= 100)
       if (!GetDefCoreVal("Construction", "DefCore") = 0)
        if (!FindObject(DSTR,0,0,0,0,0,"Destruct",obj))
          return(obj);
  return(0);
}

Aber das wirft aktuell noch einen Fehler aus, iwas mit der linken Seite des Gleichheitszeichen, dass ein & erwartet würde, aber keine ahnung warum.
Ich möchte, dass er letzlich weitermacht und das obj im return angibt, wenn der Wert von Construction im DefCore nicht Null ist. (wenn garkein Construction drin steht, ist er automatisch Null, oder produziert das einen Fehler?)
Parent - - By Gecko (More than 500 posts.) Date 16.09.2014 07:21
       if (GetDefCoreVal("Construction", "DefCore",GetID(obj)) != 0)
So müsste es sein. Nur " = " würde den Wert auf 0 setzen.
Das Ausrufezeichen für "Nicht" kann direkt vor das Gleichheitszeichnen, Sprich: "Ist Nicht". :)
Und bei GetDefCoreVal hat der dritte Parameter gefehlt. Quasi die Referenz, bei welchem Objekt die Werte abgefragt werden sollen..
Parent - By Serpens66 (More than 200 posts.) Date 16.09.2014 12:48 Edited 16.09.2014 12:59
Super danke, das funktioniert =)

Ich sehe gerade die "Reparieren" Funktion, funktioniert auch für Fahrzeuge, was ja auch sinnvoll ist.  Dummerweise wird das Licht wohl auch als Objekt Fahrzeug gesehen (im gegensatz zu der Gebäude Definition steht "C4D_Vehicle" sogar im DefCore von dem Lichtobjekt, aber keine Ahnung, wie wichtig das ist und ob man es entfernen könnte..).  Also brauche ich nun etwas, dass bei allen Fahrzeugen vorhanden ist.  Bin gerade mal die DefCore verschiedener Fahrzeuge durchgegangen. Es gibt den Eintrag "VehicleControl", dessen Wert halt 0, 1 oder 2 sein kann. 

Leider hat z.b eine Lore den Wert Null (bzw. der Eintrag ist nicht vorhanden). würde es schaden, wenn ich einfach bei jedem Fahrzeug, wo dieser Eintrag nicht vorhanden ist, den Wert auf 1 setze?

Oder gibt es noch was anderes, was alle Fahrzeuge gemeinsam haben, abgesehen von der Objektdefintion Vehicle?

Edit:
Falls es da keine vernünftige Lösung gibt, könnte ich auch versuchen Eigenschaften die nur das Licht hat auszuschließen. Aber versuchen wir es erstmal so, weil glaube ich ab und zu sogar verbrannte/tote Bäume als Ziel vom reparieren angezeigt werden.
Parent - - By alex (More than 200 posts.) Date 16.09.2014 12:25
Um mit der Log Funktion Variablen auszugeben, musst du es wie mit dem Format Befehl angeben, also z.b.:
                  
                       
var con = GetDefCoreVal("Width", "DefCore",WOOD);
Log("%v", con);
Parent - By Serpens66 (More than 200 posts.) Date 16.09.2014 12:49
dankesehr =)
- - By Serpens66 (More than 200 posts.) Date 16.09.2014 13:57
weils allgemein dazu passt noch ein paar Fragen zur Schreibweise

"GetCategory(obj) & C4D_Vehicle()"
warum wird hier ein & genutzt? Wie kann ich das logisch erklären, sodass ich in Zukunft weiß, dass da ein & zwischen muss?

es gibt
if (GetName(obj) ne "Fundament")
was dafür sorgt, dass kein Fundament das Ziel sein kann.  Wie kann ich das ganze umkehren? also ich möchte, dass nur Fundamente das Ziel sind.

folgendes:
if (GetName(obj)  "Fundament")         oder      if (GetName(obj) & "Fundament")       oder       if (GetName(obj) = "Fundament") 
funktioniert nicht.. und weiter weiß ich nicht =/ 

Außerdem findet man diese Zeichen "&" oder "ne" nicht per Suche in der Entwicklerdoku =/
Parent - - By Cmdr. Adler (More than 200 posts.) Date 16.09.2014 14:14

> Außerdem findet man diese Zeichen "&" oder "ne" nicht per Suche in der Entwicklerdoku =/


Das sind Operatoren. Du findest diese unter Inhalt und dann Operatoren. :)
Parent - - By Serpens66 (More than 200 posts.) Date 16.09.2014 14:30 Edited 16.09.2014 14:32
dankesehr =)
also sollte für die Umkehrung "eq" anstelle von "ne" funktionieren, oder?

Hm.. leider klappt es nicht.. fragt sich nur, ob es daran, oder an was anderem liegt:
if(GetCategory(obj) & C4D_Structure() || GetCategory(obj) & C4D_Vehicle() || GetName(obj) eq "Fundament" || GetName(obj) eq "Basement" )
Ich will damit erreichen, dass alle Gebäude, Fahrzeuge und Fundamente reparierbar sind. Steckt in diesem Teil ein Fehler, oder muss ich ihn woanders suchen?

Da fällt mir auf, vorher, als nur    if(GetCategory(obj) & C4D_Structure() || GetCategory(obj) & C4D_Vehicle())    dort stand,  konnte man fundamente auch nicht reparieren, obwohl es ja Gebäude sind... also wird es vermutlich noch irgendwo etwas geben, was das verhindert.. ich such mal weiter...

edit:
schließt "NoContainer" Fundamente aus? Was heißt NoContainer? Die Beschreibung in der Entwicklerdoku sagt mir nicht soviel =/
Parent - - By Luchs (More than 1000 posts.) Date 16.09.2014 14:57

>also sollte für die Umkehrung "eq" anstelle von "ne" funktionieren, oder?


Ja. Allerdings sind das die veralteten Operatoren für Zeichenkettenvergleiche. In CR kannst du problemlos auch die bekannten `==` und `!=` für alles verwenden.

>`if(GetCategory(obj) & C4D_Structure() || GetCategory(obj) & C4D_Vehicle() || GetName(obj) eq "Fundament" || GetName(obj) eq "Basement" )`


Du solltest auf gar keinen Fall die Namen von Objekten in Vergleichen verwenden. Du hast das Problem dabei schon erkannt - der Name hängt davon ab, welche Sprache man eingestellt hat. Wenn du nicht alle Sprachen richtig abdeckst, dann bekommst du im Netzwerkspiel Desyncs, da etwa einer mit deutschem Clonk Fundamente reparieren kann, aber jemand mit englischem nicht.

Stattdessen verwende besser wenn möglich ID-Vergleiche, oder im Fall von speziellen Objektklassen Funktionsaufrufe. Leider bietet das Fundament von Haus aus keine Funktion an, um es als solches zu erkennen. Mit einem appendto hast du das aber schnell nachgerüstet:

```
#strict 2
#appendto BAS7

public func IsBasement() {
  return GetID() == BasementID();
}
```

Dann kannst du das abfragen durch `if (obj->~IsBasement())`. Der Operator ->~ bewirkt im Gegensatz zum regulären Funktionsaufrufoperator ->, dass kein Fehler ausgegeben wird, wenn die Funktion nicht existiert (und sie existiert ja nur für Fundamente und Gebäude, die das Fundament inkludieren).
Parent - - By Serpens66 (More than 200 posts.) Date 16.09.2014 15:58
Vielen Dank, auch an Zapper und Cmdr. Adler =)
Stimmt, das mit "IsBasement" ist eine sehr gute Idee, sollte ich auch mit den Fahrzeugen so machen, also einfach zu jedem Fahrzeug sowas wie "IstReparierbar" hinzufügen :)

Leider kann ich Basements immernoch nicht reparieren, was aber nicht hieran liegt, sondern ich konnte sie wie gesagt auch schon vorher nicht repaireren, obwohl es Gebäude sind.
Also entweder verhindert irgendetwas den Vorgang oder es liegt daran, dass man sich nie vor einem Basement befinden kann.

Das sind die wichtigen Funktionen:
public func FindDamagedObject()
{
  var obj;
  while(obj= FindObject(0,-1,+9,0,0,0,0,0,NoContainer(),obj))
   if(GetCategory(obj) & C4D_Structure() || GetCategory(obj) & C4D_Vehicle() || obj->~IsBasement() )
    if(GetDamage(obj))
     if(GetOwner(obj)== GetOwner() || GetOwner(obj)== NO_OWNER())
      return(obj);
}

public func ContextReperatur(pCaller)
{
  [$RepairObject$|Image=CXCN|Condition=FindDamagedObject]
  if(!FindDamagedObject()) return(0);
  CreateMenu(CXCN,0,0,0,"$WhatIsToRepair$",0,1);
  var obj;
  while(obj= FindObject(0,-1,+9,0,0,0,0,0,NoContainer(),obj))
  if(GetCategory(obj) & C4D_Structure() || GetCategory(obj) & C4D_Vehicle()|| obj->~IsBasement() )
    if(GetDamage(obj))
     if(GetOwner(obj)== GetOwner() || GetOwner(obj)== NO_OWNER())
      AddMenuItem(Format("%s (%d C.)",GetName(obj),GetDamage(obj) /2),"Repair",GetID(obj),0,0,obj,0,0,4,obj);
  AddMenuItem("$Nothing$","No",MCMX);
}


steht da irgendetwas drin, das verhindern könnte, dass Fundamente repariert werden können?

Falls nicht, müsste man vermutlich dan Radius etwas erweitern, sodass man ein Fundament auch reparieren kann, wenn man auf/neben ihm steht. Nicht zuviel, aber eben so, dass es klappt.  Welche Zahlen müsste ich dafür wie ändern?
Parent - - By Luchs (More than 1000 posts.) Date 16.09.2014 18:01
Mit [FindObjects2](http://crdocs.clonkspot.org/de/sdk/script/fn/FindObject2.html) bzw. FindObjects kannst du verschiedene Suchparameter ganz einfach kombinieren. Damit kannst du deinen Fall bestimmt besser realisieren, weil du dann nicht erst noch mit if filtern musst. In der momentanen Fassung könntest du dein `FindDamagedObject()` auf einen einzigen Suchaufruf reduzieren, ungefähr so:

```
FindObject2(Find_Distance(9), Find_NoContainer(), Find_Or(Find_Category(C4D_Structure), Find_Category(C4D_Vehicle), Find_Func("IsBasement")), Find_Or(Find_Owner(GetOwner()), Find_Owner(NO_OWNER)), Find_Func("GetDamage"));
```

`Find_Distance` ist meistens nützlicher, als ein Suchrechteck zu spezifizieren wie es `FindObject` verwendet. Vielleicht findest du damit einen Wert, der für dich funktioniert.
Parent - - By Serpens66 (More than 200 posts.) Date 16.09.2014 18:44
danke :)

also sollte es so funktionieren? (das script ist "strict"):

public func FindDamagedObject()
{
  var obj;
obj = FindObject2(Find_Distance(9), Find_NoContainer(), Find_Or(Find_Category(C4D_Structure), Find_Category(C4D_Vehicle), Find_Func("IsBasement")), Find_Or(Find_Owner(GetOwner()), Find_Owner(NO_OWNER)), Find_Func("GetDamage"));
      return(obj);
}

public func ContextReperatur(pCaller)
{
  [$RepairObject$|Image=CXCN|Condition=FindDamagedObject]
  if(!FindDamagedObject()) return(0);
  var obj;
obj = FindObject2(Find_Distance(9), Find_NoContainer(), Find_Or(Find_Category(C4D_Structure), Find_Category(C4D_Vehicle), Find_Func("IsBasement")), Find_Or(Find_Owner(GetOwner()), Find_Owner(NO_OWNER)), Find_Func("GetDamage"));
  CreateMenu(CXCN,0,0,0,"$WhatIsToRepair$",0,1);
  AddMenuItem(Format("%s (%d C.)",GetName(obj),GetDamage(obj) /2),"Repair",GetID(obj),0,0,obj,0,0,4,obj);
  AddMenuItem("$Nothing$","No",MCMX);
}


es gibt immerhin keine Fehlermeldung, aber das Menü "reparieren" wird garnicht mehr angezeigt... =/
Parent - - By Luchs (More than 1000 posts.) Date 16.09.2014 18:52
Dann musst du vermutlich die Suchparameter anpassen. Das geht am besten, in dem du im Entwicklermodus das Eigenschaftenfenster deines Clonks öffnest, während er etwas reparieren können sollte. Dazu musst du im Hauptfenster den weißen, mittleren Cursor auswählen und dann den Clonk rechts anklicken. In das Fenster kannst du dann dein FindObject2(...) reinkopieren und ausprobieren.

Was jetzt verloren gegangen ist, ist dass dein Menü davor mehrere Einträge anzeigen konnte. Dazu müsstest du FindObjects() verwenden, das gibt dir dann ein Array zurück. Also etwa so:

```
for (var obj in FindObjects(...)) {
  AddMenuItem(...);
}
```
Parent - - By Serpens66 (More than 200 posts.) Date 16.09.2014 19:13
okay.. das fenster beim Clonk hab ich gefunden. ich gebe da die komplette funktion:
FindObject2(Find_Distance(9), Find_NoContainer(), Find_Or(Find_Category(C4D_Structure), Find_Category(C4D_Vehicle), Find_Func("IsBasement")), Find_Or(Find_Owner(GetOwner()), Find_Owner(NO_OWNER)), Find_Func("GetDamage"));
ein, und obwohl direkt dahinter ein beschädigtes Schloss steht, gibt er einen Wert 0 aus.
Inwiefern kann ich hier nun ausprobieren?  Bei Find_Distance die Zahl verändern? Hab 22 ausprobiert, aber das ändert nichts. Welche Größenordnung sollte ich probieren?

Hmm... das mit dem Menü und vorallem "Array" überfordert mich jetzt... Arrays klingt so verdammt kompliziert, sodass ich sowas wenn möglich vermeiden will.

Vllt sollte ich es doch in der Form lassen, wie es bisher war und stattdessen dieses "Suchrechteck" vergrößern?  Wie mache ich das? Bisher waren da die X und Y Werte ja -1 und +9.   Habe es mal auf -19 und +19 geändert und dachte, dass es dadurch sehr groß werden müsse, aber offensichtlich funktioniert das nicht so... welche Werte muss ich eintragen, um das Suchrechteck zu vergrößern?
Parent - - By Luchs (More than 1000 posts.) Date 16.09.2014 19:17
`FindObject2` kombiniert ja mehrere Suchparameter. Alle Parameter müssen zutreffen, damit ein Objekt gefunden wird. Versuche also mal, ein Parameter nach dem anderen zu entfernen, bis es funktioniert.
Parent - - By Serpens66 (More than 200 posts.) Date 16.09.2014 20:30
es scheitert offensichtlich schon am structure Teil
FindObject2(Find_Distance(9), Find_Category(C4D_Structure));
findet 0, obwohl ich vor einem schloss stehe.
Wenn ich den structure Teil auch noch wegnehme, dann findet er den angeklickten Clonk.
Parent - - By Luchs (More than 1000 posts.) Date 16.09.2014 21:27
Und wenn du die Distanz stark erhöhst? Es handelt sich dabei um die Distanz zum Mittelpunkt.
Parent - - By Serpens66 (More than 200 posts.) Date 16.09.2014 21:52 Edited 16.09.2014 21:56
ah okay, daran lag es, gut. Nun findet er auch mit dem vollständigen Befehl beschädigte dinge, leider aber natürlich auch das Licht ^^
Daher nehme ich anstelle von "Find_Category(C4D_Structure)"  -> "GetDefCoreVal("Construction","DefCore",GetID())" und anstelle von "Find_Category(C4D_Vehicle)" -> "Find_Func("IsRepa")" , welches ich als appendto an alle Fahrzeuge gehängt habe.

also insg dann:
FindObject2(Find_Distance(90), Find_NoContainer(), Find_Or(GetDefCoreVal("Construction","DefCore",GetID()), Find_Func("IsRepa"), Find_Func("IsBasement")), Find_Or(Find_Owner(GetOwner()), Find_Owner(NO_OWNER)), Find_Func("GetDamage"));

Dummerweise liefert das nun wieder "0", obwohl das Basement, welches ich nicht verändert habe und beschädigt ist, vorher mit der alten Formel und größerer distance gefunden wurde... also hab ich die Funktion kaputt gemacht?

edit:
hab gesehen beim Defcore könnte das "Find_" fehlen.. aber ich weiß nicht, wie es richtig aussehen müsste...:
Find_DefCoreVal("Construction","DefCore",GetID())
funktioniert leider nicht =(
Parent - - By Luchs (More than 1000 posts.) Date 17.09.2014 09:12
Du kannst natürlich nur die Suchkriterien nutzen, die auch definiert sind. Die Dokumentation ist da relativ vollständig. Für eigene Kriterien ist generell Find_Func da. Kannst du dein GetDefCoreVal-Check nicht in deine `IsRepa`-Funktion mit integrieren?
Parent - - By Zapper (More than 500 posts.) Date 17.09.2014 09:16

>Kannst du dein GetDefCoreVal-Check nicht in deine IsRepa-Funktion mit integrieren?


Vielleicht reicht sogar schon Find_Func("GetDefCoreVal", "Construction", "DefCore")
Parent - - By Serpens66 (More than 200 posts.) Date 17.09.2014 12:57
danke, das funktioniert =)
nur hab ich gemerkt, dass meine "IsRepa" Funktion nicht funktioniert... Es scheint aber auch die "IsBasement" Funktion nicht zu gehen nach der ich meine Repa Funktion gebaut habe.
Woran könnte das nun wieder liegen?
und angenommen die Basement Funktion wäre richtig, oder ich hab nen anderen Fehler gemacht und sie ist richtig:
public func IsBasement() {
  return GetID() == BasementID();
}

wie müsste dann meine IsRepa Funktion aussehen?
public func IsRepa() {
  return(1);
}

so sieht sie bisher aus.
Parent - - By Luchs (More than 1000 posts.) Date 17.09.2014 14:56
Deine Funktion sieht gut aus. Vielleicht habe ich bei IsBasement auch einfach falsch gedacht. Hast du die Funktion mal mit dem Eigenschaften-Fenster ausprobiert?
Parent - - By Serpens66 (More than 200 posts.) Date 17.09.2014 15:29 Edited 17.09.2014 15:44
Was genau meinst du mit dem "eigenschaften-fenster"?
Ich im Editor gestartetem Spiel den clonk angeklickt, neben ihm eine Lore und
FindObject2(Find_Distance(90), Find_Func("IsRepa"));
probiert, was aber leider nichts findet.

edit: ich teste nochmal genauer, hab grad die repa funktion in die lore selbst geschrieben und es funktioniert... hab wohl was beim appendto falsch gemacht.

edit2:
hab den Fehler gefunden... ich hatte vergessen, dass appendto Scripte in einen System.c4g Ordner rein müssen, um zu funktionieren... ^^
jetzt nur noch testen, ob jetzt endlich alles so funzt, wie es soll =)

edit3:
soo, es funktioniert nun alles einwandfrei, alles was repaierbar sein soll, kann repariert werden :) und falls noch sowas wie ein Fahrstuhlkorb aus der Reihe hüpft, füge ich ihn einfach in der appendto Liste hinzu :)
Jetzt zu dem Menü..

> Was jetzt verloren gegangen ist, ist dass dein Menü davor mehrere Einträge anzeigen konnte. Dazu müsstest du FindObjects() verwenden, das gibt dir dann ein Array zurück.


Was muss ich da eintragen, wo du "..." geschrieben hast?
(fertig mit editieren)
Parent - - By Luchs (More than 1000 posts.) Date 17.09.2014 16:29

>Was muss ich da eintragen, wo du "..." geschrieben hast?


Na dasselbe, wie bei der vorigen while-Schleife: der `AddMenuItem()`-Aufruf.
Parent - - By Serpens66 (More than 200 posts.) Date 17.09.2014 18:21
die Funktion im Script sieht nun so aus:

public func ContextReperatur(pCaller)
{
  [$RepairObject$|Image=CXCN|Condition=FindDamagedObject]
  if(!FindDamagedObject()) return(0);
  CreateMenu(CXCN,0,0,0,"$WhatIsToRepair$",0,1);
  var obj;
obj = FindObject2(Find_Distance(40), Find_NoContainer(), Find_Or(Find_Func("GetDefCoreVal", "Construction", "DefCore"), Find_Func("IsRepa"), Find_Func("IsBasement")), Find_Or(Find_Owner(GetOwner()), Find_Owner(NO_OWNER)), Find_Func("GetDamage"));
      AddMenuItem(Format("%s (%d C.)",GetName(obj),GetDamage(obj) /2),"Repair",GetID(obj),0,0,obj,0,0,4,obj);
  AddMenuItem("$Nothing$","No",MCMX);
}


wo soll ich dort nun noch

for (var obj in FindObjects(...)) {
  AddMenuItem(...);
}


einfügen? es gibt doch schon ein AddMenu..., das habe ich nicht verändert, dennoch wird jetzt nur noch ein gebäude aufeinmal angezeigt, obwohl es zuvor alle waren.  Ich habe keine Ahnung warum, weshalb ich auch nicht weiß, wie ich das nun korrigiere =/
Parent - - By Luchs (More than 1000 posts.) Date 17.09.2014 18:29
Davor war da eine while-Schleife, die hast du entfernt. Die Schleife hatte den Effekt, dass alle gefundenen Objekte ein Menüeintrag bekommen, und nicht nur eines. Mit der for-Schleife und FindObjects() kannst du dasselbe erreichen. Du musst also den FindObject2-Aufruf entsprechend ersetzen.
Parent - - By Serpens66 (More than 200 posts.) Date 17.09.2014 19:47
die Schleife hab ich übersehen, danke.

mit schleifen kenn ich mich noch nicht so aus.. aber die while schleife sieht in der entwickler doku ja recht einfach aus. 
Deswegen hab ich es jetzt mal so probiert:

public func ContextReperatur(pCaller)
{
  [$RepairObject$|Image=CXCN|Condition=FindDamagedObject]
  if(!FindDamagedObject()) return(0);
  CreateMenu(CXCN,0,0,0,"$WhatIsToRepair$",0,1);
  var obj;
while( obj = FindObject2(Find_Distance(40), Find_NoContainer(), Find_Or(Find_Func("GetDefCoreVal", "Construction", "DefCore"), Find_Func("IsRepa"), Find_Func("IsBasement")), Find_Or(Find_Owner(GetOwner()), Find_Owner(NO_OWNER)), Find_Func("GetDamage")))
      AddMenuItem(Format("%s (%d C.)",GetName(obj),GetDamage(obj) /2),"Repair",GetID(obj),0,0,obj,0,0,4,obj);
  AddMenuItem("$Nothing$","No",MCMX);
}


aber das hat meinen ganzen PC zum abschmieren gebracht :D  warum? es ist doch fast kein unterschied zum Original, bis auf andere Suchkriterien...

Also klappt eine while schleife hier nicht? 

also dann zu der for schleife:
for (var obj in FindObjects(...)) {
  AddMenuItem(...);
}

woher kommt der "var obj in FindObjects" teil? woher weiß man, dass da ein "in" hin muss, sowas hab ich noch nie gesehen =/   und zusätzlich verwendest du solche Klammern {}, die kann ich doch nicht innerhalb einer Funktioin verwenden, da sie doch selbst eine Funktion darstellen, oder etwa doch?  Ich habe echt keine Idee, wie das mit dieser for Schleife funktioniert =/
Parent - - By Luchs (More than 1000 posts.) Date 17.09.2014 20:31
```c4script
public func ContextReperatur(pCaller) {
  [$RepairObject$|Image=CXCN|Condition=FindDamagedObject]
  if(!FindDamagedObject()) return 0;
  CreateMenu(CXCN,0,0,0,"$WhatIsToRepair$",0,1);
  for(var obj in FindObjects(Find_Distance(40), Find_NoContainer(), Find_Or(Find_Func("GetDefCoreVal", "Construction", "DefCore"), Find_Func("IsRepa"), Find_Func("IsBasement")), Find_Or(Find_Owner(GetOwner()), Find_Owner(NO_OWNER)), Find_Func("GetDamage"))) {
    AddMenuItem(Format("%s (%d C.)",GetName(obj),GetDamage(obj) /2),"Repair",GetID(obj),0,0,obj,0,0,4,obj);
  }
  AddMenuItem("$Nothing$","No",MCMX);
}
```

FindObjects() gibt dir ein Array (d.h. eine Liste) aller gefundenen Objekte zurück. `for (var item in array) { ... }` iteriert über alle Elemente des Arrays und führt für jedes Element den Code in den geschweiften Klammern aus. In deinem Fall willst du ja für jedes gefundene Objekt ein Menüeintrag hinzufügen, daher kommt in die geschweiften Klammern das `AddMenuItem()`.
Parent - By Serpens66 (More than 200 posts.) Date 17.09.2014 20:49
danke für die Formel und die Erklärung :)  Vermutlich hätte ich die Formel anhand deiner Hinweise auch so gemacht, aber mich hat dieses "in" und vorallem die { Klammern stark irritiert.

Damit ist dieses Projekt abgeschlossen und es geht hier weiter:
https://clonkspot.org/forum/topic_show.pl?tid=305
Parent - - By Zapper (More than 500 posts.) Date 17.09.2014 18:00

>und angenommen die Basement Funktion wäre richtig, oder ich hab nen anderen Fehler gemacht und sie ist richtig:


Wo stehen die Scriptausschnitte denn?
Parent - - By Serpens66 (More than 200 posts.) Date 17.09.2014 18:16
na weiter oben in einem meiner post in dieser baumstruktur ^^
aber auch garnicht mehr so wichtig, habe wie hier gepostet den Fehler ja schon gefunden, hatte das appendto nicht im system.c4g Ordner.
Parent - By Zapper (More than 500 posts.) Date 18.09.2014 05:52

>aber auch garnicht mehr so wichtig, habe wie hier gepostet den Fehler ja schon gefunden, hatte das appendto nicht im system.c4g Ordner.


Ja, darauf wollte ich hinaus -  nicht wo die Scripte hier im Forum stehen :)
Parent - By Zapper (More than 500 posts.) Date 16.09.2014 14:57

>schließt "NoContainer" Fundamente aus? Was heißt NoContainer? Die Beschreibung in der Entwicklerdoku sagt mir nicht soviel =/


NoContainer ist eine konstante für FindObject, die angibt, dass nur Objekte im Freien gefunden werden sollten.

Solange deine Fundamente nicht eingesammelt sind, sollte das keine Auswirkungen haben.
Parent - By Cmdr. Adler (More than 200 posts.) Date 16.09.2014 15:00
Ich bin weder Scripter noch Programmierer. Dafür musst du auf Antworten der Profis warten. :)

> schließt "NoContainer" Fundamente aus? Was heißt NoContainer? Die Beschreibung in der Entwicklerdoku sagt mir nicht soviel =/


Gemäß dem dortigen Beispiel betrifft es alle Objekte die nicht in einem Gebäude/Fahrzeuge/etc. enthalten sind. Wenn du ein Objekt in einem Gebäude ablegst, wird es von NoContainer nicht gefunden.

NoContainer ist laut Dokumentation aber auch veraltet (siehe Engine-Version 4.65 Clonk Planet) und wurde durch Find_NoContainer ersetzt (Engine-Version 4.96 / Clonk Rage). Dort geht's allerdings mit Arrays los, davon hab ich tatsächlich keine Ahnung.

Edit:
Zapper und Luchs haben dir geantwortet, daher kannst du meine Nachricht ignorieren.
Parent - - By Zapper (More than 500 posts.) Date 16.09.2014 14:54
Also erstmal ganz grob:
Benutz für Vergleiche immer ==, auch für Strings! eq und ne sind für die Zeit von vor #strict 2 und mittlerweile veraltet.

Ganz ganz wichtig: Benutze bei Vergleichen niemals ein einfaches Gleichheitszeichen (=). Das ist nämlich dann eine Zuweisung.
zB:
var i = Random(5); // ziehe eine Zufallszahl
if (i = 1) Log("Zufallszahl war 1"); // <- falsch!

In dem Beispiel wird immer der Log ausgegeben, weil der Variable i immer der Wert 1 zugewiesen werden kann (und dieser Wert nicht 0 ist) - das ist kein Vergleich an der Stelle!

Jetzt der Zusatz für die bitweisen Operatoren (&, | etc.):
Die Operatoren sind mathematische Operatoren! Wenn du schreibst if (GetCategory() & C4D_Vehicle) dann schreibst und meinst du eigentlich if ((GetCategory() & C4D_Vehicle) != 0).
Der Vergleich mit 0 kann immer auch weggelassen werden:
Deshalb funktioniert zB if (FindObject(CLNK)) (da eigentlich if (FindObject(CLNK) != 0)).
Und deshalb funktioniert auch das Beispiel von oben: if (i = 1) ist naemlich eigentlich if ((i = 1) != 0) - und 1 != 0 ist immer wahr!

Wenn du wissen willst wie die mathematischen, bitweisen Operatoren funktionieren, dann google einfach mal nach anschaulichen Beispielen. Da gibt es bestimmt welche mit Bildern.
Up Topic Deutsch / Hilfestellung / [Gelöst] "AddLight" abändern, weil sonst Gebäude
1 2 Previous Next  

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill