diff --git a/src/physics/collision_scene.c b/src/physics/collision_scene.c index 19ec2be..89b1438 100644 --- a/src/physics/collision_scene.c +++ b/src/physics/collision_scene.c @@ -423,7 +423,7 @@ int collisionSceneRaycastOnlyDynamic(struct CollisionScene* scene, struct Ray* r return hit->distance != maxDistance; } -int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ray* ray, int collisionLayers, float maxDistance, int passThroughPortals, struct RaycastHit* hit) { +int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ray* ray, int collisionLayers, float maxDistance, int passThroughPortals, struct RaycastHit* hit, short* numPortalsPassed) { hit->distance = maxDistance; hit->throughPortal = NULL; hit->roomIndex = roomIndex; @@ -458,6 +458,12 @@ int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ra collisionSceneIsPortalOpen()) { for (int i = 0; i < 2; ++i) { if (collisionSceneIsTouchingSinglePortal(&hit->at, &hit->normal, gCollisionScene.portalTransforms[i], i)) { + if (i == 0){ + *numPortalsPassed += 1; + }else{ + *numPortalsPassed -= 1; + } + struct Transform portalTransform; collisionSceneGetPortalTransform(i, &portalTransform); @@ -468,7 +474,7 @@ int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ra struct RaycastHit newHit; - int result = collisionSceneRaycast(scene, gCollisionScene.portalRooms[1 - i], &newRay, collisionLayers, maxDistance - hit->distance, 0, &newHit); + int result = collisionSceneRaycast(scene, gCollisionScene.portalRooms[1 - i], &newRay, collisionLayers, maxDistance - hit->distance, passThroughPortals, &newHit, numPortalsPassed); if (result) { newHit.distance += hit->distance; diff --git a/src/physics/collision_scene.h b/src/physics/collision_scene.h index a200b18..67e154f 100644 --- a/src/physics/collision_scene.h +++ b/src/physics/collision_scene.h @@ -44,7 +44,7 @@ struct Transform* collisionSceneTransformToPortal(int fromPortal); void collisionScenePushObjectsOutOfPortal(int portalIndex); -int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ray* ray, int collisionLayers, float maxDistance, int passThroughPortals, struct RaycastHit* hit); +int collisionSceneRaycast(struct CollisionScene* scene, int roomIndex, struct Ray* ray, int collisionLayers, float maxDistance, int passThroughPortals, struct RaycastHit* hit, short* numPortalsPassed); int collisionSceneRaycastOnlyDynamic(struct CollisionScene* scene, struct Ray* ray, int collisionLayers, float maxDistance, struct RaycastHit* hit); void collisionSceneGetPortalTransform(int fromPortal, struct Transform* out); diff --git a/src/player/player.c b/src/player/player.c index c380663..9ccb011 100644 --- a/src/player/player.c +++ b/src/player/player.c @@ -234,16 +234,18 @@ void playerHandleCollision(struct Player* player) { } void playerApplyPortalGrab(struct Player* player, int portalIndex) { - if (player->grabbingThroughPortal == PLAYER_GRABBING_THROUGH_NOTHING) { - player->grabbingThroughPortal = portalIndex; - } else if (player->grabbingThroughPortal != portalIndex) { - player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING; + if (portalIndex){ + player->grabbingThroughPortal -= 1; + }else{ + player->grabbingThroughPortal += 1; } } void playerSetGrabbing(struct Player* player, struct CollisionObject* grabbing) { if (grabbing && grabbing->flags & COLLISION_OBJECT_PLAYER_STANDING){ player->grabConstraint.object = NULL; + contactSolverRemovePointConstraint(&gContactSolver, &player->grabConstraint); + player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING; } else if (grabbing && !player->grabConstraint.object) { pointConstraintInit(&player->grabConstraint, grabbing, 8.0f, 5.0f, 1.0f); @@ -253,6 +255,7 @@ void playerSetGrabbing(struct Player* player, struct CollisionObject* grabbing) player->grabConstraint.object = NULL; contactSolverRemovePointConstraint(&gContactSolver, &player->grabConstraint); hudResolvePrompt(&gScene.hud, CutscenePromptTypeDrop); + player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING; } else if (grabbing != player->grabConstraint.object) { pointConstraintInit(&player->grabConstraint, grabbing, 8.0f, 5.0f, 1.0f); } @@ -290,7 +293,7 @@ int playerIsGrabbing(struct Player* player) { return player->grabConstraint.object != NULL; } -int playerRaycastGrab(struct Player* player, struct RaycastHit* hit, int checkPastObject) { +int playerRaycastGrab(struct Player* player, struct RaycastHit* hit, int checkPastObject, short* numPortalsPassed) { struct Ray ray; ray.origin = player->lookTransform.position; @@ -303,11 +306,11 @@ int playerRaycastGrab(struct Player* player, struct RaycastHit* hit, int checkPa if (checkPastObject){ short prevCollisionLayers = player->grabConstraint.object->collisionLayers; player->grabConstraint.object->collisionLayers = 0; - result = collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, COLLISION_LAYERS_TANGIBLE, GRAB_RAYCAST_DISTANCE, 1, hit); + result = collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, COLLISION_LAYERS_TANGIBLE, GRAB_RAYCAST_DISTANCE, 1, hit, numPortalsPassed); player->grabConstraint.object->collisionLayers = prevCollisionLayers; } else{ - result = collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, COLLISION_LAYERS_GRABBABLE | COLLISION_LAYERS_TANGIBLE, GRAB_RAYCAST_DISTANCE, 1, hit); + result = collisionSceneRaycast(&gCollisionScene, player->body.currentRoom, &ray, COLLISION_LAYERS_GRABBABLE | COLLISION_LAYERS_TANGIBLE, GRAB_RAYCAST_DISTANCE, 1, hit, numPortalsPassed); } player->collisionObject.collisionLayers = PLAYER_COLLISION_LAYERS; @@ -325,19 +328,15 @@ void playerUpdateGrabbedObject(struct Player* player) { playerSetGrabbing(player, NULL); } else { struct RaycastHit hit; + short numPortalsPassed = 0; - if (playerRaycastGrab(player, &hit, 0)) { + if (playerRaycastGrab(player, &hit, 0, &numPortalsPassed)) { hit.object->flags |= COLLISION_OBJECT_INTERACTED; - if (hit.object->body && (hit.object->body->flags & RigidBodyFlagsGrabbable)) { + if (hit.object->body && (hit.object->body->flags & RigidBodyFlagsGrabbable) && !(hit.object->flags & COLLISION_OBJECT_PLAYER_STANDING)) { playerSetGrabbing(player, hit.object); player->flags |= PlayerJustSelect; - - if (hit.throughPortal) { - player->grabbingThroughPortal = hit.throughPortal == gCollisionScene.portalTransforms[0] ? 0 : 1; - } else { - player->grabbingThroughPortal = PLAYER_GRABBING_THROUGH_NOTHING; - } + player->grabbingThroughPortal = numPortalsPassed; } else if ((hit.object->body)){ player->flags |= PlayerJustSelect; @@ -357,6 +356,18 @@ void playerUpdateGrabbedObject(struct Player* player) { playerSetGrabbing(player, NULL); } + // if the object is being held through a portal and can no longer be seen, drop it. + if (player->grabConstraint.object && player->grabbingThroughPortal){ + struct RaycastHit testhit; + short testnumPortalsPassed = 0; + if (playerRaycastGrab(player, &testhit, 0, &testnumPortalsPassed)){ + if ((testnumPortalsPassed != player->grabbingThroughPortal) && (testhit.object != player->grabConstraint.object)){ + playerSetGrabbing(player, NULL); + return; + } + } + } + if (player->grabConstraint.object) { if (player->body.flags & RigidBodyFlagsCrossedPortal0) { playerApplyPortalGrab(player, 1); @@ -380,7 +391,8 @@ void playerUpdateGrabbedObject(struct Player* player) { // try to determine how far away to set the grab dist struct RaycastHit hit; struct Vector3 temp_grab_dist = gGrabDistance; - if (playerRaycastGrab(player, &hit, 1)){ + short unused = 0; + if (playerRaycastGrab(player, &hit, 1, &unused)){ float dist = hit.distance; temp_grab_dist.z = maxf(((-1.0f*fabsf(dist))+0.2f), gGrabDistance.z); temp_grab_dist.z = minf(temp_grab_dist.z, -0.2f); @@ -401,12 +413,14 @@ void playerUpdateGrabbedObject(struct Player* player) { } struct Transform pointTransform; - collisionSceneGetPortalTransform(player->grabbingThroughPortal, &pointTransform); + collisionSceneGetPortalTransform(player->grabbingThroughPortal > 0 ? 0 : 1, &pointTransform); - transformPoint(&pointTransform, &grabPoint, &grabPoint); - struct Quaternion finalRotation; - quatMultiply(&pointTransform.rotation, &grabRotation, &finalRotation); - grabRotation = finalRotation; + for (int i = 0; i < abs(player->grabbingThroughPortal); ++i) { + transformPoint(&pointTransform, &grabPoint, &grabPoint); + struct Quaternion finalRotation; + quatMultiply(&pointTransform.rotation, &grabRotation, &finalRotation); + grabRotation = finalRotation; + } } pointConstraintUpdateTarget(&player->grabConstraint, &grabPoint, &grabRotation); diff --git a/src/player/player.h b/src/player/player.h index 04f6fda..ef142cb 100644 --- a/src/player/player.h +++ b/src/player/player.h @@ -11,7 +11,7 @@ #include "../sk64/skelatool_armature.h" #include "../physics/point_constraint.h" -#define PLAYER_GRABBING_THROUGH_NOTHING -1 +#define PLAYER_GRABBING_THROUGH_NOTHING 0 #define PLAYER_HEAD_HEIGHT 1.0f diff --git a/src/scene/portal_gun.c b/src/scene/portal_gun.c index 10a6658..cef6c2b 100644 --- a/src/scene/portal_gun.c +++ b/src/scene/portal_gun.c @@ -212,8 +212,9 @@ void portalGunUpdate(struct PortalGun* portalGun, struct Player* player) { } struct RaycastHit hit; + short numPortalsPassed; - if (collisionSceneRaycast(&gCollisionScene, projectile->roomIndex, &projectile->positionDirection, COLLISION_LAYERS_STATIC | COLLISION_LAYERS_BLOCK_PORTAL, PORTAL_PROJECTILE_SPEED * FIXED_DELTA_TIME + 0.1f, 0, &hit)) { + if (collisionSceneRaycast(&gCollisionScene, projectile->roomIndex, &projectile->positionDirection, COLLISION_LAYERS_STATIC | COLLISION_LAYERS_BLOCK_PORTAL, PORTAL_PROJECTILE_SPEED * FIXED_DELTA_TIME + 0.1f, 0, &hit, &numPortalsPassed)) { if (!sceneOpenPortalFromHit( &gScene, &projectile->positionDirection, @@ -247,8 +248,9 @@ void portalGunFire(struct PortalGun* portalGun, int portalIndex, struct Ray* ray struct PortalGunProjectile* projectile = &portalGun->projectiles[portalIndex]; struct RaycastHit hit; + short numPortalsPassed; - if (!collisionSceneRaycast(&gCollisionScene, roomIndex, ray, COLLISION_LAYERS_STATIC | COLLISION_LAYERS_BLOCK_PORTAL, 1000000.0f, 0, &hit)) { + if (!collisionSceneRaycast(&gCollisionScene, roomIndex, ray, COLLISION_LAYERS_STATIC | COLLISION_LAYERS_BLOCK_PORTAL, 1000000.0f, 0, &hit, &numPortalsPassed)) { vector3AddScaled(&ray->origin, &ray->dir, NO_HIT_DISTANCE, &hit.at); hit.distance = NO_HIT_DISTANCE; hit.normal = gZeroVec; diff --git a/src/scene/scene.c b/src/scene/scene.c index 4b0e400..6ebe7d0 100644 --- a/src/scene/scene.c +++ b/src/scene/scene.c @@ -939,8 +939,9 @@ int sceneOpenPortalFromHit(struct Scene* scene, struct Ray* ray, struct RaycastH int sceneFirePortal(struct Scene* scene, struct Ray* ray, struct Vector3* playerUp, int portalIndex, int roomIndex, int fromPlayer, int just_checking) { struct RaycastHit hit; + short numPortalsPassed; - if (!collisionSceneRaycast(&gCollisionScene, roomIndex, ray, COLLISION_LAYERS_STATIC | COLLISION_LAYERS_BLOCK_PORTAL, 1000000.0f, 0, &hit)) { + if (!collisionSceneRaycast(&gCollisionScene, roomIndex, ray, COLLISION_LAYERS_STATIC | COLLISION_LAYERS_BLOCK_PORTAL, 1000000.0f, 0, &hit, &numPortalsPassed)) { return 0; } diff --git a/src/scene/security_camera.c b/src/scene/security_camera.c index 9c23a2b..02e0627 100644 --- a/src/scene/security_camera.c +++ b/src/scene/security_camera.c @@ -140,6 +140,9 @@ void securityCameraInit(struct SecurityCamera* securityCamera, struct SecurityCa } void securityCameraUpdate(struct SecurityCamera* securityCamera) { + if (securityCamera->collisionObject.flags & COLLISION_OBJECT_PLAYER_STANDING) { + securityCamera->collisionObject.flags &= ~COLLISION_OBJECT_PLAYER_STANDING; + } if (decorObjectUpdateFizzler(&securityCamera->collisionObject, &securityCamera->fizzleTime) == FizzleCheckResultEnd) { dynamicSceneRemove(securityCamera->dynamicId); collisionSceneRemoveDynamicObject(&securityCamera->collisionObject);