-
-
Save Bananattack/47a6b92e443070508082e2dd7686cdf5 to your computer and use it in GitHub Desktop.
entity_move.wiz
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace entity { | |
in ram { | |
let COUNT = 32; | |
var data : [Entity; COUNT]; | |
namespace move_flags { | |
namespace bit { | |
let COLLIDED_X = 0; | |
let COLLIDED_Y = 1; | |
let NUDGE = 6; | |
let IGNORE_BOUNDS = 7; | |
} | |
namespace mask { | |
let NONE = 0x00; | |
let COLLIDED_X = 0x01; | |
let COLLIDED_Y = 0x02; | |
let NUDGE = 0x40; | |
let IGNORE_BOUNDS = 0x80; | |
} | |
} | |
let HITBOX_X = 2; | |
let HITBOX_X2 = 13; | |
let HITBOX_Y = 1; | |
let HITBOX_Y2 = 15; | |
} | |
// ... | |
func move(ent : *Entity in ix, x_speed : u8 in b0, y_speed : u8 in b1, flags : u8 in b) : u8 in b { | |
a = x_speed; | |
// TODO: Handle entity hitscan collisions. | |
// or simply set collision tiles behind enemies? | |
^if a != 0 { | |
// Sign extend speed to 16.8 | |
l = a; | |
d = 0; | |
if l$7 { | |
d--; | |
} | |
c = d; | |
// Convert speed from 4.4 to 16.8. | |
// (upper byte won't be affected) | |
inline for in 1 .. 4 { | |
a <<= 1; | |
d <<<<#= 1; | |
} | |
// Add 16.8 speed to 16.8 entity position. | |
var temp_subpixel_x : u8 in e = a = a + <:ent.x; | |
var temp_pixel_x : u8 in d = a = d +# >:ent.x; | |
var temp_screen_x : u8 in c = a = c +# #:ent.x; | |
push(de); | |
push(af); | |
if l$7 { | |
temp_pixel_x = a = temp_pixel_x + HITBOX_X; | |
temp_screen_x = a = temp_screen_x +# 0; | |
} else { | |
temp_pixel_x = a = temp_pixel_x +# HITBOX_X2; | |
temp_screen_x = a = temp_screen_x +# 0; | |
} | |
// If not on the current screen, we're out of bounds. | |
if { | |
l = a = room_screen_x; | |
a = temp_screen_x; | |
} && a != l { | |
^goto success if flags$move_flags.bit.IGNORE_BOUNDS; | |
// Less than current screen? clamp to left edge. | |
if a$7 || a < l { | |
<:ent.x = a = 0; | |
>:ent.x = a = 256 - HITBOX_X; | |
l--; | |
// Greater than current screen? clamp to right edge. | |
} else if { a++; } && a >= l { | |
<:ent.x = a = 0; | |
>:ent.x = a = ROOM_TILEMAP_WIDTH * 16 - HITBOX_X2; | |
} | |
#:ent.x = a = l; | |
flags$move_flags.bit.COLLIDED_X = true; | |
^goto failure; | |
} | |
l = a = room_screen_y; | |
a = #:ent.y; | |
if a$7 || a < l { | |
h = l = 0; | |
} else if zero { | |
a = >:ent.y + HITBOX_Y; | |
if carry || a >= ROOM_TILEMAP_HEIGHT * 16 { | |
h = l = (ROOM_TILEMAP_HEIGHT - 1) * 16; | |
} else { | |
l = a = a & 0xF0; | |
a = >:ent.y + HITBOX_Y2; | |
if carry || a >= ROOM_TILEMAP_HEIGHT * 16 { | |
a = (ROOM_TILEMAP_HEIGHT - 1) * 16; | |
} else { | |
a = a & 0xF0; | |
} | |
h = a; | |
} | |
} else { | |
h = l = (ROOM_TILEMAP_HEIGHT - 1) * 16; | |
} | |
push(hl); | |
// Calculate top tile coord. | |
a = (temp_pixel_x >>> 4) | l; | |
// Get tile at top. | |
var ptr : *u8 in hl = &room_tilemap[0]; | |
<:ptr = a = a + <:ptr; | |
>:ptr = a = >:ptr +# 0; | |
a = *ptr; | |
// Get collision info. | |
ptr = &tileset.flags_data[0]; | |
<:ptr = a = a + <:ptr; | |
>:ptr = a = >:ptr +# 0; | |
// Check collision. | |
if { a = (tileset.flags.mask.PIT | tileset.flags.mask.WALL) & *ptr; } && !zero { | |
// Snap to closest x. | |
<:ent.x = a = <:ent.x & 0xF0; | |
flags$move_flags.bit.COLLIDED_X = true; | |
} | |
// Calculate bottom tile coord. | |
hl = pop(); | |
a = (temp_pixel_x >>> 4) | h; | |
// Get tile at bottom | |
ptr = &room_tilemap[0]; | |
<:ptr = a = a + <:ptr; | |
>:ptr = a = >:ptr +# 0; | |
a = *ptr; | |
// Get collision info. | |
ptr = &tileset.flags_data[0]; | |
<:ptr = a = a + <:ptr; | |
>:ptr = a = >:ptr +# 0; | |
// Check collision. | |
if { a = (tileset.flags.mask.PIT | tileset.flags.mask.WALL) & *ptr; } && !zero { | |
// Snap to closest x. | |
<:ent.x = a = <:ent.x & 0xF0; | |
// We collided below. If we're nudging, but didn't collide above, nudge up. | |
if { a = flags & (move_flags.mask.COLLIDED_X | move_flags.mask.NUDGE); } && a == move_flags.mask.NUDGE | |
&& { a = y_speed; } && a == 0 { | |
af = pop(); | |
de = pop(); | |
ptr = &x_speed; | |
*ptr++ = 0; | |
*ptr++ = -0x10 as u8; | |
flags = a = flags & move_flags.mask.IGNORE_BOUNDS; | |
^return move(ent, x_speed, y_speed, flags); | |
} | |
flags$move_flags.bit.COLLIDED_X = true; | |
} | |
// We didn't collide below. If we're nudging, and we collided above, nudge down. | |
else if { a = flags & (move_flags.mask.COLLIDED_X | move_flags.mask.NUDGE); } && a == (move_flags.mask.COLLIDED_X | move_flags.mask.NUDGE) | |
&& { a = y_speed; } && a == 0 { | |
af = pop(); | |
de = pop(); | |
ptr = &x_speed; | |
*ptr++ = 0; | |
*ptr++ = 0x10; | |
flags = a = flags & move_flags.mask.IGNORE_BOUNDS; | |
^return move(ent, x_speed, y_speed, flags); | |
} | |
goto failure if flags$move_flags.bit.COLLIDED_X; | |
success: { | |
af = pop(); | |
de = pop(); | |
<:ent.x = temp_subpixel_x; | |
>:ent.x = temp_pixel_x; | |
#:ent.x = a; | |
goto done; | |
} | |
failure: { | |
af = pop(); | |
de = pop(); | |
} | |
done: | |
} | |
a = y_speed; | |
^if a != 0 { | |
// Sign extend speed to 16.8 | |
l = a; | |
d = 0; | |
if l$7 { | |
d--; | |
} | |
c = d; | |
// Convert speed from 4.4 to 16.8. | |
// (upper byte won't be affected) | |
inline for in 1 .. 4 { | |
a <<= 1; | |
d <<<<#= 1; | |
} | |
// Add 16.8 speed to 16.8 entity position. | |
var temp_subpixel_y : u8 in e = a = a + <:ent.y; | |
var temp_pixel_y : u8 in d = a = d +# >:ent.y; | |
var temp_screen_y : u8 in c = a = c +# #:ent.y; | |
push(de); | |
push(af); | |
if l$7 { | |
temp_pixel_y = a = temp_pixel_y + HITBOX_Y; | |
temp_screen_y = a = temp_screen_y +# 0; | |
} else { | |
temp_pixel_y = a = temp_pixel_y +# HITBOX_Y2; | |
temp_screen_y = a = temp_screen_y +# 0; | |
} | |
// If not on the current screen, we're out of bounds. | |
if { | |
l = a = room_screen_y; | |
a = temp_screen_y; | |
} && a != l { | |
^goto success if flags$move_flags.bit.IGNORE_BOUNDS; | |
// Less than current screen? clamp to left edge. | |
if a$7 || a < l { | |
<:ent.y = a = 0; | |
>:ent.y = a = 256 - HITBOX_Y; | |
l--; | |
// Greater than current screen? clamp to right edge. | |
} else if { a++; } && a >= l { | |
<:ent.y = a = 0; | |
>:ent.y = a = ROOM_TILEMAP_HEIGHT * 16 - HITBOX_Y2; | |
} | |
#:ent.y = a = l; | |
flags$move_flags.bit.COLLIDED_Y = true; | |
^goto failure; | |
} else if { | |
l = a = ROOM_TILEMAP_HEIGHT * 16; | |
a = temp_pixel_y; | |
} && a >= l { | |
^goto success if flags$move_flags.bit.IGNORE_BOUNDS; | |
<:ent.y = a = 0; | |
>:ent.y = a = ROOM_TILEMAP_HEIGHT * 16 - HITBOX_Y2; | |
flags$move_flags.bit.COLLIDED_Y = true; | |
^goto failure; | |
} | |
l = a = room_screen_x; | |
a = #:ent.x; | |
if a$7 || a < l { | |
h = l = 0; | |
} else if zero { | |
a = >:ent.x + HITBOX_X; | |
if carry { | |
h = l = ROOM_TILEMAP_WIDTH - 1; | |
} else { | |
a >>>= 4; | |
l = a; | |
a = >:ent.x + HITBOX_X2; | |
if carry { | |
a = ROOM_TILEMAP_WIDTH - 1; | |
} else { | |
a >>>= 4; | |
} | |
h = a; | |
} | |
} else { | |
h = l = ROOM_TILEMAP_WIDTH - 1; | |
} | |
push(hl); | |
// Calculate left tile coord. | |
a = (temp_pixel_y & 0xF0) | l; | |
// Get tile at left. | |
var ptr : *u8 in hl = &room_tilemap[0]; | |
<:ptr = a = a + <:ptr; | |
>:ptr = a = >:ptr +# 0; | |
a = *ptr; | |
// Get collision info. | |
ptr = &tileset.flags_data[0]; | |
<:ptr = a = a + <:ptr; | |
>:ptr = a = >:ptr +# 0; | |
// Check collision. | |
if { a = (tileset.flags.mask.PIT | tileset.flags.mask.WALL) & *ptr; } && !zero { | |
// Snap to closest y. | |
<:ent.y = a = <:ent.y & 0xF0; | |
flags$move_flags.bit.COLLIDED_Y = true; | |
} | |
// Calculate right tile coord. | |
hl = pop(); | |
a = (temp_pixel_y & 0xF0) | h; | |
// Get tile at right. | |
ptr = &room_tilemap[0]; | |
<:ptr = a = a + <:ptr; | |
>:ptr = a = >:ptr +# 0; | |
a = *ptr; | |
// Get collision info. | |
ptr = &tileset.flags_data[0]; | |
<:ptr = a = a + <:ptr; | |
>:ptr = a = >:ptr +# 0; | |
// Check collision. | |
if { a = (tileset.flags.mask.PIT | tileset.flags.mask.WALL) & *ptr; } && !zero { | |
// Snap to closest y. | |
<:ent.y = a = <:ent.y & 0xF0; | |
// We collided on the right. If we're nudging, but didn't collide on the left, nudge left. | |
if { a = flags & (move_flags.mask.COLLIDED_Y | move_flags.mask.NUDGE); } && a == move_flags.mask.NUDGE | |
&& { a = x_speed; } && a == 0 { | |
af = pop(); | |
de = pop(); | |
ptr = &x_speed; | |
*ptr++ = -0x10 as u8; | |
*ptr++ = 0; | |
flags = a = flags & move_flags.mask.IGNORE_BOUNDS; | |
^return move(ent, x_speed, y_speed, flags); | |
} | |
flags$move_flags.bit.COLLIDED_Y = true; | |
} | |
// We didn't collide on the right. If we're nudging, and we collided on the left, nudge right. | |
else if { a = flags & (move_flags.mask.COLLIDED_Y | move_flags.mask.NUDGE); } && a == (move_flags.mask.COLLIDED_Y | move_flags.mask.NUDGE) | |
&& { a = x_speed; } && a == 0 { | |
af = pop(); | |
de = pop(); | |
ptr = &x_speed; | |
*ptr++ = 0x10; | |
*ptr++ = 0; | |
flags = a = flags & move_flags.mask.IGNORE_BOUNDS; | |
^return move(ent, x_speed, y_speed, flags); | |
} | |
goto failure if flags$move_flags.bit.COLLIDED_Y; | |
success: { | |
af = pop(); | |
de = pop(); | |
<:ent.y = temp_subpixel_y; | |
>:ent.y = temp_pixel_y; | |
#:ent.y = a; | |
goto done; | |
} | |
failure: { | |
af = pop(); | |
de = pop(); | |
} | |
done: | |
} | |
return flags; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
*Entity in ix
❤️