diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index 0f63673c085..b70fad502fc 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -280,6 +280,10 @@
C?.give_award(/datum/award/achievement/misc/threekhours, C.mob)
if(hours > 4000)
C?.give_award(/datum/award/achievement/misc/fourkhours, C.mob)
+ //NSV13 - emergency repair achievement hook
+ if(C && GLOB.plating_repairers["[C.ckey]"] && GLOB.plating_repairers["[C.ckey]"] >= 200)
+ C.give_award(/datum/award/achievement/misc/emergency_repairs, C.mob)
+ //NSV13 end
CHECK_TICK
diff --git a/code/datums/achievements/_achievement_data.dm b/code/datums/achievements/_achievement_data.dm
index c3b78a89d02..fce8e09d990 100644
--- a/code/datums/achievements/_achievement_data.dm
+++ b/code/datums/achievements/_achievement_data.dm
@@ -76,7 +76,7 @@
/datum/achievement_data/proc/increase_score(datum/award/score/achievement_type, mob/user, value)
var/datum/award/score/A = SSachievements.awards[achievement_type]
get_data(achievement_type) //Get the current status first if necessary
- if(length(A.high_scores) == 0 || A.high_scores[A.high_scores[1]] < value)
+ if(A.announce_highscore && (length(A.high_scores) == 0 || A.high_scores[A.high_scores[1]] < value)) //NSV13 - Adds support for non-spamming scores.
to_chat(world, "[user.client.key] set a new high score in [A.name]: [value]")
if(!data[achievement_type] || value > data[achievement_type])
data[achievement_type] = value
diff --git a/code/datums/achievements/_awards.dm b/code/datums/achievements/_awards.dm
index 01b52b8dd81..eb2324101e4 100644
--- a/code/datums/achievements/_awards.dm
+++ b/code/datums/achievements/_awards.dm
@@ -90,6 +90,8 @@
default_value = 0
var/track_high_scores = TRUE
var/list/high_scores = list()
+ ///Determines whether we announce if we achieve a new highscore.
+ var/announce_highscore = TRUE //NSV13 - no spammies
/datum/award/score/New()
. = ..()
diff --git a/config/starmap/starmap_default.json b/config/starmap/starmap_default.json
index e5f9871a8e3..0bf3032dcca 100644
--- a/config/starmap/starmap_default.json
+++ b/config/starmap/starmap_default.json
@@ -1146,7 +1146,7 @@
"is_hypergate": 0,
"preset_trader": null,
"audio_cues": "[]",
- "startup_proc": null
+ "startup_proc": "STARTUP_PROC_TYPE_DOLOS"
},
{
"name": "Abassi",
@@ -1169,7 +1169,7 @@
"is_hypergate": 0,
"preset_trader": null,
"audio_cues": "[]",
- "startup_proc": null
+ "startup_proc": "STARTUP_PROC_TYPE_ABASSI"
},
{
"name": "Oasis Fidei",
diff --git a/nsv13/code/__DEFINES/medal.dm b/nsv13/code/__DEFINES/medal.dm
index 5f2fcb4c76c..06107ab7fc3 100644
--- a/nsv13/code/__DEFINES/medal.dm
+++ b/nsv13/code/__DEFINES/medal.dm
@@ -2,3 +2,12 @@
#define MEDAL_CREW_VERYCOMPETENT "On the frontlines"
#define MEDAL_CREW_EXTREMELYCOMPETENT "Pre-emptive strike"
#define MEDAL_CREW_HYPERCOMPETENT "Cleared the Abassi Ridge"
+
+#define MEDAL_PIRATE_EXTERMINATOR "Pirate Exterminator"
+#define MEDAL_FIST_BREAKER "Fist Breaker"
+#define MEDAL_TORP_DIRECTHIT "OW!!!"
+#define MEDAL_EMERGENCY_REPAIRS "Emergency Repairs"
+#define MEDAL_BLACKHOLE_INCIDENT "AAAAAAAAAAAAA"
+#define MEDAL_ILLEGAL_TECHNOLOGY "Regulation 10124"
+
+#define TORPCOUNT_SCORE "Torpedo Technician"
diff --git a/nsv13/code/__DEFINES/starsystem.dm b/nsv13/code/__DEFINES/starsystem.dm
index 47dbd5c63e7..050249ef105 100644
--- a/nsv13/code/__DEFINES/starsystem.dm
+++ b/nsv13/code/__DEFINES/starsystem.dm
@@ -13,3 +13,5 @@
#define SECTOR_SOL 1
#define SECTOR_NEUTRAL 2
#define SECTOR_SYNDICATE 3
+
+#define COMSIG_STAR_SYSTEM_AFTER_ENTER "star_system_after_enter"
diff --git a/nsv13/code/controllers/subsystem/overmap_mode.dm b/nsv13/code/controllers/subsystem/overmap_mode.dm
index f0e6b0903a5..921a148c8d9 100644
--- a/nsv13/code/controllers/subsystem/overmap_mode.dm
+++ b/nsv13/code/controllers/subsystem/overmap_mode.dm
@@ -49,6 +49,11 @@ SUBSYSTEM_DEF(overmap_mode)
var/list/modes
var/list/mode_names
+ ///Have we already handed people the base achievement this round?
+ var/patrol_achievement_base_granted = FALSE
+ ///Have we already handed people the extended patrol achievement this round?
+ var/patrol_achievement_adv_granted = FALSE
+
/datum/controller/subsystem/overmap_mode/Initialize(start_timeofday)
//Retrieve the list of modes
//Check our map for any white/black lists
@@ -458,6 +463,27 @@ SUBSYSTEM_DEF(overmap_mode)
mode.winner = F //This should allow the mode to finish up by itself
mode.check_finished()
if((objective_check >= objective_length) && !failed)
+ var/achievement_type
+ if(!SSovermap_mode.round_extended)
+ if(!SSovermap_mode.patrol_achievement_base_granted)
+ achievement_type = /datum/award/achievement/misc/crew_competent
+ SSovermap_mode.patrol_achievement_base_granted = TRUE
+ else
+ if(!SSovermap_mode.patrol_achievement_adv_granted)
+ achievement_type = /datum/award/achievement/misc/crew_very_competent
+ SSovermap_mode.patrol_achievement_adv_granted = TRUE
+ if(achievement_type)
+ for(var/mob/living/living_mob in GLOB.mob_living_list)
+ if(!living_mob.job)
+ continue
+ var/datum/job/job_ref = SSjob.GetJob(living_mob.job)
+ if(!job_ref)
+ continue
+ if(job_ref.faction != "Station")
+ continue
+ if(!living_mob.client)
+ continue
+ living_mob.client.give_award(achievement_type, living_mob)
victory()
/datum/overmap_gamemode/proc/victory()
diff --git a/nsv13/code/controllers/subsystem/starsystem.dm b/nsv13/code/controllers/subsystem/starsystem.dm
index a75482a2061..51445fd48e5 100644
--- a/nsv13/code/controllers/subsystem/starsystem.dm
+++ b/nsv13/code/controllers/subsystem/starsystem.dm
@@ -384,6 +384,24 @@ Returns a faction datum by its name (case insensitive!)
return FALSE
return (world.time - info["from_time"])/(info["to_time"] - info["from_time"])
+/datum/controller/subsystem/star_system/proc/dolos_visited(datum/star_system/source, obj/structure/overmap/entering)
+ SIGNAL_HANDLER
+ if(entering.ai_controlled)
+ return
+ for(var/mob/living/visitor in entering.mobs_in_ship)
+ if(!visitor.client)
+ continue
+ INVOKE_ASYNC(visitor.client, TYPE_PROC_REF(/client, give_award), /datum/award/achievement/misc/crew_extremely_competent, visitor)
+
+/datum/controller/subsystem/star_system/proc/abassi_visited(datum/star_system/source, obj/structure/overmap/entering)
+ SIGNAL_HANDLER
+ if(entering.ai_controlled)
+ return
+ for(var/mob/living/visitor in entering.mobs_in_ship)
+ if(!visitor.client)
+ continue
+ INVOKE_ASYNC(visitor.client, TYPE_PROC_REF(/client, give_award), /datum/award/achievement/misc/crew_hypercompetent, visitor)
+
//////star_system DATUM///////
/datum/star_system
@@ -447,6 +465,10 @@ Returns a faction datum by its name (case insensitive!)
if("STARTUP_PROC_TYPE_BRASIL_LITE")
addtimer(CALLBACK(src, PROC_REF(generate_litelands)), 5 SECONDS)
return
+ if("STARTUP_PROC_TYPE_DOLOS")
+ addtimer(CALLBACK(src, PROC_REF(register_dolos_achievement)), 5 SECONDS)
+ if("STARTUP_PROC_TYPE_ABASSI")
+ addtimer(CALLBACK(src, PROC_REF(register_abassi_achievement)), 5 SECONDS)
message_admins("WARNING: Invalid startup_proc declared for [name]! Review your defines (~L438, starsystem.dm), please.")
return 1
@@ -661,10 +683,10 @@ Returns a faction datum by its name (case insensitive!)
OM.disable_dampeners()
RegisterSignal(OM, COMSIG_PARENT_QDELETING, PROC_REF(handle_affecting_del))
for(var/obj/structure/overmap/OM as() in affecting)
- if(overmap_dist(src, OM) > influence_range || !z || OM.z != z)
+ var/dist = overmap_dist(src, OM)
+ if(dist > influence_range || !z || OM.z != z)
stop_affecting(OM)
continue
- var/dist = get_dist(src, OM)
var/grav_level = OVERMAP_SINGULARITY_PROX_GRAVITY
if(dist <= redshift_range)
var/redshift ="#[num2hex(130-dist,2)][num2hex(0,2)][num2hex(0,2)]"
@@ -685,6 +707,7 @@ Returns a faction datum by its name (case insensitive!)
if(istype(crushed, /area/space))
continue
crushed.has_gravity = OVERMAP_SINGULARITY_DEATH_GRAV //You are dead.
+ grant_death_achievement(OM)
qdel(OM)
continue
if(grav_tracker[OM] != grav_level)
@@ -724,6 +747,12 @@ Returns a faction datum by its name (case insensitive!)
cached_colours[deleting] = null
UnregisterSignal(deleting, COMSIG_PARENT_QDELETING)
+/obj/effect/overmap_anomaly/singularity/proc/grant_death_achievement(obj/structure/overmap/congratulations)
+ for(var/mob/living/nice_job in congratulations.mobs_in_ship)
+ if(!nice_job.client)
+ continue
+ nice_job.client.give_award(/datum/award/achievement/misc/blackhole_incident, nice_job)
+
#undef OVERMAP_SINGULARITY_PROX_GRAVITY
#undef OVERMAP_SINGULARITY_REDSHIFT_GRAV
#undef OVERMAP_SINGULARITY_DANGER_GRAV
@@ -1567,6 +1596,17 @@ Random starsystem. Excluded from starmap saving, as they're generated at init.
#undef RANDOM_CONNECTION_BASE_CHANCE
#undef RANDOM_CONNECTION_REPEAT_PENALTY
+/*
+These are used to check if someone is visiting one of the special systems.
+Handled this way and done on the starsystem controller so we do not conflict with other signals that rely on star systems registering a signal onto themselves.
+*/
+
+/datum/star_system/proc/register_dolos_achievement()
+ SSstar_system.RegisterSignal(src, COMSIG_STAR_SYSTEM_AFTER_ENTER, TYPE_PROC_REF(/datum/controller/subsystem/star_system, dolos_visited))
+
+/datum/star_system/proc/register_abassi_achievement()
+ SSstar_system.RegisterSignal(src, COMSIG_STAR_SYSTEM_AFTER_ENTER, TYPE_PROC_REF(/datum/controller/subsystem/star_system, abassi_visited))
+
/*
Welcome to the endgame. This sector is the hardest you'll encounter in game and holds the Syndicate capital.
@@ -1629,6 +1669,7 @@ Welcome to the endgame. This sector is the hardest you'll encounter in game and
hidden = FALSE
desc = "A place where giants fell. You feel nothing save for an odd sense of unease and an eerie silence."
system_traits = STARSYSTEM_NO_ANOMALIES | STARSYSTEM_NO_WORMHOLE
+ startup_proc = "STARTUP_PROC_TYPE_DOLOS"
/datum/star_system/sector4/abassi
name = "Abassi"
@@ -1644,6 +1685,7 @@ Welcome to the endgame. This sector is the hardest you'll encounter in game and
threat_level = THREAT_LEVEL_DANGEROUS
hidden = TRUE
system_traits = STARSYSTEM_NO_ANOMALIES | STARSYSTEM_NO_WORMHOLE
+ startup_proc = "STARTUP_PROC_TYPE_ABASSI"
/datum/star_system/sector4/laststand
name = "Oasis Fidei" //oasis of faith
diff --git a/nsv13/code/datums/achievements/nsv_achievements.dm b/nsv13/code/datums/achievements/nsv_achievements.dm
index dc44bab2310..60d7f356797 100644
--- a/nsv13/code/datums/achievements/nsv_achievements.dm
+++ b/nsv13/code/datums/achievements/nsv_achievements.dm
@@ -1,23 +1,69 @@
/datum/award/achievement/misc/crew_competent
name = "Patrolling the border"
- desc = "FIXME"
+ desc = "Your first successful patrol!"
database_id = MEDAL_CREW_COMPETENT
- reward = 500
+ reward = 400
+ achievement_version = 2
/datum/award/achievement/misc/crew_very_competent
name = "On the frontlines"
- desc = "FIXME"
+ desc = "Shore leave? What is that?"
database_id = MEDAL_CREW_VERYCOMPETENT
- reward = 1000
+ reward = 800
+ achievement_version = 2
/datum/award/achievement/misc/crew_extremely_competent
name = "Pre-emptive strike"
- desc = "FIXME"
+ desc = "See a legendary battlefield with your own eyes."
database_id = MEDAL_CREW_EXTREMELYCOMPETENT
- reward = 2000
+ reward = 1500
+ achievement_version = 2
/datum/award/achievement/misc/crew_hypercompetent
name = "Cleared the Abassi Ridge"
- desc = "FIXME"
+ desc = "Visit a system few have lived to tell the tale of."
database_id = MEDAL_CREW_HYPERCOMPETENT
- reward = 5000
+ reward = 3000
+ achievement_version = 2
+
+/datum/award/achievement/misc/pirate_exterminator
+ name = "Pirate Exterminator"
+ desc = "Emerge victorious against a powerful pirate foe."
+ database_id = MEDAL_PIRATE_EXTERMINATOR
+ reward = 1000
+
+/datum/award/achievement/misc/fist_breaker
+ name = "Fist Breaker"
+ desc = "Syndicate Battleship? More like Syndicate scrap!"
+ database_id = MEDAL_FIST_BREAKER
+ reward = 1000
+
+/datum/award/achievement/misc/torp_directhit
+ name = "OW!!!"
+ desc = "Have a face-to-face encounter with a torpedo."
+ database_id = MEDAL_TORP_DIRECTHIT
+ reward = 200
+
+/datum/award/achievement/misc/emergency_repairs
+ name = "Emergency Repairs"
+ desc = "Repair a lot of armor plates during a single patrol."
+ database_id = MEDAL_EMERGENCY_REPAIRS
+ reward = 1000
+
+/datum/award/achievement/misc/blackhole_incident
+ name = "AAAAAAAAAAAAA"
+ desc = "Get a little bit too close to a black hole."
+ database_id = MEDAL_BLACKHOLE_INCIDENT
+ reward = 200
+
+/datum/award/achievement/misc/illegal_technology
+ name = "Regulation 10124"
+ desc = "Forget something important."
+ database_id = MEDAL_ILLEGAL_TECHNOLOGY
+ reward = 200
+
+/datum/award/score/torpcount
+ name = "Torpedo Technician"
+ desc = "Better get to making those torps!"
+ database_id = TORPCOUNT_SCORE
+ announce_highscore = FALSE //Please do not spam the chat if some muni tech is cooking.
diff --git a/nsv13/code/modules/munitions/ammunition/torpedos/torpedo_construction.dm b/nsv13/code/modules/munitions/ammunition/torpedos/torpedo_construction.dm
index 3a3a2cc6b9d..c97c802e585 100644
--- a/nsv13/code/modules/munitions/ammunition/torpedos/torpedo_construction.dm
+++ b/nsv13/code/modules/munitions/ammunition/torpedos/torpedo_construction.dm
@@ -214,13 +214,15 @@
if(tool.use_tool(src, user, 40, amount=1, volume=100))
to_chat(user, "")
state = 11
- check_completion()
+ check_completion(user)
return TRUE
. = ..()
-/obj/item/ship_weapon/ammunition/torpedo/torpedo_casing/proc/check_completion()
+/obj/item/ship_weapon/ammunition/torpedo/torpedo_casing/proc/check_completion(mob/user)
update_icon()
if(state >= 11)
+ if(user && user.client)
+ INVOKE_ASYNC(user.client, TYPE_PROC_REF(/client, give_award), /datum/award/score/torpcount, user)
new_torpedo(wh, gs, ps, iff)
return TRUE
diff --git a/nsv13/code/modules/overmap/FTL/ftl_jump.dm b/nsv13/code/modules/overmap/FTL/ftl_jump.dm
index 08cbd3547fd..bcdfc6b9120 100644
--- a/nsv13/code/modules/overmap/FTL/ftl_jump.dm
+++ b/nsv13/code/modules/overmap/FTL/ftl_jump.dm
@@ -42,6 +42,7 @@
after_enter(OM)
/datum/star_system/proc/after_enter(obj/structure/overmap/OM)
+ SEND_SIGNAL(src, COMSIG_STAR_SYSTEM_AFTER_ENTER, OM)
if(desc)
OM.relay(null, "Now entering [name]...
")
OM.relay(null, "[desc]")
diff --git a/nsv13/code/modules/overmap/ai-skynet.dm b/nsv13/code/modules/overmap/ai-skynet.dm
index 82be49c4fe0..650158d08c2 100644
--- a/nsv13/code/modules/overmap/ai-skynet.dm
+++ b/nsv13/code/modules/overmap/ai-skynet.dm
@@ -818,6 +818,19 @@ Adding tasks is easy! Just define a datum for it.
fleet_trait = FLEET_TRAIT_DEFENSE
reward = 100 //Difficult pirate fleet, so default reward.
+/datum/fleet/pirate/tortuga/defeat()
+ if(!current_system)
+ return ..()
+ for(var/obj/structure/overmap/survivor in current_system.system_contents)
+ if(survivor.ai_controlled)
+ continue
+ for(var/mob/living/victorious_mob in survivor.mobs_in_ship)
+ if(!victorious_mob.client)
+ continue
+ victorious_mob.client.give_award(/datum/award/achievement/misc/pirate_exterminator, victorious_mob)
+ return ..()
+
+
//Boss battles.
/datum/fleet/rubicon //Crossing the rubicon, are we?
@@ -991,6 +1004,13 @@ Adding tasks is easy! Just define a datum for it.
shield_scan_target.hail("Scans have detected that you are in posession of prohibited technology. \n Your IFF signature has been marked as 'persona non grata'. \n In accordance with SGC-reg #10124, your ship and lives are now forfeit. Evacuate all civilian personnel immediately and surrender yourselves.", name)
shield_scan_target.relay_to_nearby('nsv13/sound/effects/ship/solgov_scan_alert.ogg', ignore_self=FALSE)
shield_scan_target.faction = shield_scan_target.name
+ grant_oopsie_achievement(shield_scan_target)
+
+/datum/fleet/solgov/proc/grant_oopsie_achievement(obj/structure/overmap/fugitive)
+ for(var/mob/living/traitor in fugitive.mobs_in_ship)
+ if(!traitor.client)
+ continue
+ traitor.client.give_award(/datum/award/achievement/misc/illegal_technology, traitor)
/datum/fleet/solgov/interdiction
name = "\improper Solgov hunter fleet"
diff --git a/nsv13/code/modules/overmap/hull_plating.dm b/nsv13/code/modules/overmap/hull_plating.dm
index 8904276da2f..033c09f8616 100644
--- a/nsv13/code/modules/overmap/hull_plating.dm
+++ b/nsv13/code/modules/overmap/hull_plating.dm
@@ -1,3 +1,6 @@
+///A list used to see how has repaired how many plates.
+GLOBAL_LIST_EMPTY(plating_repairers) //A tiiny bit inefficient but the only alternative I can see would be messing with the achievement subsystem (I am not doing that)
+
/obj/structure/hull_plate
name = "nanolaminate reinforced hull plating"
desc = "A heavy piece of hull plating designed to reinforced the ship's superstructure. The Nanotrasen official starship operational manual states that any damage sustained can be patched up temporarily with a welder."
@@ -142,6 +145,11 @@ Method to try locate an overmap object that we should attach to. Recursively cal
if(armour_broken)
parent?.armour_plates ++
armour_broken = FALSE
+ if(user && user.client)
+ if(!GLOB.plating_repairers["[user.client.ckey]"])
+ GLOB.plating_repairers["[user.client.ckey]"] = 1
+ else
+ GLOB.plating_repairers["[user.client.ckey]"] = GLOB.plating_repairers["[user.client.ckey]"] + 1
return
/obj/structure/hull_plate/update_icon()
diff --git a/nsv13/code/modules/overmap/types/syndicate.dm b/nsv13/code/modules/overmap/types/syndicate.dm
index df542fc4112..29427a2ebf7 100644
--- a/nsv13/code/modules/overmap/types/syndicate.dm
+++ b/nsv13/code/modules/overmap/types/syndicate.dm
@@ -496,6 +496,18 @@
weapon_types[FIRE_MODE_FLAK] = new /datum/ship_weapon/flak(src)
weapon_types[FIRE_MODE_MISSILE] = new /datum/ship_weapon/missile_launcher(src)
+/obj/structure/overmap/syndicate/ai/fistofsol/Destroy()
+ if(!current_system)
+ return ..()
+ for(var/obj/structure/overmap/survivor in (current_system.system_contents - src)) //In case for some reason our Fist is piloted
+ if(survivor.ai_controlled)
+ continue
+ for(var/mob/living/victorious_mob in survivor.mobs_in_ship)
+ if(!victorious_mob.client)
+ continue
+ victorious_mob.client.give_award(/datum/award/achievement/misc/fist_breaker, victorious_mob)
+ return ..()
+
/obj/structure/overmap/hostile/ai/alicorn
name = "SGV Alicorn"
desc = "One Billion Lives!"
diff --git a/nsv13/code/modules/overmap/weapons/projectiles_fx.dm b/nsv13/code/modules/overmap/weapons/projectiles_fx.dm
index 10e23391736..96b18231f3c 100644
--- a/nsv13/code/modules/overmap/weapons/projectiles_fx.dm
+++ b/nsv13/code/modules/overmap/weapons/projectiles_fx.dm
@@ -212,6 +212,8 @@ Misc projectile types, effects, think of this as the special FX file.
if(isliving(target)) //Someone got bonked by an incendiary torpedo, daamn.
var/mob/living/L = target
+ if(L.client)
+ L.client.give_award(/datum/award/achievement/misc/torp_directhit, L)
if(L.mind && L.mind.assigned_role == "Clown")
return (prob(50) ? 2 : -2) //We all know clowns are cursed.
return 2
@@ -387,6 +389,10 @@ Misc projectile types, effects, think of this as the special FX file.
qdel(P)
return FALSE //Didn't take the hit
if(!isprojectile(target)) //This is lazy as shit but is necessary to prevent explosions triggering on the overmap when two bullets collide. Fix this shit please.
+ if(isliving(target))
+ var/mob/living/living_target = target
+ if(living_target.client)
+ living_target.client.give_award(/datum/award/achievement/misc/torp_directhit, living_target)
detonate(target)
else
return FALSE
@@ -558,7 +564,7 @@ Misc projectile types, effects, think of this as the special FX file.
/obj/item/projectile/beam/laser/heavylaser/phaser/relayed
projectile_piercing = PASSGLASS|PASSGRILLE|PASSTABLE
flag = "laser"
- damage = 80 //let's give them a chance to live, instead of smiting them with the full wraith of the Enterprise
+ damage = 80 //let's give them a chance to live, instead of smiting them with the full wraith of the Enterprise
/obj/item/projectile/beam/laser/heavylaser/phaser/relayed/on_hit(atom/target, blocked)
. = ..()
@@ -568,7 +574,7 @@ Misc projectile types, effects, think of this as the special FX file.
name = "point defense phaser"
damage = 60 // Doesn't scale with power input, but fires fairly quickly especially when upgraded
icon = 'nsv13/icons/obj/projectiles_nsv.dmi'
- icon_state = "pdphaser"
+ icon_state = "pdphaser"
relay_projectile_type = /obj/item/projectile/beam/laser/phaser/pd/relayed
/obj/item/projectile/beam/laser/phaser/pd/relayed