From edef78a1e4a75eb347237d9408e4a50c7e64aaec Mon Sep 17 00:00:00 2001 From: JimTheCactus Date: Fri, 11 Jul 2014 00:17:10 -0600 Subject: [PATCH 01/12] Testing out branch management. Nothing to see here. --- IfImHereDeleteMe.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 IfImHereDeleteMe.txt diff --git a/IfImHereDeleteMe.txt b/IfImHereDeleteMe.txt new file mode 100644 index 0000000000..6268d817ef --- /dev/null +++ b/IfImHereDeleteMe.txt @@ -0,0 +1 @@ +This is just because I'm a n00b at git. \ No newline at end of file From 75fb62d1a18c12d5ef06826657b7d7466ab785c4 Mon Sep 17 00:00:00 2001 From: John-Michael O'Brien Date: Fri, 11 Jul 2014 00:29:45 -0600 Subject: [PATCH 02/12] Delete IfImHereDeleteMe.txt --- IfImHereDeleteMe.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 IfImHereDeleteMe.txt diff --git a/IfImHereDeleteMe.txt b/IfImHereDeleteMe.txt deleted file mode 100644 index 6268d817ef..0000000000 --- a/IfImHereDeleteMe.txt +++ /dev/null @@ -1 +0,0 @@ -This is just because I'm a n00b at git. \ No newline at end of file From 646aad945e67ccfa15df55d3f9eb941eac4dde27 Mon Sep 17 00:00:00 2001 From: JimTheCactus Date: Sun, 27 Jul 2014 17:21:19 -0600 Subject: [PATCH 03/12] Merged getFlatIcon rendering from tgstation Based on tgstation #2826. This is not all of it though. --- code/__HELPERS/icons.dm | 96 +++++++++++++++++++++++++------------ code/__HELPERS/type2type.dm | 7 +++ code/datums/datacore.dm | 2 +- 3 files changed, 73 insertions(+), 32 deletions(-) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 0ca515486b..d193fcb26e 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -634,20 +634,60 @@ as a single icon. Useful for when you want to manipulate an icon via the above a The _flatIcons list is a cache for generated icon files. */ -proc - getFlatIcon(atom/A, dir) // 1 = use cache, 2 = override cache, 0 = ignore cache +proc // Creates a single icon from a given /atom or /image. Only the first argument is required. + getFlatIcon(image/A, defdir=A.dir, deficon=A.icon, defstate=A.icon_state, defblend=A.blend_mode) + // We start with a blank canvas, otherwise some icon procs crash silently + var/icon/flat = icon('icons/effects/effects.dmi', "nothing") // Final flattened icon + if(!A) + return flat + if(A.alpha <= 0) + return flat + var/noIcon = FALSE + + var/curicon + if(A.icon) + curicon = A.icon + else + curicon = deficon + + if(!curicon) + noIcon = TRUE // Do not render this object. + + var/curstate + if(A.icon_state) + curstate = A.icon_state + else + curstate = defstate + + if(!noIcon && !(curstate in icon_states(curicon))) + if("" in icon_states(curicon)) + curstate = "" + else + noIcon = TRUE // Do not render this object. + + var/curdir + if(A.dir) + curdir = A.dir + else + curdir = defdir + + var/curblend + if(A.blend_mode == BLEND_DEFAULT) + curblend = defblend + else + curblend = A.blend_mode + // Layers will be a sorted list of icons/overlays, based on the order in which they are displayed var/list/layers = list() - - // Add the atom's icon itself - if(A.icon) - // Make a copy without pixel_x/y settings - var/image/copy = image(icon=A.icon,icon_state=A.icon_state,layer=A.layer,dir=A.dir) + var/image/copy + // Add the atom's icon itself, without pixel_x/y offsets. + if(!noIcon) + copy = image(icon=curicon, icon_state=curstate, layer=A.layer, dir=curdir) + copy.color = A.color + copy.alpha = A.alpha + copy.blend_mode = curblend layers[copy] = A.layer - // dir defaults to A's dir - if(!dir) dir = A.dir - // Loop through the underlays, then overlays, sorting them into the layers list var/list/process = A.underlays // Current list being processed var/pSet=0 // Which list is being processed: 0 = underlays, 1 = overlays @@ -662,7 +702,7 @@ proc if(!current) continue currentLayer = current:layer if(currentLayer<0) // Special case for FLY_LAYER - if(currentLayer <= -1000) return 0 + if(currentLayer <= -1000) return flat if(pSet == 0) // Underlay currentLayer = A.layer+currentLayer/1000 else // Overlay @@ -688,8 +728,6 @@ proc else // All done break - // We start with a blank canvas, otherwise some icon procs crash silently - var/icon/flat = icon('icons/effects/effects.dmi', "icon_state"="nothing") // Final flattened icon var/icon/add // Icon of overlay being added // Current dimensions of flattened icon @@ -699,24 +737,15 @@ proc for(var/I in layers) - if(I:icon) - if(I:icon_state) - // Has icon and state set - add = icon(I:icon, I:icon_state) - else - if(A.icon_state in icon_states(I:icon)) - // Inherits icon_state from atom - add = icon(I:icon, A.icon_state) - else - // Uses default state ("") - add = icon(I:icon) - else if(I:icon_state) - // Inherits icon from atom - add = icon(A.icon, I:icon_state) - else - // Unknown + if(I:alpha == 0) continue + if(I == copy) // 'I' is an /image based on the object being flattened. + curblend = BLEND_OVERLAY + add = icon(I:icon, I:icon_state, I:dir) + else // 'I' is an appearance object. + add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend) + // Find the new dimensions of the flat icon to fit the added overlay addX1 = min(flatX1, I:pixel_x+1) addX2 = max(flatX2, I:pixel_x+add.Width()) @@ -730,9 +759,14 @@ proc flatY1=addY1;flatY2=addY2 // Blend the overlay into the flattened icon - flat.Blend(add,ICON_OVERLAY,I:pixel_x+2-flatX1,I:pixel_y+2-flatY1) + flat.Blend(add, blendMode2iconMode(curblend), I:pixel_x + 2 - flatX1, I:pixel_y + 2 - flatY1) - return flat + if(A.color) + flat.Blend(A.color, ICON_MULTIPLY) + if(A.alpha < 255) + flat.Blend(rgb(255, 255, 255, A.alpha), ICON_MULTIPLY) + + return icon(flat, "", SOUTH) getIconMask(atom/A)//By yours truly. Creates a dynamic mask for a mob/whatever. /N var/icon/alpha_mask = new(A.icon,A.icon_state)//So we want the default icon and icon state of A. diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm index 885de82c44..8c188d0d18 100644 --- a/code/__HELPERS/type2type.dm +++ b/code/__HELPERS/type2type.dm @@ -298,6 +298,13 @@ proc/tg_list2text(list/list, glue=",") /proc/angle2text(var/degree) return dir2text(angle2dir(degree)) +//Converts a blend_mode constant to one acceptable to icon.Blend() +/proc/blendMode2iconMode(blend_mode) + switch(blend_mode) + if(BLEND_MULTIPLY) return ICON_MULTIPLY + if(BLEND_ADD) return ICON_ADD + if(BLEND_SUBTRACT) return ICON_SUBTRACT + else return ICON_OVERLAY //Converts a rights bitfield into a string /proc/rights2text(rights,seperator="") diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index 98da4a58de..a1a626313b 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -119,7 +119,7 @@ L.fields["b_dna"] = H.dna.unique_enzymes L.fields["enzymes"] = H.dna.SE // Used in respawning L.fields["identity"] = H.dna.UI // " - L.fields["image"] = getFlatIcon(H,0) //This is god-awful + L.fields["image"] = getFlatIcon(H) //This is god-awful locked += L return From 1d7310c49d3febfd14450439cabf9d956ede99fc Mon Sep 17 00:00:00 2001 From: JimTheCactus Date: Sun, 27 Jul 2014 22:05:24 -0600 Subject: [PATCH 04/12] Patched display and dealt with lying. --- code/__HELPERS/icons.dm | 6 ++-- code/modules/paperwork/photography.dm | 50 +++++++++++++++------------ 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index d193fcb26e..65807c0575 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -637,7 +637,7 @@ The _flatIcons list is a cache for generated icon files. proc // Creates a single icon from a given /atom or /image. Only the first argument is required. getFlatIcon(image/A, defdir=A.dir, deficon=A.icon, defstate=A.icon_state, defblend=A.blend_mode) // We start with a blank canvas, otherwise some icon procs crash silently - var/icon/flat = icon('icons/effects/effects.dmi', "nothing") // Final flattened icon + var/icon/flat = icon('icons/effects/effects.dmi', "icon_state"="nothing") // Final flattened icon if(!A) return flat if(A.alpha <= 0) @@ -666,7 +666,7 @@ proc // Creates a single icon from a given /atom or /image. Only the first argu noIcon = TRUE // Do not render this object. var/curdir - if(A.dir) + if(A.dir != 2) curdir = A.dir else curdir = defdir @@ -682,6 +682,7 @@ proc // Creates a single icon from a given /atom or /image. Only the first argu var/image/copy // Add the atom's icon itself, without pixel_x/y offsets. if(!noIcon) + world.log << "***Rendering Icon [A.type] in state '[curstate]' on layer [A.layer] in direction [curdir]" // #JMO copy = image(icon=curicon, icon_state=curstate, layer=A.layer, dir=curdir) copy.color = A.color copy.alpha = A.alpha @@ -744,6 +745,7 @@ proc // Creates a single icon from a given /atom or /image. Only the first argu curblend = BLEND_OVERLAY add = icon(I:icon, I:icon_state, I:dir) else // 'I' is an appearance object. + world.log << "***Recursing to render Icon [I:type] in state '[curstate]' in direction [curdir]" // #JMO add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend) // Find the new dimensions of the flat icon to fit the added overlay diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index f0d39337b6..c2399a3f04 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -157,36 +157,41 @@ //i.e. pretty much all wall-mounted machinery var/icon/res = icon('icons/effects/96x96.dmi', "") - var/icon/turficon = build_composite_icon(the_turf) - res.Blend(turficon, ICON_OVERLAY, 33, 33) + world.log << "***Calling build composite..." //#JMO + //var/icon/turficon = build_composite_icon(the_turf) + res.Blend(getFlatIcon(the_turf), blendMode2iconMode(the_turf.blend_mode),33,33) + world.log << "***Exiting build composite..." //#JMO + //res.Blend(turficon, ICON_OVERLAY, 33, 33) var/atoms[] = list() for(var/atom/A in the_turf) if(A.invisibility) continue atoms.Add(A) - //Sorting icons based on levels - var/gap = atoms.len - var/swapped = 1 - while (gap > 1 || swapped) - swapped = 0 - if(gap > 1) - gap = round(gap / 1.247330950103979) - if(gap < 1) - gap = 1 - for(var/i = 1; gap + i <= atoms.len; i++) - var/atom/l = atoms[i] //Fucking hate - var/atom/r = atoms[gap+i] //how lists work here - if(l.layer > r.layer) //no "atoms[i].layer" for me - atoms.Swap(i, gap + i) - swapped = 1 + //Sorting icons based on levels. + //JMO: I have no idea what they were doing here before, but the magic number alone + // was worth replacing it over. "gap = round(gap / 1.247330950103979)" really? + var/list/sorted = list() + var/j + for(var/i = 1 to atoms.len) + var/atom/c = atoms[i] + for(j = sorted.len, j > 0, --j) + var/atom/c2 = sorted[j] + if(c2.layer <= c.layer) + break + sorted.Insert(j+1, c) - for(var/i; i <= atoms.len; i++) - var/atom/A = atoms[i] + for(var/i; i <= sorted.len; i++) + var/atom/A = sorted[i] if(A) - var/icon/img = getFlatIcon(A, A.dir)//build_composite_icon(A) - if(istype(img, /icon)) - res.Blend(new/icon(img, "", A.dir), ICON_OVERLAY, 33 + A.pixel_x, 33 + A.pixel_y) + world.log << "**Calling getFlatIcon to render [A.type]" //#JMO + var/icon/img = getFlatIcon(A)//build_composite_icon(A) + if(istype(A, /mob/living) && A:lying) + world.log << "[A.type] is lying down. Making it look as such..." // #JMO; + img.BecomeLying() + + //if(istype(img, /icon)) + res.Blend(img, blendMode2iconMode(A.blend_mode), 33 + A.pixel_x, 33 + A.pixel_y) return res @@ -220,6 +225,7 @@ var/icon/temp = icon('icons/effects/96x96.dmi',"") var/icon/black = icon('icons/turf/space.dmi', "black") var/mobs = "" + world << "Proof that this thing is alive! 1.0" // #JMO for(var/i = 1; i <= 3; i++) for(var/j = 1; j <= 3; j++) var/turf/T = locate(x_c, y_c, z_c) From bdbc404d07867a5b83f598f60c2d5dc7cbabc5cb Mon Sep 17 00:00:00 2001 From: JimTheCactus Date: Mon, 28 Jul 2014 01:04:52 -0600 Subject: [PATCH 05/12] Added workaround for non-directional icons with dir!=2 Several items in the map are set with a dir other than 2 but the icon associated with the item doesn't have directions. As such they misrender. This resolves that specific issue, for the most part. Due to an odd behavior of Byond, when this circumstance occurs the icon proc produces a 32x32 image that is all alpha 0. At least that's what my testing suggests; it may be possible with large icons to encounter this as an issue and cause it to ignore an icon that should be reloaded from the default. However, this can't do any worse than the current software. --- code/__HELPERS/icons.dm | 31 ++++++++++++++++++++++++++- code/modules/paperwork/photography.dm | 15 +++++++------ 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 65807c0575..b0bc3091e6 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -684,6 +684,10 @@ proc // Creates a single icon from a given /atom or /image. Only the first argu if(!noIcon) world.log << "***Rendering Icon [A.type] in state '[curstate]' on layer [A.layer] in direction [curdir]" // #JMO copy = image(icon=curicon, icon_state=curstate, layer=A.layer, dir=curdir) + if (isnull(copy)) // #JMO + world.log << "****Created a null!" // #JMO + else // #JMO + world.log << "****Created a thing of type [copy.type]" // #JMO copy.color = A.color copy.alpha = A.alpha copy.blend_mode = curblend @@ -744,6 +748,31 @@ proc // Creates a single icon from a given /atom or /image. Only the first argu if(I == copy) // 'I' is an /image based on the object being flattened. curblend = BLEND_OVERLAY add = icon(I:icon, I:icon_state, I:dir) + // This checks for a silent failure mode of the icon routine. If the requested dir + // doesn't exist in this icon state it returns a 32x32 icon with 0 alpha. + if (I:dir != SOUTH && add.Width() == 32 && add.Height() == 32) + // Since checking every pixel for blank isn't trivial, we make some assumptions about + // the content of the image to determine if it actually is blank. On a rare occassions + // this will cause the software to return a non-directional icon for when a + // directionalized one would be more appropriate. This is rare enough that this + // will suffice in place of a map rework that properly normalizes directions. + var/blankpixel=1; + // Check the four corners... + blankpixel &= isnull(add.GetPixel(1,1)) + blankpixel &= isnull(add.GetPixel(32,1)) + blankpixel &= isnull(add.GetPixel(32,32)) + blankpixel &= isnull(add.GetPixel(32,1)) + // The thirds... + blankpixel &= isnull(add.GetPixel(11,11)) + blankpixel &= isnull(add.GetPixel(11,22)) + blankpixel &= isnull(add.GetPixel(22,22)) + blankpixel &= isnull(add.GetPixel(22,11)) + // and the center... + blankpixel &= isnull(add.GetPixel(16,16)) + // If we ALWAYS returned a null (which happens when GetPixel encounters something with alpha 0) + if (blankpixel) + // Pull the default direction. + add = icon(I:icon, I:icon_state) else // 'I' is an appearance object. world.log << "***Recursing to render Icon [I:type] in state '[curstate]' in direction [curdir]" // #JMO add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend) @@ -819,4 +848,4 @@ proc/adjust_brightness(var/color, var/value) RGB[1] = Clamp(RGB[1]+value,0,255) RGB[2] = Clamp(RGB[2]+value,0,255) RGB[3] = Clamp(RGB[3]+value,0,255) - return rgb(RGB[1],RGB[2],RGB[3]) \ No newline at end of file + return rgb(RGB[1],RGB[2],RGB[3]) diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index c2399a3f04..67e5eb76e8 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -152,7 +152,7 @@ ..() -/obj/item/device/camera/proc/get_icon(turf/the_turf as turf) +/obj/item/device/camera/proc/get_icon(turf/the_turf as turf,mob/user as mob) //#JMO Added mob/user for debug for debug //Bigger icon base to capture those icons that were shifted to the next tile //i.e. pretty much all wall-mounted machinery var/icon/res = icon('icons/effects/96x96.dmi', "") @@ -184,14 +184,16 @@ for(var/i; i <= sorted.len; i++) var/atom/A = sorted[i] if(A) - world.log << "**Calling getFlatIcon to render [A.type]" //#JMO + world.log << "**Calling getFlatIcon to render [A]" //#JMO var/icon/img = getFlatIcon(A)//build_composite_icon(A) + // Check if we're looking at a mob that's lying down if(istype(A, /mob/living) && A:lying) - world.log << "[A.type] is lying down. Making it look as such..." // #JMO; + world.log << "[A] is lying down. Making it look as such..." // #JMO; + // If they are, apply that effect to their picture. img.BecomeLying() - //if(istype(img, /icon)) - res.Blend(img, blendMode2iconMode(A.blend_mode), 33 + A.pixel_x, 33 + A.pixel_y) + if(istype(img, /icon)) + res.Blend(img, blendMode2iconMode(A.blend_mode), 33 + A.pixel_x, 33 + A.pixel_y) return res @@ -225,7 +227,6 @@ var/icon/temp = icon('icons/effects/96x96.dmi',"") var/icon/black = icon('icons/turf/space.dmi', "black") var/mobs = "" - world << "Proof that this thing is alive! 1.0" // #JMO for(var/i = 1; i <= 3; i++) for(var/j = 1; j <= 3; j++) var/turf/T = locate(x_c, y_c, z_c) @@ -234,7 +235,7 @@ if(user.client) //To make shooting through security cameras possible viewer = user.client.eye if(dummy in viewers(world.view, viewer)) - temp.Blend(get_icon(T), ICON_OVERLAY, 32 * (j-1-1), 32 - 32 * (i-1)) + temp.Blend(get_icon(T,user), ICON_OVERLAY, 32 * (j-1-1), 32 - 32 * (i-1)) else temp.Blend(black, ICON_OVERLAY, 32 * (j-1), 64 - 32 * (i-1)) mobs += get_mobs(T) From 8e4ac0a807e452301b3d7da00deaf2243bbadc92 Mon Sep 17 00:00:00 2001 From: JimTheCactus Date: Mon, 28 Jul 2014 01:46:07 -0600 Subject: [PATCH 06/12] Modified to check every pixel Checking only a few pixels had the tendancy to turn my charcter's head inside out when I was pointing directions other than south. Worse case is 1024 tests per object in the image. This test should be uncommon and the CPU usage is constrained by other factors. --- code/__HELPERS/icons.dm | 35 +++++++++------------------ code/modules/paperwork/photography.dm | 10 ++------ 2 files changed, 13 insertions(+), 32 deletions(-) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index b0bc3091e6..8c400df60c 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -682,12 +682,7 @@ proc // Creates a single icon from a given /atom or /image. Only the first argu var/image/copy // Add the atom's icon itself, without pixel_x/y offsets. if(!noIcon) - world.log << "***Rendering Icon [A.type] in state '[curstate]' on layer [A.layer] in direction [curdir]" // #JMO copy = image(icon=curicon, icon_state=curstate, layer=A.layer, dir=curdir) - if (isnull(copy)) // #JMO - world.log << "****Created a null!" // #JMO - else // #JMO - world.log << "****Created a thing of type [copy.type]" // #JMO copy.color = A.color copy.alpha = A.alpha copy.blend_mode = curblend @@ -751,30 +746,22 @@ proc // Creates a single icon from a given /atom or /image. Only the first argu // This checks for a silent failure mode of the icon routine. If the requested dir // doesn't exist in this icon state it returns a 32x32 icon with 0 alpha. if (I:dir != SOUTH && add.Width() == 32 && add.Height() == 32) - // Since checking every pixel for blank isn't trivial, we make some assumptions about - // the content of the image to determine if it actually is blank. On a rare occassions - // this will cause the software to return a non-directional icon for when a - // directionalized one would be more appropriate. This is rare enough that this - // will suffice in place of a map rework that properly normalizes directions. - var/blankpixel=1; - // Check the four corners... - blankpixel &= isnull(add.GetPixel(1,1)) - blankpixel &= isnull(add.GetPixel(32,1)) - blankpixel &= isnull(add.GetPixel(32,32)) - blankpixel &= isnull(add.GetPixel(32,1)) - // The thirds... - blankpixel &= isnull(add.GetPixel(11,11)) - blankpixel &= isnull(add.GetPixel(11,22)) - blankpixel &= isnull(add.GetPixel(22,22)) - blankpixel &= isnull(add.GetPixel(22,11)) - // and the center... - blankpixel &= isnull(add.GetPixel(16,16)) + // Check every pixel for blank (computationally expensive, but the process is limited + // by the amount of film on the station, only happens when we hit something that's + // turned, and bails at the very first pixel it sees. + var/blankpixel; + for(var/y;y<=32;y++) + for(var/x;x<32;x++) + blankpixel = isnull(add.GetPixel(x,y)) + if(!blankpixel) + break + if(!blankpixel) + break // If we ALWAYS returned a null (which happens when GetPixel encounters something with alpha 0) if (blankpixel) // Pull the default direction. add = icon(I:icon, I:icon_state) else // 'I' is an appearance object. - world.log << "***Recursing to render Icon [I:type] in state '[curstate]' in direction [curdir]" // #JMO add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend) // Find the new dimensions of the flat icon to fit the added overlay diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index 67e5eb76e8..948b023ac4 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -152,16 +152,12 @@ ..() -/obj/item/device/camera/proc/get_icon(turf/the_turf as turf,mob/user as mob) //#JMO Added mob/user for debug for debug +/obj/item/device/camera/proc/get_icon(turf/the_turf as turf) //Bigger icon base to capture those icons that were shifted to the next tile //i.e. pretty much all wall-mounted machinery var/icon/res = icon('icons/effects/96x96.dmi', "") - world.log << "***Calling build composite..." //#JMO - //var/icon/turficon = build_composite_icon(the_turf) res.Blend(getFlatIcon(the_turf), blendMode2iconMode(the_turf.blend_mode),33,33) - world.log << "***Exiting build composite..." //#JMO - //res.Blend(turficon, ICON_OVERLAY, 33, 33) var/atoms[] = list() for(var/atom/A in the_turf) @@ -184,11 +180,9 @@ for(var/i; i <= sorted.len; i++) var/atom/A = sorted[i] if(A) - world.log << "**Calling getFlatIcon to render [A]" //#JMO var/icon/img = getFlatIcon(A)//build_composite_icon(A) // Check if we're looking at a mob that's lying down if(istype(A, /mob/living) && A:lying) - world.log << "[A] is lying down. Making it look as such..." // #JMO; // If they are, apply that effect to their picture. img.BecomeLying() @@ -235,7 +229,7 @@ if(user.client) //To make shooting through security cameras possible viewer = user.client.eye if(dummy in viewers(world.view, viewer)) - temp.Blend(get_icon(T,user), ICON_OVERLAY, 32 * (j-1-1), 32 - 32 * (i-1)) + temp.Blend(get_icon(T), ICON_OVERLAY, 32 * (j-1-1), 32 - 32 * (i-1)) else temp.Blend(black, ICON_OVERLAY, 32 * (j-1), 64 - 32 * (i-1)) mobs += get_mobs(T) From 5457cee52792fe4995010e1b349c6ce52f96c413 Mon Sep 17 00:00:00 2001 From: Loganbacca Date: Mon, 28 Jul 2014 20:39:42 +1200 Subject: [PATCH 07/12] More train fixes - No passing plastic flaps - Only human based mobs can board trains - Adjacent checks for exiting vehicles - Cleaned up as many direct loc moves as possible - Places removed cells in the removers hand --- code/game/supplyshuttle.dm | 17 ++++++++++------- code/modules/vehicles/cargo_train.dm | 13 +++++++++---- code/modules/vehicles/train.dm | 6 ++---- code/modules/vehicles/vehicle.dm | 16 ++++++++-------- 4 files changed, 29 insertions(+), 23 deletions(-) diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm index 0b042eeb7b..b908d09b66 100644 --- a/code/game/supplyshuttle.dm +++ b/code/game/supplyshuttle.dm @@ -54,7 +54,10 @@ var/list/mechtoys = list( if (istype(A, /obj/structure/stool/bed) && B.buckled_mob)//if it's a bed/chair and someone is buckled, it will not pass return 0 - else if(istype(A, /mob/living)) // You Shall Not Pass! + if(istype(A, /obj/vehicle)) //no vehicles + return 0 + + if(istype(A, /mob/living)) // You Shall Not Pass! var/mob/living/M = A if(!M.lying && !istype(M, /mob/living/carbon/monkey) && !istype(M, /mob/living/carbon/slime) && !istype(M, /mob/living/simple_animal/mouse) && !istype(M, /mob/living/silicon/robot/drone)) //If your not laying down, or a small creature, no pass. return 0 @@ -455,7 +458,7 @@ var/list/mechtoys = list( if ("undocking") dat += "Undocking from station [shuttle.can_force()? "Force Launch" : ""]
" else dat += "Station
" - + if (shuttle.can_launch()) dat += "Send away" else if (shuttle.can_cancel()) @@ -472,14 +475,14 @@ var/list/mechtoys = list( else dat += "*Shuttle is busy*" dat += "
\n
" - - + + dat += {"
\nSupply points: [supply_controller.points]
\n
\nOrder items
\n
\nView requests
\n
\nView orders
\n
\nClose"} - + user << browse(dat, "window=computer;size=575x450") onclose(user, "computer") @@ -520,13 +523,13 @@ var/list/mechtoys = list( shuttle.launch(src) temp = "The supply shuttle has been called and will arrive in approximately [round(supply_controller.movetime/600,1)] minutes.

OK" post_signal("supply") - + if (href_list["force_send"]) shuttle.force_launch(src) if (href_list["cancel_send"]) shuttle.cancel_launch(src) - + else if (href_list["order"]) //if(!shuttle.idle()) return //this shouldn't be necessary it seems if(href_list["order"] == "categories") diff --git a/code/modules/vehicles/cargo_train.dm b/code/modules/vehicles/cargo_train.dm index b6f91feec7..11d0c53fb8 100644 --- a/code/modules/vehicles/cargo_train.dm +++ b/code/modules/vehicles/cargo_train.dm @@ -43,6 +43,7 @@ ..() cell = new /obj/item/weapon/cell/high verbs -= /atom/movable/verb/pull + verbs -= /obj/vehicle/train/cargo/engine/verb/stop_engine key = new() var/image/I = new(icon = 'icons/obj/vehicles.dmi', icon_state = "cargo_engine_overlay", layer = src.layer + 0.2) //over mobs overlays += I @@ -70,8 +71,8 @@ if(istype(W, /obj/item/weapon/key/cargo_train)) if(!key) user.drop_item() + W.forceMove(src) key = W - W.loc = src verbs += /obj/vehicle/train/cargo/engine/verb/remove_key return ..() @@ -97,7 +98,7 @@ var/obj/machinery/door/D = Obstacle var/mob/living/carbon/human/H = load if(istype(D) && istype(H)) - D.Bumped(H) //a little hacky, but hey, it works, and repects access rights + D.Bumped(H) //a little hacky, but hey, it works, and respects access rights ..() @@ -194,6 +195,8 @@ turn_on() if (on) usr << "You start [src]'s engine." + verbs += /obj/vehicle/train/cargo/engine/verb/stop_engine + verbs -= /obj/vehicle/train/cargo/engine/verb/start_engine else if(cell.charge < power_use) usr << "[src] is out of power." @@ -215,6 +218,8 @@ turn_off() if (!on) usr << "You stop [src]'s engine." + verbs -= /obj/vehicle/train/cargo/engine/verb/stop_engine + verbs += /obj/vehicle/train/cargo/engine/verb/start_engine /obj/vehicle/train/cargo/engine/verb/remove_key() set name = "Remove key" @@ -243,7 +248,7 @@ /obj/vehicle/train/cargo/trolley/load(var/atom/movable/C) if(ismob(C) && !passenger_allowed) return 0 - if(!istype(C,/obj/machinery) && !istype(C,/obj/structure/closet) && !istype(C,/obj/structure/largecrate) && !istype(C,/obj/structure/reagent_dispensers) && !istype(C,/obj/structure/ore_box) && !ismob(C)) + if(!istype(C,/obj/machinery) && !istype(C,/obj/structure/closet) && !istype(C,/obj/structure/largecrate) && !istype(C,/obj/structure/reagent_dispensers) && !istype(C,/obj/structure/ore_box) && !istype(C, /mob/living/carbon/human)) return 0 ..() @@ -255,7 +260,7 @@ return 1 /obj/vehicle/train/cargo/engine/load(var/atom/movable/C) - if(!ismob(C)) + if(!istype(C, /mob/living/carbon/human)) return 0 return ..() diff --git a/code/modules/vehicles/train.dm b/code/modules/vehicles/train.dm index deaed1130c..d29933b5ed 100644 --- a/code/modules/vehicles/train.dm +++ b/code/modules/vehicles/train.dm @@ -68,8 +68,7 @@ if(user != load) if(user in src) //for handling players stuck in src - this shouldn't happen - but just in case it does - user.loc = T - contents -= user + user.forceMove(T) return 1 return 0 @@ -93,8 +92,7 @@ return 0 if(user != load && (user in src)) - user.loc = loc //for handling players stuck in src - contents -= user + user.forceMove(loc) //for handling players stuck in src else if(load) unload(user) //unload if loaded else if(!load && !user.buckled) diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm index 5e5affac99..caec0c896a 100644 --- a/code/modules/vehicles/vehicle.dm +++ b/code/modules/vehicles/vehicle.dm @@ -50,7 +50,7 @@ anchored = init_anc if(load) - load.loc = loc + load.forceMove(loc)// = loc load.dir = dir return 1 @@ -196,7 +196,7 @@ new /obj/item/weapon/cable_coil/cut(Tsec) if(cell) - cell.loc = Tsec + cell.forceMove(Tsec) cell.update_icon() cell = null @@ -234,8 +234,8 @@ return H.drop_from_inventory(C) + C.forceMove(src) cell = C - C.loc = null //this wont be GC'd since it's referrenced above powercheck() usr << "You install [C] in [src]." @@ -244,7 +244,8 @@ return usr << "You remove [cell] from [src]." - cell.loc = get_turf(H) + cell.forceMove(get_turf(H)) + H.put_in_hands(cell) cell = null powercheck() @@ -271,7 +272,7 @@ if(istype(crate)) crate.close() - C.loc = loc + C.forceMove(loc) C.dir = dir C.anchored = 1 @@ -310,7 +311,7 @@ var/list/options = new() for(var/test_dir in alldirs) var/new_dir = get_step_to(src, get_step(src, test_dir)) - if(new_dir) + if(new_dir && load.Adjacent(new_dir)) options += new_dir if(options.len) dest = pick(options) @@ -320,8 +321,7 @@ if(!isturf(dest)) //if there still is nowhere to unload, cancel out since the vehicle is probably in nullspace return 0 - - load.loc = dest + load.forceMove(dest) load.dir = get_dir(loc, dest) load.anchored = initial(load.anchored) load.pixel_x = initial(load.pixel_x) From df3fcbc9b23039d6dd81bf32a209f109b16526fa Mon Sep 17 00:00:00 2001 From: JimTheCactus Date: Mon, 28 Jul 2014 11:54:01 -0600 Subject: [PATCH 08/12] Ported nearest-neighbor scaling from TG --- code/__HELPERS/icons.dm | 19 +++++++++++++++++++ code/modules/paperwork/photography.dm | 25 +++++++++---------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 8c400df60c..e7a6bbba96 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -836,3 +836,22 @@ proc/adjust_brightness(var/color, var/value) RGB[2] = Clamp(RGB[2]+value,0,255) RGB[3] = Clamp(RGB[3]+value,0,255) return rgb(RGB[1],RGB[2],RGB[3]) + +proc/sort_atoms_by_layer(var/list/atoms) + // Comb sort icons based on levels + var/list/result = atoms.Copy() + var/gap = result.len + var/swapped = 1 + while (gap > 1 || swapped) + swapped = 0 + if(gap > 1) + gap = round(gap / 1.3) // 1.3 is the emperic comb sort coefficient + if(gap < 1) + gap = 1 + for(var/i = 1; gap + i <= result.len; i++) + var/atom/l = result[i] //Fucking hate + var/atom/r = result[gap+i] //how lists work here + if(l.layer > r.layer) //no "result[i].layer" for me + result.Swap(i, gap + i) + swapped = 1 + return result diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index 948b023ac4..da6edc63ea 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -53,10 +53,10 @@ /obj/item/weapon/photo/proc/show(mob/user as mob) user << browse_rsc(img, "tmp_photo.png") user << browse("[name]" \ - + "" \ - + "
Written on the back:
[scribble]" : ]"\ - + "", "window=book;size=200x[scribble ? 400 : 200]") + + "" \ + + "" \ + + "[scribble ? "
Written on the back:
[scribble]" : ""]"\ + + "", "window=book;size=192x[scribble ? 400 : 192]") onclose(user, "[name]") return @@ -164,18 +164,8 @@ if(A.invisibility) continue atoms.Add(A) - //Sorting icons based on levels. - //JMO: I have no idea what they were doing here before, but the magic number alone - // was worth replacing it over. "gap = round(gap / 1.247330950103979)" really? - var/list/sorted = list() - var/j - for(var/i = 1 to atoms.len) - var/atom/c = atoms[i] - for(j = sorted.len, j > 0, --j) - var/atom/c2 = sorted[j] - if(c2.layer <= c.layer) - break - sorted.Insert(j+1, c) + // Sort the atoms into their layers + var/list/sorted = sort_atoms_by_layer(atoms) for(var/i; i <= sorted.len; i++) var/atom/A = sorted[i] @@ -220,6 +210,9 @@ var/icon/temp = icon('icons/effects/96x96.dmi',"") var/icon/black = icon('icons/turf/space.dmi', "black") + // Initialize the photograph to black. + temp.Blend("#000", ICON_OVERLAY) + var/mobs = "" for(var/i = 1; i <= 3; i++) for(var/j = 1; j <= 3; j++) From f0594b6e21dc5d9ec7905d819001f61723f0e0a8 Mon Sep 17 00:00:00 2001 From: JimTheCactus Date: Mon, 28 Jul 2014 12:10:21 -0600 Subject: [PATCH 09/12] Made camera render turf effects. --- code/modules/paperwork/photography.dm | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index da6edc63ea..d563c9cc1e 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -157,9 +157,10 @@ //i.e. pretty much all wall-mounted machinery var/icon/res = icon('icons/effects/96x96.dmi', "") - res.Blend(getFlatIcon(the_turf), blendMode2iconMode(the_turf.blend_mode),33,33) - var/atoms[] = list() + // Add outselves to the list of stuff to draw + atoms.Add(the_turf); + // As well as anything that isn't invisible. for(var/atom/A in the_turf) if(A.invisibility) continue atoms.Add(A) @@ -171,13 +172,18 @@ var/atom/A = sorted[i] if(A) var/icon/img = getFlatIcon(A)//build_composite_icon(A) - // Check if we're looking at a mob that's lying down - if(istype(A, /mob/living) && A:lying) - // If they are, apply that effect to their picture. - img.BecomeLying() + // If what we got back is actually a picture, draw it. if(istype(img, /icon)) + // Check if we're looking at a mob that's lying down + if(istype(A, /mob/living) && A:lying) + // If they are, apply that effect to their picture. + img.BecomeLying() res.Blend(img, blendMode2iconMode(A.blend_mode), 33 + A.pixel_x, 33 + A.pixel_y) + + + // Lastly, render any contained effects on top. + res.Blend(getFlatIcon(the_turf.loc), blendMode2iconMode(the_turf.blend_mode),33,33) return res From 6b1f696203415ec65eed8c7616aef7ff713d122c Mon Sep 17 00:00:00 2001 From: JimTheCactus Date: Mon, 28 Jul 2014 12:44:42 -0600 Subject: [PATCH 10/12] Ported multi-turf behavior This allows for layering that moves across tiles and enables alternate methods of enumerating the tile list (not used at present.) --- code/modules/paperwork/photography.dm | 47 +++++++++++++++------------ 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index d563c9cc1e..dcc7c9f55e 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -152,18 +152,22 @@ ..() -/obj/item/device/camera/proc/get_icon(turf/the_turf as turf) +/obj/item/device/camera/proc/get_icon(list/turfs, turf/center) + //Bigger icon base to capture those icons that were shifted to the next tile //i.e. pretty much all wall-mounted machinery var/icon/res = icon('icons/effects/96x96.dmi', "") + // Initialize the photograph to black. + res.Blend("#000", ICON_OVERLAY) var/atoms[] = list() - // Add outselves to the list of stuff to draw - atoms.Add(the_turf); - // As well as anything that isn't invisible. - for(var/atom/A in the_turf) - if(A.invisibility) continue - atoms.Add(A) + for(var/turf/the_turf in turfs) + // Add outselves to the list of stuff to draw + atoms.Add(the_turf); + // As well as anything that isn't invisible. + for(var/atom/A in the_turf) + if(A.invisibility) continue + atoms.Add(A) // Sort the atoms into their layers var/list/sorted = sort_atoms_by_layer(atoms) @@ -179,11 +183,17 @@ if(istype(A, /mob/living) && A:lying) // If they are, apply that effect to their picture. img.BecomeLying() - res.Blend(img, blendMode2iconMode(A.blend_mode), 33 + A.pixel_x, 33 + A.pixel_y) - + // Calculate where we are relative to the center of the photo + var/xoff = (A.x - center.x) * 32 + var/yoff = (A.y - center.y) * 32 + res.Blend(img, blendMode2iconMode(A.blend_mode), 33 + A.pixel_x + xoff, 33 + A.pixel_y + yoff) // Lastly, render any contained effects on top. - res.Blend(getFlatIcon(the_turf.loc), blendMode2iconMode(the_turf.blend_mode),33,33) + for(var/turf/the_turf in turfs) + // Calculate where we are relative to the center of the photo + var/xoff = (the_turf.x - center.x) * 32 + var/yoff = (the_turf.y - center.y) * 32 + res.Blend(getFlatIcon(the_turf.loc), blendMode2iconMode(the_turf.blend_mode),33 + xoff,33 + yoff) return res @@ -214,11 +224,8 @@ var/y_c = target.y + 1 var/z_c = target.z - var/icon/temp = icon('icons/effects/96x96.dmi',"") - var/icon/black = icon('icons/turf/space.dmi', "black") - // Initialize the photograph to black. - temp.Blend("#000", ICON_OVERLAY) + var/list/turfs = list() var/mobs = "" for(var/i = 1; i <= 3; i++) for(var/j = 1; j <= 3; j++) @@ -228,9 +235,7 @@ if(user.client) //To make shooting through security cameras possible viewer = user.client.eye if(dummy in viewers(world.view, viewer)) - temp.Blend(get_icon(T), ICON_OVERLAY, 32 * (j-1-1), 32 - 32 * (i-1)) - else - temp.Blend(black, ICON_OVERLAY, 32 * (j-1), 64 - 32 * (i-1)) + turfs.Add(T) mobs += get_mobs(T) dummy.loc = null dummy = null //Alas, nameless creature //garbage collect it instead @@ -238,12 +243,14 @@ y_c-- x_c = x_c - 3 + var/icon/photoimage = get_icon(turfs, target) + var/obj/item/weapon/photo/P = new/obj/item/weapon/photo() P.loc = user.loc if(!user.get_inactive_hand()) user.put_in_inactive_hand(P) - var/icon/small_img = icon(temp) - var/icon/tiny_img = icon(temp) + var/icon/small_img = icon(photoimage) + var/icon/tiny_img = icon(photoimage) var/icon/ic = icon('icons/obj/items.dmi',"photo") var/icon/pc = icon('icons/obj/bureaucracy.dmi', "photo") small_img.Scale(8, 8) @@ -252,7 +259,7 @@ pc.Blend(tiny_img,ICON_OVERLAY, 12, 19) P.icon = ic P.tiny = pc - P.img = temp + P.img = photoimage P.desc = mobs P.pixel_x = rand(-10, 10) P.pixel_y = rand(-10, 10) From f5df1acaaa3379ab09c585117f2b5f492fca1643 Mon Sep 17 00:00:00 2001 From: JimTheCactus Date: Mon, 28 Jul 2014 13:05:29 -0600 Subject: [PATCH 11/12] Added handler for pixel stepping --- code/modules/paperwork/photography.dm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index dcc7c9f55e..cbc119eaf5 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -186,6 +186,9 @@ // Calculate where we are relative to the center of the photo var/xoff = (A.x - center.x) * 32 var/yoff = (A.y - center.y) * 32 + if (istype(A,/atom/movable)) + xoff+=A:step_x + yoff+=A:step_y res.Blend(img, blendMode2iconMode(A.blend_mode), 33 + A.pixel_x + xoff, 33 + A.pixel_y + yoff) // Lastly, render any contained effects on top. From 9680cd85b740ff96286edc22dbc7be427e6b2617 Mon Sep 17 00:00:00 2001 From: mwerezak Date: Mon, 28 Jul 2014 20:51:04 -0400 Subject: [PATCH 12/12] Fixes chest not being coloured by necrosis --- code/modules/mob/living/carbon/human/update_icons.dm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 1fa7e6349d..5a06f2cfbe 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -251,7 +251,7 @@ proc/get_damage_icon_part(damage_state, body_part) icon_key = "[icon_key]0" else if(part.status & ORGAN_ROBOT) icon_key = "[icon_key]2" - else if(part.status & ORGAN_DEAD) //Do we even have necrosis in our current code? ~Z + else if(part.status & ORGAN_DEAD) icon_key = "[icon_key]3" else icon_key = "[icon_key]1" @@ -274,6 +274,10 @@ proc/get_damage_icon_part(damage_state, body_part) //No icon stored, so we need to start with a basic one. var/datum/organ/external/chest = get_organ("chest") base_icon = chest.get_icon(g) + + if(chest.status & ORGAN_DEAD) + base_icon.ColorTone(necrosis_color_mod) + base_icon.SetIntensity(0.7) for(var/datum/organ/external/part in organs)