#include #include #include #include #include #include #include #include #include #include #include #include #include "hash.h" #include "base.h" #include "entities.h" #include "proj.h" #include "move.h" #include "display.h" #include "music.h" // ---------------------------------------------------------------------------------------------------- // double sensitivity = 0.06; double fov = 90.0; double creative_speed = 0.5; double speed = 5.0; double vtmult = 2.7; double min_dist = 0.4; double friction = 0.3; double gravity_factor = 26.0; // ---------------------------------------------------------------------------------------------------- // const double blockRestitution = 0.2; entity* entToVelCheck = NULL; bool doUpdateEntVel = false; entity* movingPlatformUpdate = NULL; bool doUpdateMoving = false; bool is_clipping = false; int clip_dps = 500; int njumps; double fx; double fy; double fz; bool updateForces = false; int player_hp; bool stop_evetything; double camx; double camy; double camz; double camvx; double camvy; double camvz; double rot_hz; double rot_vt; double tan_fov; int draw_type; int fade_dmg; bool has_changed; int collisionVal = 0; double room_width; double room_depth; double sq2; float dmgCD; int lastDmg; bool buttonSwitch[16]; float buttonTimes[16]; float buttonMaxT[16]; bool mathSignal; int mathSigCD; void init_csts() { camx = 2.0; camy = 5.0; camz = 2.0; player_chx = 0; player_chy = 0; camvx = 0.0; camvy = 0.0; camvz = 0.0; rot_hz = 0.0; rot_vt = 0.0; room_width = 16.0; room_depth = 16.0; coins = 0; player_hp = 1000; njumps = 1; draw_type = 0; fade_dmg = 0; mathSignal = false; mathSigCD = 4; for(int k = 0; k < 16; k++) { buttonTimes[k] = 0.0f; buttonSwitch[k] = false; buttonMaxT[k] = 0.0f; } dmgCD = 0.0f; lastDmg = player_hp; stop_evetything = false; tan_fov = tan((fov * 3.14159 / 180.0) / 2.0); sq2 = sqrt(2); } void update_buttons(float dtime) { for(int k = 0; k < 16; k++) { if(buttonSwitch[k]) { if(buttonTimes[k] <= dtime && buttonMaxT[k] > 0.0) { buttonTimes[k] = 0.0f; buttonSwitch[k] = false; } else { buttonTimes[k] -= dtime; } } } } void set_player_coords(int old_chx, int old_chy) { for(int k = 0; k < current_room->tps_size; k++) { if(current_room->tps[k]->dest_chx == old_chx && current_room->tps[k]->dest_chy == old_chy) { if(true) { camx = current_room->tps[k]->hitbox->x + current_room->tps[k]->hitbox->w/2.0; camy = current_room->tps[k]->hitbox->y + current_room->tps[k]->hitbox->h +1.5; camz = current_room->tps[k]->hitbox->z + current_room->tps[k]->hitbox->d/2.0; } return; } } // no TP has been found, placing to the middle of the room camx = 0.0; camy = 10.0; camz = 0.0; } pt_2d surface[3]; pt_2d directors[2]; pt_2d normal; double p1, p2, p3; void getSF(cube_0* cb, int sf) { if(sf == 0 || sf == 1) { project_to_cube(cb->x + (sf==0)*(cb->w), cb->y , cb->z , &p1, &p2, &p3, cb); surface[0] = (pt_2d){.x = p1, .y = p2, .z = p3}; project_to_cube(cb->x + (sf==0)*(cb->w), cb->y + cb->h, cb->z , &p1, &p2, &p3, cb); surface[1] = (pt_2d){.x = p1, .y = p2, .z = p3}; project_to_cube(cb->x + (sf==0)*(cb->w), cb->y , cb->z + cb->d, &p1, &p2, &p3, cb); surface[2] = (pt_2d){.x = p1, .y = p2, .z = p3}; } else if(sf == 2 || sf == 3) { project_to_cube(cb->x , cb->y + (sf==2)*(cb->h), cb->z , &p1, &p2, &p3, cb); surface[0] = (pt_2d){.x = p1, .y = p2, .z = p3}; project_to_cube(cb->x + cb->w, cb->y + (sf==2)*(cb->h), cb->z , &p1, &p2, &p3, cb); surface[1] = (pt_2d){.x = p1, .y = p2, .z = p3}; project_to_cube(cb->x , cb->y + (sf==2)*(cb->h), cb->z + cb->d, &p1, &p2, &p3, cb); surface[2] = (pt_2d){.x = p1, .y = p2, .z = p3}; } else { project_to_cube(cb->x , cb->y , cb->z + (sf==4)*(cb->d), &p1, &p2, &p3, cb); surface[0] = (pt_2d){.x = p1, .y = p2, .z = p3}; project_to_cube(cb->x + cb->w, cb->y , cb->z + (sf==4)*(cb->d), &p1, &p2, &p3, cb); surface[1] = (pt_2d){.x = p1, .y = p2, .z = p3}; project_to_cube(cb->x , cb->y + cb->h, cb->z + (sf==4)*(cb->d), &p1, &p2, &p3, cb); surface[2] = (pt_2d){.x = p1, .y = p2, .z = p3}; } } void getDirectors() { directors[0] = (pt_2d){.x = surface[1].x - surface[0].x, .y = surface[1].y - surface[0].y, .z = surface[1].z - surface[0].z}; directors[1] = (pt_2d){.x = surface[2].x - surface[0].x, .y = surface[2].y - surface[0].y, .z = surface[2].z - surface[0].z}; } void getNormal() { normal.x = directors[0].y*directors[1].z - directors[1].y*directors[0].z; normal.y = directors[0].z*directors[1].x - directors[1].z*directors[0].x; normal.z = directors[0].x*directors[1].y - directors[1].x*directors[0].y; double norm = sqrt(normal.x*normal.x + normal.y*normal.y + normal.z*normal.z); normal.x /= norm; normal.y /= norm; normal.z /= norm; } pt_2d cross_product(pt_2d p1, pt_2d p2) { return (pt_2d){ .x = p1.y*p2.z - p1.z*p2.y, .y = p1.z*p2.x - p1.x*p2.z, .z = p1.x*p2.y - p1.y*p2.x }; } void normalize(pt_2d* p) { double norm = sqrt(p->x*p->x + p->y*p->y + p->z*p->z); p->x /= norm; p->y /= norm; p->z /= norm; } void debugMove(cube_0* cb) { for(int d = 0; d < 6; d++) { cb->x -= min_dist; cb->y -= min_dist; cb->z -= min_dist; cb->w += 2*min_dist; cb->h += 2*min_dist; cb->d += 2*min_dist; getSF(cb, d); cb->x += min_dist; cb->y += min_dist; cb->z += min_dist; cb->w -= 2*min_dist; cb->h -= 2*min_dist; cb->d -= 2*min_dist; for(int k = 0; k < 3; k++) { cube_0* cb2 = create_cube_0(surface[k].x-0.1, surface[k].y-0.1, surface[k].z-0.1, 0.2, 0.2, 0.2, 0.0, 0.0, 255, 255, 255); gl_renderCube(cb2, 0.0, 0.0, 0.0); free(cb2); } } } void updateF_movableCrate(cube_0* cb, double dtime, entity* ent) { for(int d = 0; d < 6; d++) { cb->x -= min_dist; cb->y -= min_dist; cb->z -= min_dist; cb->w += 2*min_dist; cb->h += 2*min_dist; cb->d += 2*min_dist; getSF(cb, d); cb->x += min_dist; cb->y += min_dist; cb->z += min_dist; cb->w -= 2*min_dist; cb->h -= 2*min_dist; cb->d -= 2*min_dist; getDirectors(); getNormal(); if(d==2 || d==5 || d==1) { normal.x *= -1.0; normal.y *= -1.0; normal.z *= -1.0; } //printf("%lf %lf\n", dot3D(normal, directors[0]), dot3D(normal, directors[1])); pt_2d vt = (pt_2d){.x = camx-camvx*dtime - surface[0].x, .y = camy-camvy*dtime - surface[0].y, .z = camz-camvz*dtime - surface[0].z}; pt_2d vtdt = (pt_2d){.x = camx - surface[0].x, .y = camy - surface[0].y, .z = camz - surface[0].z}; normalize(&vtdt); normalize(&vt); if( (dot3D(vt, normal) <= 0.0 && dot3D(vtdt, normal) >= 0.0) || (dot3D(vt, normal) >= 0.0 && dot3D(vtdt, normal) <= 0.0) ) { //printf("%d\n", d); switch (d) { case 0: ent->metad1 += camvx; break; case 1: ent->metad1 += camvx; break; case 3: break; case 2: ent->metad2 += camvy; break; case 4: ent->metad3 += camvz; break; case 5: ent->metad3 += camvz; break; default: break; } return; } } } pt_2d normal_axis = {.x = 0.0, .y = 1.0, .z = 0.0}; pt_2d normal_axis2 = {.x = 1.0, .y = 0.0, .z = 0.0}; // rotation axis void updateF(cube_0* cb, double dtime, entity* ent) { for(int d = 0; d < 6; d++) { cb->x -= min_dist; cb->y -= min_dist; cb->z -= min_dist; cb->w += 2*min_dist; cb->h += 2*min_dist; cb->d += 2*min_dist; getSF(cb, d); cb->x += min_dist; cb->y += min_dist; cb->z += min_dist; cb->w -= 2*min_dist; cb->h -= 2*min_dist; cb->d -= 2*min_dist; getDirectors(); getNormal(); if(d==2 || d==5 || d==1) { normal.x *= -1.0; normal.y *= -1.0; normal.z *= -1.0; } //printf("%lf %lf\n", dot3D(normal, directors[0]), dot3D(normal, directors[1])); pt_2d vt = (pt_2d){.x = camx-camvx*dtime - surface[0].x, .y = camy-camvy*dtime - surface[0].y, .z = camz-camvz*dtime - surface[0].z}; pt_2d vtdt = (pt_2d){.x = camx - surface[0].x, .y = camy - surface[0].y, .z = camz - surface[0].z}; normalize(&vtdt); normalize(&vt); if( (dot3D(vt, normal) <= 0.0 && dot3D(vtdt, normal) >= 0.0) || (dot3D(vt, normal) >= 0.0 && dot3D(vtdt, normal) <= 0.0) ) { //printf("%d\n", d); double normv = sqrt(camvx*camvx + camvy*camvy + camvz*camvz); double alpha = acos(dot3D(normal, (pt_2d){.x = camvx, .y = camvy, .z = camvz})/normv); double beta = 3.1415926535 - 2*alpha; double nu = normv*sqrt(1-cos(beta)); pt_2d u = (pt_2d){.x = normal.x*nu, .y = normal.y*nu, .z = normal.z*nu}; normalize(&u); if(ent != NULL && ent->entity_type == 2) { double radspeed = distance_pt_pt_3d(camx, camy, camz, ent->metad4+ent->pos->w/2.0, camy, ent->metad6+ent->pos->d/2.0 )*(ent->metad1); double radspeed2 = distance_pt_pt_3d(camx, camy, camz, camx, ent->metad5+ent->pos->h/2.0, ent->metad6+ent->pos->d/2.0 )*(ent->metad2); pt_2d camD; camD.x = camx - ent->pos->w/2.0 - ent->metad4; camD.y = 0.0; camD.z = camz - ent->pos->d/2.0 - ent->metad6; if(camD.x*camD.x + camD.y*camD.y + camD.z*camD.z >= 0.001) { // avoid division by 0.0 normalize(&camD); } pt_2d utheta = cross_product(camD, normal_axis); pt_2d camD2; camD2.x = 0.0; camD2.y = camy - ent->pos->h/2.0 - ent->metad5; camD2.z = camz - ent->pos->d/2.0 - ent->metad6; if(camD2.x*camD2.x + camD2.y*camD2.y + camD2.z*camD2.z >= 0.001) { // avoid division by 0.0 normalize(&camD2); } pt_2d utheta2 = cross_product(camD2, normal_axis2); //printf("(HZ) %lf %lf %lf\n", utheta.x*radspeed , utheta.y*radspeed , utheta.z*radspeed ); //printf("(VT) %lf %lf %lf\n\n", utheta2.x*radspeed2, utheta2.y*radspeed2, utheta2.z*radspeed2); camvx = u.x*normv*(blockRestitution) + utheta.x*radspeed + utheta2.x*radspeed2; camvy = u.y*normv*(blockRestitution) + utheta.y*radspeed + utheta2.y*radspeed2; camvz = u.z*normv*(blockRestitution) + utheta.z*radspeed + utheta2.z*radspeed2; } else { camvx = u.x*normv*(blockRestitution); camvy = u.y*normv*(blockRestitution); camvz = u.z*normv*(blockRestitution); } is_clipping = false; } } } void updateF_specific(cube_0* cb, double dtime, entity* ent) { double dilat = distance_pt_cube_0_3d_infinite(camx, camy, camz, cb); for(int d = 0; d < 6; d++) { // force a collision cb->x -= dilat; cb->y -= dilat; cb->z -= dilat; getSF(cb, d); cb->x += dilat; cb->y += dilat; cb->z += dilat; getDirectors(); getNormal(); if(d==2 || d==5 || d==1) { normal.x *= -1.0; normal.y *= -1.0; normal.z *= -1.0; } //printf("%lf %lf\n", dot3D(normal, directors[0]), dot3D(normal, directors[1])); pt_2d vt = (pt_2d){.x = camx-camvx*dtime - surface[0].x, .y = camy-camvy*dtime - surface[0].y, .z = camz-camvz*dtime - surface[0].z}; pt_2d vtdt = (pt_2d){.x = camx - surface[0].x, .y = camy - surface[0].y, .z = camz - surface[0].z}; normalize(&vtdt); normalize(&vt); if( (dot3D(vt, normal) <= 0.0 && dot3D(vtdt, normal) >= 0.0) || (dot3D(vt, normal) >= 0.0 && dot3D(vtdt, normal) <= 0.0) ) { double normv = sqrt(camvx*camvx + camvy*camvy + camvz*camvz); double alpha = acos(dot3D(normal, (pt_2d){.x = camvx, .y = camvy, .z = camvz})/normv); double beta = 3.1415926535 - 2*alpha; double nu = normv*sqrt(1-cos(beta)); pt_2d u = (pt_2d){.x = normal.x*nu, .y = normal.y*nu, .z = normal.z*nu}; normalize(&u); camvx = u.x*normv*(blockRestitution); camvy = u.y*normv*(blockRestitution); camvz = u.z*normv*(blockRestitution); is_clipping = false; } } if(ent != NULL && ent->entity_type == 2) { double radspeed = distance_pt_pt_3d(camx, camy, camz, ent->metad4+ent->pos->w/2.0, camy, ent->metad6+ent->pos->d/2.0 )*(ent->metad1); double radspeed2 = distance_pt_pt_3d(camx, camy, camz, camx, ent->metad5+ent->pos->h/2.0, ent->metad6+ent->pos->d/2.0 )*(ent->metad2); pt_2d camD; camD.x = camx - ent->pos->w/2.0 - ent->metad4; camD.y = 0.0; camD.z = camz - ent->pos->d/2.0 - ent->metad6; if(camD.x*camD.x + camD.y*camD.y + camD.z*camD.z >= 0.001) { // avoid division by 0.0 normalize(&camD); } pt_2d utheta = cross_product(camD, normal_axis); pt_2d camD2; camD2.x = 0.0; camD2.y = camy - ent->pos->h/2.0 - ent->metad5; camD2.z = camz - ent->pos->d/2.0 - ent->metad6; if(camD2.x*camD2.x + camD2.y*camD2.y + camD2.z*camD2.z >= 0.001) { // avoid division by 0.0 normalize(&camD2); } pt_2d utheta2 = cross_product(camD2, normal_axis2); //printf("(HZ) %lf %lf %lf\n", utheta.x*radspeed , utheta.y*radspeed , utheta.z*radspeed ); //printf("(VT) %lf %lf %lf\n\n", utheta2.x*radspeed2, utheta2.y*radspeed2, utheta2.z*radspeed2); camvx = utheta.x*radspeed + utheta2.x*radspeed2; camvy = utheta.y*radspeed + utheta2.y*radspeed2; camvz = utheta.z*radspeed + utheta2.z*radspeed2; } //printf("\n"); } bool update_physics = true; bool is_colliding(float dtime) { bool globalCollision = false; if(doUpdateEntVel) { updateF_movableCrate(entToVelCheck->pos, (double)dtime, entToVelCheck); doUpdateEntVel = false; } if(doUpdateMoving) { updateF_specific(movingPlatformUpdate->pos, (double)dtime, movingPlatformUpdate); doUpdateMoving = false; } for(int w = -1; w <= 1; w++) { for(int h = -1; h <= 1; h++) { room* vstd = hashtbl_find_opt(visited, player_chx+w, player_chy+h); if(vstd != NULL) { for(int k = 0; k < vstd->map_size; k++) { double dist = distance_pt_cube_0_3d_infinite(camx-2*room_width*w, camy, camz-2*room_depth*h, vstd->map[k]); //if(vstd->map[k]->vt_angle != 0.0) { // printf("(%lf)\n", dist); //} if(dist <= min_dist) { if(update_physics && updateForces) { updateF(vstd->map[k], (double)dtime, NULL); } globalCollision = true; } } for(int k = 0; k < vstd->tps_size; k++) { double dist = distance_pt_cube_0_3d_infinite(camx-2*room_width*w, camy, camz-2*room_depth*h, vstd->tps[k]->hitbox); if(dist <= min_dist) { if(update_physics && updateForces) { updateF(vstd->tps[k]->hitbox, (double)dtime, NULL); } int old_chx = player_chx; int old_chy = player_chy; player_chx = vstd->tps[k]->dest_chx; player_chy = vstd->tps[k]->dest_chy; vstd = hashtbl_find_opt(visited, player_chx, player_chy); set_player_coords(old_chx, old_chy); resetProj(); globalCollision = true; } } for(int k = 0; k < vstd->ent_len; k++) { //printf("%d -> %d\n", k, vstd->ents[k]->entity_type); if( (vstd->ents[k]->entity_type != 12 || xor(buttonSwitch[vstd->ents[k]->metai1], vstd->ents[k]->metai2)) && // disabled button block (vstd->ents[k]->entity_type != 9 || vstd->ents[k]->metai1) && // off-beat block (vstd->ents[k]->entity_type != 13 || (vstd->ents[k]->metad1 == 0.0 || vstd->ents[k]->metai1 == 0)) // hollow math block ) { double dist = distance_pt_cube_0_3d_infinite(camx-2*room_width*w, camy, camz-2*room_depth*h, vstd->ents[k]->pos); //printf("%lf vs %lf\n", dist, min_dist); if(dist <= min_dist) { bool exists = true; if(vstd->ents[k]->onHit != NULL) { (*vstd->ents[k]->onHit)(dtime, vstd->ents[k]->hitpoints, &vstd->ents[k]->damage, vstd->ents[k], &(*(vstd->ents[k]->pos))); if(*(vstd->ents[k]->hitpoints) <= 0) { if(vstd->ents[k]->onDeath != NULL) { (*vstd->ents[k]->onDeath)(dtime); } if(vstd->ents[k]->entity_type == 0) { play_sound("sound/audio/smw_coin.wav"); } remove_entity(vstd->ents, &vstd->ent_memlen, &vstd->ent_len, k); is_clipping = false; exists = false; k =- 1; } } if(update_physics && exists && updateForces && vstd->ents[k]->entity_type != 0) { updateF(vstd->ents[k]->pos, (double)dtime, vstd->ents[k]); } if(exists && ( vstd->ents[k]->entity_type == 13 || vstd->ents[k]->entity_type == 9 || vstd->ents[k]->entity_type == 4 || vstd->ents[k]->entity_type == 5 )) { is_clipping = false; } globalCollision = true; } } } } } } return globalCollision; } double old_camx = 0.0; double old_camy = 0.0; double old_camz = 0.0; void movePlayerG(float dtime) { old_camx = camx; old_camy = camy; old_camz = camz; updateForces = true; fx = 0.0; fy = 0.0; fz = 0.0; camvy -= gravity_factor*dtime; bool isfalling = camvy < 0.0; double oldvy = camvy; double delx = camvx*dtime; double dely = camvy*dtime; double delz = camvz*dtime; camx += delx; camy += dely; camz += delz; is_clipping = true; update_physics = true; if(is_colliding(dtime)) { if(is_clipping) { //player_hp -= (dtime)*clip_dps; } //printf("HIT\n"); //printf("[%lf, %lf, %lf]\n{%lf, %lf, %lf}\n\n", fx, fy, fz, camvx, camvy, camvz); } camx -= delx; camy -= dely; camz -= delz; //printf("%lf | %lf | %lf\n", fx, fy, fz); updateForces = false; camvx += fx*dtime; camvy += fy*dtime; camvz += fz*dtime; //printf("%lf | %lf | %lf\n\n", camvx, camvy, camvz); if(isfalling && camvy > 0.0) { njumps = 1; //printf("%lf\n", absf(oldvy)); if(is_HR==1 && absf(oldvy) >= 15.0) { player_hp -= (int)(0.75*absf(oldvy)); } } camx += camvx*dtime; camy += camvy*dtime; camz += camvz*dtime; camvx *= (1.0 - friction*((double)(dtime))); camvy *= (1.0 - friction*((double)(dtime))); camvz *= (1.0 - friction*((double)(dtime))); if(camy <= -48) { camx = 0.0; camz = 0.0; camy = 5.0; camvx = 0.0; camvy = 0.0; camvz = 0.0; player_chx = 0; player_chy = 0; if(is_HR==1) { player_hp = 0; } else { player_hp -= 250; } current_room = hashtbl_find_opt(visited, player_chx, player_chy); resetProj(); } update_physics = false; if(is_colliding(dtime)) { camx = old_camx; camy = old_camy; camz = old_camz; } } void teleport_on_edge() { if(camx >= room_width) { if(!is_one_room) { camx -= 2.0*room_width; player_chx += 1; current_room = hashtbl_find_opt(visited, player_chx, player_chy); resetProj(); } } else if(camx <= -room_width) { if(!is_one_room) { camx += 2.0*room_width; player_chx -= 1; current_room = hashtbl_find_opt(visited, player_chx, player_chy); resetProj(); } } else if(camz >= room_depth) { if(!is_one_room) { camz -= 2.0*room_depth; player_chy += 1; current_room = hashtbl_find_opt(visited, player_chx, player_chy); resetProj(); } } else if(camz <= -room_depth) { if(!is_one_room) { camz += 2.0*room_depth; player_chy -= 1; current_room = hashtbl_find_opt(visited, player_chx, player_chy); resetProj(); } } }