Files
Paradise/code/modules/arcade/mob_hunt/mob_datums.dm
2018-09-02 20:27:52 +08:00

501 lines
16 KiB
Plaintext

#define TYPE_FIRE /datum/mob_type/fire
#define TYPE_WATER /datum/mob_type/water
#define TYPE_GRASS /datum/mob_type/grass
#define TYPE_ELECTRIC /datum/mob_type/electric
#define TYPE_GROUND /datum/mob_type/ground
#define TYPE_ROCK /datum/mob_type/rock
#define TYPE_BUG /datum/mob_type/bug
#define TYPE_POISON /datum/mob_type/poison
#define TYPE_NORMAL /datum/mob_type/normal
#define TYPE_FIGHTING /datum/mob_type/fighting
#define TYPE_PSYCHIC /datum/mob_type/psychic
#define TYPE_GHOST /datum/mob_type/ghost
#define TYPE_ICE /datum/mob_type/ice
#define TYPE_FLYING /datum/mob_type/flying
#define TYPE_BLUESPACE /datum/mob_type/bluespace
#define TYPE_DARK /datum/mob_type/dark
#define TYPE_STEEL /datum/mob_type/steel
/datum/mob_hunt
//GENERAL STATS AND VARIABLES
var/mob_name = "Generic Mob" //the mob's original name (its species/type/whatever)
var/nickname = "" //the mob's nickname (if given by the owner)
var/run_chance = 0 //percent chance the mob will escape capture attempts (higher is obviously more likely to get away)
//COMBAT STATS AND VARIABLES
var/level = 0 //actual level of this mob (don't set this, it gets overwritten in New())
var/min_level = 1 //minimum level of this mob (used for randomizing the actual level)
var/max_level = 1 //maximum level of this mob (used for randomizing the actual level)
var/exp = 0 //number of battles the mob has won towards the next level (resets to 0 on level-up)
var/exp_to_level = 3 //number of battles the mob must win to level up (in case we want to make some mobs harder or easier to level)
//the types of the mob will be used for battles to determine damage resistance or weakness (mob_type_datums.dm)
var/datum/mob_type/primary_type //Make sure you set this or the mob will be unable to deal damage and will take absurd damage in battles
var/datum/mob_type/secondary_type //Don't set if not a dual-type mob so the mob will only calculate damage based on primary type
var/base_attack = 5 //base damage dealt by the mob's attacks for battling (effectively damage dealt at level 0)
var/base_health = 5 //base health of the mob for battling (effectively max health at level 0)
var/attack_multiplier = 1 //how much additional damage per level the mob deals (level * attack_multiplier)
var/health_multiplier = 1 //how much additional health per level the mob gets (level * health_multiplier) for calculating max health
var/cur_health = 0
var/max_health = 0
//SPAWN PREFERENCES AND VARIABLES
//A note on mob spawn preferences: The mob types also have preferences, which are handled prior to per-mob preferences, so ultimately you use a combined set of preferences
var/list/area_blacklist = list() //list of areas this mob can NOT spawn in (such as the bridge)
var/list/turf_blacklist = list() //list of turfs this mob can NOT spawn on (such as wood floors)
var/list/area_whitelist = list() //list of areas this mob is more likely to spawn in (can be used to reinclude subtypes of blacklisted areas)
var/list/turf_whitelist = list() //list of turfs this mob is more likely to spawn on (can be used to reinclude subtypes of blacklisted turfs)
var/turf/spawn_point //gets set and sent to the game server to spawn its avatar (generated in select_spawn or assigned via set_trap)
var/lifetime = 6000 //number of deciseconds the mob will remain before despawning (REMEMBER: DECISECONDS! So 6000 is 600 seconds which is 10 minutes)
var/is_shiny = 0 //if this gets set at spawn (super rare), the mob is considered "shiny" and will use the shiny icon_state and holographic cards
//the icon file for mob_hunt stuff is 'icons/effects/mob_hunt.dmi' so reference that for the following vars
var/icon_state_normal = "placeholder" //the icon_state for this mob's normal version
var/icon_state_shiny = "placeholder" //the icon_state for this mob's rare shiney version
var/is_trap = 0 //if this gets set, the mob is a booby-trap and will electrocute any players that dare attempt to catch it
/datum/mob_hunt/New(set_trap = 0, turf/trap_turf = null, no_register = 0)
if(set_trap)
level = max_level
is_trap = 1
spawn_point = trap_turf
else
level = rand(min_level, max_level)
if(prob(1) && prob(1))
is_shiny = 1
max_health = base_health + (level * health_multiplier)
cur_health = max_health
if(primary_type)
primary_type = new primary_type()
if(secondary_type)
secondary_type = new secondary_type()
if(no_register) //for booster pack cards
return
if(SSmob_hunt)
if(set_trap)
if(SSmob_hunt.register_trap(src))
return
else if(select_spawn())
if(SSmob_hunt.register_spawn(src))
return
qdel(src) //if you reach this, the datum is just pure clutter, so delete it
/datum/mob_hunt/proc/select_spawn()
var/list/possible_areas = get_possible_areas()
if(!possible_areas.len)
log_admin("No possible areas to spawn [type] found. Possible code/mapping error?")
return 0
while(possible_areas.len)
//randomly select an area from our possible_areas list to try spawning in, then remove it from possible_areas so it won't get picked over and over forever.
var/area/spawn_area = locate(pickweight(possible_areas))
possible_areas -= spawn_area
if(!spawn_area)
break
//clear and generate a fresh list of turfs in the selected area, weighted based on white/black lists
var/list/possible_turfs = get_possible_turfs(spawn_area)
if(!possible_turfs.len) //If we don't have any possible turfs, this attempt was a failure. Try again.
continue
//if we got this far, we're spawning on this attempt, hooray!
spawn_point = pickweight(possible_turfs)
break
if(!spawn_point)
//if we get to this, we failed every attempt to find a suitable turf for EVERY area in our list of possible areas. DAMN.
log_admin("No acceptable turfs to spawn [type] on could be located. Possible code/mapping error, or someone replaced/destroyed all the acceptable turf types?")
return 0
return 1
/datum/mob_hunt/proc/get_possible_areas()
var/list/possible_areas = list()
//setup, sets all station areas (and subtypes) to weight 1
for(var/A in the_station_areas)
if(A == /area/holodeck) //don't allow holodeck areas as possible spawns since it will allow it to spawn in the holodeck rooms on z2 as well
continue
if(A in possible_areas)
continue
for(var/areapath in typesof(A))
possible_areas[areapath] = 1
//primary type preferences
if(primary_type)
for(var/A in primary_type.area_whitelist)
for(var/areapath in typesof(A))
possible_areas[areapath] += 4
for(var/A in primary_type.area_blacklist)
for(var/areapath in typesof(A))
possible_areas[areapath] -= 2
//secondary type preferences
if(secondary_type)
for(var/A in secondary_type.area_whitelist)
for(var/areapath in typesof(A))
possible_areas[areapath] += 4
for(var/A in secondary_type.area_blacklist)
for(var/areapath in typesof(A))
possible_areas[areapath] -= 2
//mob preferences
for(var/A in area_whitelist)
for(var/areapath in typesof(A))
possible_areas[areapath] += 4
for(var/A in area_blacklist)
for(var/areapath in typesof(A))
possible_areas[areapath] -= 2
//removes "bad areas" which shouldn't be on-station but are subtypes of station areas. probably should the unused ones and consider repathing the rest
var/list/bad_areas = list(subtypesof(/area/construction), /area/solar/derelict_starboard, /area/solar/derelict_aft, /area/solar/constructionsite)
for(var/A in bad_areas)
possible_areas -= A
//weight check, remove negative or zero weight areas from the list, then return the list.
for(var/areapath in possible_areas)
//remove any areas that shouldn't be on the station-level
if(possible_areas[areapath] < 1)
possible_areas -= areapath
continue
return possible_areas
/datum/mob_hunt/proc/get_possible_turfs(area/spawn_area)
if(!spawn_area)
return list()
var/list/possible_turfs = list()
//setup, sets all turfs in spawn_area to weight 1
for(var/turf/T in spawn_area)
if(!is_station_level(T.z)) //mobs will only consider station-level turfs for spawning. Largely here so we won't have to worry about mapping errors or mobs on the derelict solars
continue
possible_turfs[T] = 1
//primary type preferences
if(primary_type)
if(is_type_in_list(T, primary_type.turf_whitelist))
possible_turfs[T] += 4
if(is_type_in_list(T, primary_type.turf_blacklist))
possible_turfs[T] -= 2
//secondary type preferences
if(secondary_type)
if(is_type_in_list(T, secondary_type.turf_whitelist))
possible_turfs[T] += 4
if(is_type_in_list(T, secondary_type.turf_blacklist))
possible_turfs[T] -= 2
//mob preferences
if(is_type_in_list(T, turf_whitelist))
possible_turfs[T] += 4
if(is_type_in_list(T, turf_blacklist))
possible_turfs[T] -= 2
//weight check, remove negative or zero weight turfs from the list, then return the list
if(possible_turfs[T] < 1)
possible_turfs -= T
return possible_turfs
/datum/mob_hunt/proc/calc_def_multiplier(datum/mob_type/attack_type)
if(!primary_type)
return 99 //typeless mobs are weak to everything since they shouldn't exist
if(!attack_type) //typeless attacks will return a multiplier of 1 in case we want to use this for calculating unmodified damage for some reason (UI maybe?)
return 1
var/multiplier = 1
if(attack_type in primary_type.immunity)
return 0 //a single immunity negates all damage
else if(attack_type in primary_type.resistance)
multiplier *= 0.5
else if(attack_type in primary_type.weakness)
multiplier *= 2
else
multiplier *= 1
if(!secondary_type) //if we don't have a second type, we're done here
return multiplier
if(attack_type in secondary_type.immunity)
return 0 //a single immunity negates all damage
else if(attack_type in secondary_type.resistance)
multiplier *= 0.5
else if(attack_type in secondary_type.weakness)
multiplier *= 2
else
multiplier *= 1
return multiplier
/datum/mob_hunt/proc/take_damage(raw_damage, datum/mob_type/attack_type)
var/message = ""
var/multiplier = calc_def_multiplier(attack_type)
var/total_damage = raw_damage * multiplier
if(!cur_health) //it's already downed, quit hitting it
return null
if(!total_damage)
message += "The attack is completely ineffective! "
else
cur_health = max(cur_health - total_damage, 0)
switch(multiplier)
if(0)
message += "The attack is completely ineffective! "
if(0.25)
message += "It's barely effective... "
if(0.5)
message += "It's not very effective... "
if(2)
message += "It's super effective! "
if(4)
message += "It's ultra effective! "
if(99)
message += pick("REKT! ", "DUNKED! ", "DEFENSE BREAK! ", "WOMBO-COMBO'D!")
if(!cur_health)
message += "[nickname ? nickname : mob_name] is downed!"
return message
/datum/mob_hunt/proc/get_raw_damage()
return (level * attack_multiplier)
/datum/mob_hunt/proc/get_attack_type()
var/datum/mob_type/attack_type = primary_type
if(secondary_type && prob(40))
attack_type = secondary_type
return attack_type
/datum/mob_hunt/proc/gain_exp()
exp++
var/message = "[nickname ? nickname : mob_name] gained EXP! ([exp] / [exp_to_level] EXP)"
if(exp >= exp_to_level)
message = levelup()
return message
/datum/mob_hunt/proc/levelup()
var/message = ""
level++
exp = 0
if(level > max_level) //This is where we would trigger an evolution, when those are added (need to add evolved forms first)
level = max_level //for now though, we'll just cap them back at their max_level
message += "[nickname ? nickname : mob_name] can't get any stronger right now!"
else
max_health = base_health + (level * health_multiplier)
cur_health = max_health //full heal on level-up
message += "[nickname ? nickname : mob_name] has reached level [level]!"
return message
/datum/mob_hunt/proc/get_type1()
if(!primary_type)
return "Typeless"
else
return primary_type.name
/datum/mob_hunt/proc/get_type2()
if(!secondary_type)
return null
else
return secondary_type.name
/datum/mob_hunt/nemabug
mob_name = "Nemabug"
run_chance = 50
min_level = 1
max_level = 10
primary_type = TYPE_BUG
icon_state_normal = "nemabug"
icon_state_shiny = "nemabug_shiny"
lifetime = 6000
/datum/mob_hunt/stoutquill
mob_name = "Stoutquill"
run_chance = 50
min_level = 5
max_level = 15
primary_type = TYPE_ICE
icon_state_normal = "stoutquill"
icon_state_shiny = "stoutquill_shiny"
lifetime = 4500
/datum/mob_hunt/spectra
mob_name = "Spectra"
run_chance = 35
min_level = 1
max_level = 10
primary_type = TYPE_POISON
icon_state_normal = "spectra"
icon_state_shiny = "spectra_shiny"
lifetime = 6000
/datum/mob_hunt/dunny
mob_name = "Dunny"
run_chance = 35
min_level = 1
max_level = 10
primary_type = TYPE_FIRE
icon_state_normal = "dunny"
icon_state_shiny = "dunny_shiny"
lifetime = 6000
/datum/mob_hunt/buffsel
mob_name = "Buffsel"
run_chance = 35
min_level = 1
max_level = 10
primary_type = TYPE_ROCK
icon_state_normal = "buffsel"
icon_state_shiny = "buffsel_shiny"
lifetime = 6000
/datum/mob_hunt/quarrel
mob_name = "Quarrel"
run_chance = 35
min_level = 1
max_level = 10
primary_type = TYPE_NORMAL
icon_state_normal = "quarrel"
icon_state_shiny = "quarrel_shiny"
lifetime = 6000
/datum/mob_hunt/vulerrt
mob_name = "Vulerrt"
run_chance = 50
min_level = 5
max_level = 15
primary_type = TYPE_DARK
icon_state_normal = "vulerrt"
icon_state_shiny = "vulerrt_shiny"
turf_whitelist = list()
lifetime = 4500
/datum/mob_hunt/strudel
mob_name = "Strudel"
run_chance = 35
min_level = 1
max_level = 10
primary_type = TYPE_ELECTRIC
icon_state_normal = "strudel"
icon_state_shiny = "strudel_shiny"
lifetime = 4500
/datum/mob_hunt/folstick
mob_name = "Folstick"
run_chance = 35
min_level = 1
max_level = 10
primary_type = TYPE_WATER
icon_state_normal = "folstick"
icon_state_shiny = "folstick_shiny"
lifetime = 6000
/datum/mob_hunt/glimmerflare
mob_name = "Glimmerflare"
run_chance = 50
min_level = 5
max_level = 15
primary_type = TYPE_PSYCHIC
icon_state_normal = "glimmerflare"
icon_state_shiny = "glimmerflare_shiny"
lifetime = 4500
/datum/mob_hunt/leecoon
mob_name = "Leecoon"
run_chance = 35
min_level = 1
max_level = 10
primary_type = TYPE_GRASS
icon_state_normal = "leecoon"
icon_state_shiny = "leecoon_shiny"
lifetime = 6000
/datum/mob_hunt/halk
mob_name = "Halk"
run_chance = 35
min_level = 1
max_level = 10
primary_type = TYPE_FLYING
icon_state_normal = "halk"
icon_state_shiny = "halk_shiny"
lifetime = 6000
/datum/mob_hunt/gooby
mob_name = "Gooby"
run_chance = 65
min_level = 5
max_level = 20
primary_type = TYPE_ELECTRIC
secondary_type = TYPE_BUG
icon_state_normal = "gooby"
icon_state_shiny = "gooby_shiny"
lifetime = 3000
/datum/mob_hunt/pandoom
mob_name = "Pandoom"
run_chance = 50
min_level = 5
max_level = 15
primary_type = TYPE_GHOST
icon_state_normal = "pandoom"
icon_state_shiny = "pandoom_shiny"
lifetime = 4500
/datum/mob_hunt/relish
mob_name = "Relish"
run_chance = 65
min_level = 5
max_level = 20
primary_type = TYPE_FIRE
secondary_type = TYPE_GROUND
icon_state_normal = "relish"
icon_state_shiny = "relish_shiny"
lifetime = 3000
/datum/mob_hunt/xofine
mob_name = "Xofine"
run_chance = 50
min_level = 5
max_level = 10
primary_type = TYPE_FIRE
secondary_type = TYPE_NORMAL
icon_state_normal = "xofine"
icon_state_shiny = "xofine_shiny"
lifetime = 3000
/datum/mob_hunt/gitten
mob_name = "Gitten"
run_chance = 65
min_level = 5
max_level = 20
primary_type = TYPE_WATER
secondary_type = TYPE_POISON
icon_state_normal = "gitten"
icon_state_shiny = "gitten_shiny"
lifetime = 3000
/datum/mob_hunt/nai
mob_name = "Nai"
run_chance = 65
min_level = 5
max_level = 20
primary_type = TYPE_GRASS
secondary_type = TYPE_NORMAL
icon_state_normal = "nai"
icon_state_shiny = "nai_shiny"
lifetime = 3000
/datum/mob_hunt/pyroghast
mob_name = "Pyroghast"
run_chance = 65
min_level = 5
max_level = 20
primary_type = TYPE_FIRE
secondary_type = TYPE_GHOST
icon_state_normal = "pyroghast"
icon_state_shiny = "pyroghast"
lifetime = 4500
/datum/mob_hunt/starslam
mob_name = "Starslam"
run_chance = 65
min_level = 5
max_level = 20
primary_type = TYPE_FIGHTING
secondary_type = TYPE_ICE
icon_state_normal = "starslam"
icon_state_shiny = "starslam_shiny"
lifetime = 2500
/datum/mob_hunt/pheron
mob_name = "Pheron"
run_chance = 85
min_level = 10
max_level = 20
primary_type = TYPE_BLUESPACE
icon_state_normal = "pheron"
icon_state_shiny = "pheron_shiny"
area_blacklist = list()
turf_blacklist = list()
area_whitelist = list()
turf_whitelist = list()
lifetime = 2000