ID:1930793
 
Resolved
/client now has a new set of vars: bounds, bound_x, bound_y, bound_width, and bound_height. These return pixel coordinates of the viewport, in the same format used by the bounds() proc. (Note: world.map_format and client.dir are not taken into account.)
  • bound_x, bound_y are the pixel coordinates of the lower left corner of the viewport. These are affected by client.pixel_x/y/z as well as the eye's pixel and step offsets, edge_limit, etc.
  • bound_width, bound_height are the width and height of the viewport, in pixels.
  • bounds is a list of all four of the above values, plus a z coordinate.
All of these values are read-only.
Applies to:DM Language
Status: Resolved (509.1300)

This issue has been resolved.
I had to sit down today to work out something that the server already knows: Where the bottom-left corner of the current viewport is.

This is the monstrous, ugly, hacked-in behemoth I had to slap together to get two numbers just so I could point the mouse somewhere on the screen, save the current screen mouse position, and apply it to the current position in the world after the client's eye has been moved. Something that should just plain be simple as all get-out wound up eating 4 hours of my time. It's just maddening that something this basic that the engine already needs to calculate just to do view sending and rendering takes this much work to do.

You want to see it? You sure you want to see it?

client
var
view_x
view_y

view_width = 31
view_height = 17

edge_limit_x1
edge_limit_y1
edge_limit_x2
edge_limit_y2
New()
. = ..()
if(.)
__checkView()

proc
setEdgeLimit(x1,y1,x2,y2)
if(x1&&y1&&x2&&y2)
edge_limit_x1 = x1
edge_limit_y1 = y1
edge_limit_x2 = x2
edge_limit_y2 = y2
perspective |= EDGE_PERSPECTIVE
edge_limit = "[x1],[y1] to [x2],[y2]"
else
edge_limit_x1 = null
edge_limit_y1 = null
edge_limit_x2 = null
edge_limit_y2 = null
perspective &= ~EDGE_PERSPECTIVE
edge_limit = null

__checkView()
set waitfor = 0
var/opersp = perspective
var/olimit = edge_limit
var/atom/movable/oeye = virtual_eye
var/cx = null
var/cy = null
if(virtual_eye)
if(ismovable(virtual_eye))
cx = (oeye:x-1)*TILE_WIDTH + oeye:step_x + oeye:bound_x
cy = (oeye:y-1)*TILE_HEIGHT + oeye:step_y + oeye:bound_y
else
cx = (oeye:x-1)*TILE_WIDTH
cy = (oeye:y-1)*TILE_HEIGHT
var/ox = cx
var/oy = cy
var/opx = pixel_x
var/opy = pixel_y
var/oview = view
UpdateViewLoc()
sleep(TICK_LAG)
while(1)
. = 0
if(view!=oview)
oview = view
if(isnum(view))
view_width = view*2+1
view_height = view_width
else
view_width = text2num(view)
view_height = text2num(str_copy_after(view,"x"))
. = 1
if(opx!=pixel_x||opy!=pixel_y)
opx = pixel_x
opy = pixel_y
. = 1
if(perspective!=opersp)
opersp = perspective
. = 1
if(olimit!=edge_limit)
olimit = edge_limit
. = 1
if(virtual_eye!=oeye)
oeye = virtual_eye
if(oeye)
if(ismovable(oeye))
cx = (oeye:x-1)*TILE_WIDTH + oeye:step_x + oeye:bound_x
cy = (oeye:y-1)*TILE_HEIGHT + oeye:step_y + oeye:bound_y
else
cx = (oeye:x-1)*TILE_WIDTH
cy = (oeye:y-1)*TILE_HEIGHT
else
cx = null
cy = null
if(ox!=cx||oy!=cy)
ox = cx
oy = cy
. = 1
if(.)
UpdateViewLoc()
sleep(TICK_LAG)

UpdateViewLoc()
var/oldx = view_x
var/oldy = view_y
if(eye:z)
var/mov = ismovable(eye)
if(view_width>=world.maxx)
view_x = ((world.maxx - view_width)*TILE_WIDTH)/2 + pixel_x
else if(perspective&EDGE_PERSPECTIVE)
var/vx = floor(view_width/2)
if(eye:x<=edge_limit_x1+vx)
view_x = (edge_limit_x1-1)*TILE_WIDTH + pixel_x
else if(eye:x>=world.maxx-vx)
view_x = (edge_limit_x2-view_width+vx-1)*TILE_WIDTH + pixel_x
else
var/ox = 0
var/ow = TILE_WIDTH
if(mov)
ow = eye:bound_width
ox = eye:step_x + eye:bound_x
view_x = (eye:x - 1)*TILE_WIDTH - (view_width*TILE_WIDTH-ow)/2 + pixel_x + ox + 1
else
var/ox = 0
var/ow = TILE_WIDTH
if(mov)
ow = eye:bound_width
ox = eye:step_x + eye:bound_x
view_x = (eye:x - 1)*TILE_WIDTH - (view_width*TILE_WIDTH-ow)/2 + pixel_x + ox + 1
if(view_height>=world.maxy)
view_y = ((world.maxy - view_height)*TILE_HEIGHT)/2 + pixel_y
else if(perspective&EDGE_PERSPECTIVE)
var/vy = floor(view_height/2)
if(eye:y<=edge_limit_y1+vy)
view_y = (edge_limit_y1-1)*TILE_HEIGHT + pixel_y
else if(eye:y>=world.maxy-vy)
view_y = (edge_limit_y2-view_height+vy-1)*TILE_HEIGHT + pixel_y
else
var/oy = 0
var/oh = TILE_HEIGHT
if(mov)
oh = eye:bound_height
oy = eye:step_y + eye:bound_y
view_y = (eye:y - 1)*TILE_HEIGHT - (view_height*TILE_HEIGHT-oh)/2 + pixel_y + oy + 1
else
var/oy = 0
var/oh = TILE_HEIGHT
if(mov)
oh = eye:bound_height
oy = eye:step_y + eye:bound_y
view_y = (eye:y - 1)*TILE_HEIGHT - (view_height*TILE_HEIGHT-oh)/2 + pixel_y + oy + 1
else
view_x = null
view_y = null

if(oldx!=view_x||oldy!=view_y)
ViewMoved(oldx,oldy)

ViewMoved(OldX,OldY)


Lummox Pls.
+1
It doesn't have to be this waaay.
+1

This kind of reminds me of how we can't loop through everything in one zone of the map file without checking the whole world. Well, at least I think we can't I haven't ever needed it badly enough to check thoroughly.

Another good one would be how little control over the eye we have. It should be easy to have the mob appear at any point on the screen and maintain that spot at all times, but last I checked it can be a little bit difficult. Example? Games like Space Invaders. Probably tougher to do that than it should be.

Anyways moral of this post is I agree, this should be much more accessable by default.
In response to Toddab503
Toddab503 wrote:
+1

This kind of reminds me of how we can't loop through everything in one zone of the map file without checking the whole world. Well, at least I think we can't I haven't ever needed it badly enough to check thoroughly.

You can loop over /area contents, or use block().

Another good one would be how little control over the eye we have. It should be easy to have the mob appear at any point on the screen and maintain that spot at all times, but last I checked it can be a little bit difficult. Example? Games like Space Invaders. Probably tougher to do that than it should be.

Insanely easy to do that kind of eye positioning.
In response to Nadrew
That's a pretty decent way to do it. I hadn't thought of that.

Okay, the eye thing is just a prime example of why I shouldn't speak on things I only toyed with minimally, and over a year or two ago. It did seem like it should be, I just ran into a lot of bugs trying to do it with pixel movement. Again, minimal effort and much less familiar with DM at the time though.
This is the best time for me to add new vars. What format do you think would work best for such a var?
I think to continue with the trend you've started of not using strings for everything, a list of values in global pixel coordinates starting at 1,1 (for consistency with bounds() functionality).

e.g.: list(x1,y1,x2,y2)

This list should go below 1 if the left/bottom corner of the viewport is beyond the left edge of the map, and beyond world.maxx*TILE_WIDTH / world.maxy*TILE_HEIGHT if over the right/top corner of the map.

These values should all be null if the viewport is not on a z layer (the eye is in null space)

IMO, this should always be capped at the internal view size, NOT the map element's size. Only the area that actually gets tiles rendered on it should be represented in this rectangle. Extra padding added by screen objects beyond the normal edges, and so on shouldn't count.
Should those cords be map-pixel cords like bounds(), or something else?
a list of values in global pixel coordinates starting at 1,1 (for consistency with bounds() functionality).
In response to Ter13
Wouldn't it be more consistent with bounds(x, y, width, height, z) if it was list(x, y, width, height)?
True. I suppose either format works.
or just add some base data holding datums like rects, points, etc
Lummox JR resolved issue with message:
/client now has a new set of vars: bounds, bound_x, bound_y, bound_width, and bound_height. These return pixel coordinates of the viewport, in the same format used by the bounds() proc. (Note: world.map_format and client.dir are not taken into account.)
  • bound_x, bound_y are the pixel coordinates of the lower left corner of the viewport. These are affected by client.pixel_x/y/z as well as the eye's pixel and step offsets, edge_limit, etc.
  • bound_width, bound_height are the width and height of the viewport, in pixels.
  • bounds is a list of all four of the above values, plus a z coordinate.
All of these values are read-only.