Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mob ai: iff factions, small turbolift/maploader fix #6702

Merged
merged 23 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions citadel.dme
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@
#include "code\__DEFINES\mobs\biology.dm"
#include "code\__DEFINES\mobs\characteristics.dm"
#include "code\__DEFINES\mobs\grab.dm"
#include "code\__DEFINES\mobs\iff.dm"
#include "code\__DEFINES\mobs\intent.dm"
#include "code\__DEFINES\mobs\life.dm"
#include "code\__DEFINES\mobs\mobility.dm"
Expand Down Expand Up @@ -3496,6 +3497,7 @@
#include "code\modules\mob\mob-keybind-triggers.dm"
#include "code\modules\mob\mob.dm"
#include "code\modules\mob\mob_defines.dm"
#include "code\modules\mob\mob-iff.dm"
#include "code\modules\mob\mob_helpers.dm"
#include "code\modules\mob\mob_transformation_simple.dm"
#include "code\modules\mob\mobility.dm"
Expand Down Expand Up @@ -3903,7 +3905,6 @@
#include "code\modules\mob\living\simple_mob\subtypes\humanoid\humanoid_vr.dm"
#include "code\modules\mob\living\simple_mob\subtypes\humanoid\pirates.dm"
#include "code\modules\mob\living\simple_mob\subtypes\humanoid\possessed.dm"
#include "code\modules\mob\living\simple_mob\subtypes\humanoid\russian.dm"
#include "code\modules\mob\living\simple_mob\subtypes\humanoid\mercs\mercs.dm"
#include "code\modules\mob\living\simple_mob\subtypes\humanoid\mercs\mercs_vr.dm"
#include "code\modules\mob\living\simple_mob\subtypes\illusion\illusion.dm"
Expand Down Expand Up @@ -3983,7 +3984,7 @@
#include "code\modules\mob\living\simple_mob\subtypes\vore\snake.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\solargrub.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\solargrub_larva.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\solarmoth_ch.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\solarmoth.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\vore.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\wolf.dm"
#include "code\modules\mob\living\simple_mob\subtypes\vore\wolfgirl.dm"
Expand Down
109 changes: 109 additions & 0 deletions code/__DEFINES/mobs/iff.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2024 Citadel Station developers. *//

//* IFF Factions *//

//? -- Special; These must start with '!' -- ?//
//? ?//
//? These are only valid syntax in places ?//
//? where you should be using them, aka ?//
//? initializers. ?//

/// get an arbitrary faction that's the same on a given /datum/map_level
#define MOB_IFF_FACTION_BIND_TO_LEVEL "!bind-level"
/// get an arbitrary faction that's the same on a given /datum/map
///
/// * acts like BIND_TO_LEVEL if there's no parent /datum/map for a /datum/map_level
#define MOB_IFF_FACTION_BIND_TO_MAP "!bind-map"
/// get an arbitrary faction that's the same on a given /datum/map_level for a given key
///
/// * GROUP must be a string
#define MOB_IFF_FACTION_BIND_TO_LEVEL_GROUP(GROUP) list(MOB_IFF_FACTION_BIND_TO_LEVEL = GROUP)
/// get an arbitrary faction that's the same on a given /datum/map for a given key
///
/// * GROUP must be a string
/// * acts like BIND_TO_LEVEL if there's no parent /datum/map for a /datum/map_level
#define MOB_IFF_FACTION_BIND_TO_MAP_GROUP list(MOB_IFF_FACTION_BIND_TO_MAP = GROUP)

// todo: "bind to map template" (?)
// todo: "bind to /area" (?)
// todo: "bind to specific type" handling; maybe just input typepath?

/// automatically detect what we should bind to
///
/// * submap
/// * map
/// todo: impl
#define MOB_IFF_FACTION_BIND_AUTO MOB_IFF_FACTION_BIND_TO_MAP
/// automatically detect what we should bind to, and use a specific separated group
///
/// * submap
/// * map
/// todo: impl
#define MOB_IFF_FACTION_BIND_AUTO_GROUP(GROUP) list(MOB_IFF_FACTION_BIND_TO_MAP = GROUP)

//? Default factions *//

/// mobs have this by default
///
/// * this makes a lot of things assume that the mob is nonhostile.
/// * this should be removed for hostile mobs
#define MOB_IFF_FACTION_NEUTRAL "neutral"
/// generic hostile mob faction
///
/// * do not check for this; most hostile mobs do not have this
/// * having FACTION_NEUTRAL is an effect; having this is not, this is just a generic one so the mob has a faction.
/// * you probably shouldn't even be using this unless you're doing BIND_TO_LEVEL/MAP_GROUP with this.
#define MOB_IFF_FACTION_HOSTILE "hostile"

//? AI / machine intelligence factions ?//

#define MOB_IFF_FACTION_HIVEBOT "ai-hivebot"
#define MOB_IFF_FACTION_SWARMER "ai-swarmer"

//? Alien factions

#define MOB_IFF_FACTION_BLOB "alien-blob"
#define MOB_IFF_FACTION_CHIMERIC "alien-chimeric"
#define MOB_IFF_FACTION_SLIME "alien-slime"
#define MOB_IFF_FACTION_STATUE "alien-statue"
#define MOB_IFF_FACTION_XENOMORPH "alien-xenomorph"

//? Animal factions ?//
//* Farm refers to 'this would not be out of place in a normal earth farm that isn't in a horror series'

/// goats, cows, sheep
#define MOB_IFF_FACTION_FARM_ANIMAL "farm-animal"
/// ducks, other 'non producing' (canonically, anyways)
#define MOB_IFF_FACTION_FARM_NEUTRAL "farm-neutral"
/// mice and similar
#define MOB_IFF_FACTION_FARM_PEST "farm-pest"
/// cats, dogs
#define MOB_IFF_FACTION_FARM_PET "pet"

/// man's worst enemy (spiders)
#define MOB_IFF_FACTION_SPIDER "spider"
/// fallout gone wrong - wait what?! (cockroaches)
#define MOB_IFF_FACTION_ROACH "roach"
/// biotech gone wrong (genetic horrors)
#define MOB_IFF_FACTION_MUTANT "mutant"
/// hydroponics gone wrong (literally any hostile plane)
#define MOB_IFF_FACTION_PLANT "plant"
/// is this a dune reference??? (space worms)
#define MOB_IFF_FACTION_WORM "worm"
/// we're going whaling! (space carps)
#define MOB_IFF_FACTION_CARP "carp"
/// the bane of engineering (solargrubs)
#define MOB_IFF_FACTION_GRUB "grubs"

//? Human factions ?//

#define MOB_IFF_FACTION_MERCENARY "mercenary"
#define MOB_IFF_FACTION_MERCENARY_GROUP(GROUP) ("mercenary-" + GROUP)
#define MOB_IFF_FACTION_PIRATE "mercenary"
#define MOB_IFF_FACTION_PIRATE_GROUP(GROUP) ("mercenary-" + GROUP)

//? Paracausal factions ?//

#define MOB_IFF_FACTION_CLOCKWORK_CULT "clock-cult"
#define MOB_IFF_FACTION_SANGUINE_CULT "blood-cult"
1 change: 0 additions & 1 deletion code/game/machinery/computer/arcade/orion.dm
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,6 @@ GLOBAL_LIST_INIT(orion_events, generate_orion_events())
/mob/living/simple_mob/hostile/humanoid/orion
name = "spaceport security"
desc = "Premier corporate security forces for all spaceports found along the Orion Trail."
faction = "orion"
loot_list = list()
//del_on_death = TRUE

Expand Down
2 changes: 1 addition & 1 deletion code/game/machinery/turrets/turret.dm
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@
if(L.invisibility >= INVISIBILITY_LEVEL_ONE) // Cannot see him. see_invisible is a mob-var
return TURRET_NOT_TARGET

if(faction && L.faction == faction)
if(faction && L.has_iff_faction(faction))
return TURRET_NOT_TARGET

if(!emagged && issilicon(L) && check_all == FALSE) // Don't target silica, unless told to neutralize everything.
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/items/weapons/nullrod.dm
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@
if(used_blessing)
else if(user.mind && (user.mind.isholy))
to_chat(user, "You are blessed by Carp-Sie. Wild space carp will no longer attack you.")
user.faction |= "carp"
user.add_iff_faction(MOB_IFF_FACTION_CARP)
used_blessing = TRUE

/obj/item/nullrod/claymore/bostaff //May as well make it a "claymore" and inherit the blocking
Expand Down
4 changes: 2 additions & 2 deletions code/game/objects/items/weapons/other.dm
Original file line number Diff line number Diff line change
Expand Up @@ -427,11 +427,11 @@
. = CLICKCHAIN_DO_NOT_PROPAGATE
if(!target.mind)
return
if(target.faction == user.faction)
if(target.shares_iff_faction(user))
to_chat(target, "<span class='notice'>You are graced by the familiar gaze of the Mother for a brief moment.</span>")

to_chat(user, "<span class='notice'>You smear the Mark of the Mother on [target]'s forehead using the [src].</span>")
to_chat(target, "<span class='notice'>You sense an unfamiliar presence looming over you. It encases you in a gentle, all-encompassing warmth.</span>")
target.faction = user.faction
target.copy_iff_factions(user)
playsound(src, pick(use_sound), 25)
qdel(src)
6 changes: 3 additions & 3 deletions code/game/objects/mob_spawner.dm
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
if(total_spawns > 0)
total_spawns--
if(mob_faction)
L.faction = mob_faction
L.set_iff_factions(mob_faction)
return L

/obj/structure/mob_spawner/proc/get_death_report(var/mob/living/L)
Expand Down Expand Up @@ -102,7 +102,7 @@ It also makes it so a ghost wont know where all the goodies/mobs are.
if(world.time > last_spawn + spawn_delay)
var/turf/mainloc = get_turf(src)
for(var/mob/living/A in range(range,mainloc))
if ((A.faction != mob_faction) && (A.move_speed < 12))
if (((!mob_faction || !A.has_iff_faction(mob_faction))) && (A.move_speed < 12))
var/chosen_mob = choose_spawn()
if(chosen_mob)
do_spawn(chosen_mob)
Expand Down Expand Up @@ -279,7 +279,7 @@ It also makes it so a ghost wont know where all the goodies/mobs are.
my_mob.low_priority = TRUE

if(faction)
my_mob.faction = faction
my_mob.set_iff_factions(faction)

if(atmos_comp)
var/turf/T = get_turf(src)
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/random/mob.dm
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@
. = ..()
if(istype(., /mob/living/simple_mob))
var/mob/living/simple_mob/this_mob = .
this_mob.faction = src.faction
this_mob.copy_iff_factions(src)
if (this_mob.minbodytemp > 200) // Temporary hotfix. Eventually I'll add code to change all mob vars to fit the environment they are spawned in.
this_mob.minbodytemp = 200
//wander the mobs around so they aren't always in the same spots
Expand Down
8 changes: 4 additions & 4 deletions code/game/objects/structures/ashlander.dm
Original file line number Diff line number Diff line change
Expand Up @@ -397,10 +397,10 @@

/obj/structure/ashlander/statue/proc/Bless(mob/user)
var/mob/living/carbon/human/H = usr
if(!H.faction == "lavaland")
to_chat(user, "<span class='danger'>You feel as if an eye briefly regards you, and then turns away.</span>")
else
H.add_modifier(/datum/modifier/ashlander_blessing, 15 MINUTES)
// if(!H.faction == "lavaland")
// to_chat(user, "<span class='danger'>You feel as if an eye briefly regards you, and then turns away.</span>")
// else
H.add_modifier(/datum/modifier/ashlander_blessing, 15 MINUTES)

/datum/modifier/ashlander_blessing
name = "The Mother's Blessing"
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/structures/props/nest.dm
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
var/spawn_choice = pick(creature_types)
var/mob/living/L = new spawn_choice(spawnpoint)
if(den_faction)
L.faction = den_faction
L.set_iff_factions(den_faction)
visible_message("<span class='warning'>\The [L] crawls out of \the [src].</span>")
den_mobs += L
tally++
Expand Down
8 changes: 5 additions & 3 deletions code/game/objects/structures/props/swarm.dm
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
/obj/structure/cult/pylon/swarm/CanAllowThrough(atom/movable/mover, turf/target)
if(istype(mover, /mob/living))
var/mob/living/L = mover
if(L.faction == "swarmer")
if(L.has_iff_faction(MOB_IFF_FACTION_SWARMER))
return TRUE
else if(istype(mover, /obj/projectile))
var/obj/projectile/P = mover
if(istype(P.firer) && P.firer.faction == "swarmer")
return TRUE
if(isliving(P.firer))
var/mob/living/L = P.firer
if(L.has_iff_faction(MOB_IFF_FACTION_SWARMER))
return TRUE
return ..()

/obj/structure/cult/pylon/swarm/Initialize(mapload)
Expand Down
7 changes: 7 additions & 0 deletions code/game/turfs/change_turf.dm
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ GLOBAL_LIST_INIT(multiz_hole_baseturfs, typecacheof(list(

/**
* get what /turf/baseturf_bottom should be
*
* todo: using a proc is inefficient. is there a better way? like a define?
*/
/turf/proc/baseturf_core()
// todo: this is shitcode, pull it out on maploader refactor.
Expand All @@ -58,13 +60,17 @@ GLOBAL_LIST_INIT(multiz_hole_baseturfs, typecacheof(list(
. = /turf/simulated/open
/**
* get baseturf on bottom
*
* todo: using a proc is inefficient. is there a better way? like a define?
*/
/turf/proc/baseturf_bottom()
. = islist(baseturfs)? baseturfs[1] : baseturfs
return (. == /turf/baseturf_bottom)? baseturf_core() : .

/**
* get baseturf underneath
*
* todo: using a proc is inefficient. is there a better way? like a define?
*/
/turf/proc/baseturf_underneath()
. = islist(baseturfs)? baseturfs[length(baseturfs)] : baseturfs
Expand All @@ -82,6 +88,7 @@ GLOBAL_LIST_INIT(multiz_hole_baseturfs, typecacheof(list(
// then we can skip all this bullshit and have proper space zmimic
// as long as zm overhead isn't too high.
//* THIS CANNOT CALL ANY PROCS UP UNTIL 'new path'! *//
// todo: this entire switch section is kind of ass
switch(path)
if(null)
return
Expand Down
3 changes: 2 additions & 1 deletion code/modules/ai/holders/polaris/ai_holder_cooperation.dm
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@

// Find another AI-controlled mob in the same faction if possible.
var/mob/living/first_friend
// todo: this isn't good because we now use factions for different reasons than binding, so all of the same map is often just friends under this defintion
for(var/mob/living/L in living_mob_list)
if(L.faction == holder.faction && L.ai_holder)
if(L.shares_iff_faction(holder) && L.ai_holder)
first_friend = L
break

Expand Down
2 changes: 1 addition & 1 deletion code/modules/ai/holders/polaris/ai_holder_targeting.dm
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
var/obj/machinery/porta_turret/P = the_target
if(P.machine_stat & BROKEN)
return FALSE // Already dead.
if(P.faction == holder.faction)
if(holder.has_iff_faction(P.faction))
return FALSE // Don't shoot allied turrets.
if(!P.raised && !P.raising)
return FALSE // Turrets won't get hurt if they're still in their cover.
Expand Down
2 changes: 1 addition & 1 deletion code/modules/ai/holders/polaris/interfaces.dm
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
return say(message)

/mob/living/proc/IIsAlly(mob/living/L)
return src.faction == L.faction
return shares_iff_faction(L)

/mob/living/simple_mob/IIsAlly(mob/living/L)
. = ..()
Expand Down
14 changes: 9 additions & 5 deletions code/modules/blob2/blobs/base_blob.dm
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,14 @@ var/list/blobs = list()
return TRUE
else if(istype(mover, /mob/living))
var/mob/living/L = mover
if(L.faction == "blob")
if(L.has_iff_faction(MOB_IFF_FACTION_BLOB))
return TRUE
else if(istype(mover, /obj/projectile))
var/obj/projectile/P = mover
if(istype(P.firer) && P.firer.faction == "blob")
return TRUE
if(isliving(P.firer))
var/mob/living/L = P.firer
if(L.has_iff_faction(MOB_IFF_FACTION_BLOB))
return TRUE
return FALSE

/obj/structure/blob/examine(mob/user, dist)
Expand Down Expand Up @@ -253,8 +255,10 @@ var/list/blobs = list()
/obj/structure/blob/on_bullet_act(obj/projectile/proj, impact_flags, list/bullet_act_args)
. = ..()

if(istype(proj.firer) && proj.firer.faction == "blob")
return
if(isliving(proj.firer))
var/mob/living/L = proj.firer
if(L.has_iff_faction(MOB_IFF_FACTION_BLOB))
return TRUE

var/damage = proj.get_structure_damage() // So tasers don't hurt the blob.
if(!damage)
Expand Down
2 changes: 1 addition & 1 deletion code/modules/blob2/blobs/factory.dm
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
var/mob/living/simple_mob/blob/spore/S = null
if(overmind)
S = new overmind.blob_type.spore_type(src.loc, src)
S.faction = "blob"
S.set_iff_factions(MOB_IFF_FACTION_BLOB)
if(istype(S))
S.overmind = overmind
overmind.blob_mobs.Add(S)
Expand Down
3 changes: 2 additions & 1 deletion code/modules/blob2/overmind/overmind.dm
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ var/list/overminds = list()
see_in_dark = 8
invisibility = INVISIBILITY_OBSERVER

faction = "blob"
iff_factions = MOB_IFF_FACTION_BLOB

var/obj/structure/blob/core/blob_core = null // The blob overmind's core
var/blob_points = 0
var/max_blob_points = 200
Expand Down
2 changes: 1 addition & 1 deletion code/modules/blob2/overmind/powers.dm
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@
for(var/mob/living/L in view(src))
if(L.stat == DEAD)
continue // Already dying or dead.
if(L.faction == "blob")
if(L.has_iff_faction(MOB_IFF_FACTION_BLOB))
continue // No friendly fire.
if(locate(/obj/structure/blob) in L.loc)
continue // Already has a blob over them.
Expand Down
Loading
Loading