ID:154753
 
I'm trying to create a faction system of sorts for my roguelike and I'm not quite sure how to go about making it work the way I envisioned it. Here is a scenario:

Skeletons and rats would be their own group. They would not attack each other. Skeletons and rats will attack goblins though.

Guards will attack any sort of monster. Guards will not attack players, unless players attack guards.

Turtles do their own thing. No one would really bother to attack turtles.

Basically I'd need to be able to easily define different groups and add/remove allegiances so groups will attack/ignore each other.
This is essentially two questions mixed together. One is relatively easy - "How do I model the concept of monsters belonging to a 'faction', and factions having opinions about other factions?'. You could, for example, give monsters a textual faction tag, and use it as a key for an associative list containing faction datums, which are an associative list of other faction names and value representing how friendly the faction is with the other faction.

var/const
FACTION_HOSTILE = 0
FACTION_FRIENDLY = 1
FACTION_NEUTRAL = 2

FACTION_DEFAULT = FACTION_NEUTRAL

faction
var/list/faction_rels = list()

proc
get_relation(other_fac)
if (faction_rels[other_fac] == NULL) return FACTION_DEFAULT
return faction_rels[other_fac]

var/list/faction_list = list()
proc/get_faction(faction)
return faction_list[faction]

mob
var/faction

proc/check_relation(mob/other)
var/faction/f = get_faction(faction)
if (!f) return FACTION_DEFAULT
return f.get_relation(other.faction)


The second, more complicated question is about how to model AI that uses this information. That depends entirely on how complex your game is and how you want to run things. This DreamMakers article contains a discussion about a state-machine based approach to AI that might be worth considering.
In response to Jp (#1)
I see. Thank you. I've never really used associative lists before. Would this example be the right way based on what you posted?

var/list/faction_list = list(/faction/player = "the_player", /faction/undead_vermin = "skeletons_and_rats")

faction
player

undead_vermin
faction_rels = list(/faction/player = FACTION_HOSTILE)

mob
player
faction = "the_player"

enemy
rat
faction = "skeletons_and_rats"

skeleton
faction = "skeletons_and_rats"
In response to LordAndrew (#2)
Not quite. You're associating types with strings, not instances of the datum, and you've got them the wrong way around.

More something like this:

faction
player
faction_rels = list("undead_vermin" = FACTION_HOSTILE)

undead_vermin
faction_rels = list("player" = FACTION_HOSTILE, "undead_vermin" = FACTION_FRIENDLY)

var/list/faction_list = list("player" = new /faction/player, "undead_vermin" = new /faction/undead_vermin)

mob
player
faction = "player"

enemy
rat
faction = "undead_vermin"

skeleton
faction = "undead_vermin"


Obviously doesn't solve the AI problem, but part of the solution. Also, untested.

I'd recommend reading the reference entry on associative lists and playing around with them a bit - they're /very/ useful.
In response to Jp (#3)
OH. Wow, haha. Thank you again Jp, and I will make sure to have a look at the reference.