| // (c) by Padreic (Padreic@mg.mud.de) |
| |
| /* 12 Juli 1998, Padreic |
| * |
| * Dieser Master dient zum einsparen von call_out Ketten bei Laufnpcs. |
| * Anmelden bei diesem Master geschieht ueber die Funktion RegisterWalker(). |
| * varargs void RegisterWalker(int time, int random, closure walk_closure) |
| * time - in welchen Abstaenden soll das Objekt bewegt werden |
| * rand - dieser Wert wird als random immer beim bewegen zu time addiert |
| * walk_closure - die Closure die immer aufgerufen werden muss, wenn dieser |
| * Parameter weggelassen wird, wird statdessen die Funktion |
| * Walk() im NPC aufgerufen. |
| * |
| * Abgemeldet wird der NPC sobald die Closure bzw. die Walk-Funktion 0 |
| * returned. Bei allen Werten !=0 bleibt der NPC aktiv. |
| * |
| * Hinweis: Der NPC muss sich mind. alle 180 sek. bewegen (time+random), |
| * ansonsten kann dieser Master nicht verwendet werden. |
| */ |
| |
| #define MAX_DELAYTIME 90 /* max. delay ist 2*MAX_DELAYTIME */ |
| #define DEFAULT_WALK_DELAY 180 /* ist der billigste Wert :) */ |
| #define MAX_JOB_COST 200000 /* Wieviel Zeit darf ein NPC max. nutzen */ |
| |
| // Funktionen zum vereinfachten Zugriff auf die Komprimierten Daten |
| // im Walkerarray |
| #define TIME(t) (t & 0x00ff) /* 8 Bit = 256 */ |
| #define RANDOM(r) ((r & 0xff00) >> 8) /* 8 Bit = 256 */ |
| #define WERT(t, r) ((t & 0x00ff)+((r << 8) & 0xff00)) /* 16 Bit */ |
| |
| static int counter; // zur Orientierung im walker-array |
| static int num_walker; // anzahl der walker im array |
| //static mixed *walker; // ({ ..., ({ ..., ({ wert, closure }), ...}), ...}) |
| nosave < < <int|closure>* >* >* walker; |
| |
| protected void create() |
| { |
| if (clonep(this_object())) { |
| destruct(this_object()); |
| raise_error("walk_master can't be clonend.\n"); |
| } |
| walker=({}); |
| num_walker=0; |
| enable_commands(); // ohne das, kein heart_beat() |
| } |
| |
| #define ERROR(x) raise_error(sprintf(x, previous_object())); |
| |
| // Man muss selbst darauf aufpassen, das sich ein NPC immer nur einmal |
| // anmeldet, da sonst auch mehrere Paralelle Walk-Ketten laufen!!! |
| // Am besten nie direkt sondern nur ueber einen Standardnpc benutzen. |
| varargs void RegisterWalker(int time, int rand, closure walk_closure) |
| { |
| int wert, next; |
| closure func; |
| |
| // pruefen ob die Paramter zulaessig sind... |
| if (time<0) ERROR("negative time to RegisterWalker() from %O.\n"); |
| if (rand<0) ERROR("negative random to RegisterWalker() from %O.\n"); |
| if ((time+rand) > (2*MAX_DELAYTIME)) |
| ERROR("Too long delaytime from %s to RegisterWalker().\n"); |
| |
| wert=WERT(time, rand); |
| if (!wert && !rand) wert=DEFAULT_WALK_DELAY; |
| if (walk_closure) |
| func=walk_closure; |
| else { |
| func=symbol_function("Walk", previous_object()); |
| if (!func) |
| raise_error("RegisterWalker() call from Object without Walk() function.\n"); |
| } |
| if (!num_walker) { |
| set_heart_beat(1); |
| if (!pointerp(walker) || !sizeof(walker)) |
| walker=map(allocate(MAX_DELAYTIME+1), #'allocate); |
| } |
| next=counter; |
| next+=(time+random(rand))/2; |
| if (next>MAX_DELAYTIME) next-=MAX_DELAYTIME; |
| walker[next]+=({ ({ wert, func }) }); |
| num_walker++; |
| } |
| |
| int dummy_walk() // liefert immer 0 fuer abbrechen... |
| { return 0; } |
| |
| // Aufruf nach Moeglichkeit bitte vermeiden, da recht aufwendig. Meist ist |
| // es leicht im NPC "sauber Buch zu fuehren" und dann ggf. aus Walk() |
| // 0 zu returnen. |
| void RemoveWalker() |
| { |
| int i, j; |
| if (!num_walker) return; |
| for (i=MAX_DELAYTIME; i>=0; i--) { |
| for (j=sizeof(walker[i])-1; j>=0; j--) |
| { |
| if (get_type_info(walker[i][j][1], 2)==previous_object()) |
| { |
| if (i==counter) // koennte gerade im heart_beat stecken... |
| walker[i][j]=({ 0, #'dummy_walk }); |
| else |
| walker[i][j]=0; |
| num_walker--; |
| } |
| } |
| if (i!=counter) // koennte gerade im heart_beat stecken... |
| walker[i]-=({ 0 }); |
| } |
| } |
| |
| // Aufruf nach Moeglichkeit bitte vermeiden, da recht aufwendig. Meist ist |
| // es leichter im NPC "sauber Buch zu fuehren" und sich zu merken, ob er |
| // bereits angemeldet ist. Liefert zurueck, wie oft ein NPC als Walker |
| // angemeldet ist (normalfall nie mehr als 1). |
| int Registration() |
| { |
| int i, j, reg; |
| if (!num_walker) return 0; |
| reg=0; |
| for (i=MAX_DELAYTIME; i>=0; i--) |
| { |
| for (j=sizeof(walker[i])-1; j>=0; j--) |
| if (get_type_info(walker[i][j][1], 2)==previous_object()) |
| reg++; |
| } |
| return reg; |
| } |
| |
| void heart_beat() |
| { |
| int i; |
| if (num_walker && i=sizeof(walker[counter])) { |
| int tmp; |
| num_walker-=i; |
| for (i--;i>=0;i--) { |
| if (get_eval_cost() < MAX_JOB_COST) { |
| // nicht abgefertigte NPCs im naechsten heart_beat ausfuehren |
| walker[counter]=walker[counter][0..i]; |
| num_walker+=i+1; |
| return; |
| } |
| else { |
| if (walker[counter][i][1] && |
| !catch(tmp=(int)funcall(walker[counter][i][1])) && tmp) { |
| tmp=counter+(TIME(walker[counter][i][0]) |
| +random(RANDOM(walker[counter][i][0])))/2; |
| if (tmp>MAX_DELAYTIME) tmp-=MAX_DELAYTIME; |
| walker[tmp]+=({ walker[counter][i] }); |
| num_walker++; |
| } |
| } |
| } |
| walker[counter]=({}); // komplett leeren |
| } |
| if (counter == MAX_DELAYTIME) |
| counter=0; |
| else counter++; |
| if (!num_walker) { |
| set_heart_beat(0); |
| walker=({}); // Speicher freigeben... |
| } |
| } |
| |
| void reset() |
| // kostet maximal einen unnoetigen heart_beat() pro reset -> vertretbar |
| // dient zu einem wieder anwerfen im Falle eines Fehlers im heart_beat() |
| { |
| if (set_heart_beat(0)<=0) { |
| int i; |
| num_walker=0; // neu berechnen... |
| if (!sizeof(walker)) return; |
| for (i=MAX_DELAYTIME; i>=0; i--) |
| num_walker+=sizeof(walker[i]); |
| if (num_walker>0) { |
| write_file(object_name()+".err", sprintf( |
| "%s: Fehler im heart_beat(). %d aktive Prozesse.\n", |
| dtime(time()), num_walker)); |
| enable_commands(); |
| set_heart_beat(1); |
| } |
| } |
| else set_heart_beat(1); |
| } |
| |
| mixed *WalkerList() // nur fuer Debugzwecke |
| { return ({ num_walker, walker, counter }); } |