From 0a0c2c79f9bcf8c0aa2d71d38d492c3f9aed780f Mon Sep 17 00:00:00 2001 From: ZomgPonies Date: Tue, 17 Sep 2013 14:27:25 -0400 Subject: [PATCH] Framework for Job Objectives --- baystation12.dme | 2 + .../helper_datums/construction_datum.dm | 12 ++- code/datums/mind.dm | 9 ++ code/game/gamemodes/game_mode.dm | 70 ++++++++++++++-- code/game/gamemodes/gameticker.dm | 3 + code/game/jobs/job/job.dm | 6 ++ code/game/jobs/job/science.dm | 22 +++++ code/game/jobs/job_controller.dm | 11 +++ code/game/jobs/job_objective.dm | 83 +++++++++++++++++++ code/game/jobs/job_objectives/science.dm | 60 ++++++++++++++ code/game/objects/items/robot/robot_parts.dm | 4 + code/modules/research/rdconsole.dm | 16 ++++ code/modules/research/research.dm | 11 +++ 13 files changed, 303 insertions(+), 6 deletions(-) create mode 100644 code/game/jobs/job_objective.dm create mode 100644 code/game/jobs/job_objectives/science.dm diff --git a/baystation12.dme b/baystation12.dme index d3fe8271b4e..2eae08c0638 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -282,6 +282,7 @@ #include "code\game\gamemodes\wizard\wizard.dm" #include "code\game\jobs\access.dm" #include "code\game\jobs\job_controller.dm" +#include "code\game\jobs\job_objective.dm" #include "code\game\jobs\jobprocs.dm" #include "code\game\jobs\jobs.dm" #include "code\game\jobs\whitelist.dm" @@ -295,6 +296,7 @@ #include "code\game\jobs\job\science.dm" #include "code\game\jobs\job\security.dm" #include "code\game\jobs\job\silicon.dm" +#include "code\game\jobs\job_objectives\science.dm" #include "code\game\machinery\adv_med.dm" #include "code\game\machinery\ai_slipper.dm" #include "code\game\machinery\airlock_control.dm" diff --git a/code/datums/helper_datums/construction_datum.dm b/code/datums/helper_datums/construction_datum.dm index 7c2fabbc9b8..03c0eba193a 100644 --- a/code/datums/helper_datums/construction_datum.dm +++ b/code/datums/helper_datums/construction_datum.dm @@ -57,8 +57,18 @@ return 0 - proc/spawn_result() + proc/spawn_result(mob/user as mob) if(result) + // PAY ME + var/taskpath=null + switch(result) + if(/obj/mecha/working/ripley) + taskpath = /datum/job_objective/make_ripley + if(taskpath) + var/datum/job_objective/task = user.mind.findJobTask(taskpath) + if(istype(task)) + task.unit_completed() + new result(get_turf(holder)) spawn() del holder diff --git a/code/datums/mind.dm b/code/datums/mind.dm index de62826dffa..ed05177a4a0 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -99,6 +99,15 @@ datum/mind output += "Objective #[obj_count]: [objective.explanation_text]" obj_count++ + if(job_objectives.len>0) + output += "
Job Objectives:" + recipient << browse(output,"window=memory") proc/edit_memory() diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 2bb9526117d..33a9ef20d6b 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -22,7 +22,7 @@ var/explosion_in_progress = 0 //sit back and relax var/list/datum/mind/modePlayer = new var/list/restricted_jobs = list() // Jobs it doesn't make sense to be. I.E chaplain or AI cultist - var/list/protected_jobs = list() // Jobs that can't be tratiors because + var/list/protected_jobs = list() // Jobs that can't be trators var/required_players = 0 var/required_players_secret = 0 //Minimum number of players for that game mode to be chose in Secret var/required_enemies = 0 @@ -70,10 +70,6 @@ Implants; (Pointless) Badassery; /obj/item/toy/syndicateballoon:10:For showing that You Are The BOSS (Useless Balloon);"} -// Items removed from above: -/* -/obj/item/weapon/cloaking_device:4:Cloaking Device; //Replacing cloakers with thermals. -Pete -*/ /datum/game_mode/proc/announce() //to be calles when round starts world << "Notice: [src] did not define announce()" @@ -122,6 +118,70 @@ Implants; /datum/game_mode/proc/process() return 0 +//Called by the gameticker +/datum/game_mode/proc/process_job_tasks() + var/obj/machinery/message_server/useMS = null + if(message_servers) + for (var/obj/machinery/message_server/MS in message_servers) + if(MS.active) + useMS = MS + break + for(var/mob/M in player_list) + if(M.mind) + var/obj/item/device/pda/P=null + for(var/obj/item/device/pda/check_pda in sortAtom(PDAs)) + if (check_pda.owner==M.name) + P=check_pda + break + var/count=0 + for(var/datum/job_objective/objective in M.mind.job_objectives) + count++ + var/msg="" + var/pay=0 + if(objective.per_unit && objective.units_needing_compensation>0) + var/newunits = objective.units_needing_compensation + msg="We see that you completed [newunits] new unit[newunits>1?"s":""] for Task #[count]! " + pay=objective.completion_payment * newunits + else if(!objective.completed) + if(objective.is_completed()) + pay=objective.completion_payment + msg="Task #[count] completed! " + if(pay>0) + if(M.mind.initial_account) + M.mind.initial_account.money += objective.completion_payment + var/datum/transaction/T = new() + T.target_name = "[command_name()] Payroll" + T.purpose = "Payment" + T.amount = objective.completion_payment + T.date = current_date_string + T.time = worldtime2text() + T.source_terminal = "\[CLASSIFIED\] Terminal #[rand(111,333)]" + M.mind.initial_account.transaction_log.Add(T) + msg += "You have been sent the $[pay], as agreed." + else + msg += "However, we were unable to send you the $[pay] you're entitled." + if(useMS) + // THIS SHOULD HAVE DONE EVERYTHING FOR ME + useMS.send_pda_message("[P.owner]", "[command_name()] Payroll", msg) + + // BUT NOPE, NEED TO DO THIS BULLSHIT. + P.tnote += "← From [command_name()] (Payroll):
[msg]
" + + if (!P.silent) + playsound(P.loc, 'sound/machines/twobeep.ogg', 50, 1) + for (var/mob/O in hearers(3, P.loc)) + if(!P.silent) O.show_message(text("\icon[P] *[P.ttone]*")) + //Search for holder of the PDA. + var/mob/living/L = null + if(P.loc && isliving(P.loc)) + L = P.loc + //Maybe they are a pAI! + else + L = get(P, /mob/living/silicon) + + if(L) + L << "\icon[P] Message from [command_name()] (Payroll), \"[msg]\" (Unable to Reply)" + break /datum/game_mode/proc/check_finished() //to be called by ticker if(emergency_shuttle.location==2 || station_was_nuked) diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index 4d83aa5eefa..edf58d23756 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -298,6 +298,7 @@ var/global/datum/controller/gameticker/ticker return 0 mode.process() + mode.process_job_tasks() emergency_shuttle.process() @@ -366,6 +367,8 @@ var/global/datum/controller/gameticker/ticker mode.declare_completion()//To declare normal completion. + mode.declare_job_completion() + //calls auto_declare_completion_* for all modes for(var/handler in typesof(/datum/game_mode/proc)) if (findtext("[handler]","auto_declare_completion_")) diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index 682c80f1741..2c312a49ff5 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -41,6 +41,12 @@ //If you have use_age_restriction_for_jobs config option enabled and the database set up, this option will add a requirement for players to be at least minimal_player_age days old. (meaning they first signed in at least that many days before.) var/minimal_player_age = 0 + ///////////////////////////////// + // /vg/ feature: Job Objectives! + ///////////////////////////////// + var/required_objectives=list() // Objectives that are ALWAYS added. + var/optional_objectives=list() // Objectives that are SOMETIMES added. + /datum/job/proc/equip(var/mob/living/carbon/human/H) return 1 diff --git a/code/game/jobs/job/science.dm b/code/game/jobs/job/science.dm index 8f0f10c214d..059423206b2 100644 --- a/code/game/jobs/job/science.dm +++ b/code/game/jobs/job/science.dm @@ -19,6 +19,11 @@ access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch) minimal_player_age = 7 + // All science-y guys get bonuses for maxing out their tech. + required_objectives=list( + /datum/job_objective/maximize_research + ) + equip(var/mob/living/carbon/human/H) if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/rd(H), slot_ears) @@ -49,6 +54,11 @@ minimal_access = list(access_tox, access_tox_storage, access_research, access_xenoarch) alt_titles = list("Xenoarcheologist", "Anomalist", "Plasma Researcher") + // All science-y guys get bonuses for maxing out their tech. + required_objectives=list( + /datum/job_objective/maximize_research + ) + equip(var/mob/living/carbon/human/H) if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_sci(H), slot_ears) @@ -76,6 +86,12 @@ access = list(access_robotics, access_tox, access_tox_storage, access_research, access_xenobiology) minimal_access = list(access_research, access_xenobiology) + // All science-y guys get bonuses for maxing out their tech. + required_objectives=list( + /datum/job_objective/maximize_research + ) + + equip(var/mob/living/carbon/human/H) if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_sci(H), slot_ears) @@ -103,6 +119,12 @@ minimal_access = list(access_robotics, access_tech_storage, access_morgue, access_research) //As a job that handles so many corpses, it makes sense for them to have morgue access. alt_titles = list("Biomechanical Engineer","Mechatronic Engineer") + required_objectives=list( + /datum/job_objective/make_cyborg, +// /datum/job_objective/make_mommi, + /datum/job_objective/make_ripley + ) + equip(var/mob/living/carbon/human/H) if(!H) return 0 H.equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_sci(H), slot_ears) diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm index fc5f7df203a..7ede79586b2 100644 --- a/code/game/jobs/job_controller.dm +++ b/code/game/jobs/job_controller.dm @@ -59,6 +59,17 @@ var/global/datum/controller/occupations/job_master Debug("Player: [player] is now Rank: [rank], JCP:[job.current_positions], JPL:[position_limit]") player.mind.assigned_role = rank player.mind.role_alt_title = GetPlayerAltTitle(player, rank) + + // JOB OBJECTIVES OH SHIT + player.mind.job_objectives.Cut() + for(var/objectiveType in job.required_objectives) + new objectiveType(player.mind) + + // 50/50 chance of getting optional objectives. + for(var/objectiveType in job.optional_objectives) + if(prob(50)) + new objectiveType(player.mind) + unassigned -= player job.current_positions++ return 1 diff --git a/code/game/jobs/job_objective.dm b/code/game/jobs/job_objective.dm new file mode 100644 index 00000000000..1c8bbe79fcc --- /dev/null +++ b/code/game/jobs/job_objective.dm @@ -0,0 +1,83 @@ +/datum/mind/var/list/job_objectives=list() + +#define FINDJOBTASK_DEFAULT_NEW 1 // Make a new task of this type if one can't be found. +/datum/mind/proc/findJobTask(var/typepath,var/options) + var/datum/job_objective/task = locate(typepath) in src.job_objectives + if(!istype(task,typepath)) + if(options & FINDJOBTASK_DEFAULT_NEW) + task = new typepath() + src.job_objectives += task + return task + else + return null + +/datum/job_objective + var/datum/mind/owner = null //Who owns the objective. + var/completed = 0 //currently only used for custom objectives. + var/per_unit = 0 + var/units_completed = 0 + var/units_needing_compensation = 0 // Shit not yet paid for + var/units_requested = INFINITY + var/completion_payment = 0 // Credits paid to owner when completed + +/datum/job_objective/New(var/datum/mind/new_owner) + owner=new_owner + owner.job_objectives += src + +/datum/job_objective/Del() + +/datum/job_objective/proc/get_description() + return "Placeholder objective." + +/datum/job_objective/proc/unit_completed(var/count=1) + units_completed += count + units_needing_compensation += count + +/datum/job_objective/proc/is_completed() + if(!completed) + completed = check_for_completion() + return completed + +/datum/job_objective/proc/check_for_completion() + return 0 + +/datum/game_mode/proc/declare_job_completion() + var/text = "Job Completion:" + for(var/datum/mind/employee in player_list) + if(!employee.job_objectives.len)//If the employee had no objectives, don't need to process this. + return + var/tasks_completed=0 + + //text += "[L.name] ([ckey(D.mind.key)]), the [L.job]:\n" + text += "
[employee.key] was [employee.name] (" + if(employee.current) + if(employee.current.stat == DEAD) + text += "died" + else + text += "survived" + if(employee.current.real_name != employee.name) + text += " as [employee.current.real_name]" + else + text += "body destroyed" + text += ")" + + var/count = 1 + for(var/datum/job_objective/objective in employee.job_objectives) + if(objective.is_completed(1)) + text += "
Task #[count]: [objective.get_description()] Completed!" + feedback_add_details("employee_objective","[objective.type]|SUCCESS") + tasks_completed++ + else + text += "
Task #[count]: [objective.get_description()] Fail." + feedback_add_details("employee_objective","[objective.type]|FAIL") + count++ + + if(tasks_completed>=1) + text += "
The [employee.assigned_role] did their fucking job!" + feedback_add_details("employee_success","SUCCESS") + else + text += "
The [employee.assigned_role] was a worthless sack of shit!" + feedback_add_details("employee_success","FAIL") + + world << text + return 1 \ No newline at end of file diff --git a/code/game/jobs/job_objectives/science.dm b/code/game/jobs/job_objectives/science.dm new file mode 100644 index 00000000000..996193ba66e --- /dev/null +++ b/code/game/jobs/job_objectives/science.dm @@ -0,0 +1,60 @@ +///////////////////////////////////////////////////////////////////////////////////////// +// Research +///////////////////////////////////////////////////////////////////////////////////////// + +// MAXIMUM SCIENCE +/datum/job_objective/maximize_research + completion_payment=1000 + +/datum/job_objective/maximize_research/get_description() + return "Maximize all legal research tech levels." + +/datum/job_objective/maximize_research/check_for_completion() + var/obj/machinery/r_n_d/server/server = null + for(var/obj/machinery/r_n_d/server/serber in machines) + if(serber.name == "Core R&D Server") + server=serber + break + if(!server) + // This was just used for testing. + //world << "UNABLE TO FIND A GODDAMN RND SERVER. FUCK." + return + for(var/datum/tech/T in server.files.possible_tech) + if(T.max_level==0) // Ignore illegal tech, etc + continue + var/datum/tech/KT = locate(T.type, server.files.known_tech) + if(!KT) + return 0 // Obviously haven't maxed everything if we don't know a tech. + if(KT.level