/* ----- [ check_pc ] ------------------------------------------------------- */ int check_pc(struct Var_conf *config, struct model *model, enum Color **piece, SDL_Rect pos) { int i = 0,j = 0; // Getting high left corner position int x = pos.x; int y = pos.y; // Check for(i = 0;i < PC_NB_HBLC;i++) { for(j = 0;j < PC_NB_LBLC;j++) { // if the current bloc is not empty and // not on the panel, then the position is not good if(piece[i][j] != CL_MPT && (x + j < 0 || x + j >= PNL_LB || y + i < 0 || y + i >= model_height(model)) ) return 0; // if the current bloc is not empty // the bloc is on the panel // and the bloc of the model is not empty, // then it is no valable position if(piece[i][j] != CL_MPT && x + j >= 0 && x + j < PNL_LB && y + i >= 0 && y + i < model_height(model) && model_get(model,y + i,x + j) != CL_MPT ) return 0; } } return 1; }
/** * Page in debris bitmaps at level load */ void debris_page_in() { uint i; Debris_model = model_load( NOX("debris01.pof"), 0, NULL ); if (Debris_model >= 0) { polymodel * pm; pm = model_get(Debris_model); Debris_num_submodels = pm->n_models; } Debris_vaporize_model = model_load( NOX("debris02.pof"), 0, NULL ); for (i=0; i<Species_info.size(); i++ ) { species_info *species = &Species_info[i]; nprintf(( "Paging", "Paging in debris texture '%s'\n", species->debris_texture.filename)); species->debris_texture.bitmap_id = bm_load(species->debris_texture.filename); if (species->debris_texture.bitmap_id < 0) { Warning( LOCATION, "Couldn't load species %s debris\ntexture, '%s'\n", species->species_name, species->debris_texture.filename); } bm_page_in_texture(species->debris_texture.bitmap_id); } }
/** * Render debris */ void debris_render(object * obj) { int i, num, swapped; polymodel *pm; debris *db; swapped = -1; pm = NULL; num = obj->instance; Assert(num >= 0 && num < MAX_DEBRIS_PIECES); db = &Debris[num]; Assert(db->flags & DEBRIS_USED); texture_info *tbase = NULL; model_clear_instance( db->model_num ); // Swap in a different texture depending on the species if (db->species >= 0) { pm = model_get( db->model_num ); //WMC - Someday, we should have glowing debris. if ( pm != NULL && (pm->n_textures == 1) ) { tbase = &pm->maps[0].textures[TM_BASE_TYPE]; swapped = tbase->GetTexture(); tbase->SetTexture(Species_info[db->species].debris_texture.bitmap_id); } } // Only render electrical arcs if within 500m of the eye (for a 10m piece) if ( vm_vec_dist_quick( &obj->pos, &Eye_position ) < obj->radius*50.0f ) { for (i=0; i<MAX_DEBRIS_ARCS; i++ ) { if ( timestamp_valid( db->arc_timestamp[i] ) ) { model_add_arc( db->model_num, db->submodel_num, &db->arc_pts[i][0], &db->arc_pts[i][1], MARC_TYPE_NORMAL ); } } } if ( db->is_hull ) { MONITOR_INC(NumHullDebrisRend,1); submodel_render( db->model_num, db->submodel_num, &obj->orient, &obj->pos ); } else { MONITOR_INC(NumSmallDebrisRend,1); submodel_render( db->model_num, db->submodel_num, &obj->orient, &obj->pos, MR_NO_LIGHTING ); } if (tbase != NULL && (swapped!=-1) && pm) { tbase->SetTexture(swapped); } }
// Returns which octant point pnt is in. This might return // -1 if the point isn't in any octant. // If model_orient and/or model_pos are NULL, pnt is assumed to already // be rotated into the model's local coordinates. // If oct is not null, it will be filled in with a pointer to the octant // data. Or NULL if the pnt isn't in the octant. int model_which_octant(vec3d* pnt, int model_num, matrix* model_orient, vec3d* model_pos, model_octant** oct) { polymodel* pm; vec3d tempv, rotpnt; pm = model_get(model_num); if (model_orient && model_pos) { // First, rotate pnt into the model's frame of reference. vm_vec_sub(&tempv, pnt, model_pos); vm_vec_rotate(&rotpnt, &tempv, model_orient); } else { rotpnt = *pnt; } vec3d center; vm_vec_avg(¢er, &pm->mins, &pm->maxs); int i, x, y, z; if (rotpnt.xyz.x > center.xyz.x) x = 1; else x = 0; if (rotpnt.xyz.y > center.xyz.y) y = 1; else y = 0; if (rotpnt.xyz.z > center.xyz.z) z = 1; else z = 0; i = (x << 2) | (y << 1) | z; if (point_in_octant(pm, &pm->octants[i], &rotpnt)) { if (oct) *oct = &pm->octants[i]; return i; } if (oct) *oct = NULL; return -1; }
void model_collide_preprocess(matrix *orient, int model_instance_num) { polymodel_instance *pmi; polymodel *pm; pmi = model_get_instance(model_instance_num); pm = model_get(pmi->model_num); matrix current_orient = *orient; vec3d current_pos; vm_vec_zero(¤t_pos); model_collide_preprocess_subobj(¤t_pos, ¤t_orient, pm, pmi, pm->detail[0]); }
// What we're doing here is projecting each object extent onto the directrix, calculating the distance between the // projected point and the origin, and then taking the maximum distance as the semilatus rectum. We're actually // maintaining the square of the distance rather than the actual distance, as it's faster to calculate and it gives // the same result in a greater-than or less-than comparison. When we're done calculating everything for all // objects (i.e. when we return to the parent function) we take the square root of the final value. void dock_calc_max_semilatus_rectum_squared_parallel_to_directrix_helper(object *objp, dock_function_info *infop) { vec3d world_point, local_point[6], nearest; polymodel *pm; int i; float temp, dist_squared; // line parameters vec3d *line_start = infop->parameter_variables.vecp_value; vec3d *line_end = infop->parameter_variables.vecp_value2; // We must find world coordinates for each of the six endpoints on the three axes of the object. I looked up // which axis is front/back, left/right, and up/down, as well as which endpoint is which. It doesn't really // matter, though, as all we need are the distances. // grab our model Assert(objp->type == OBJ_SHIP); pm = model_get(Ship_info[Ships[objp->instance].ship_info_index].model_num); // set up the points we want to check memset(local_point, 0, sizeof(vec3d) * 6); local_point[0].xyz.x = pm->maxs.xyz.x; // right point (max x) local_point[1].xyz.x = pm->mins.xyz.x; // left point (min x) local_point[2].xyz.y = pm->maxs.xyz.y; // top point (max y) local_point[3].xyz.y = pm->mins.xyz.y; // bottom point (min y) local_point[4].xyz.z = pm->maxs.xyz.z; // front point (max z) local_point[5].xyz.z = pm->mins.xyz.z; // rear point (min z) // check points for (i = 0; i < 6; i++) { // calculate position of point vm_vec_rotate(&world_point, &local_point[i], &objp->orient); vm_vec_add2(&world_point, &objp->pos); // find the nearest point along the line vm_vec_dist_squared_to_line(&world_point, line_start, line_end, &nearest, &temp); // find the distance squared between the origin of the line and the point on the line dist_squared = vm_vec_dist_squared(line_start, &nearest); // update with farthest distance squared if (dist_squared > infop->maintained_variables.float_value) infop->maintained_variables.float_value = dist_squared; } }
// Returns which octant point pnt is closet to. This will always return // a valid octant (0-7) since the point doesn't have to be in an octant. // If model_orient and/or model_pos are NULL, pnt is assumed to already // be rotated into the model's local coordinates. // If oct is not null, it will be filled in with a pointer to the octant // data. int model_which_octant_distant_many(vec3d* pnt, int model_num, matrix* model_orient, vec3d* model_pos, polymodel** pm, int* octs) { vec3d tempv, rotpnt; *pm = model_get(model_num); if (model_orient && model_pos) { // First, rotate pnt into the model's frame of reference. vm_vec_sub(&tempv, pnt, model_pos); vm_vec_rotate(&rotpnt, &tempv, model_orient); } else { rotpnt = *pnt; } vec3d center; vm_vec_avg(¢er, &((*pm)->mins), &((*pm)->maxs)); int i, x, y, z; if (rotpnt.xyz.x > center.xyz.x) x = 1; else x = 0; if (rotpnt.xyz.y > center.xyz.y) y = 1; else y = 0; if (rotpnt.xyz.z > center.xyz.z) z = 1; else z = 0; i = ((x << 2) | (y << 1) | z); octs[0] = i; octs[1] = i ^ 4; // Adjacent octant in x dimension octs[2] = i ^ 2; // Adjacent octant in y dimension octs[3] = i ^ 1; // Adjacent octant in z dimension return i; }
void create_shield_explosion(int objnum, int model_num, matrix *orient, vec3d *centerp, vec3d *tcp, int tr0) { matrix tom; // Texture Orientation Matrix shield_info *shieldp; polymodel *pm; int i; if (Objects[objnum].flags & OF_NO_SHIELDS) return; pm = model_get(model_num); Num_tris = pm->shield.ntris; shieldp = &pm->shield; if (Num_tris == 0) return; if ( (Detail.shield_effects == 1) || (Detail.shield_effects == 2) ) { create_shield_low_detail(objnum, model_num, orient, centerp, tcp, tr0, shieldp); return; } for (i=0; i<Num_tris; i++) shieldp->tris[i].used = 0; // Compute orientation matrix from normal of surface hit. // Note, this will cause the shape of the bitmap to change abruptly // as the impact point moves to another triangle. To prevent this, // you could average the normals at the vertices, then interpolate the // normals from the vertices to get a smoothly changing normal across the face. // I had tried using the vector from the impact point to the center, which // changes smoothly, but this looked surprisingly bad. vm_vector_2_matrix(&tom, &shieldp->tris[tr0].norm, NULL, NULL); // Create the shield from the current triangle, as well as its neighbors. create_shield_from_triangle(tr0, orient, shieldp, tcp, centerp, Objects[objnum].radius, &tom.vec.rvec, &tom.vec.uvec); for (i=0; i<3; i++) create_shield_from_triangle(shieldp->tris[tr0].neighbors[i], orient, shieldp, tcp, centerp, Objects[objnum].radius, &tom.vec.rvec, &tom.vec.uvec); copy_shield_to_globals(objnum, shieldp); }
void prevent_spawning_collision(object *new_obj) { int collided; ship_obj *moveup; object *hit_check; ship *s_check; do { collided = 0; for (moveup = GET_FIRST(&Ship_obj_list); moveup != END_OF_LIST(&Ship_obj_list); moveup = GET_NEXT(moveup)) { // don't check the new object itself!! if (moveup->objnum == OBJ_INDEX(new_obj)) continue; hit_check = &Objects[moveup->objnum]; Assert(hit_check->type == OBJ_SHIP); Assert(hit_check->instance >= 0); if ((hit_check->type != OBJ_SHIP) || (hit_check->instance < 0)) continue; s_check = &Ships[hit_check->instance]; // just to make sure we don't get any strange magnitude errors if (vm_vec_same(&hit_check->pos, &new_obj->pos)) new_obj->pos.xyz.x += 1.0f; polymodel *pm = model_get(Ship_info[s_check->ship_info_index].model_num); WITHIN_BBOX(); if (collided) { MOVE_AWAY_BBOX(); break; } } } while (collided); }
/* ----- [ undo_load ] ------------------------------------------------------ */ void undo_load(struct Var_conf *config, struct Undo *undo_historic) { int i = 0, j = 0; struct Undo_i *del = NULL; if(undo_historic->counter > 0) { // Get historic del = undo_historic->first; // Copy model for(i = 0;i < PNL_HB;i++) for(j = 0;j < PNL_LB;j++) model_set(config->model,i,j,model_get(del->model,i,j)); // Copy piece config->pc_next_id = config->pc_cur_id; config->pc_cur_id = del->piece; // Copy level and score config->level = del->level; config->score = del->score; config->lines = del->lines; // Restart position config->piece_pos.x = (PNL_LB / 2) - (PC_NB_LBLC / 2); config->piece_pos.y = 1; // Update references undo_historic->first = del->prev; if(--(undo_historic->counter) > 0) del->prev->next = NULL; // Free historic undo_free_historic(config,del); } }
void multi_respawn_place(object *new_obj, int team) { ship_obj *moveup; ship *s_check; ship *pri = NULL; object *pri_obj = NULL; object *hit_check; int collided, idx, lookup; // first determine if there are any appropriate priority ships to use pri = NULL; pri_obj = NULL; for(idx=0; idx<Multi_respawn_priority_count; idx++){ // all relevant ships if((Multi_respawn_priority_ships[idx].team == team) || !(Netgame.type_flags & NG_TYPE_TEAM)){ lookup = ship_name_lookup(Multi_respawn_priority_ships[idx].ship_name); if( (lookup >= 0) && ((pri == NULL) || (Ships[lookup].respawn_priority > pri->respawn_priority)) && (Ships[lookup].objnum >= 0) && (Ships[lookup].objnum < MAX_OBJECTS)){ pri = &Ships[lookup]; pri_obj = &Objects[Ships[lookup].objnum]; } } } // if we have a relevant respawn ship if((pri != NULL) && (pri_obj != NULL)){ // pick a point just outside his bounding box polymodel *pm = model_get(pri->modelnum); // hmm, ugly. Pick a point 2000 meters to the y direction if(pm == NULL){ vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.rvec, 2000.0f); } else { // pick a random direction int d = (int)frand_range(0.0f, 5.9f); switch(d){ case 0: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.rvec, (pm->maxs.xyz.x - pm->mins.xyz.x)); break; case 1: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.rvec, -(pm->maxs.xyz.x - pm->mins.xyz.x)); break; case 2: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.uvec, (pm->maxs.xyz.y - pm->mins.xyz.y)); break; case 3: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.uvec, -(pm->maxs.xyz.y - pm->mins.xyz.y)); break; case 4: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.fvec, (pm->maxs.xyz.z - pm->mins.xyz.z)); break; case 5: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.fvec, -(pm->maxs.xyz.z - pm->mins.xyz.z)); break; default: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.v.uvec, -(pm->maxs.xyz.y - pm->mins.xyz.y)); break; } } } // otherwise, resort to plain respawn points else { Assert(Multi_respawn_point_count > 0); // get the next appropriate respawn point by team lookup = 0; int count = 0; while(!lookup && (count < 13)){ if((team == TEAM_TRAITOR) || (team == Multi_respawn_points[Multi_next_respawn_point].team)){ lookup = 1; } // next item if(!lookup){ if(Multi_next_respawn_point >= (Multi_respawn_point_count-1)){ Multi_next_respawn_point = 0; } else { Multi_next_respawn_point++; } } count++; } // set respawn info new_obj->pos = Multi_respawn_points[Multi_next_respawn_point].pos; } // now make sure we're not colliding with anyone do { collided = 0; moveup = GET_FIRST(&Ship_obj_list); while(moveup!=END_OF_LIST(&Ship_obj_list)){ // don't check the new_obj itself!! if(Objects[moveup->objnum].net_signature != new_obj->net_signature){ hit_check = &Objects[moveup->objnum]; Assert(hit_check->type == OBJ_SHIP); Assert(hit_check->instance >= 0); if((hit_check->type != OBJ_SHIP) || (hit_check->instance < 0)){ continue; } s_check = &Ships[hit_check->instance]; // just to make sure we don't get any strange magnitude errors if(vm_vec_same(&hit_check->pos, &new_obj->pos)){ new_obj->pos.xyz.x += 1.0f; } WITHIN_BBOX(); if(collided){ MOVE_AWAY_BBOX(); break; } collided = 0; } moveup = GET_NEXT(moveup); } } while(collided); }
BOOL CShipTexturesDlg::OnInitDialog() { int i, j, k, z, duplicate; char *p = NULL; char texture_file[MAX_FILENAME_LEN]; CComboBox *box; // get our model polymodel *pm = model_get(Ship_info[Ships[self_ship].ship_info_index].model_num); // empty old and new fields texture_count = 0; for (i=0; i<MAX_REPLACEMENT_TEXTURES; i++) { *old_texture_name[i] = 0; *new_texture_name[i] = 0; } // set up pointer to combo box box = (CComboBox *) GetDlgItem(IDC_OLD_TEXTURE_LIST); box->ResetContent(); // look for textures to populate the combo box for (i=0; i<pm->n_textures; i++) { for(j = 0; j < TM_NUM_TYPES; j++) { // get texture file name bm_get_filename(pm->maps[i].textures[j].GetOriginalTexture(), texture_file); // skip blank textures if (!strlen(texture_file)) continue; // get rid of file extension p = strchr( texture_file, '.' ); if ( p ) { //mprintf(( "ignoring extension on file '%s'\n", texture_file )); *p = 0; } // check for duplicate textures in list duplicate = -1; for (k=0; k<texture_count; k++) { if (!stricmp(old_texture_name[k], texture_file)) { duplicate = k; break; } } if (duplicate >= 0) continue; // make old texture lowercase strlwr(texture_file); // now add it to the box z = box->AddString(texture_file); // and add it to the field as well strcpy_s(old_texture_name[texture_count], texture_file); // increment texture_count++; // sort sort_textures(); } } // now look for new textures k=0; while (k < Fred_num_texture_replacements) { if (!stricmp(Ships[self_ship].ship_name, Fred_texture_replacements[k].ship_name)) { // look for corresponding old texture for (i=0; i<texture_count; i++) { // if match if (!stricmp(old_texture_name[i], Fred_texture_replacements[k].old_texture)) { // assign new texture strcpy_s(new_texture_name[i], Fred_texture_replacements[k].new_texture); // we found one, so no more to check break; } } } k++; // increment down the list of texture replacements } // end of new texture check // set indexes and flags m_old_texture_list = 0; active_texture_index = 0; modified = 0; // display new texture, if we have one m_new_texture = CString(new_texture_name[0]); CDialog::OnInitDialog(); UpdateData(FALSE); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE }
int ship_weapon_check_collision(object *ship_objp, object *weapon_objp, float time_limit = 0.0f, int *next_hit = NULL) { mc_info mc, mc_shield, mc_hull; ship *shipp; ship_info *sip; weapon *wp; weapon_info *wip; Assert( ship_objp != NULL ); Assert( ship_objp->type == OBJ_SHIP ); Assert( ship_objp->instance >= 0 ); shipp = &Ships[ship_objp->instance]; sip = &Ship_info[shipp->ship_info_index]; Assert( weapon_objp != NULL ); Assert( weapon_objp->type == OBJ_WEAPON ); Assert( weapon_objp->instance >= 0 ); wp = &Weapons[weapon_objp->instance]; wip = &Weapon_info[wp->weapon_info_index]; Assert( shipp->objnum == OBJ_INDEX(ship_objp)); // Make ships that are warping in not get collision detection done if ( shipp->flags & SF_ARRIVING ) return 0; // if one object is a capital, only check player and player weapons with // the capital -- too slow for now otherwise. // if ( Polygon_models[Ships[num].modelnum].use_grid && !( (other_objp == Player_obj) || (&Objects[other_objp->parent] == Player_obj)) ) // return 0; // If either of these objects doesn't get collision checks, abort. if (Ship_info[shipp->ship_info_index].flags & SIF_NO_COLLIDE) return 0; // Return information for AI to detect incoming fire. // Could perhaps be done elsewhere at lower cost --MK, 11/7/97 float dist = vm_vec_dist_quick(&ship_objp->pos, &weapon_objp->pos); if (dist < weapon_objp->phys_info.speed) { update_danger_weapon(ship_objp, weapon_objp); } ship_model_start(ship_objp); int valid_hit_occurred = 0; // If this is set, then hitpos is set int quadrant_num = -1; polymodel *pm = model_get(sip->model_num); // total time is flFrametime + time_limit (time_limit used to predict collisions into the future) vec3d weapon_end_pos; vm_vec_scale_add( &weapon_end_pos, &weapon_objp->pos, &weapon_objp->phys_info.vel, time_limit ); // Goober5000 - I tried to make collision code here much saner... here begin the (major) changes // set up collision structs mc.model_num = sip->model_num; mc.submodel_num = -1; mc.orient = &ship_objp->orient; mc.pos = &ship_objp->pos; mc.p0 = &weapon_objp->last_pos; mc.p1 = &weapon_end_pos; memcpy(&mc_shield, &mc, sizeof(mc_info)); memcpy(&mc_hull, &mc, sizeof(mc_info)); // (btw, these are leftover comments from below...) // // Note: This code is obviously stupid. We want to add the shield point if there is shield to hit, but: // 1. We want the size/color of the hit effect to indicate shield damage done. (i.e., for already-weak shield, smaller effect) // 2. Currently (8/9/97), apply_damage_to_shield() passes lefer damage to hull, which might not make sense. If // wouldn't have collided with hull, shouldn't do damage. Once this is fixed, the code below needs to cast the // vector through to the hull if there is leftover damage. // // WIF2_PIERCE_SHIELDS pierces shields // AL 1-14-97: "Puncture" doesn't mean penetrate shield anymore, it means that it punctures // hull to inflict maximum subsystem damage // // _argv[-1], 16 Jan 2005: Surface shields. // Surface shields allow for shields on a ship without a shield mesh. Good for putting real shields // on the Lucifer. This also fixes the strange bug where shots will occasionally go through the // shield mesh when they shouldn't. I don't know what causes this, but this fixes that -- shields // will absorb it when it hits the hull instead. This has no fancy graphical effect, though. // Someone should make one. // set flags mc_shield.flags = MC_CHECK_SHIELD; mc_hull.flags = MC_CHECK_MODEL; // check both kinds of collisions int shield_collision = (pm->shield.ntris > 0) ? model_collide(&mc_shield) : 0; int hull_collision = model_collide(&mc_hull); // check shields for impact if (!(ship_objp->flags & OF_NO_SHIELDS)) { // pick out the shield quadrant if (shield_collision) quadrant_num = get_quadrant(&mc_shield.hit_point); else if (hull_collision && (sip->flags2 & SIF2_SURFACE_SHIELDS)) quadrant_num = get_quadrant(&mc_hull.hit_point); // make sure that the shield is active in that quadrant if ((quadrant_num >= 0) && ((shipp->flags & SF_DYING) || !ship_is_shield_up(ship_objp, quadrant_num))) quadrant_num = -1; // see if we hit the shield if (quadrant_num >= 0) { // do the hit effect if (shield_collision) add_shield_point(OBJ_INDEX(ship_objp), mc_shield.shield_hit_tri, &mc_shield.hit_point); else /* TODO */; // if this weapon pierces the shield, then do the hit effect, but act like a shield collision never occurred; // otherwise, we have a valid hit on this shield if (wip->wi_flags2 & WIF2_PIERCE_SHIELDS) quadrant_num = -1; else valid_hit_occurred = 1; } } // see which impact we use if (shield_collision && valid_hit_occurred) { memcpy(&mc, &mc_shield, sizeof(mc_info)); Assert(quadrant_num >= 0); } else if (hull_collision) { memcpy(&mc, &mc_hull, sizeof(mc_info)); valid_hit_occurred = 1; } //nprintf(("AI", "Frame %i, Hit tri = %i\n", Framecount, mc.shield_hit_tri)); ship_model_stop(ship_objp); // deal with predictive collisions. Find their actual hit time and see if they occured in current frame if (next_hit && valid_hit_occurred) { // find hit time *next_hit = (int) (1000.0f * (mc.hit_dist*(flFrametime + time_limit) - flFrametime) ); if (*next_hit > 0) // if hit occurs outside of this frame, do not do damage return 1; } if ( valid_hit_occurred ) { Script_system.SetHookObjects(4, "Ship", ship_objp, "Weapon", weapon_objp, "Self",ship_objp, "Object", weapon_objp); bool ship_override = Script_system.IsConditionOverride(CHA_COLLIDEWEAPON, ship_objp); Script_system.SetHookObjects(2, "Self",weapon_objp, "Object", ship_objp); bool weapon_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, weapon_objp); if(!ship_override && !weapon_override) { ship_weapon_do_hit_stuff(ship_objp, weapon_objp, &mc.hit_point_world, &mc.hit_point, quadrant_num, mc.hit_submodel, mc.hit_normal); } Script_system.SetHookObjects(2, "Self",ship_objp, "Object", weapon_objp); if(!(weapon_override && !ship_override)) Script_system.RunCondition(CHA_COLLIDEWEAPON, '\0', NULL, ship_objp); Script_system.SetHookObjects(2, "Self",weapon_objp, "Object", ship_objp); if((weapon_override && !ship_override) || (!weapon_override && !ship_override)) Script_system.RunCondition(CHA_COLLIDESHIP, '\0', NULL, weapon_objp); Script_system.RemHookVars(4, "Ship", "Weapon", "Self","Object"); /* if(!Script_system.IsOverride(wip->sc_collide_ship)) { ship_weapon_do_hit_stuff(ship_objp, weapon_objp, &mc.hit_point_world, &mc.hit_point, quadrant_num, mc.hit_submodel, mc.hit_normal); } if(wip->sc_collide_ship.IsValid()) { ade_odata lua_self_obj = l_Weapon.Set(object_h(weapon_objp)); ade_odata lua_ship_obj = l_Ship.Set(object_h(ship_objp)); Script_system.SetHookVar("Self", 'o', &lua_self_obj); Script_system.SetHookVar("Ship", 'o', &lua_ship_obj); Script_system.RunBytecode(wip->sc_collide_ship); Script_system.RemHookVar("Self"); Script_system.RemHookVar("Ship"); }*/ } else if ((Missiontime - wp->creation_time > F1_0/2) && (wip->wi_flags & WIF_HOMING) && (wp->homing_object == ship_objp)) { if (dist < wip->shockwave.inner_rad) { vec3d vec_to_ship; vm_vec_normalized_dir(&vec_to_ship, &ship_objp->pos, &weapon_objp->pos); if (vm_vec_dot(&vec_to_ship, &weapon_objp->orient.vec.fvec) < 0.0f) { // check if we're colliding against "invisible" ship if (!(shipp->flags2 & SF2_DONT_COLLIDE_INVIS)) { wp->lifeleft = 0.001f; if (ship_objp == Player_obj) nprintf(("Jim", "Frame %i: Weapon %i set to detonate, dist = %7.3f.\n", Framecount, OBJ_INDEX(weapon_objp), dist)); valid_hit_occurred = 1; } } } } return valid_hit_occurred; }
/* ----- [ ai_score_pos ] --------------------------------------------------- */ int ai_score_pos(struct Var_conf *config, struct model *model, enum Piece_bloc piece_id, SDL_Rect position) { int score = 0; int k = 0, l = 0; int sum = 0, lines = 0; SDL_Rect pos; pos.x = position.x; pos.y = position.y; // Check if position is right if(!check_pc(config,model,config->pieces[piece_id],pos)) { score -= 16*PNL_LB; return score; } // Get dropped position while(check_pc(config,model,config->pieces[piece_id],pos) && pos.y != PNL_HB) pos.y++; pos.y--; // Check holes for(k = 0;k < PC_NB_LBLC;k++) { l = PC_NB_HBLC-1; while(l >= 0 && config->pieces[piece_id][l][k] == CL_MPT) l--; if(l <= -1) continue; else { // Holes if((pos.x+k >= 0 && pos.x+k < PNL_LB && pos.y+l+1 >= 0 && pos.y+l+1 < PNL_HB) && (model_get(model,pos.y+l+1,pos.x+k) == CL_MPT)) score -= 72; } } // Check lines lines = 0; for(k = 0;k < PC_NB_HBLC;k++) { sum = 0; for(l = 0;l < PNL_LB;l++) if((pos.y+k >= 0 && pos.y+k < PNL_HB) && (model_get(model,pos.y+k,l) != CL_MPT || (l-pos.x >= 0 && l-pos.x < PC_NB_LBLC && config->pieces[piece_id][k][l-pos.x] != CL_MPT))) sum++; // Lines if(sum >= PNL_LB) lines++; } score += lines*lines*PNL_LB; // Height is very bad score += 4*pos.y; // Try to reduce height variance int i = 0, j = 0; int min_height = -1; int max_height = PNL_HB + 1; int sum_height = 0; int mean_height = 0; int heights[(int)PNL_LB]; // Compute mean for(i = 0;i < PNL_LB;i++) { for(j = 0;j < PNL_HB;j++) { if( model_get(model,i,j) != CL_MPT || (pos.y <= j && j < pos.y + PC_NB_HBLC && pos.x <= i && i < pos.x + PC_NB_LBLC && config->pieces[piece_id][j - pos.y][i - pos.x] != CL_MPT)) { heights[i] = j; sum_height += j; break; } } // If end reached, current height not yet taken into account if(j == PNL_HB) { heights[i] = j; sum_height += PNL_HB; } } mean_height = sum_height / PNL_LB; // Compute variance int var_height = 0; for(i = 0;i < PNL_LB;i++) { var_height += (heights[i] - mean_height) * (heights[i] - mean_height); } score -= 4 * var_height; return score; }
/* ----- [ ai_best_pos ] ---------------------------------------------------- */ void ai_best_pos(struct Var_conf *config,struct model *model_tmp, SDL_Rect *position, int *turning) { enum Piece_bloc piece_id = config->pc_cur_id; enum Piece_bloc piece_next_id = config->pc_next_id; SDL_Rect pos; SDL_Rect next_pos; int score_tmp; int i = 0, j = 0, k = 0, l = 0; int sum = 0; int max_score = 0; // Init table of scores int scores[4*4][((int)PNL_LB+4)*((int)PNL_LB+4)]; for(i = 0;i < 4*4;i++) for(j = 0;j < (PNL_LB+4)*(PNL_LB+4);j++) scores[i][j] = 0; // Init position pos.x = 0; pos.y = config->piece_pos.y; // Checking each configuration // checking each position // checking holes // checking lines // checking each rotation // checking holes // checking lines for(i = 0;i < 4;i++) { for(j = 0;j < PNL_LB+4;j++) { // Update position pos.x = j-4; pos.y = config->piece_pos.y; score_tmp = ai_score_pos(config,model_tmp,piece_id,pos); for(k = 0;k < 4;k++) for(l = 0;l < PNL_LB+4;l++) scores[i*4+k][(int)(j*(PNL_LB+4)+l)] = score_tmp; // Get dropped position if(check_pc(config,model_tmp,config->pieces[piece_id],pos)) { while(check_pc(config,model_tmp,config->pieces[piece_id],pos) && pos.y != PNL_HB) pos.y++; pos.y--; // Take off piece in temporary model takeoff(config,model_tmp,&piece_id,pos,0); // Remove lines remove_lines(config,model_tmp,0); // Get next piece piece_next_id = config->pc_next_id; // For all turns for(k = 0;k < 4;k++) { // For all positions for(l = 0;l < (PNL_LB+4);l++) { // Get new position next_pos.x = l-4; next_pos.y = 1; // Calculate score for new piece position score_tmp = ai_score_pos(config,model_tmp, piece_next_id,next_pos); scores[i*4+k][(int)(j*(PNL_LB+4)+l)] += score_tmp; } // Turn new piece next_pos.x = config->piece_pos.x; turn(config,model_tmp,&piece_next_id,&next_pos,HORLO,0,0); } // Copy model for(k = 0;k < PNL_HB;k++) for(l = 0;l < PNL_LB;l++) model_set(model_tmp,k,l,model_get(config->model,k,l)); } } // Turn turn(config,model_tmp,&piece_id,&(config->piece_pos), HORLO,0,0); } // Get best position pos.x = 0; *turning = 0; max_score = scores[0][0]; for(i = 0;i < 4;i++) { for(j = 0;j < PNL_LB+4;j++) { for(k = 0;k < 4;k++) for(l = 0;l < (PNL_LB+4);l++) //printf("%d ",scores[i][j]); if(scores[i*4+k][(int)(j*(PNL_LB+4)+l)] > max_score) { max_score = scores[i*4+k][(int)(j*(PNL_LB+4)+l)]; pos.x = j-4; *turning = i; } } //printf("\n"); } // Print scores table /*for(i = 0;i < 4;i++) { for(j = 0;j < PNL_LB+4;j++) { for(k = 0;k < 4;k++) { for(l = 0;l < PNL_LB+4;l++) { if( 3 < j & j < 10) printf("%d ",scores[i*4+k][(int)(j*(PNL_LB+4)+l)]); } if( 3 < j & j < 10) printf("\n"); } if( 3 < j & j < 10) printf("\n\n"); } if( 3 < j & j < 10) printf("\n\n"); }*/ position->x = pos.x; //printf("i = %d j = %d \n",pos->x,*turning); }
void camera::get_info(vec3d *position, matrix *orientation) { if(position == NULL && orientation == NULL) return; eye* eyep = NULL; vec3d host_normal; //POSITION if(!(flags & CAM_STATIONARY_POS) || object_host.IsValid()) { c_pos = vmd_zero_vector; vec3d pt; pos_x.get(&pt.xyz.x, NULL); pos_y.get(&pt.xyz.y, NULL); pos_z.get(&pt.xyz.z, NULL); if(object_host.IsValid()) { object *objp = object_host.objp; int model_num = object_get_model(objp); polymodel *pm = NULL; if(model_num > -1) { pm = model_get(model_num); } if(object_host_submodel < 0 || pm == NULL) { vm_vec_unrotate(&c_pos, &pt, &object_host.objp->orient); vm_vec_add2(&c_pos, &object_host.objp->pos); } else { eyep = get_submodel_eye(pm, object_host_submodel); if(eyep) { vec3d c_pos_in; find_submodel_instance_point_normal( &c_pos_in, &host_normal, objp, eyep->parent, &eyep->pnt, &eyep->norm); vm_vec_unrotate(&c_pos, &c_pos_in, &objp->orient); vm_vec_add2(&c_pos, &objp->pos); } else { model_find_world_point( &c_pos, &pt, pm->id, object_host_submodel, &objp->orient, &objp->pos ); } } } else { c_pos = pt; } //Do custom position stuff, if needed if(func_custom_position != NULL && !eyep) { func_custom_position(this, &c_pos); } } if(position != NULL) *position = c_pos; //ORIENTATION if(orientation != NULL) { bool target_set = false; if(!(flags & CAM_STATIONARY_ORI) || object_target.IsValid() || object_host.IsValid()) { if(object_target.IsValid()) { object *objp = object_target.objp; int model_num = object_get_model(objp); polymodel *pm = NULL; vec3d target_pos = vmd_zero_vector; //See if we can get the model if(model_num > -1) { pm = model_get(model_num); } //If we don't have a submodel or don't have the model use object pos //Otherwise, find the submodel pos as it is rotated if(object_target_submodel < 0 || pm == NULL) { target_pos = objp->pos; } else { model_find_world_point( &target_pos, &vmd_zero_vector, pm->id, object_target_submodel, &objp->orient, &objp->pos ); } vec3d targetvec; vm_vec_normalized_dir(&targetvec, &target_pos, &c_pos); vm_vector_2_matrix(&c_ori, &targetvec, NULL, NULL); target_set = true; } else if(object_host.IsValid()) { if(eyep) { vm_vector_2_matrix(&c_ori, &host_normal, vm_vec_same(&host_normal, &object_host.objp->orient.vec.uvec)?NULL:&object_host.objp->orient.vec.uvec, NULL); target_set = true; } else { c_ori = object_host.objp->orient; } } else { c_ori = vmd_identity_matrix; } matrix mtxA = c_ori; matrix mtxB = IDENTITY_MATRIX; float pos = 0.0f; for(int i = 0; i < 9; i++) { ori[i].get(&pos, NULL); mtxB.a1d[i] = pos; } vm_matrix_x_matrix(&c_ori, &mtxA, &mtxB); vm_orthogonalize_matrix(&c_ori); } //Do custom orientation stuff, if needed if(func_custom_orientation != NULL && !target_set) { func_custom_orientation(this, &c_ori); } *orientation = c_ori; } }
int ship_weapon_check_collision(object *ship_objp, object *weapon_objp, float time_limit = 0.0f, int *next_hit = NULL) { mc_info mc, mc_shield, mc_hull; ship *shipp; ship_info *sip; weapon *wp; weapon_info *wip; Assert( ship_objp != NULL ); Assert( ship_objp->type == OBJ_SHIP ); Assert( ship_objp->instance >= 0 ); shipp = &Ships[ship_objp->instance]; sip = &Ship_info[shipp->ship_info_index]; Assert( weapon_objp != NULL ); Assert( weapon_objp->type == OBJ_WEAPON ); Assert( weapon_objp->instance >= 0 ); wp = &Weapons[weapon_objp->instance]; wip = &Weapon_info[wp->weapon_info_index]; Assert( shipp->objnum == OBJ_INDEX(ship_objp)); // Make ships that are warping in not get collision detection done if ( shipp->is_arriving() ) return 0; // Return information for AI to detect incoming fire. // Could perhaps be done elsewhere at lower cost --MK, 11/7/97 float dist = vm_vec_dist_quick(&ship_objp->pos, &weapon_objp->pos); if (dist < weapon_objp->phys_info.speed) { update_danger_weapon(ship_objp, weapon_objp); } int valid_hit_occurred = 0; // If this is set, then hitpos is set int quadrant_num = -1; polymodel *pm = model_get(sip->model_num); // total time is flFrametime + time_limit (time_limit used to predict collisions into the future) vec3d weapon_end_pos; vm_vec_scale_add( &weapon_end_pos, &weapon_objp->pos, &weapon_objp->phys_info.vel, time_limit ); // Goober5000 - I tried to make collision code here much saner... here begin the (major) changes mc_info_init(&mc); // set up collision structs mc.model_instance_num = shipp->model_instance_num; mc.model_num = sip->model_num; mc.submodel_num = -1; mc.orient = &ship_objp->orient; mc.pos = &ship_objp->pos; mc.p0 = &weapon_objp->last_pos; mc.p1 = &weapon_end_pos; mc.lod = sip->collision_lod; memcpy(&mc_shield, &mc, sizeof(mc_info)); memcpy(&mc_hull, &mc, sizeof(mc_info)); // (btw, these are leftover comments from below...) // // Note: This code is obviously stupid. We want to add the shield point if there is shield to hit, but: // 1. We want the size/color of the hit effect to indicate shield damage done. (i.e., for already-weak shield, smaller effect) // 2. Currently (8/9/97), apply_damage_to_shield() passes lefer damage to hull, which might not make sense. If // wouldn't have collided with hull, shouldn't do damage. Once this is fixed, the code below needs to cast the // vector through to the hull if there is leftover damage. // // WIF2_PIERCE_SHIELDS pierces shields // AL 1-14-97: "Puncture" doesn't mean penetrate shield anymore, it means that it punctures // hull to inflict maximum subsystem damage // // _argv[-1], 16 Jan 2005: Surface shields. // Surface shields allow for shields on a ship without a shield mesh. Good for putting real shields // on the Lucifer. This also fixes the strange bug where shots will occasionally go through the // shield mesh when they shouldn't. I don't know what causes this, but this fixes that -- shields // will absorb it when it hits the hull instead. This has no fancy graphical effect, though. // Someone should make one. // check both kinds of collisions int shield_collision = 0; int hull_collision = 0; // check shields for impact if (!(ship_objp->flags[Object::Object_Flags::No_shields])) { if (sip->flags[Ship::Info_Flags::Auto_spread_shields]) { // The weapon is not allowed to impact the shield before it reaches this point vec3d shield_ignored_until = weapon_objp->last_pos; float weapon_flown_for = vm_vec_dist(&wp->start_pos, &weapon_objp->last_pos); float min_weapon_span; if (sip->auto_shield_spread_min_span >= 0.0f) { min_weapon_span = sip->auto_shield_spread_min_span; } else { min_weapon_span = sip->auto_shield_spread; } // If weapon hasn't yet flown a distance greater than the maximum ignore // range, then some part of the currently checked range needs to be // ignored if (weapon_flown_for < min_weapon_span) { vm_vec_sub(&shield_ignored_until, &weapon_end_pos, &wp->start_pos); vm_vec_normalize(&shield_ignored_until); vm_vec_scale(&shield_ignored_until, min_weapon_span); vm_vec_add2(&shield_ignored_until, &wp->start_pos); } float this_range = vm_vec_dist(&weapon_objp->last_pos, &weapon_end_pos); // The range during which the weapon is not allowed to collide with the // shield, except if it actually hits the hull float ignored_range; // If the weapon has not yet surpassed the ignore range, calculate the // remaining ignore range if (vm_vec_dist(&wp->start_pos, &shield_ignored_until) > weapon_flown_for) ignored_range = vm_vec_dist(&weapon_objp->last_pos, &shield_ignored_until); else ignored_range = 0.0f; // The range during which the weapon may impact the shield float active_range = this_range - ignored_range; // During the ignored range, we only check for a ray collision with // the model if (ignored_range > 0.0f) { mc_shield.flags = MC_CHECK_MODEL; mc_shield.p1 = &shield_ignored_until; shield_collision = model_collide(&mc_shield); mc_shield.p1 = &weapon_end_pos; mc_shield.hit_dist = mc_shield.hit_dist * (ignored_range / this_range); } // If no collision with the model found in the ignore range, only // then do we check for sphereline collisions with the model during the // non-ignored range if (!shield_collision && weapon_flown_for + this_range > min_weapon_span) { mc_shield.p0 = &shield_ignored_until; mc_shield.p1 = &weapon_end_pos; mc_shield.radius = sip->auto_shield_spread; if (sip->auto_shield_spread_from_lod > -1) { mc_shield.lod = sip->auto_shield_spread_from_lod; } mc_shield.flags = MC_CHECK_MODEL | MC_CHECK_SPHERELINE; shield_collision = model_collide(&mc_shield); mc_shield.lod = sip->collision_lod; mc_shield.submodel_num = -1; // Because we manipulated p0 and p1 above, hit_dist will be // relative to the values we used, not the values the rest of // the code expects; this fixes that mc_shield.p0 = &weapon_objp->last_pos; mc_shield.p1 = &weapon_end_pos; mc_shield.hit_dist = (ignored_range + (active_range * mc_shield.hit_dist)) / this_range; } if (shield_collision) { // If we used a sphereline check, then the collision point will lie // somewhere on the ship's hull; this re-positions it to lie on the // correct point along the weapon's path if (mc_shield.flags & MC_CHECK_SPHERELINE) { vec3d tempv; vm_vec_sub(&tempv, mc_shield.p1, mc_shield.p0); vm_vec_scale(&tempv, mc_shield.hit_dist); vm_vec_add2(&tempv, mc_shield.p0); mc_shield.hit_point_world = tempv; } // Re-calculate hit_point because it's likely pointing to the wrong // place vec3d tempv; vm_vec_sub(&tempv, &mc_shield.hit_point_world, &ship_objp->pos); vm_vec_rotate(&mc_shield.hit_point, &tempv, &ship_objp->orient); } } else if (sip->flags[Ship::Info_Flags::Surface_shields]) { if (pm->shield.ntris > 0) { // If there is a shield mesh, we need to check that first mc_shield.flags = MC_CHECK_SHIELD; shield_collision = model_collide(&mc_shield); } if (!shield_collision) { // But if no shield mesh or it was missed, check for a hull collision mc_shield.flags = MC_CHECK_MODEL; shield_collision = model_collide(&mc_shield); // Because we used MC_CHECK_MODEL, the returned hit position might be // in a submodel's frame of reference, so we need to ensure we end up // in the ship's frame of reference vec3d local_pos; vm_vec_sub(&local_pos, &mc_shield.hit_point_world, &ship_objp->pos); vm_vec_rotate(&mc_shield.hit_point, &local_pos, &ship_objp->orient); } } else { // Normal collision check against a shield mesh mc_shield.flags = MC_CHECK_SHIELD; shield_collision = (pm->shield.ntris > 0) ? model_collide(&mc_shield) : 0; } } // If we found a shield collision but were only checking for a simple model // collision, we can re-use the same collision info for the hull as well if (shield_collision && mc_shield.flags == MC_CHECK_MODEL) { memcpy(&mc_hull, &mc_shield, sizeof(mc_info)); hull_collision = shield_collision; // The weapon has impacted on the hull, so if it should therefore bypass // the shields altogether, we do it here if (sip->auto_shield_spread_bypass) { shield_collision = 0; } } else { mc_hull.flags = MC_CHECK_MODEL; hull_collision = model_collide(&mc_hull); } if (shield_collision) { // pick out the shield quadrant quadrant_num = get_quadrant(&mc_shield.hit_point, ship_objp); // make sure that the shield is active in that quadrant if (shipp->flags[Ship::Ship_Flags::Dying] || !ship_is_shield_up(ship_objp, quadrant_num)) quadrant_num = -1; // see if we hit the shield if (quadrant_num >= 0) { // do the hit effect if ( mc_shield.shield_hit_tri != -1 && (mc_shield.hit_dist*(flFrametime + time_limit) - flFrametime) < 0.0f ) { add_shield_point(OBJ_INDEX(ship_objp), mc_shield.shield_hit_tri, &mc_shield.hit_point); } // if this weapon pierces the shield, then do the hit effect, but act like a shield collision never occurred; // otherwise, we have a valid hit on this shield if (wip->wi_flags[Weapon::Info_Flags::Pierce_shields]) quadrant_num = -1; else valid_hit_occurred = 1; } } // see which impact we use if (shield_collision && valid_hit_occurred) { memcpy(&mc, &mc_shield, sizeof(mc_info)); Assert(quadrant_num >= 0); } else if (hull_collision) { memcpy(&mc, &mc_hull, sizeof(mc_info)); valid_hit_occurred = 1; } // check if the hit point is beyond the clip plane when warping out. if ((shipp->flags[Ship::Ship_Flags::Depart_warp]) && (shipp->warpout_effect) && (valid_hit_occurred)) { vec3d warp_pnt, hit_direction; matrix warp_orient; shipp->warpout_effect->getWarpPosition(&warp_pnt); shipp->warpout_effect->getWarpOrientation(&warp_orient); vm_vec_sub(&hit_direction, &mc.hit_point_world, &warp_pnt); if (vm_vec_dot(&hit_direction, &warp_orient.vec.fvec) < 0.0f) { valid_hit_occurred = 0; } } // deal with predictive collisions. Find their actual hit time and see if they occured in current frame if (next_hit && valid_hit_occurred) { // find hit time *next_hit = (int) (1000.0f * (mc.hit_dist*(flFrametime + time_limit) - flFrametime) ); if (*next_hit > 0) // if hit occurs outside of this frame, do not do damage return 1; } if ( valid_hit_occurred ) { wp->collisionInfo = new mc_info; // The weapon will free this memory later memcpy(wp->collisionInfo, &mc, sizeof(mc_info)); Script_system.SetHookObjects(4, "Ship", ship_objp, "Weapon", weapon_objp, "Self",ship_objp, "Object", weapon_objp); bool ship_override = Script_system.IsConditionOverride(CHA_COLLIDEWEAPON, ship_objp); Script_system.SetHookObjects(2, "Self",weapon_objp, "Object", ship_objp); bool weapon_override = Script_system.IsConditionOverride(CHA_COLLIDESHIP, weapon_objp); if(!ship_override && !weapon_override) { if (shield_collision && quadrant_num >= 0) { if ((sip->shield_impact_explosion_anim > -1) && (wip->shield_impact_explosion_radius > 0)) { shield_impact_explosion(&mc.hit_point, ship_objp, wip->shield_impact_explosion_radius, sip->shield_impact_explosion_anim); } } ship_weapon_do_hit_stuff(ship_objp, weapon_objp, &mc.hit_point_world, &mc.hit_point, quadrant_num, mc.hit_submodel, mc.hit_normal); } Script_system.SetHookObjects(2, "Self",ship_objp, "Object", weapon_objp); if(!(weapon_override && !ship_override)) Script_system.RunCondition(CHA_COLLIDEWEAPON, '\0', NULL, ship_objp, wp->weapon_info_index); Script_system.SetHookObjects(2, "Self",weapon_objp, "Object", ship_objp); if((weapon_override && !ship_override) || (!weapon_override && !ship_override)) Script_system.RunCondition(CHA_COLLIDESHIP, '\0', NULL, weapon_objp); Script_system.RemHookVars(4, "Ship", "Weapon", "Self","Object"); } else if ((Missiontime - wp->creation_time > F1_0/2) && (wip->is_homing()) && (wp->homing_object == ship_objp)) { if (dist < wip->shockwave.inner_rad) { vec3d vec_to_ship; vm_vec_normalized_dir(&vec_to_ship, &ship_objp->pos, &weapon_objp->pos); if (vm_vec_dot(&vec_to_ship, &weapon_objp->orient.vec.fvec) < 0.0f) { // check if we're colliding against "invisible" ship if (!(shipp->flags[Ship::Ship_Flags::Dont_collide_invis])) { wp->lifeleft = 0.001f; if (ship_objp == Player_obj) nprintf(("Jim", "Frame %i: Weapon %d set to detonate, dist = %7.3f.\n", Framecount, OBJ_INDEX(weapon_objp), dist)); valid_hit_occurred = 1; } } } } return valid_hit_occurred; }
// See model.h for usage. I don't want to put the // usage here because you need to see the #defines and structures // this uses while reading the help. int model_collide(mc_info *mc_info_obj) { Mc = mc_info_obj; MONITOR_INC(NumFVI,1); Mc->num_hits = 0; // How many collisions were found Mc->shield_hit_tri = -1; // Assume we won't hit any shield polygons Mc->hit_bitmap = -1; Mc->edge_hit = 0; if ( (Mc->flags & MC_CHECK_SHIELD) && (Mc->flags & MC_CHECK_MODEL) ) { Error( LOCATION, "Checking both shield and model!\n" ); return 0; } //Fill in some global variables that all the model collide routines need internally. Mc_pm = model_get(Mc->model_num); Mc_orient = *Mc->orient; Mc_base = *Mc->pos; Mc_mag = vm_vec_dist( Mc->p0, Mc->p1 ); Mc_edge_time = FLT_MAX; if ( Mc->model_instance_num >= 0 ) { Mc_pmi = model_get_instance(Mc->model_instance_num); } else { Mc_pmi = NULL; } // DA 11/19/98 - disable this check for rotating submodels // Don't do check if for very small movement // if (Mc_mag < 0.01f) { // return 0; // } float model_radius; // How big is the model we're checking against int first_submodel; // Which submodel gets returned as hit if MC_ONLY_SPHERE specified if ( (Mc->flags & MC_SUBMODEL) || (Mc->flags & MC_SUBMODEL_INSTANCE) ) { first_submodel = Mc->submodel_num; model_radius = Mc_pm->submodel[first_submodel].rad; } else { first_submodel = Mc_pm->detail[0]; model_radius = Mc_pm->rad; } if ( Mc->flags & MC_CHECK_SPHERELINE ) { if ( Mc->radius <= 0.0f ) { Warning(LOCATION, "Attempting to collide with a sphere, but the sphere's radius is <= 0.0f!\n\n(model file is %s; submodel is %d, mc_flags are %d)", Mc_pm->filename, first_submodel, Mc->flags); return 0; } // Do a quick check on the Bounding Sphere if (fvi_segment_sphere(&Mc->hit_point_world, Mc->p0, Mc->p1, Mc->pos, model_radius+Mc->radius) ) { if ( Mc->flags & MC_ONLY_SPHERE ) { Mc->hit_point = Mc->hit_point_world; Mc->hit_submodel = first_submodel; Mc->num_hits++; return (Mc->num_hits > 0); } // continue checking polygons. } else { return 0; } } else { int r; // Do a quick check on the Bounding Sphere if ( Mc->flags & MC_CHECK_RAY ) { r = fvi_ray_sphere(&Mc->hit_point_world, Mc->p0, Mc->p1, Mc->pos, model_radius); } else { r = fvi_segment_sphere(&Mc->hit_point_world, Mc->p0, Mc->p1, Mc->pos, model_radius); } if (r) { if ( Mc->flags & MC_ONLY_SPHERE ) { Mc->hit_point = Mc->hit_point_world; Mc->hit_submodel = first_submodel; Mc->num_hits++; return (Mc->num_hits > 0); } // continue checking polygons. } else { return 0; } } if ( Mc->flags & MC_SUBMODEL ) { // Check only one subobject mc_check_subobj( Mc->submodel_num ); // Check submodel and any children } else if (Mc->flags & MC_SUBMODEL_INSTANCE) { mc_check_subobj(Mc->submodel_num); } else { // Check all the the highest detail model polygons and subobjects for intersections // Don't check it or its children if it is destroyed if (!Mc_pm->submodel[Mc_pm->detail[0]].blown_off) { mc_check_subobj( Mc_pm->detail[0] ); } } //If we found a hit, then rotate it into world coordinates if ( Mc->num_hits ) { if ( Mc->flags & MC_SUBMODEL ) { // If we're just checking one submodel, don't use normal instancing to find world points vm_vec_unrotate(&Mc->hit_point_world, &Mc->hit_point, Mc->orient); vm_vec_add2(&Mc->hit_point_world, Mc->pos); } else { if ( Mc_pmi ) { model_instance_find_world_point(&Mc->hit_point_world, &Mc->hit_point, Mc->model_instance_num, Mc->hit_submodel, Mc->orient, Mc->pos); } else { model_find_world_point(&Mc->hit_point_world, &Mc->hit_point, Mc->model_num, Mc->hit_submodel, Mc->orient, Mc->pos); } } } return Mc->num_hits; }
void ship_draw_shield( object *objp) { int model_num; int i; vec3d pnt; polymodel * pm; if (objp->flags & OF_NO_SHIELDS) return; Assert(objp->instance >= 0); model_num = Ship_info[Ships[objp->instance].ship_info_index].model_num; if ( Fred_running ) return; pm = model_get(model_num); if (pm->shield.ntris<1) return; // Scan all the triangles in the mesh. for (i=0; i<pm->shield.ntris; i++ ) { int j; vec3d gnorm, v2f, tri_point; vertex prev_pnt, pnt0; shield_tri *tri; tri = &pm->shield.tris[i]; if (i == Break_value) Int3(); // Hack! Only works for object in identity orientation. // Need to rotate eye position into object's reference frame. // Only draw facing triangles. vm_vec_rotate(&tri_point, &pm->shield.verts[tri->verts[0]].pos, &Eye_matrix); vm_vec_add2(&tri_point, &objp->pos); vm_vec_sub(&v2f, &tri_point, &Eye_position); vm_vec_unrotate(&gnorm, &tri->norm, &objp->orient); if (vm_vec_dot(&gnorm, &v2f) < 0.0f) { int intensity; intensity = (int) (Ships[objp->instance].shield_integrity[i] * 255); if (intensity < 0) intensity = 0; else if (intensity > 255) intensity = 255; gr_set_color(0, 0, intensity); // Process the vertices. // Note this rotates each vertex each time it's needed, very dumb. for (j=0; j<3; j++ ) { vertex tmp; // Rotate point into world coordinates vm_vec_unrotate(&pnt, &pm->shield.verts[tri->verts[j]].pos, &objp->orient); vm_vec_add2(&pnt, &objp->pos); // Pnt is now the x,y,z world coordinates of this vert. // For this example, I am just drawing a sphere at that // point. g3_rotate_vertex(&tmp, &pnt); if (j) g3_draw_line(&prev_pnt, &tmp); else pnt0 = tmp; prev_pnt = tmp; } g3_draw_line(&pnt0, &prev_pnt); } } }
/* ----- [ remove_lines ] --------------------------------------------------- */ int remove_lines(struct Var_conf *config,struct model *model, int blink) { int height = model_height(model); int *lines = malloc(sizeof(int) * height); int i = 0, j = 0, k = 0, sum = 0; for(i = 0;i < height;i++) lines[i] = 0; // Check full lines for(i = 0;i < height;i++) { sum = 0; for(j = 0;j < PNL_LB;j++) if(model_get(model,i,j) != CL_MPT) sum++; if(sum == PNL_LB) lines[i] = 1; } // Count lines to remove sum = 0; for(i = 0;i < height;i++) if(lines[i]) sum++; if(blink) { // Blink lines for(k = 0;k < LN_NBCLIC * 2;k++) { for(i = 0;i < height;i++) { for(j = 0;j < PNL_LB;j++) { if(lines[i]) model_set(model,i,j,((model_get(model,i,j) != CL_MPT) ? CL_MPT : CL_GREY1)); } SDL_Delay(LN_DELAY); } disp_gamepanel(config); } } // Delete lines for(i = 0;i < height;i++) { if(lines[i]) { for(j = 0;j < PNL_LB;j++) { for(k = i;k > 0;k--) { model_set(model,k,j,model_get(model,k - 1,j)); } model_set(model,0,j,CL_MPT); } } } free(lines); if(ENABLE_DYNPNL) { int r = 0; for(r = 0;r < sum && model_height(config->model) > PNL_HB;r++) model_remove_first(config->model,CL_MPT); } return sum; }
void multi_respawn_place(object *new_obj, int team) { ship *pri = NULL; object *pri_obj = NULL; int idx, lookup; // first determine if there are any appropriate priority ships to use pri = NULL; pri_obj = NULL; for(idx=0; idx<Multi_respawn_priority_count; idx++){ // all relevant ships if((Multi_respawn_priority_ships[idx].team == team) || !(Netgame.type_flags & NG_TYPE_TEAM)){ lookup = ship_name_lookup(Multi_respawn_priority_ships[idx].ship_name); if( (lookup >= 0) && ((pri == NULL) || (Ships[lookup].respawn_priority > pri->respawn_priority)) && (Ships[lookup].objnum >= 0) && (Ships[lookup].objnum < MAX_OBJECTS)){ pri = &Ships[lookup]; pri_obj = &Objects[Ships[lookup].objnum]; } } } // if we have a relevant respawn ship if((pri != NULL) && (pri_obj != NULL)){ // pick a point just outside his bounding box polymodel *pm = model_get(Ship_info[pri->ship_info_index].model_num); // hmm, ugly. Pick a point 2000 meters to the y direction if(pm == NULL){ vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.rvec, 2000.0f); } else { // pick a random direction int d = (int)frand_range(0.0f, 5.9f); switch(d){ case 0: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.rvec, (pm->maxs.xyz.x - pm->mins.xyz.x)); break; case 1: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.rvec, -(pm->maxs.xyz.x - pm->mins.xyz.x)); break; case 2: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.uvec, (pm->maxs.xyz.y - pm->mins.xyz.y)); break; case 3: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.uvec, -(pm->maxs.xyz.y - pm->mins.xyz.y)); break; case 4: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.fvec, (pm->maxs.xyz.z - pm->mins.xyz.z)); break; case 5: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.fvec, -(pm->maxs.xyz.z - pm->mins.xyz.z)); break; default: vm_vec_scale_add(&new_obj->pos, &pri_obj->pos, &pri_obj->orient.vec.uvec, -(pm->maxs.xyz.y - pm->mins.xyz.y)); break; } } } // otherwise, resort to plain respawn points else { Assert(Multi_respawn_point_count > 0); // get the next appropriate respawn point by team lookup = 0; int count = 0; while(!lookup && (count < 13)){ if((team == Iff_traitor) || (team == Multi_respawn_points[Multi_next_respawn_point].team)){ lookup = 1; } // next item if(!lookup){ if(Multi_next_respawn_point >= (Multi_respawn_point_count-1)){ Multi_next_respawn_point = 0; } else { Multi_next_respawn_point++; } } count++; } // set respawn info new_obj->pos = Multi_respawn_points[Multi_next_respawn_point].pos; } // now make sure we're not colliding with anyone prevent_spawning_collision(new_obj); }
void HudGaugeReticle::getFirepointStatus() { //First, get the player ship ship_info* sip; ship* shipp; polymodel* pm; Assert(Objects[Player->objnum].type == OBJ_SHIP); if (Objects[Player->objnum].type == OBJ_SHIP) { shipp = &Ships[Objects[Player->objnum].instance]; sip = &Ship_info[shipp->ship_info_index]; //Get the player eyepoint pm = model_get(sip->model_num); if (pm->n_view_positions == 0) { mprintf(("Model %s does not have a defined eyepoint. Firepoint display could not be generated\n", pm->filename)); } else { if (pm->n_guns > 0) { eye eyepoint = pm->view_positions[shipp->current_viewpoint]; vec2d ep = { eyepoint.pnt.xyz.x, eyepoint.pnt.xyz.y }; for (int i = 0; i < pm->n_guns; i++) { int bankactive = 0; ship_weapon *swp = &shipp->weapons; if (!timestamp_elapsed(shipp->weapons.next_primary_fire_stamp[i])) bankactive = 1; else if (timestamp_elapsed(shipp->weapons.primary_animation_done_time[i])) bankactive = 1; else if (i == shipp->weapons.current_primary_bank || shipp->flags[Ship::Ship_Flags::Primary_linked]) bankactive = 2; int num_slots = pm->gun_banks[i].num_slots; for (int j = 0; j < num_slots; j++) { int fpactive = bankactive; if (sip->flags[Ship::Info_Flags::Dyn_primary_linking]) { // If this firepoint is not among the next shot(s) to be fired, dim it one step if ( !( (j >= (shipp->last_fired_point[i]+1) % num_slots) && (j <= (shipp->last_fired_point[i]+swp->primary_bank_slot_count[i]) % num_slots) ) ) { fpactive--; } } else if (Weapon_info[swp->primary_bank_weapons[i]].wi_flags[Weapon::Info_Flags::Cycle]) { // If this firepoint is not the next one to be fired, dim it one step if (j != (shipp->last_fired_point[i]+1) % num_slots) { fpactive--; } } vec3d fpfromeye; matrix eye_orient, player_transpose; vm_copy_transpose(&player_transpose, &Objects[Player->objnum].orient); vm_matrix_x_matrix(&eye_orient, &player_transpose, &Eye_matrix); vm_vec_rotate(&fpfromeye, &pm->gun_banks[i].pnt[j], &eye_orient); firepoint tmp = { { fpfromeye.xyz.x - ep.x, ep.y - fpfromeye.xyz.y }, fpactive }; fp.push_back(tmp); } } } } } }
void techroom_ships_render(float frametime) { // render all the common stuff tech_common_render(); if(Cur_entry_index == -1) return; // now render the trackball ship, which is unique to the ships tab float rev_rate = REVOLUTION_RATE; angles rot_angles, view_angles; int z, i, j; ship_info *sip = &Ship_info[Cur_entry_index]; model_render_params render_info; if (sip->uses_team_colors) { render_info.set_team_color(sip->default_team_name, "none", 0, 0); } // get correct revolution rate z = sip->flags; if (z & SIF_BIG_SHIP) { rev_rate *= 1.7f; } if (z & SIF_HUGE_SHIP) { rev_rate *= 3.0f; } // rotate the ship as much as required for this frame Techroom_ship_rot += PI2 * frametime / rev_rate; while (Techroom_ship_rot > PI2){ Techroom_ship_rot -= PI2; } // reorient ship if (Trackball_active) { int dx, dy; matrix mat1, mat2; if (Trackball_active) { mouse_get_delta(&dx, &dy); if (dx || dy) { vm_trackball(-dx, -dy, &mat1); vm_matrix_x_matrix(&mat2, &mat1, &Techroom_ship_orient); Techroom_ship_orient = mat2; } } } else { // setup stuff needed to render the ship view_angles.p = -0.6f; view_angles.b = 0.0f; view_angles.h = 0.0f; vm_angles_2_matrix(&Techroom_ship_orient, &view_angles); rot_angles.p = 0.0f; rot_angles.b = 0.0f; rot_angles.h = Techroom_ship_rot; vm_rotate_matrix_by_angles(&Techroom_ship_orient, &rot_angles); } gr_set_clip(Tech_ship_display_coords[gr_screen.res][SHIP_X_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_Y_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_W_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_H_COORD], GR_RESIZE_MENU); // render the ship g3_start_frame(1); g3_set_view_matrix(&sip->closeup_pos, &vmd_identity_matrix, sip->closeup_zoom * 1.3f); // lighting for techroom light_reset(); vec3d light_dir = vmd_zero_vector; light_dir.xyz.y = 1.0f; light_dir.xyz.x = 0.0000001f; light_add_directional(&light_dir, 0.85f, 1.0f, 1.0f, 1.0f); light_rotate_all(); // lighting for techroom Glowpoint_use_depth_buffer = false; model_clear_instance(Techroom_ship_modelnum); render_info.set_detail_level_lock(0); polymodel *pm = model_get(Techroom_ship_modelnum); for (i = 0; i < sip->n_subsystems; i++) { model_subsystem *msp = &sip->subsystems[i]; if (msp->type == SUBSYSTEM_TURRET) { float p = 0.0f; float h = 0.0f; for (j = 0; j < msp->n_triggers; j++) { // special case for turrets p = msp->triggers[j].angle.xyz.x; h = msp->triggers[j].angle.xyz.y; } if ( msp->subobj_num >= 0 ) { model_set_instance_techroom(Techroom_ship_modelnum, msp->subobj_num, 0.0f, h ); } if ( (msp->subobj_num != msp->turret_gun_sobj) && (msp->turret_gun_sobj >= 0) ) { model_set_instance_techroom(Techroom_ship_modelnum, msp->turret_gun_sobj, p, 0.0f ); } } } if(Cmdline_shadow_quality) { gr_reset_clip(); shadows_start_render(&Eye_matrix, &Eye_position, Proj_fov, gr_screen.clip_aspect, -sip->closeup_pos.xyz.z + pm->rad, -sip->closeup_pos.xyz.z + pm->rad + 200.0f, -sip->closeup_pos.xyz.z + pm->rad + 2000.0f, -sip->closeup_pos.xyz.z + pm->rad + 10000.0f); render_info.set_flags(MR_NO_TEXTURING | MR_NO_LIGHTING | MR_AUTOCENTER); model_render_immediate(&render_info, Techroom_ship_modelnum, &Techroom_ship_orient, &vmd_zero_vector); shadows_end_render(); gr_set_clip(Tech_ship_display_coords[gr_screen.res][SHIP_X_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_Y_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_W_COORD], Tech_ship_display_coords[gr_screen.res][SHIP_H_COORD], GR_RESIZE_MENU); } if (!Cmdline_nohtl) { gr_set_proj_matrix(Proj_fov, gr_screen.clip_aspect, Min_draw_distance, Max_draw_distance); gr_set_view_matrix(&Eye_position, &Eye_matrix); } uint render_flags = MR_AUTOCENTER; if(sip->flags2 & SIF2_NO_LIGHTING) render_flags |= MR_NO_LIGHTING; render_info.set_flags(render_flags); model_render_immediate(&render_info, Techroom_ship_modelnum, &Techroom_ship_orient, &vmd_zero_vector); Glowpoint_use_depth_buffer = true; batch_render_all(); if (!Cmdline_nohtl) { gr_end_view_matrix(); gr_end_proj_matrix(); } g3_end_frame(); gr_reset_clip(); }
/* ----- [ add ] ------------------------------------------------------------ */ void add(struct Var_conf *config) { int timer = 1; // Fix bug of timer int random = 0; SDL_Rect pos; // Pieces id's enum Piece_bloc pieces[PC_NB] = { SQR1,SQR1,SQR1,SQR1, BAR1,BAR1,BAR2,BAR2, L1,L2,L3,L4, LINV1,LINV2,LINV3,LINV4, S1,S1,S2,S2, SINV1,SINV1,SINV2,SINV2, DP1,DP2,DP3,DP4 }; // Disable timer config->state = J_PAUSE; if(!config->dropping && !config->down_pressed && !SDL_RemoveTimer(config->timer)) { fprintf(stderr, "[ERROR] Cannot remove timer in %s at line %d.\n", __FILE__,__LINE__); timer = 0; } // Get a random piece random = rand() % PC_NB + 1; // Copy next piece in current piece config->pc_cur_id = config->pc_next_id; // Copy random piece in next piece config->pc_next_id = pieces[random - 1]; // Check position pos.x = (PNL_LB / 2) - (PC_NB_LBLC / 2); pos.y = 1; // Dynamic height panel management if(ENABLE_DYNPNL) { // Empty lines check int r = 0; int s = 0; int empty = 1; // Check if half the panel is empty for(r = 0;r < 2 * PC_NB_HBLC && empty;r++) { for(s = 0;s < model_width(config->model) && empty;s++) { if(model_get(config->model,r,s) != CL_MPT) empty = 0; } } // If a quarter of the panel is not empty, add a quarter of empty lines if(!empty) for(r = 0;r < 2 * PC_NB_HBLC;r++) model_add_first(config->model,CL_MPT); } // Position is good if(check_pc(config,config->model,config->pieces[config->pc_cur_id],pos)) { config->piece_pos.x = pos.x; config->piece_pos.y = pos.y; // Piece ghost pos.x = config->piece_pos.x; pos.y = config->piece_pos.y; while(check_pc(config, config->model, config->pieces[config->pc_cur_id], pos) && pos.y != model_height(config->model)) pos.y++; pos.y--; config->ghost_pos.x = config->piece_pos.x; config->ghost_pos.y = pos.y; // Display next piece disp_next_pc(config); // Trigger AI if launched if(config->ai_started) config->ai_trigger = 1; // Enable timer config->state = J_PLAY; if(timer) if(!config->dropping && !config->down_pressed && (config->timer = SDL_AddTimer(config->interv, step,config)) == NULL) fprintf(stderr, "[ERROR] Cannot initialize timer in %s at line %d.\n", __FILE__,__LINE__); return; } // Game Over else { config->pc_cur_id = PCMPTY; lost(config); return; } }