sm64

A Super Mario 64 decompilation
Log | Files | Refs | README | LICENSE

object_collision.c (6778B)


      1 #include <PR/ultratypes.h>
      2 
      3 #include "sm64.h"
      4 #include "debug.h"
      5 #include "interaction.h"
      6 #include "mario.h"
      7 #include "object_list_processor.h"
      8 #include "spawn_object.h"
      9 
     10 struct Object *debug_print_obj_collision(struct Object *a) {
     11     struct Object *sp24;
     12     UNUSED u8 filler[4];
     13     s32 i;
     14 
     15     for (i = 0; i < a->numCollidedObjs; i++) {
     16         print_debug_top_down_objectinfo("ON", 0);
     17         sp24 = a->collidedObjs[i];
     18         if (sp24 != gMarioObject) {
     19             return sp24;
     20         }
     21     }
     22     return NULL;
     23 }
     24 
     25 s32 detect_object_hitbox_overlap(struct Object *a, struct Object *b) {
     26     f32 sp3C = a->oPosY - a->hitboxDownOffset;
     27     f32 sp38 = b->oPosY - b->hitboxDownOffset;
     28     f32 dx = a->oPosX - b->oPosX;
     29     UNUSED f32 sp30 = sp3C - sp38;
     30     f32 dz = a->oPosZ - b->oPosZ;
     31     f32 collisionRadius = a->hitboxRadius + b->hitboxRadius;
     32     f32 distance = sqrtf(dx * dx + dz * dz);
     33 
     34     if (collisionRadius > distance) {
     35         f32 sp20 = a->hitboxHeight + sp3C;
     36         f32 sp1C = b->hitboxHeight + sp38;
     37 
     38         if (sp3C > sp1C) {
     39             return 0;
     40         }
     41         if (sp20 < sp38) {
     42             return 0;
     43         }
     44         if (a->numCollidedObjs >= 4) {
     45             return 0;
     46         }
     47         if (b->numCollidedObjs >= 4) {
     48             return 0;
     49         }
     50         a->collidedObjs[a->numCollidedObjs] = b;
     51         b->collidedObjs[b->numCollidedObjs] = a;
     52         a->collidedObjInteractTypes |= b->oInteractType;
     53         b->collidedObjInteractTypes |= a->oInteractType;
     54         a->numCollidedObjs++;
     55         b->numCollidedObjs++;
     56         return 1;
     57     }
     58 
     59     //! no return value
     60 #ifdef AVOID_UB
     61     return 0;
     62 #endif
     63 }
     64 
     65 s32 detect_object_hurtbox_overlap(struct Object *a, struct Object *b) {
     66     f32 sp3C = a->oPosY - a->hitboxDownOffset;
     67     f32 sp38 = b->oPosY - b->hitboxDownOffset;
     68     f32 sp34 = a->oPosX - b->oPosX;
     69     UNUSED f32 sp30 = sp3C - sp38;
     70     f32 sp2C = a->oPosZ - b->oPosZ;
     71     f32 sp28 = a->hurtboxRadius + b->hurtboxRadius;
     72     f32 sp24 = sqrtf(sp34 * sp34 + sp2C * sp2C);
     73 
     74     if (a == gMarioObject) {
     75         b->oInteractionSubtype |= INT_SUBTYPE_DELAY_INVINCIBILITY;
     76     }
     77 
     78     if (sp28 > sp24) {
     79         f32 sp20 = a->hitboxHeight + sp3C;
     80         f32 sp1C = b->hurtboxHeight + sp38;
     81 
     82         if (sp3C > sp1C) {
     83             return 0;
     84         }
     85         if (sp20 < sp38) {
     86             return 0;
     87         }
     88         if (a == gMarioObject) {
     89             b->oInteractionSubtype &= ~INT_SUBTYPE_DELAY_INVINCIBILITY;
     90         }
     91         return 1;
     92     }
     93 
     94     //! no return value
     95 #ifdef AVOID_UB
     96     return 0;
     97 #endif
     98 }
     99 
    100 void clear_object_collision(struct Object *a) {
    101     struct Object *sp4 = (struct Object *) a->header.next;
    102 
    103     while (sp4 != a) {
    104         sp4->numCollidedObjs = 0;
    105         sp4->collidedObjInteractTypes = 0;
    106         if (sp4->oIntangibleTimer > 0) {
    107             sp4->oIntangibleTimer--;
    108         }
    109         sp4 = (struct Object *) sp4->header.next;
    110     }
    111 }
    112 
    113 void check_collision_in_list(struct Object *a, struct Object *b, struct Object *c) {
    114     if (a->oIntangibleTimer == 0) {
    115         while (b != c) {
    116             if (b->oIntangibleTimer == 0) {
    117                 if (detect_object_hitbox_overlap(a, b) && b->hurtboxRadius != 0.0f) {
    118                     detect_object_hurtbox_overlap(a, b);
    119                 }
    120             }
    121             b = (struct Object *) b->header.next;
    122         }
    123     }
    124 }
    125 
    126 void check_player_object_collision(void) {
    127     struct Object *sp1C = (struct Object *) &gObjectLists[OBJ_LIST_PLAYER];
    128     struct Object *sp18 = (struct Object *) sp1C->header.next;
    129 
    130     while (sp18 != sp1C) {
    131         check_collision_in_list(sp18, (struct Object *) sp18->header.next, sp1C);
    132         check_collision_in_list(sp18, (struct Object *) gObjectLists[OBJ_LIST_POLELIKE].next,
    133                       (struct Object *) &gObjectLists[OBJ_LIST_POLELIKE]);
    134         check_collision_in_list(sp18, (struct Object *) gObjectLists[OBJ_LIST_LEVEL].next,
    135                       (struct Object *) &gObjectLists[OBJ_LIST_LEVEL]);
    136         check_collision_in_list(sp18, (struct Object *) gObjectLists[OBJ_LIST_GENACTOR].next,
    137                       (struct Object *) &gObjectLists[OBJ_LIST_GENACTOR]);
    138         check_collision_in_list(sp18, (struct Object *) gObjectLists[OBJ_LIST_PUSHABLE].next,
    139                       (struct Object *) &gObjectLists[OBJ_LIST_PUSHABLE]);
    140         check_collision_in_list(sp18, (struct Object *) gObjectLists[OBJ_LIST_SURFACE].next,
    141                       (struct Object *) &gObjectLists[OBJ_LIST_SURFACE]);
    142         check_collision_in_list(sp18, (struct Object *) gObjectLists[OBJ_LIST_DESTRUCTIVE].next,
    143                       (struct Object *) &gObjectLists[OBJ_LIST_DESTRUCTIVE]);
    144         sp18 = (struct Object *) sp18->header.next;
    145     }
    146 }
    147 
    148 void check_pushable_object_collision(void) {
    149     struct Object *sp1C = (struct Object *) &gObjectLists[OBJ_LIST_PUSHABLE];
    150     struct Object *sp18 = (struct Object *) sp1C->header.next;
    151 
    152     while (sp18 != sp1C) {
    153         check_collision_in_list(sp18, (struct Object *) sp18->header.next, sp1C);
    154         sp18 = (struct Object *) sp18->header.next;
    155     }
    156 }
    157 
    158 void check_destructive_object_collision(void) {
    159     struct Object *sp1C = (struct Object *) &gObjectLists[OBJ_LIST_DESTRUCTIVE];
    160     struct Object *sp18 = (struct Object *) sp1C->header.next;
    161 
    162     while (sp18 != sp1C) {
    163         if (sp18->oDistanceToMario < 2000.0f && !(sp18->activeFlags & ACTIVE_FLAG_UNK9)) {
    164             check_collision_in_list(sp18, (struct Object *) sp18->header.next, sp1C);
    165             check_collision_in_list(sp18, (struct Object *) gObjectLists[OBJ_LIST_GENACTOR].next,
    166                           (struct Object *) &gObjectLists[OBJ_LIST_GENACTOR]);
    167             check_collision_in_list(sp18, (struct Object *) gObjectLists[OBJ_LIST_PUSHABLE].next,
    168                           (struct Object *) &gObjectLists[OBJ_LIST_PUSHABLE]);
    169             check_collision_in_list(sp18, (struct Object *) gObjectLists[OBJ_LIST_SURFACE].next,
    170                           (struct Object *) &gObjectLists[OBJ_LIST_SURFACE]);
    171         }
    172         sp18 = (struct Object *) sp18->header.next;
    173     }
    174 }
    175 
    176 void detect_object_collisions(void) {
    177     clear_object_collision((struct Object *) &gObjectLists[OBJ_LIST_POLELIKE]);
    178     clear_object_collision((struct Object *) &gObjectLists[OBJ_LIST_PLAYER]);
    179     clear_object_collision((struct Object *) &gObjectLists[OBJ_LIST_PUSHABLE]);
    180     clear_object_collision((struct Object *) &gObjectLists[OBJ_LIST_GENACTOR]);
    181     clear_object_collision((struct Object *) &gObjectLists[OBJ_LIST_LEVEL]);
    182     clear_object_collision((struct Object *) &gObjectLists[OBJ_LIST_SURFACE]);
    183     clear_object_collision((struct Object *) &gObjectLists[OBJ_LIST_DESTRUCTIVE]);
    184     check_player_object_collision();
    185     check_destructive_object_collision();
    186     check_pushable_object_collision();
    187 }