From c2584d918dc97c5ef61cfde6c4a44469a05d97b0 Mon Sep 17 00:00:00 2001 From: suethecake Date: Fri, 27 Mar 2015 12:09:19 -0500 Subject: [PATCH] Zoom optimization. --- code/game/objects/items.dm | 82 ++++++++++++++++++ code/game/objects/items/devices/binoculars.dm | 18 ++++ code/modules/mob/living/carbon/human/life.dm | 11 ++- code/modules/mob/mob_movement.dm | 7 ++ .../projectiles/guns/energy/erifles.dm | 56 ++---------- .../projectiles/guns/energy/modular.dm | 33 +------ icons/obj/device.dmi | Bin 24541 -> 24777 bytes 7 files changed, 126 insertions(+), 81 deletions(-) create mode 100644 code/game/objects/items/devices/binoculars.dm diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 71311338..5f1686e8 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -39,6 +39,8 @@ var/armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) var/list/allowed = null //suit storage stuff. var/obj/item/device/uplink/hidden/hidden_uplink = null // All items can have an uplink hidden inside, just remember to add the triggers. + var/zoomdevicename = null //name used for message when binoculars/scope is used + var/zoom = 0 //1 if item is actively being used to zoom. For scoped guns and binoculars. /* Species-specific sprites, concept stolen from Paradise//vg/. ex: @@ -219,6 +221,11 @@ // apparently called whenever an item is removed from a slot, container, or anything else. /obj/item/proc/dropped(mob/user as mob) ..() + if(zoom) //binoculars, scope, etc + user.client.view = world.view + user.client.pixel_x = 0 + user.client.pixel_y = 0 + zoom = 0 // called just as an item is picked up (loc is not yet changed) /obj/item/proc/pickup(mob/user) @@ -644,3 +651,78 @@ if(I && !I.abstract) I.showoff(src) +/* +For zooming with scope or binoculars. This is called from +modules/mob/mob_movement.dm if you move you will be zoomed out +modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. +*/ + +/obj/item/proc/zoom(var/tileoffset = 11,var/viewsize = 12) //tileoffset is client view offset in the direction the user is facing. viewsize is how far out this thing zooms. 7 is normal view + + var/devicename + + if(zoomdevicename) + devicename = zoomdevicename + else + devicename = src.name + + var/cannotzoom + + if(usr.stat || !(istype(usr,/mob/living/carbon/human))) + usr << "You are unable to focus through the [devicename]" + cannotzoom = 1 + else if(!zoom && global_hud.darkMask[1] in usr.client.screen) + usr << "Your welding equipment gets in the way of you looking through the [devicename]" + cannotzoom = 1 + else if(!zoom && usr.get_active_hand() != src) + usr << "You are too distracted to look through the [devicename], perhaps if it was in your active hand this might work better" + cannotzoom = 1 + + if(!zoom && !cannotzoom) + if(!usr.hud_used.hud_shown) + usr.button_pressed_F12(1) // If the user has already limited their HUD this avoids them having a HUD when they zoom in + usr.button_pressed_F12(1) + usr.client.view = viewsize + zoom = 1 + + var/tilesize = 32 + var/viewoffset = tilesize * tileoffset + + switch(usr.dir) + if (NORTH) + usr.client.pixel_x = 0 + usr.client.pixel_y = viewoffset + if (SOUTH) + usr.client.pixel_x = 0 + usr.client.pixel_y = -viewoffset + if (EAST) + usr.client.pixel_x = viewoffset + usr.client.pixel_y = 0 + if (WEST) + usr.client.pixel_x = -viewoffset + usr.client.pixel_y = 0 + + usr.visible_message("[usr] peers through the [zoomdevicename ? "[zoomdevicename] of the [src.name]" : "[src.name]"].") + + /* + if(istype(usr,/mob/living/carbon/human/)) + var/mob/living/carbon/human/H = usr + usr.visible_message("[usr] holds [devicename] up to [H.get_visible_gender() == MALE ? "his" : H.get_visible_gender() == FEMALE ? "her" : "their"] eyes.") + else + usr.visible_message("[usr] holds [devicename] up to its eyes.") + */ + + else + usr.client.view = world.view + if(!usr.hud_used.hud_shown) + usr.button_pressed_F12(1) + zoom = 0 + + usr.client.pixel_x = 0 + usr.client.pixel_y = 0 + + if(!cannotzoom) + usr.visible_message("[zoomdevicename ? "[usr] looks up from the [zoomdevicename] of the [src.name]" : "[usr] lowers the [src.name]"].") + + return + diff --git a/code/game/objects/items/devices/binoculars.dm b/code/game/objects/items/devices/binoculars.dm new file mode 100644 index 00000000..e1c7b18a --- /dev/null +++ b/code/game/objects/items/devices/binoculars.dm @@ -0,0 +1,18 @@ +/obj/item/device/binoculars + + name = "binoculars" + desc = "A pair of binoculars." + icon_state = "binoculars" + + flags = FPRINT | TABLEPASS| CONDUCT + force = 5.0 + w_class = 2.0 + throwforce = 5.0 + throw_range = 15 + throw_speed = 3 + + //matter = list("metal" = 50,"glass" = 50) + + +/obj/item/device/binoculars/attack_self(mob/user) + zoom() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 0ce5fd0d..1a196a7c 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -1336,7 +1336,14 @@ if(!druggy) see_invisible = SEE_INVISIBLE_LEVEL_TWO if(healths) healths.icon_state = "health7" //DEAD healthmeter if(client) - if(client.view != world.view)if(client.view != world.view) // If mob moves while zoomed in with device, unzoom them. + if(client.view != world.view) // If mob moves while zoomed in with device, unzoom them. + for(var/obj/item/item in contents) + if(item.zoom) + item.zoom() + break + + + /* if(locate(/obj/item/weapon/gun/energy/rifle/sniperrifle, contents)) var/obj/item/weapon/gun/energy/rifle/sniperrifle/s = locate() in src if(s.zoom) @@ -1345,7 +1352,7 @@ var/obj/item/weapon/gun/energy/laser/modular/s = locate() in src if(s.zoom) s.zoom() - + */ else sight &= ~(SEE_TURFS|SEE_MOBS|SEE_OBJS) see_in_dark = species.darksight diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 3e58626b..3fcdecb0 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -190,6 +190,12 @@ return if(mob.client) if(mob.client.view != world.view) + for(var/obj/item/item in mob.contents) + if(item.zoom) + item.zoom() + break + + /* if(locate(/obj/item/weapon/gun/energy/rifle/sniperrifle, mob.contents)) // If mob moves while zoomed in with sniper rifle, unzoom them. var/obj/item/weapon/gun/energy/rifle/sniperrifle/s = locate() in mob if(s.zoom) @@ -198,6 +204,7 @@ var/obj/item/weapon/gun/energy/laser/modular/s = locate() in mob if(s.zoom) s.zoom() + */ if(Process_Grab()) return diff --git a/code/modules/projectiles/guns/energy/erifles.dm b/code/modules/projectiles/guns/energy/erifles.dm index 1ef01d0d..230f1119 100644 --- a/code/modules/projectiles/guns/energy/erifles.dm +++ b/code/modules/projectiles/guns/energy/erifles.dm @@ -133,61 +133,17 @@ Commenting out right now, due to a lack of sprites existing. I hate on-mob weapo w_class = 4.0 fire_delay_wielded = 35 //35 is normal fire_delay -- this is going to suck. Yiss, what we want! fire_delay_unwielded = 105 //3x difference, let's be an arse about this, and push the issue - var/zoom = 0 + zoomdevicename = "sniper scope" accuracy = -110 - rangedrop = -5 // fully accurate up to first 10 tiles. the last 4 zoomed tiles you are on your + rangedrop = -2 // fully accurate up to first 10 tiles. the last 4 zoomed tiles you are on your -/obj/item/weapon/gun/energy/rifle/sniperrifle/dropped(mob/user) - user.client.view = world.view - ..() - -/obj/item/weapon/gun/energy/rifle/sniperrifle/ready_to_fire() - if(!zoom) - return 0 - if(world.time >= last_fired + fire_delay) - last_fired = world.time - return 1 - else - return 0 - -///obj/item/weapon/gun/energy/rifle/sniperrifle/update_icon() //Currently only here to fuck with the on-mob icons. -// icon_state = "sniper[wielded]" -// return - -/* -This is called from -modules/mob/mob_movement.dm if you move you will be zoomed out -modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out. -*/ - -/obj/item/weapon/gun/energy/rifle/sniperrifle/verb/zoom() +/obj/item/weapon/gun/energy/rifle/sniperrifle/verb/scope() set category = "Object" - set name = "Use Sniper Scope" - set popup_menu = 0 - if(usr.stat || !(istype(usr,/mob/living/carbon/human))) - usr << "You are unable to focus down the scope of the rifle." - return - if(!zoom && global_hud.darkMask[1] in usr.client.screen) - usr << "Your welding equipment gets in the way of you looking down the scope" - return - if(!zoom && usr.get_active_hand() != src) - usr << "You are too distracted to look down the scope, perhaps if it was in your active hand this might work better" - return + set name = "Use Scope" + set popup_menu = 1 - if(usr.client.view == world.view) - if(!usr.hud_used.hud_shown) - usr.button_pressed_F12(1) // If the user has already limited their HUD this avoids them having a HUD when they zoom in - usr.button_pressed_F12(1) - usr.client.view = 12 - zoom = 1 - else - usr.client.view = world.view - if(!usr.hud_used.hud_shown) - usr.button_pressed_F12(1) - zoom = 0 - usr << "Zoom mode [zoom?"en":"dis"]abled." - return + zoom() ///////////LASER CANNON////////////// diff --git a/code/modules/projectiles/guns/energy/modular.dm b/code/modules/projectiles/guns/energy/modular.dm index 87564873..0f41b1d7 100644 --- a/code/modules/projectiles/guns/energy/modular.dm +++ b/code/modules/projectiles/guns/energy/modular.dm @@ -13,7 +13,7 @@ cell_type = "/obj/item/weapon/cell" var/canzoom = 0 - var/zoom = 0 + zoomdevicename = "scan screen" var/open = 0 var/upgradepointtotal = 16 //KNOWN BUG: Crashes if you try to VV it with a lot of stuff inside. By a lot, I mean 'everything.' At least in all my tests. @@ -358,34 +358,9 @@ /obj/item/weapon/gun/energy/laser/modular/dropped(mob/user) user.client.view = world.view -/obj/item/weapon/gun/energy/laser/modular/verb/zoom() +/obj/item/weapon/gun/energy/laser/modular/verb/scope() set category = "Object" set name = "Use Scan-Screen" - set popup_menu = 0 + set popup_menu = 1 - if(usr.stat || !(istype(usr,/mob/living/carbon/human))) - usr << "You are unable to focus on the screen." - return - if(!zoom && global_hud.darkMask[1] in usr.client.screen) - usr << "Your welding equipment makes it hard to see the screen." - return - if(!zoom && usr.get_active_hand() != src) - usr << "You are too distracted to watch the screen, perhaps if it was in your active hand this might work better" - return - if((hasscreen == 0) || (canzoom == 0)) - usr << "This gun lacks the parts for components for zooming." - return - - if(usr.client.view == world.view) - if(!usr.hud_used.hud_shown) - usr.button_pressed_F12(1) // If the user has already limited their HUD this avoids them having a HUD when they zoom in - usr.button_pressed_F12(1) - usr.client.view = 12 - zoom = 1 - else - usr.client.view = world.view - if(!usr.hud_used.hud_shown) - usr.button_pressed_F12(1) - zoom = 0 - usr << "Zoom mode [zoom?"en":"dis"]abled." - return \ No newline at end of file + zoom() \ No newline at end of file diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index 449854fbfcd05232f6cae55067708cb9cdf600ef..db13b1083246a3c8bbf7205cdb44394d57a20e23 100644 GIT binary patch delta 3566 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 delta 3328 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