ID:1839527
 
(See the best response by Lummox JR.)
Problem description:

I want to create a game that expands its view automatically based on the users view, this works fine.

proc
ceiling(a)
return -round(-a)
mob
var
tmp
ClientHeight
ClientWidth
Login()
..()
var/a=winget(src,"map1","size")
ClientHeight=text2num(copytext(a,findtext(a,"x")+1))
ClientWidth=text2num(copytext(a,1,findtext(a,"x")))
client.view="[ceiling(ClientWidth/32)]x[ceiling(ClientHeight/32)]"


Next I wanted to create a stationary HUD on all 4 corners of the screen, this is fine if all tiles are displayed but I use ceiling so that there's no potential for black borders, so when I use screen_loc it's displaying off the screen partially because the tile is also off the screen partially.

How would I go about taking this into account properly and displaying in the correct position? I already use the Resize event to re-position my items on Resize as well, but I need it to position in the same place still and I can't seem to make anything work.

Can anyone help me on this?
For the screen objects, you could just cling objects to corners by using keywords like NORTHEAST, NORTHWEST SOUTHEAST, and SOUTHWEST. Everything should display on screen assuming the map is properly positioned.
In response to Super Saiyan X
Using the keywords it's still acting like before though and clinging to the tiles themselves, so in code southwest is equal to the location of 1,1 even if that tile is partially offscreen, and so now my hud would be too.

This is made even easier if you just set yourself up an un-viewable map set not to stretch, say 100x100 tiles (I don't know if that's even possible to get that big but it's just an example.) How would you go about making it cling to the edges of the VISIBLE portions of the map? because southwest makes it still cling to x1y1 even if that tile is fully offscreen for example.
You need to offset the screen objects by the difference between ClientWidth/32 and ceiling(ClientWidth/32) I think.
In response to MisterPerson
The difference between the 2 is at most 1 pixel since all ceiling does is round the number up to the nearest whole number rather than down.

EDIT: It's off by a lot more than 1 pixel by the way, it can be off by as much as 31 pixels if I don't compensate for it at all.
Best response
First, I advise against making ceil() a proc; it's better if you use #define. This will inline the code instead of adding the overhead of a proc call, useful if you use it frequently. If it's only used for routines like this of course it doesn't matter, but it's good practice to inline when you can.

#define ceil(x) (-round(-(x)))

Now for the calculations, I think I'd add a few things. I'm also fixing the naming convention.

#define floor(x) (round(x))
#define ceil(x) (-round(-(x)))
#define ICON_WIDTH 32
#define ICON_HEIGHT 32

#define clamp(x,a,b) (((x)<(a)) ? (a) : (((x)>(b)) ? (b) : (x)))

mob
var/tmp
clientWidth
clientHeight
clientTileWidth
clientTileHeight
clientFullWidth
clientFullHeight

proc/ParseMapSize(a)
var/xloc = findtextEx(a,"x")
clientWidth = text2num(copytext(a,1,xloc++))
clientHeight = text2num(copytext(a,xloc))
// make sure tile size is an odd number
//it makes view calculations easier and keeps your mob centered
clientTileWidth = ceil(clientWidth/ICON_WIDTH) | 1
clientTileHeight = ceil(clientHeight/ICON_HEIGHT) | 1
clientFullWidth = clientTileWidth * ICON_WIDTH
clientFullHeight = clientTileHeight * ICON_HEIGHT
client.view="[clientTileWidth]x[clientTileHeight]"

proc/CalcScreenLoc(dir, px=0, py=0)
var/sx, sy, spx, spy
if(dir & WEST)
px += floor((clientFullWidth-clientWidth)/2)
sx = floor(px/ICON_WIDTH)+1
sx = clamp(sx, 1, clientTileWidth)
spx = px - (sx-1)*ICON_WIDTH
sx = "[sx]:[spx]"
else if(dir & EAST)
px += clientFullWidth - ceil((clientFullWidth-clientWidth)/2) - ICON_WIDTH
sx = floor(px/ICON_WIDTH)+1
sx = clamp(sx, 1, clientTileWidth)
spx = px - (sx-1)*ICON_WIDTH
sx = "[sx]:[spx]"
else
sx = "CENTER:[px]"
if(dir & SOUTH)
py += ceil((clientFullHeight-clientHeight)/2)
sy = floor(py/ICON_HEIGHT)+1
sy = clamp(sy, 1, clientTileHeight)
spy = py - (sy-1)*ICON_HEIGHT
sy = "[sy]:[spy]"
else if(dir & NORTH)
py += clientFullHeight - floor((clientFullHeight-clientHeight)/2) - ICON_HEIGHT
sy = floor(py/ICON_HEIGHT)+1
sy = clamp(sy, 1, clientTileHeight)
spy = py - (sy-1)*ICON_HEIGHT
sy = "[sy]:[spy]"
else
sy = "CENTER:[py]"
return "[sx],[sy]"

That code could be cleaned up a little. The gist is that you'd call that to get a screen_loc for any HUD items you wanted to place, and you'd also want to re-call it (after first re-parsing the map size) and adjust all those HUD items if the client's map size ever changed.
In response to Lummox JR
It doesn't appear to be working, I call ParseMapSize() with winget(src,"map1","size") and I call to CalcScreenLoc() with CalcScreenLoc(SOUTHWEST) which should be putting my image square in the bottom left corner of the screen, right?

Or no?

I made sure my view size was being set to 5x5 in the test, at 160x160 pixels it puts it in the corner like it should, but at 150x150 pixels to try with odd numbers still in the view, it comes away from the corner, not by 10 pixels but it looks like 3 or 4 pixels away.
In response to Superbike32
Whoops, I forgot a division I needed in my calculations. Edited the post. That code is still not really tested, so there might be some irregularities.
In response to Lummox JR
It appears to work perfectly now Lummox, thanks for that.

It's kind of sad that you have to do so much though in order to display a hud object on screen under these conditions though, and then it adds to the view a little bit I'm assuming if it's not an odd number to make it an odd number for both width and height.

After trying on my own for so long, I came up with another solution, although it only applies to the bottom left.

screen_loc="CENTER:[16+WestOffset-ceil(clientWidth/2)],CENTER:[16+SouthOffset-ceil(clientHeight/2)]"


I will still be using your code though in every situation, even if I could come up with code like this for every position I needed for my screen objects it's not elegant at all.

Hopefully even with all that code though that yours runs through it will still be fast if I end up with quite a few screen objects needing placed in that way.
I think the odd view is better all around, as it will keep your mob centered.

Speed probably isn't a huge concern unless you're changing your HUD objects' placement frequently. It should only come up when adding/moving an element, or when the player's map resizes. You probably will want all HUD objects to keep their dir/px/py values handy so they can recalculate as needed.