LPMuds.net
September 09, 2010, 04:17:05 AM *
Welcome, Guest. Please login or register.

Login with username, password and session length
News: This is the forum page. For the main LPMuds page, visit http://lpmuds.net
 
   Home   SITE FAQ INTERMUD DOWNLOADS LINKS Help Search Login Register  
Pages: [1] 2   Go Down
  Print  
Author Topic: Lenarics help thread  (Read 1309 times)
Lenaric
Acquaintance
*
Offline Offline

Posts: 10


View Profile
« on: March 22, 2010, 03:30:13 AM »

1. Disabling magic?
2. Disabling Equipment loss on death?
3. Does anyone have an example of a proper skill progression for modern?
4. HP Bar? Instead of numbers would be cool.
Logged
Am0k
Acquaintance
*
Offline Offline

Posts: 5


View Profile
« Reply #1 on: March 22, 2010, 09:56:57 AM »

4. Tigwyk has posted code for a command that will display hps as a nice looking 'HP bar' in the Code Vault section.

This should atleast get you started.
Logged
Lenaric
Acquaintance
*
Offline Offline

Posts: 10


View Profile
« Reply #2 on: March 23, 2010, 01:54:37 PM »

Awesome, I think I'll get that implemented today.
Logged
tigwyk
Acquaintance
*
Offline Offline

Posts: 38


View Profile
« Reply #3 on: March 29, 2010, 07:56:37 PM »

I hope my code gives you a good place to start, and I'm honoured someone thought it was worth mentioning. Wink
Logged
Lenaric
Acquaintance
*
Offline Offline

Posts: 10


View Profile
« Reply #4 on: April 09, 2010, 12:12:38 AM »

Code:
#include <lib.h>
inherit  LIB_MAYOR;
void create(){
    ::create();
    SetKeyName("mayor jacob");
    SetId("mayor jacob");
    SetGender("male");
    SetRace("human");
    SetShort("Jacob the mayor");
    SetLong("A bit overweight, this rather mean-looking "+
            "man discharges the official duties of this town's "+
            "chief executive office. Mostly, people request "+
            "citizenship from him, for a fee of 5 dollars.");
    SetLocalCurrency("dollars");
    SetTax(5);
    SetTown("Driftwood Isle");

}
//funs
//snuf
void init() {
    ::init();
    SetSmell(([  "default" : "A rather odd, musty smell."]));
    SetListen(([  "default" : "The mayor grumbles something about an "+
                "unconscionably small tax revenue base."]));
}


My Mayor doesnt work. My town driftwood isle is my start town. So help?
« Last Edit: April 09, 2010, 12:23:01 AM by Lenaric » Logged
cratylus
Your favorite and best
Administrator
***
Offline Offline

Posts: 918


Cratylus@Dead Souls <ds> np


View Profile WWW
« Reply #5 on: April 09, 2010, 01:56:02 AM »

My Mayor doesnt work. My town driftwood isle is my start town. So help?

Quote
Dead Souls Dev /realms/cratylus/area/npc > request citizenship from mayor
You request citizenship from Mayor jacob.
You are now a citizen of Driftwood Isle.
Mayor jacob exclaims in English, "Congratulations, citizen!"
Dead Souls Dev /realms/cratylus/area/npc > call me->GetTown()
OBJ(cratylus /secure/save/creators/c/cratylus) -> GetTown() = "Driftwood Isle"

That code works fine for me.

-Crat
Logged
chaos
BFF
***
Offline Offline

Posts: 230


Job, school, social life, sleep. Pick 2.5.


View Profile WWW
« Reply #6 on: April 09, 2010, 04:31:22 PM »

In the biz, we call that "unable to replicate". Smiley
Logged

hamlet
Acquaintance
*
Offline Offline

Posts: 39


View Profile
« Reply #7 on: April 09, 2010, 08:36:07 PM »

Our task tracker has "FALSE" as a possible state just for that sort of thing.  As opposed to "CODE" or "PATCHED".
Logged
Lenaric
Acquaintance
*
Offline Offline

Posts: 10


View Profile
« Reply #8 on: June 30, 2010, 04:59:35 PM »

1. Disabling magic?
2. Disabling Equipment loss on death?
3. Does anyone have an example of a proper skill progression for modern?
4. HP Bar? Instead of numbers would be cool.


1. Fixed, just dont add any.
2. I actually am liking loss.
3. This is still a problem, but I am building tables to make appropriate balance.
4. Added, working great.


Now I have a new list. (More to come later, you should see my notebook)

1. Someone explain the default firearms system and how do I expand it?

2. What type of zombie would work best, infected with a virus (using a modified rage.c) or Undead typed zombies?

3. Spawn points. How do I spawn a city full of zombies? This is perplexing me.
Logged
quixadhal
BFF
***
Offline Offline

Posts: 229



View Profile
« Reply #9 on: June 30, 2010, 08:10:48 PM »

2. What type of zombie would work best, infected with a virus (using a modified rage.c) or Undead typed zombies?

3. Spawn points. How do I spawn a city full of zombies? This is perplexing me.

2.  Why not both?  Have a virus that is contagious and will slowly kill someone, and once they die, have them ressurect as an undead zombie?

3.  I hate spawn points.  Totally unnatural.  I prefer using a daemon to track NPC populations and randomly place new NPC's as needed, always out of direct sight of any players.  It also makes it easier to find out how many of what kind are currently loaded, since you can just ask the NPC daemon.

If, however, you don't like that idea... just code your rooms so they each have a small random chance of spawning an NPC whenever a player enters the room (assuming one isn't already there).  That gives you the same random encounter feeling as the daemon, but less coding.  Of course, also less control.
Logged

Lenaric
Acquaintance
*
Offline Offline

Posts: 10


View Profile
« Reply #10 on: June 30, 2010, 10:22:38 PM »

2.  Why not both?  Have a virus that is contagious and will slowly kill someone, and once they die, have them ressurect as an undead zombie?

3.  I hate spawn points.  Totally unnatural.  I prefer using a daemon to track NPC populations and randomly place new NPC's as needed, always out of direct sight of any players.  It also makes it easier to find out how many of what kind are currently loaded, since you can just ask the NPC daemon.

2. I am going to use a combo now. I have a solid idea.

3. I like this idea, sounds difficult tho.
Logged
Lenaric
Acquaintance
*
Offline Offline

Posts: 10


View Profile
« Reply #11 on: July 07, 2010, 03:10:01 PM »

I have begun playing with a spawn daemon. Its waaay more difficult than I thought. Does anyone have a small example I could build off of?

My "actual" world needs to be controlled by the daemon but the small zones that I use for training or "isolated" quests as I call them don't need to be affected by it.

I'm still confused on the concept of it. How would I track zombie population across a 500 or so room city? Without spawning them in safe areas?
Logged
chaos
BFF
***
Offline Offline

Posts: 230


Job, school, social life, sleep. Pick 2.5.


View Profile WWW
« Reply #12 on: July 07, 2010, 04:21:20 PM »

I'm afraid I don't have a small example, but I do have a large example.  This is the code for my "populace extension".  It's going to take a minute to explain what that even means, I guess.  For every area, I have an area control daemon, ~Project/dmn/control.c.  Most objects in my lib support a concept of "extensions", which is an object composition mechanism for managing objects that "extend" other objects.  A project control daemon can have one or more populace extensions attached to it; each populace extension manages a bunch of monsters and/or NPCs that are supposed to appear in the area.

This code is going to pervasively refer to concepts from my lib, so it will probably be hard to understand; I recommend ignoring the bits that don't make any sense.  Though two things I can tell you easily are that 'internal' means 'private static' and 'record' is just a macro for 'mixed' (though a record is normally a 'mixed array'); you FluffOS people with your fancy classes would do what I'm doing using 'records' using a class.

Code:
// Area populace extension, by Chaos Sun Oct 19 10:09:09 EDT 2003
//
// From area populace daemon module, by Chaos Mon Jul 15 01:30:05 CDT 1996
//
// For usage instructions see /txt/doc/build/populace
 
#include <daemon.h>
#include <interval.h>
#include <pathfind.h>
#include <population.h>
#include <services_defer_load.h>
#include <services_kernel.h>
#include <services_weather.h>
 
inherit "/std/extension";
 
#define Travel_Interval         6
 
// record def: make queue
 
#define Make_Queue_File         0
#define Make_Queue_Location     1
#define Make_Queue_Count        2
#define Make_Queue_Guard        3
 
#define Make_Queue_Fields       4
 
// end record def: make queue
 
// record def: travel
 
#define Travel_Actor            0
#define Travel_Object           1
#define Travel_File             2
#define Travel_Origin           3
#define Travel_Status           4
 
#define Travel_Fields           5
 
// end record def: travel
 
// record def: populace person
 
#define Populace_Person_File    0
#define Populace_Person_Home    1
#define Populace_Person_Guard   2
 
#define Populace_Person_Fields  3
 
// end record def: populace person
 
internal closure get_dir;
internal closure query_has_assignment;
internal int wander_time;
internal mapping active;
internal mapping populace;
internal status preload_immediate;
internal string array map_targets;
internal string array preferred_realms;
internal string array wander_realms;
internal string persistence_key;
internal string persistence_tag;
internal record array people;
internal record array queue;
internal record array travel;
 
object query_assignment(object who);
private varargs string array populace_get_dir(string path, int flags);
void process_make_queue();
void process_travel();
 
// Section: Serialization Support
 
mapping serialize_extension() {
    return ([
        "populace"          : populace,
        "people"            : people,
        "active"            : active,
        "travel"            : travel,
        "queue"             : queue,
        "persistence_tag"   : persistence_tag,
        "preferred_realms"  : preferred_realms,
        "wander_realms"     : wander_realms,
        "wander_time"       : wander_time,
    ]);
}
 
void deserialize_extension(mapping info) {
    populace = info["populace"];
    people = info["people"];
    active = info["active"];
    travel = info["travel"];
    queue = info["queue"];
    persistence_tag = info["persistence_tag"];
    preferred_realms = info["preferred_realms"];
    wander_realms = info["wander_realms"];
    wander_time = info["wander_time"];
    if(persistence_tag) {
        string name = extends->query_project_name();
        if(!name)
            error("Cannot use persistence tag on project with no project name");
        persistence_key = name + "|" + persistence_tag;
    } else {
        persistence_key = 0;
    }
}
 
// Section: Configuration Interface
 
void set_persistence_tag(string val) {
    if(!is_a(extends, "/mod/daemon/persistence"))
        error("Persistence tag requires that host daemon support persistence (inherit /mod/daemon/persistence)");
    object array exts = extends->query_extension(load_name(this_object()));
    if(exts)
        foreach(object ext : exts)
            if(ext && ext != this_object() && ext->query_persistence_tag() == val)
                error("Cannot use same persistence tag as " + printable(ext));
    string name = project_name(extends);
    if(!name)
        error("Cannot use persistence tag on project with no project_name()");
    persistence_tag = val;
    persistence_key = name + "|" + persistence_tag;
}
 
string query_persistence_tag() {
    return persistence_tag;
}
 
string query_persistence_key() {
    return persistence_key;
}
 
void set_preload_immediate(status val) {
    preload_immediate = val && True;
}
 
status query_preload_immediate() {
    return preload_immediate;
}
 
void set_wander_time(int val) {
    check_argument(1, val, #'intp);
    wander_time = val;
}
 
int query_wander_time() {
    return wander_time;
}
 
void set_wander_realms(string array val) {
    check_argument(1, val, (: arrayp($1) && all($1, #'stringp) :));
    wander_realms = val;
}
 
string array query_wander_realms() {
    return wander_realms;
}
 
void set_preferred_realms(string array val) {
    check_argument(1, val, (: arrayp($1) && all($1, #'stringp) :));
    preferred_realms = val;
}
 
string array query_preferred_realms() {
    return preferred_realms;
}
 
void set_file_targets(string array val) {
    populace["file_targets"] = val;
}
 
string array query_file_targets() {
    return populace["file_targets"] || ({});
}
 
void add_file_target(string val) {
    set_file_targets(query_file_targets() + ({ val }));
}
 
void add_file_selector(string val) {
    check_argument(1, val, #'stringp);
    populace["file_selectors"] ||= ({});
    populace["file_selectors"] += ({ val });
    if(member(val, '*') == Null && member(val, '?') == Null)
        warn("selector " + printable(val) + " contains no wildcards");
    string array matches = populace_get_dir(val, GETDIR_PATH);
    switch(sizeof(matches)) {
    case 0 :
        if(val[<1] != '*')
            warn("selector " + printable(val) + " matches no files (may need * on end, or possibly should be target)");
        else
            warn("selector " + printable(val) + " matches no files (probably should be target)");
        break;
    case 1 :
        warn("selector " + printable(val) + " matches only one file (probably should be target)");
        break;
    }
}
 
void set_file_selectors(string array val) {
    populace["file_selectors"] = ({});
    foreach(string item : val)
        add_file_selector(item);
}
 
string array query_file_selectors() {
    return populace["file_selectors"] || ({});
}
 
void set_dynamic_targets(closure array val) {
    populace["dynamic_targets"] = val;
}
 
closure array query_dynamic_targets() {
    return populace["dynamic_targets"] || ({});
}
 
void add_dynamic_target(closure val) {
    set_dynamic_targets(query_dynamic_targets() + ({ val }));
}
 
void add_map_realm_target(mixed val) {
    populace["map_realm_targets"] ||= ({});
    populace["map_realm_targets"] += ({ val });
}
 
mixed array query_map_realm_targets() {
    return populace["map_realm_targets"] || ({});
}
 
void add_map_terrain_target(mixed val) {
    populace["map_terrain_targets"] ||= ({});
    populace["map_terrain_targets"] += ({ val });
}
 
mixed array query_map_terrain_targets() {
    return populace["map_terrain_targets"] || ({});
}
 
void add_map_type_target(mixed val) {
    populace["map_type_targets"] ||= ({});
    populace["map_type_targets"] += ({ val });
}
 
mixed array query_map_type_targets() {
    return populace["map_type_targets"] || ({});
}
 
void add_map_overlay_target(mixed val) {
    populace["map_overlay_targets"] ||= ({});
    populace["map_overlay_targets"] += ({ val });
}
 
mixed array query_map_overlay_targets() {
    return populace["map_overlay_targets"] || ({});
}
 
void set_populaces(mapping val) {
    populace["populaces"] = val;
}
 
mapping query_populaces() {
    return populace["populaces"] || ([]);
}
 
varargs void add_populace(string file, int num, status guard) {
    set_populaces(query_populaces() + ([ file : ({ num, guard })]));
}
 
varargs void add_population(string file, int num, status guard) {
    add_populace(file, num, guard);
}
 
void set_people(record array val) {
    people = val;
}
 
record array query_people() {
    return people;
}
 
varargs void add_person(string file, mixed loc, status guard) {
    record entry = allocate(Populace_Person_Fields);
    entry[Populace_Person_File] = file;
    entry[Populace_Person_Home] = loc;
    entry[Populace_Person_Guard] = guard;
    people += ({ entry });
}
 
// Section: Operational Interface
 
mapping query_populace_active() {
    return active;
}
 
status query_populace_managed(object obj) {
    if(clonep(obj)) {
        object array list = active[load_name(obj)];
        return list && member(list, obj) != Null;
    } else {
        string file = object_name(obj);
        foreach(record person : people)
            if(person[Populace_Person_File] == file)
                return True;
        return False;
    }
}
 
// Section: Internals
 
mixed query_populace_weather() {
    return extends()->query_weather() || Daemon_Weather;
}
 
string array resolve_map_targets() {
    string array out = ({});
    status any = False;
    string array items;
    if(items = populace["map_realm_targets"]) {
        any = True;
        foreach(mixed target : items)
            out += extends->query_map_realm_rooms(target);
    }
    if(items = populace["map_terrain_targets"]) {
        any = True;
        foreach(mixed target : items)
            out += extends->query_map_terrain_rooms(target);
    }
    if(items = populace["map_type_targets"]) {
        any = True;
        foreach(mixed target : items)
            out += extends->query_map_type_rooms(target);
    }
    if(items = populace["map_overlay_targets"]) {
        any = True;
        foreach(mixed target : items)
            out += extends->query_map_overlay_rooms(target);
    }
    if(any && !sizeof(out)) {
        string array proc = ({});
        if(items = populace["map_realm_targets"])
            proc += ({ "realm: " + implode(map(items, #'printable), ", ") });
        if(items = populace["map_terrain_targets"])
            proc += ({ "terrain: " + implode(map(items, (: Terrain($1)->query_terrain_name() :)), ", ") });
        if(items = populace["map_type_targets"])
            proc += ({ "type: " + implode(map(items, #'printable), ", ") });
        if(items = populace["map_overlay_targets"])
            proc += ({ "overlay: " + implode(items, ", ") });
        error("attached to " + printable(extends) + ", had no target results for map specification " + implode(proc, ", "));
    }
    return out;
}
 
private string array retrieve_get_dir() {
    return get_dir ||= extends->query_control_daemon_closure_get_dir() || #'get_dir;
}
 
private varargs string array populace_get_dir(string path, int flags) {
    mixed res = funcall(retrieve_get_dir(), path, flags);
    if(!res) {
        warn("directory retrieval on " + printable(path) + " had zero result; permissions problem?");
        res = ({});
    }
    return res;
}
 
private string array find_locations() {
    string array out = query_file_targets();
    foreach(string loc : query_file_selectors())
        foreach(string file : populace_get_dir(loc, GETDIR_PATH))
            if(ends_with(file, ".c"))
                out += ({ file });
    map_targets ||= resolve_map_targets();
    if(sizeof(map_targets))
        out += map_targets;
    return out;
}
 
string array query_locations() {
    return populace["locations"] ||= find_locations();
}
 
string query_location() {
    return random_element(query_locations());
}
 
object query_target_location(mixed who) {
    closure array funcs = query_dynamic_targets();
    if(sizeof(funcs)) {
        foreach(closure func : funcs) {
            mixed res = funcall(func, who);
            if(res)
                if(stringp(res))
                    return load_object(res);
                else
                    return res;
        }
    }
    mixed loc = query_location();
    switch(typeof(loc)) {
    case T_OBJECT :
        return loc;
    case T_STRING :
        return load_object(loc);
    default       :
        error("Invalid target location " + printable(loc) + ", extending " + printable(extends));
    }
    return 0;
}
 
private mixed resolve_home(mixed home, mixed who, status night) {
    switch(typeof(home)) {
    case T_STRING  :
        return load_object(home);
    case T_NUMBER  :
    case T_OBJECT  :
        return home;
    case T_CLOSURE :
        return resolve_home(funcall(home, who), who, night);
    case T_POINTER :
        return resolve_home(home[night], who, night);
    default        :
        error("Cannot resolve home " + printable(home));
    }
    return 0;
}
 
record array query_travel() {
    return travel;
}
 
record array query_make_queue() {
    return queue;
}
 
void initialize_make_queue() {
    if(eval_cost() < Eval_Extremely_High) {
        if(find_call_out("initialize_make_queue") == Null)
            call_out("initialize_make_queue", 2);
        return;
    }
    queue = ({});
    foreach(record person : people) {
        string file = person[Populace_Person_File];
        object obj = find_object(file);
        if(!obj || !environment(obj)) {
            record entry = allocate(Make_Queue_Fields);
            entry[Make_Queue_File] = file;
            entry[Make_Queue_Location] = person[Populace_Person_Home];
            entry[Make_Queue_Guard] = person[Populace_Person_Guard];
            queue += ({ entry });
        }
    }
    mapping curr = query_populace_active();
    foreach(string file, mixed array info : query_populaces()) {
        object array list = curr[file];
        if(list && member(list, 0) != Null) {
            list -= ({ 0 });
            curr[file] = list;
        }
        int amt = info[0] - sizeof(list);
        if(amt > 0) {
            record entry = allocate(Make_Queue_Fields);
            entry[Make_Queue_File] = file;
            entry[Make_Queue_Count] = amt;
            entry[Make_Queue_Guard] = info[1];
            queue += ({ entry });
        }
    }
    if(sizeof(queue))
        Population_Start(#'process_make_queue);
}
 
mixed process_make_queue() {
    record entry = random_element(queue);
    if(!entry)
        return Population_Terminate;
    string what = entry[Make_Queue_File];
    object where = resolve_home(entry[Make_Queue_Location], what, query_populace_weather()->query_night()) || query_target_location(
what);
    // Deferring loading if the room has non-incarnos inventory gives autonomoi a chance to obtain belongings by scavenging
    // rather than cloning, hopefully slightly helping with memory usage.
    status defer = where && first_inventory(where) && !Daemon_Defer_Load->query_defer_load() && !any(all_inventory(where), "is_incar
nos");
    if(defer)
        Daemon_Defer_Load->set_defer_load(True);
    object obj = load_object(what);
    unless(obj->query_unique())
        obj = new(obj);
    if(defer)
        Daemon_Defer_Load->set_defer_load(False);
    if(obj) {
        if(any_hook("can_populace_populate") || any_hook("do_populace_populate")) {
            mapping info = ([
                "who"                       : obj,
                "where"                     : where,
                "populace"                  : this_object(),
                "control"                   : extends,
            ]);
            mixed res = check_hook("can_populace_populate", info);
            if(Hook_Success(res)) {
                if(obj) {
                    if(obj->move(where) == Move_Succeed) {
                        obj->message(([
                            Message_Content : ({
                                ({ 'a', 0 }), ({ "appear", 0 }),
                            }),
                            Message_Flags   : Message_Flag_Require_Source_Discriminatory,
                            Message_Senses  : Message_Sense_Visual | Message_Sense_Kinesthetic_For_Participants,
                        ]));
                        check_hook("do_populace_populate", info);
                    } else {
                        safe_destruct(obj);
                    }
                }
            } else {
                if(Hook_Display(res)) {
                    if(obj)
                        obj->display(res);
                    info["message"] = res;
                }
                check_hook("fail_populace_populate", info);
            }
        } else {
            if(obj->move(where) == Move_Succeed && obj) {
                obj->message(([
                    Message_Content         : ({
                        ({ 'a', 0 }), ({ "appear", 0 }),
                    }),
                    Message_Flags           : Message_Flag_Require_Source_Discriminatory,
                    Message_Senses          : Message_Sense_Visual | Message_Sense_Kinesthetic_For_Participants,
                ]));
            } else {
                safe_destruct(obj);
            }
        }
        if(obj && environment(obj)) {
            if(clonep(obj)) {
                if(persistence_key) {
                    obj->set_info("System_Populace_Persistence_Key", persistence_key);
                    extends->add_persistence_target(obj);
                }
                active[what] ||= ({});
                active[what] += ({ obj });
            } else if(persistence_key) {
                string curr = obj->query_info("System_Populace_Persistence_Key");
                if(!curr) {
                    obj->set_info("System_Populace_Persistence_Key", persistence_key);
                    extends->add_persistence_target(obj);
                } else if(curr == persistence_key) {
                    extends->add_persistence_target(obj);
                } else {
                    warn("managing unique " + printable(obj) + ", with persistence, that is marked for persistence by another popula
ce extension, will not add to control persistence list");
                }
            }
            if(entry[Make_Queue_Guard])
                obj->set_area_guarding(True);
            if(wander_time)
                obj->set_move_time(semirandom(wander_time));
            if(preferred_realms)
                obj->set_preferred_realms(preferred_realms);
            if(wander_realms)
                obj->set_wander_realms(wander_realms);
        }
    }
    if(--entry[Make_Queue_Count] < 1)
        array_remove(&queue, entry);
    if(!sizeof(queue))
        return Population_Terminate;
    return;
}
 
void process_entire_make_queue() {
    while(sizeof(queue))
        process_make_queue();
}
 
void initialize_travel() {
    if(eval_cost() < Eval_Extremely_High) {
        if(find_call_out("initialize_travel") == Null)
            call_out("initialize_travel", 2);
        return;
    }
    travel = ({});
    status night = query_populace_weather()->query_night();
    foreach(record person : people) {
        if(eval_cost() < Eval_Extremely_High) {
            if(find_call_out("initialize_travel") == Null)
                call_out("initialize_travel", 2);
            return;
        }
        string file = person[Populace_Person_File];
        object obj = find_object(file);
        if(!obj || obj->query_attacker() || obj->query_incapacitated())
            continue;
        object home = resolve_home(person[Populace_Person_Home], obj, night);
        unless(home)
            continue;
        object env = environment(obj);
        if(!env || env == home)
            continue;
        if(funcall(query_has_assignment, obj))
            continue;
        if(any_hook("can_populace_start_travel") || any_hook("do_populace_start_travel") || obj->any_hook("can_populace_start_travel
") || obj->any_hook("do_populace_start_travel")) {
            mixed res;
            mapping info = ([
                "who"         : obj,
                "where"       : env,
                "destination" : home,
                "populace"    : this_object(),
                "control"     : extends,
                "night"       : night,
            ]);
            res = check_hook("can_populace_start_travel", info);
            if(Hook_Failure(res)) {
                if(Hook_Display(res)) {
                    if(obj)
                        obj->display(res);
                    info["message"] = res;
                }
                check_hook("fail_populace_start_travel", info);
                obj->check_hook("fail_populace_start_travel", info);
                continue;
            }
            res = obj->check_hook("can_populace_start_travel", info);
            if(Hook_Failure(res)) {
                if(Hook_Display(res)) {
                    if(obj)
                        obj->display(res);
                    info["message"] = res;
                }
                check_hook("fail_populace_start_travel", info);
                obj->check_hook("fail_populace_start_travel", info);
                continue;
            }
            check_hook("do_populace_start_travel", info);
            obj->check_hook("do_populace_start_travel", info);
        }
        record entry = allocate(Travel_Fields);
        entry[Travel_Actor] = obj;
        entry[Travel_Object] = home;
        entry[Travel_File] = home;
        travel += ({ entry });
    }
    if(sizeof(travel))
        Interval_Set(#'process_travel, Travel_Interval);
}
 
private void travel_path(descriptor path, descriptor pathfind) {
    record entry = Pathfind_Query_Info(pathfind, "Travel");
    if(!path) {
        array_remove(&travel, entry);
        return;
    }
    entry[Travel_Status] = path;
    object who = entry[Travel_Actor];
    if(!who)
        return;
    if(environment(who) != entry[Travel_Origin])
        return;
    if(funcall(query_has_assignment, who))
        return;
    object dest = entry[Travel_Object] || load_object(entry[Travel_File]);
    if(any_hook("can_populace_travel") || any_hook("do_populace_travel")) {
        mapping info = ([
            "who"           : who,
            "where"         : environment(who),
            "destination"   : dest,
            "path"          : path,
            "pathfind"      : pathfind,
            "populace"      : this_object(),
            "control"       : extends,
        ]);
        mixed res = check_hook("can_populace_travel", info);
        if(Hook_Failure(res)) {
            if(Hook_Display(res)) {
                if(who)
                    who->display(res);
                info["message"] = res;
            }
            check_hook("fail_populace_travel", info);
            array_remove(&travel, entry);
            return;
        }
        check_hook("do_populace_travel", info);
    }
    who->queue_path(path);
    entry[Travel_Status] = time();
}
 
mixed process_travel() {
    foreach(record entry : travel) {
        if(eval_cost() < Eval_Extremely_High)
            break;
        if(entry[Travel_Status] == Path_Processing)
            continue;
        object who = entry[Travel_Actor];
        if(!who) {
            array_remove(&travel, entry);
            continue;
        }
        object to = entry[Travel_Object];
        if(!to) {
            catch(to = load_object(entry[Travel_File]));
            if(to) {
                entry[Travel_Object] = to;
            } else {
                array_remove(&travel, entry);
                continue;
            }
            if(eval_cost() < Eval_Extremely_High)
                break;
        }
        if(environment(who) == to) {
            array_remove(&travel, entry);
            if(intp(entry[Travel_Status])) {
                if(any_hook("can_populace_end_travel") || any_hook("do_populace_end_travel")) {
                    mapping info = ([
                        "who"         : who,
                        "where"       : to,
                        "populace"    : this_object(),
                        "control"     : extends,
                    ]);
                    mixed res = check_hook("can_populace_end_travel", info);
                    if(Hook_Success(res)) {
                        check_hook("do_populace_end_travel", info);
                    } else {
                        if(Hook_Display(res)) {
                            if(who)
                                who->display(res);
                            info["message"] = res;
                        }
                        check_hook("fail_populace_end_travel", info);
                    }
                }
            }
            continue;
        }
        if(funcall(query_has_assignment, who))
            continue;
        if(intp(entry[Travel_Status]) && entry[Travel_Status] > time() - Time_Minute * 5)
            continue;
        object from = environment(who);
        entry[Travel_Origin] = from;
        entry[Travel_Status] = Path_Processing;
        object pathfinder = from->project_control() == to->project_control() ? from->project_control() : Daemon_Route;
        pathfinder->find_path(([
            Pathfind_Actor      : who,
            Pathfind_From       : from,
            Pathfind_To         : to,
            Pathfind_Validate   : Path_Appropriate_Mobility_Check(who),
            Pathfind_Callback   : #'travel_path,
            Pathfind_Info       : ([
                "Travel"        : entry,
            ]),
        ]));
    }
    return sizeof(travel) ? 0 : Interval_Terminate;
}
 
void populace_reset() {
    initialize_make_queue();
    initialize_travel();
}
 
void unregister_character(object who) {
    if(clonep(who)) {
        string key = load_name(who);
        object array list = active[key];
        if(list) {
            object array mod = list - ({ who, 0 });
            if(sizeof(mod) < sizeof(list))
                if(sizeof(mod))
                    active[key] = mod;
                else
                    map_delete(active, key);
        }
    }
}
 
void synchronize_persistence() {
    if(!persistence_key)
        error("Attempt to synchronize persistence with no persistence key");
    foreach(object obj : extends->query_persistence_targets()) {
        if(clonep(obj) && obj->query_info("System_Populace_Persistence_Key") == persistence_key) {
            string type = load_name(obj);
            active[type] ||= ({});
            active[type] += ({ obj });
        }
    }
}
 
// Section: Core Applies
 
void attach_extension(object obj) {
    query_has_assignment ||= symbol_function("query_has_assignment", obj);
    obj->add_hook("mod_daemon_reset", #'populace_reset);
    obj->add_hook("mod_daemon_unregister_character", #'unregister_character);
    if(persistence_tag)
        obj->add_hook("at_persistence_daemon_initialized", #'synchronize_persistence);
    validate_local_hooks("populace", ({
        "end_travel",
        "populate",
        "start_travel",
        "travel",
    }));
    if(Obj_Master_Kernel->query_preloading() && preload_immediate && !persistence_tag) {
        initialize_make_queue();
        limited(#'process_entire_make_queue);
    } else {
        populace_reset();
    }
}
 
void detach_extension(object obj, int reason, int remove_flags) {
    obj->remove_hook("mod_daemon_reset", #'populace_reset);
    obj->remove_hook("mod_daemon_unregister_character", #'unregister_character);
    obj->remove_hook("at_persistence_daemon_initialized", #'synchronize_persistence);
}
 
void preinit() {
    ::preinit();
    populace = ([]);
    active = ([]);
    people = ({});
}
 
void create() {
    ::create();
    if(preload_immediate && persistence_tag)
        warn("have preload_immediate and persistence_tag; preload_immediate will not take effect");
}
 
status query_extension_multiple() {
    return True;
}

Here's the /txt/doc/build/populace document that the code refers to, which I rewrote from its state of being totally out of date (documenting how to use much older code from before the extension mechanism existed) to a state of just being very incomplete, just for you:

Code:
populace              - how to set up area populace extensions

------------------------------------------------------------------------------
Populace Extensions                          how to set up populace extensions
                                                 Chaos, 1996-07-15, 2010-07-07
------------------------------------------------------------------------------

This document explains the configuration and use of the generic populace
extension, /obj/extensions/populace, to manage an area's populace independently
of monsters loaded in individual rooms.  /obj/extensions/populace is designed
to extend area control daemons, and to work well in conjunction with the
guardian extension (see /txt/doc/build/guardian), the pathfinder extension
(see /txt/doc/build/pathfinder) and the area persistence module
(/mod/daemon/persistence).

A populace extension creates and maintains a specific population for the area,
distributing it randomly amidst specified target rooms.  At each reset(), it
creates new populace to replace any killed during the intervening time.

A basic area control daemon with a populace extension configured might look
like:

    #include <daemon.h>
    #include <Project.h>

    inherit "/std/daemon";
    inherit "/mod/daemon/control";

    void configure() {
        ::configure();
        set_creator("lars");
        set_area("Project");
        add_extension(LS_Extension("populace"), (:
            $1->add_file_selector(Project_Room("east_street_*"));
            $1->add_file_selector(Project_Room("west_street_*"));
            $1->add_file_target(Project_Room("square"));
            $1->add_populace(Project_Monster("guard"), 20);
            $1->add_populace(Project_Monster("citizen"), 40);
            $1->add_populace(Project_Monster("beggar"), 5);
            $1->add_populace(Project_Monster("pickpocket"), 3);
            $1->add_person(Project_NPC("bob"));
            $1->add_person(Project_NPC("joe"));
            $1->add_person(Project_NPC("mary"));
        :));
    }

[ Basic Configuration ]

void add_file_selector(string sel);

    Defines a pattern for retrieving target rooms to which the area's populace
    will be randomly distributed.  The easiest way to do this is to simply use
    the area's room macro with wildcards.  For instance, if you wanted to have
    the populace defined spread among all rooms in the area whose filenames
    began with the word "street", you could do:

        add_file_selector(Area_Room("street*"));

    If multiple file selectors are used, any rooms consistent with more than
    one will behave as if "weighted"; i.e. a room which is returned by two file
    selectors will be twice as likely to show up as a room which is returned by
    only one.

void add_file_target(string targ);

    Sets an explicit filename to be used in addition to any files retrieved
    by file selectors.  As with selectors, weighting behavior results if a file
    ends up being specified more than once.

varargs void add_populace(string file, int number, status guard);

    Defines a populace of monsters to distribute within the area.  The
    first argument is the filename from which to clone the monsters.  The second
    argument is the number which should exist within the area.  The third,
    optional, argument is a flag which should be set to true if you want
    set_area_guarding(True) to be called in the cloned monsters.  (This is
    not necessary for monsters which are always area guardians, and so call
    set_area_guarding(True) in their own configure() function.)

varargs void add_person(string file, mixed home);

    Adds an individual (a non-cloned NPC) to the area's population.  The
    first argument is the NPC's filename.  The second, optional, argument
    designates the filename of the NPC's home; if this is specified the NPC
    will be placed at this location when created and will attempt to return
    to it periodically if it has moved (using the area control daemon's
    pathfinding capability, if any).  You may also specify a two-element
    string array; the first element is the NPC's home during the day and the
    second is its home at night.  If the home value or either element of a
    home array are closures, they will be resolved, being passed an argument
    of the NPC in question.  If nothing is specified the NPC will be
    distributed randomly amidst the locations defined by the daemon's file
    selectors, just like the rest of the populace.

[ Operational Use ]

mapping query_populace_active();

    You may use this function to retrieve the data which the daemon uses to
    track existing monsters in its population base.  This mapping's indices are
    the filenames of population elements; its values are arrays of monsters.
    These arrays may contain zero-value elements when monsters have been killed.
    Note that this mapping only tracks "populace", not "people".

status query_populace_managed(object obj);

    This function returns true if the object sent is managed by the populace
    daemon, whether as a 'populace' or 'people' object.  Cloned objects will be
    examined for whether they are part of 'populace', non-clones will be examined
    for whether they are part of 'people'.
Logged

chaos
BFF
***
Offline Offline

Posts: 230


Job, school, social life, sleep. Pick 2.5.


View Profile WWW
« Reply #13 on: July 07, 2010, 06:18:19 PM »

As it turns out, I kept on rewriting /txt/doc/build/populace until it was current, so here's where it wound up:

Code:
populace              - how to set up area populace extensions

------------------------------------------------------------------------------
Populace Extensions                          how to set up populace extensions
                                                 Chaos, 1996-07-15, 2010-07-07
------------------------------------------------------------------------------

This document explains the configuration and use of the generic populace
extension, /obj/extensions/populace, to manage an area's populace independently
of monsters loaded in individual rooms.  /obj/extensions/populace is designed
to extend area control daemons, and to work well in conjunction with the
guardian extension (see /txt/doc/build/guardian), the pathfinder extension
(see /txt/doc/build/pathfinder), the map extension (/obj/extensions/map) and
the project persistence module (/mod/daemon/persistence).

A populace extension creates and maintains a specific population for the area,
distributing it randomly amidst specified target rooms.  At each reset(), it
creates new populace to replace any killed during the intervening time.

A basic area control daemon with a populace extension configured might look
like:

    #include <daemon.h>
    #include <Project.h>

    inherit "/std/daemon";
    inherit "/mod/daemon/control";

    void configure() {
        ::configure();
        set_creator("lars");
        set_area("Project");
        add_extension(LS_Extension("populace"), (:
            $1->add_file_selector(Project_Room("east_street_*"));
            $1->add_file_selector(Project_Room("west_street_*"));
            $1->add_file_target(Project_Room("square"));
            $1->add_populace(Project_Monster("guard"), 20);
            $1->add_populace(Project_Monster("citizen"), 40);
            $1->add_populace(Project_Monster("beggar"), 5);
            $1->add_populace(Project_Monster("pickpocket"), 3);
            $1->add_person(Project_NPC("bob"));
            $1->add_person(Project_NPC("joe"));
            $1->add_person(Project_NPC("mary"));
        :));
    }

[ Basic Configuration ]

void add_file_selector(string sel);

    Defines a pattern for retrieving target rooms to which the area's populace
    will be randomly distributed.  The easiest way to do this is to simply use
    the area's room macro with wildcards.  For instance, if you wanted to have
    the populace defined spread among all rooms in the area whose filenames
    began with the word "street", you could do:

        add_file_selector(Project_Room("street*"));

    If multiple file selectors are used, any rooms consistent with more than
    one will behave as if "weighted"; i.e. a room which is returned by two file
    selectors will be twice as likely to show up as a room which is returned by
    only one.

void add_file_target(string targ);

    Sets an explicit filename to be used in addition to any files retrieved
    by file selectors.  As with selectors, weighting behavior results if a file
    ends up being specified more than once.

varargs void add_populace(string file, int number, status guard);

    Defines a populace of monsters to distribute within the area.  The
    first argument is the filename from which to clone the monsters.  The second
    argument is the number which should exist within the area.  The third,
    optional, argument is a flag which should be set to true if you want
    set_area_guarding(True) to be called in the cloned monsters.  (This is
    not necessary for monsters which are always area guardians, and so call
    set_area_guarding(True) in their own configure() function.)

varargs void add_person(string file, mixed home);

    Adds an individual (a non-cloned NPC) to the area's population.  The
    first argument is the NPC's filename.  The second, optional, argument
    designates the filename of the NPC's home; if this is specified the NPC
    will be placed at this location when created and will attempt to return
    to it periodically if it has moved (using the area control daemon's
    pathfinding capability, if any).  You may also specify a two-element
    string array; the first element is the NPC's home during the day and the
    second is its home at night.  If the home value or either element of a
    home array are closures, they will be resolved, being passed an argument
    of the NPC in question.  If nothing is specified the NPC will be
    distributed randomly amidst the locations defined by the daemon's file
    selectors, just like the rest of the populace.

[ Advanced Configuration ]

void add_dynamic_target(closure func);

    Adds a closure to use to generate on-demand target rooms for managed
    autonomoi.  When called, the closure will be passed an argument of the
    string object-blueprint filename for the autonomon being deployed.  If
    the closure returns a nonzero value, that value will be used as the
    deployment location for the autonomon in preference to any other
    potential location (like those generated from file selectors, file
    targets, and map-based targets).

void add_map_realm_target(mixed spec);

    Adds a target map realm.  This functionality requires that the area control
    daemon use a map extension.  All potential map-generated rooms that match
    the target realm specification will be considered as target rooms for
    autonomon deployment.  The specification may be a string designating a
    single realm to target, or an array of realm strings, in which case only
    rooms that have all the realms in the array will be targeted.  Note that
    only realms which are configured in the map code itself are relevant; if a
    realm is added via a custom room's configure(), for example, it will not be
    considered for purposes of this functionality.

void add_map_terrain_target(mixed spec);

    Adds a target map terrain.  This functionality requires that the area
    control daemon use a map extension.  All potential map-generated rooms
    that match the target terrain specification will be considered as target
    rooms for autonomon deployment.  The specification may be a terrain code
    (like Terrain_Forest, from /lib/terrains.h) designating a single terrain
    to target, or an array of terrain codes, in which case only rooms that
    have all the terrains in the array will be targeted.  Note that only
    terrains which are configured in the map code itself are relevant; if a
    terrain is added via a custom room's configure(), for example, it will not
    be considered for purposes of this functionality.

void add_map_access_target(string spec);

    Adds a target map access type.  This functionality requires that the area
    control daemon use a map extension.  All potential map-generated rooms
    that match the target access specification will be considered as target
    rooms for autonomon deployment.  The specification map be a map access
    type (like Map_Access_Fly, from /lib/map.h) designating the access type
    to target, or an array of access types, in which case a room matches if
    its access type occurs in the array.  This functionality keys on the
    room's "general" access type, not any access types that only apply to
    entering or exiting it by particular directions.  Note that only map
    access which is configured in the map code itself is relevant; if access
    types are manipulated via a custom room's configure(), for example, this
    will be ignored for purposes of this functionality.

void add_map_type_target(mixed spec);

    Adds a target map room type.  This functionality requires that the area
    control daemon use a map extension.  All potential map-generated rooms
    that match the target type specification will be considered as target
    rooms for autonomon deployment.  The specification may be a room type
    name as set for the map extension's map feature definitions -- e.g. if a
    map feature ~Project/def/map_area_air.c calls set_map_feature_name("air"),
    "air" is its type name for this functionality -- or an array of type
    names, in which case a room matches if its type occurs in the array.

void add_map_overlay_target(mixed spec);

    Adds a target map overlay type.  This functionality requires that the
    area control daemon use a map extension.  All potential map-generated
    rooms that match the target overlay specification will be considered as
    target rooms for autonomon deployment.  The specification map be an
    overlay name as set for the map extension's map feature definitions --
    e.g. if a map feature ~Project/def/map_overlay_road.c calls
    set_map_feature_name("road"), "road" is its overlay name for this
    functionality -- or an array of overlay names, in which case a room
    matches if it has any overlay in the array.

void set_wander_time(int base);

    If configured, autonomoi deployed by the populace extension will have
    autonomon->set_move_time(semirandom(base)) called in them.  This supports
    defining specific populaces of autonomoi that wander though not all
    instances of them do so (so it would be inappropriate to simply put a
    set_move_time() in their configure()).

void set_wander_realms(mixed spec);

    If configured, autonomoi deployed by the populace extension will have
    autonomon->set_wander_realms(spec) called in them.  Usually the
    specification is an array, which defines the wander realms to be used,
    but a string may also be given, in which case it will be added to the
    wander realm list rather than replacing it.  Wander realms define the
    realms that an autonomon will normally wander within.

void set_preferred_realms(mixed spec);

    If configured, autonomoi deployed by the populace extension will have
    autonomon->set_preferred_realms(spec) called in them.  Usually the
    specification is an array, which defines the preferred realms to be
    used, but a string may also be given, in which case it will be added
    to the preferred realm list rather than replacing it.  Preferred realms
    define the realms that an autonomon will prefer to stay within if
    possible (that is, if both wander realms and preferred realms are set,
    the autonomon will only move within wander realms if no rooms that are
    preferred realms are nearby).

void set_persistence_tag(string tag);

    This functionality allows populace managed by this extension to be
    persisted using the project persistence module (/mod/daemon/persistence).
    It can only be used if the project control daemon inherits that module.
    The tag allows different populace extensions on the same daemon to know
    what persisted populace they are responsible for; each populace extension
    on the same daemon must have a different tag, if it has a tag at all.
    Examples of tags might be "General_Populace" and "Poor_Section_Populace".
    If a persistence tag is set, autonomoi deployed by the populace extension
    will automatically be added as persistence targets for the persistence
    module.
Logged

chaos
BFF
***
Offline Offline

Posts: 230


Job, school, social life, sleep. Pick 2.5.


View Profile WWW
« Reply #14 on: July 07, 2010, 06:24:49 PM »

One more tidbit I forgot:

Code:
void set_preload_immediate(status val)

    If set to true, this causes the populace extension to attempt to
    immediately generate all its populace when it is being loaded as part
    of the MUD's preload sequence at initial startup.  (Normally, populace
    is loaded over time.)  This significantly delays startup, so should only
    be used when areas have a compelling reason to do so.
Logged

Pages: [1] 2   Go Up
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.11 | SMF © 2006-2009, Simple Machines LLC Valid XHTML 1.0! Valid CSS!