void map_prepare_mesh_poly_shadow(map_type *map,map_mesh_type *mesh,map_mesh_poly_type *poly) { int d; poly->draw.shadow_ok=TRUE; if (!poly->box.wall_like) { if (map->optimize.shadow_poly_min_area==0) return; poly->draw.shadow_ok=((poly->box.max.x-poly->box.min.x)>=map->optimize.shadow_poly_min_area) || ((poly->box.max.z-poly->box.min.z)>=map->optimize.shadow_poly_min_area); } else { // floor only drawing? if (map->optimize.shadow_floor_only) { poly->draw.shadow_ok=FALSE; return; } if (map->optimize.shadow_poly_min_area==0) return; d=distance_2D_get(poly->box.min.x,poly->box.min.z,poly->box.max.x,poly->box.max.z); poly->draw.shadow_ok=(d>=map->optimize.shadow_poly_min_area) || ((poly->box.max.y-poly->box.min.y)>=map->optimize.shadow_poly_min_area); } }
void node_path_rebuild(void) { int i,x,z,k,n; unsigned char node_hit[max_node]; node_type *node,*to_node; // precalc the distance between each // directly linked node node=map.nodes; for (n=0;n!=map.nnode;n++) { x=node->pnt.x; z=node->pnt.z; // get distance to each directly linked node for (i=0;i!=max_node_link;i++) { k=node->link[i]; if ((k==-1) || (k==n)) { node_scan[n].link_dist[i]=0; } else { to_node=&map.nodes[k]; node_scan[n].link_dist[i]=distance_2D_get(x,z,to_node->pnt.x,to_node->pnt.z); } } // clear out path hints for (k=0;k!=map.nnode;k++) { node->path_hint[k]=-1; } node++; } // find the best path between all nodes for (n=0;n!=map.nnode;n++) { node_path_trace_all(n,0,0,0,node_hit,0); } }
void camera_get_angle_from(d3pnt *pt,d3ang *ang) { int dist; d3pnt pnt; d3ang temp_ang; // get camera position camera_get_position(&pnt,&temp_ang); // find angle dist=distance_2D_get(0,0,(pnt.x-pt->x),(pnt.z-pt->z)); ang->x=-angle_find(0,0,(pnt.y-pt->y),dist); ang->y=angle_find(pt->x,pt->z,pnt.x,pnt.z); ang->z=0.0f; }
void map_prepare_mesh_poly(map_type *map,map_mesh_type *mesh,map_mesh_poly_type *poly) { int n,ptsz,y,lx,rx,lz,rz,dist; float ang; bool flat; d3pnt min,max,mid; d3pnt *pt; d3vct map_up; // find enclosing square // and middle and if polygon is flat pt=&mesh->vertexes[poly->v[0]]; min.x=max.x=mid.x=pt->x; min.y=max.y=mid.y=y=pt->y; min.z=max.z=mid.z=pt->z; flat=TRUE; ptsz=poly->ptsz; for (n=1;n<ptsz;n++) { pt=&mesh->vertexes[poly->v[n]]; // get min and max if (pt->x<min.x) min.x=pt->x; if (pt->x>max.x) max.x=pt->x; if (pt->y<min.y) min.y=pt->y; if (pt->y>max.y) max.y=pt->y; if (pt->z<min.z) min.z=pt->z; if (pt->z>max.z) max.z=pt->z; // add for middle mid.x+=pt->x; mid.y+=pt->y; mid.z+=pt->z; // check for flat y if (pt->y!=y) flat=FALSE; } memmove(&poly->box.min,&min,sizeof(d3pnt)); memmove(&poly->box.max,&max,sizeof(d3pnt)); poly->box.mid.x=mid.x/ptsz; poly->box.mid.y=mid.y/ptsz; poly->box.mid.z=mid.z/ptsz; poly->box.flat=flat; // get dot product of normal and up // vector to determine the slope of surface // and if it's wall like if (flat) { poly->slope.y=0.0f; poly->slope.ang_y=0.0f; poly->slope.move_x=0.0f; poly->slope.move_z=0.0f; poly->box.wall_like=FALSE; } else { map_up.x=0.0f; map_up.y=-1.0f; map_up.z=0.0f; ang=fabsf(vector_dot_product(&map_up,&poly->tangent_space.normal)); // use dot product to tell if wall like // and the y slope poly->box.wall_like=(ang<=0.4f); poly->slope.y=1.0f-ang; // find the slope angle map_prepare_mesh_poly_slope_ang(mesh,poly); angle_get_movement_float(poly->slope.ang_y,(map->physics.slope_max_speed*poly->slope.y),&poly->slope.move_x,&poly->slope.move_z); } // create wall "line" for wall like polygons if (poly->box.wall_like) { // get the lx,lz to rx,rz lx=poly->box.min.x; rx=poly->box.max.x; lz=poly->box.min.z; rz=poly->box.max.z; for (n=0;n!=poly->ptsz;n++) { pt=&mesh->vertexes[poly->v[n]]; if ((rx-lx)>(rz-lz)) { if (pt->x==lx) lz=pt->z; if (pt->x==rx) rz=pt->z; } else { if (pt->z==lz) lx=pt->x; if (pt->z==rz) rx=pt->x; } } poly->line.lx=lx; poly->line.rx=rx; poly->line.lz=lz; poly->line.rz=rz; // find ty,by for each point // we need to catch polygons that have higher or lower // points slightly offset from lx,lz or rx,rz, so we use // a distance calculation here (within 20% of end point) dist=distance_2D_get(lx,lz,rx,rz); dist=(dist*20)/100; poly->line.l_ty=poly->line.r_ty=poly->line.l_by=poly->line.r_by=-1; for (n=0;n!=poly->ptsz;n++) { pt=&mesh->vertexes[poly->v[n]]; if (distance_2D_get(pt->x,pt->z,lx,lz)<dist) { if ((pt->y<poly->line.l_ty) || (poly->line.l_ty==-1)) poly->line.l_ty=pt->y; if ((pt->y>poly->line.l_by) || (poly->line.l_by==-1)) poly->line.l_by=pt->y; } if (distance_2D_get(pt->x,pt->z,rx,rz)<dist) { if ((pt->y<poly->line.r_ty) || (poly->line.r_ty==-1)) poly->line.r_ty=pt->y; if ((pt->y>poly->line.r_by) || (poly->line.r_by==-1)) poly->line.r_by=pt->y; } } if (poly->line.l_ty==-1) poly->line.l_ty=poly->box.min.y; if (poly->line.r_ty==-1) poly->line.r_ty=poly->box.min.y; if (poly->line.l_by==-1) poly->line.l_by=poly->box.max.y; if (poly->line.r_by==-1) poly->line.r_by=poly->box.max.y; } // get the plane equation for ray-plane intersections map_prepare_mesh_poly_plane(mesh,poly); // determine if shadows can project on this polygon map_prepare_mesh_poly_shadow(map,mesh,poly); }
bool model_recalc_normals_determine_vector_in_out(model_type *model,int mesh_idx,int vertex_idx) { int x,y,z,k,pos_dist,neg_dist; float f_dist; bool is_out; d3pnt *pnt,min,max,center,pos_pt,neg_pt; d3vct face_vct; model_mesh_type *mesh; model_vertex_type *vertex; // get box for vertex. This will be the combination // of vertexes with the same material map_recalc_normals_get_vertex_box(model,mesh_idx,vertex_idx,&min,&max); // get the box center mesh=&model->meshes[mesh_idx]; vertex=&mesh->vertexes[vertex_idx]; pnt=&vertex->pnt; center.x=(min.x+max.x)>>1; center.y=(min.y+max.y)>>1; center.z=(min.z+max.z)>>1; // the dot product is the fall back position // if these specialized checks fail vector_create(&face_vct,pnt->x,pnt->y,pnt->z,center.x,center.y,center.z); is_out=(vector_dot_product(&vertex->tangent_space.normal,&face_vct)>0.0f); // get a point from the current normal vector // and inverse of the current normal vector, using 10% // of the distance to center f_dist=(float)distance_get(pnt->x,pnt->y,pnt->z,center.x,center.y,center.z); f_dist*=0.1f; pos_pt.x=pnt->x+(int)(vertex->tangent_space.normal.x*f_dist); pos_pt.y=pnt->y+(int)(vertex->tangent_space.normal.y*f_dist); pos_pt.z=pnt->z+(int)(vertex->tangent_space.normal.z*f_dist); neg_pt.x=pnt->x-(int)(vertex->tangent_space.normal.x*f_dist); neg_pt.y=pnt->y-(int)(vertex->tangent_space.normal.y*f_dist); neg_pt.z=pnt->z-(int)(vertex->tangent_space.normal.z*f_dist); // first we determine if we can think of the // poly's box (which is determined by all connected // polys) as a closed object in one direction // if one direction is at least 25% greater than the others // then consider it a tube like structure // if any distance calcs fail, fall back to dot product x=max.x-min.x; y=max.y-min.y; z=max.z-min.z; k=x-((x*25)/100); if ((x>y) && (x>z)) { pos_dist=distance_2D_get(pos_pt.y,pos_pt.z,center.y,center.z); neg_dist=distance_2D_get(neg_pt.y,neg_pt.z,center.y,center.z); if (pos_dist==neg_dist) return(is_out); return(pos_dist>neg_dist); } k=y-((y*25)/100); if ((y>x) && (y>z)) { pos_dist=distance_2D_get(pos_pt.x,pos_pt.z,center.x,center.z); neg_dist=distance_2D_get(neg_pt.x,neg_pt.z,center.x,center.z); if (pos_dist==neg_dist) return(is_out); return(pos_dist>neg_dist); } k=z-((z*25)/100); if ((z>x) && (z>y)) { pos_dist=distance_2D_get(pos_pt.x,pos_pt.y,center.x,center.y); neg_dist=distance_2D_get(neg_pt.x,neg_pt.y,center.x,center.y); if (pos_dist==neg_dist) return(is_out); return(pos_dist>neg_dist); } // finally fall back to dot product return(is_out); }
void melee_add(obj_type *obj,weapon_type *weap,d3pnt *pt,d3ang *ang,melee_type *melee,int ignore_uid) { int n,x,y,z,xadd,zadd,damage,dist; bool hit; char weap_name[name_str_len]; d3pnt pnt; obj_type *hurt_obj; proj_type *proj; // fail under liquid? if (weap!=NULL) { if ((weap->fail_in_liquid) && (obj->liquid_mode==lm_under)) return; } // original position for network melees pnt.x=pt->x; pnt.y=pt->y; pnt.z=pt->z; // move melee ahead for distance angle_get_movement(ang->y,melee->distance,&xadd,&zadd); x=pt->x+xadd; y=pt->y; z=pt->z+zadd; // check objects for (n=0;n!=server.count.obj;n++) { hurt_obj=&server.objs[n]; if ((hurt_obj->hidden) || (!hurt_obj->contact.projectile_on) || (hurt_obj->uid==ignore_uid)) continue; // melee hit? if (!collide_sphere_to_object(x,y,z,melee->radius,hurt_obj)) continue; // which hit box? hit=TRUE; if (hurt_obj->hit_box.on) { hit=collide_set_object_hit_box_for_sphere_hit(x,y,z,melee->radius,hurt_obj); } // get damage damage=melee->damage; if (melee->fall_off) { dist=distance_2D_get(x,z,hurt_obj->pnt.x,hurt_obj->pnt.z); dist-=obj->size.radius; if (dist>0) damage=damage-((damage*dist)/melee->radius); if (damage<1) damage=1; } // hurt if (hit) { object_damage(hurt_obj,obj,weap,NULL,pt,damage); if (weap==NULL) { scripts_post_event_console(&obj->attach,sd_event_melee,sd_event_melee_hit,0); } else { scripts_post_event_console(&weap->attach,sd_event_melee,sd_event_melee_hit,0); } scripts_post_event_console(&hurt_obj->attach,sd_event_melee,sd_event_melee_hit,0); } } // check projectiles proj=server.projs; for (n=0;n!=server.count.proj;n++) { if (collide_sphere_to_projectile(x,y,z,melee->radius,proj)) proj->flag_melee_hit=TRUE; // flag the melee hit proj++; } // do any pushes if (melee->force!=0) { collide_push_objects(x,y,z,melee->radius,melee->force); } // if this object is the player object, then spawn melee in remotes if (net_setup.client.joined) { if ((obj->uid==server.player_obj_uid) || (obj->bot)) { weap_name[0]=0x0; if (weap!=NULL) strcpy(weap_name,weap->name); net_client_send_melee_add(obj->remote.uid,weap_name,melee->radius,melee->distance,melee->damage,melee->force,&pnt,ang); } } }
bool weapon_get_projectile_position_angle_weapon_barrel(int tick,obj_type *obj,weapon_type *weap,d3pnt *fire_pnt,d3ang *fire_ang,char *err_str) { int pose_idx,bone_idx,dist; d3pnt barrel_pnt; model_type *mdl; model_draw *draw; model_draw_setup *setup; // get weapon model mdl=model_find_uid(weap->draw.uid); if (mdl==NULL) { if (err_str!=NULL) strcpy(err_str,"Weapon has no model"); return(FALSE); } // get current pose pose_idx=model_find_pose(mdl,weap->proj.fire_pose_name); if (pose_idx==-1) { if (err_str!=NULL) strcpy(err_str,"Weapon has missing or no fire pose"); return(FALSE); } // get 'fire' bone offset and calc bone_idx=model_find_bone(mdl,weap->proj.fire_bone_tag); if (bone_idx==-1) { if (err_str!=NULL) strcpy(err_str,"Weapon has missing or no fire bone"); return(FALSE); } model_draw_setup_weapon(tick,obj,weap,TRUE,weap->dual.in_dual); if (weap->dual.in_dual) { draw=&weap->draw_dual; } else { draw=&weap->draw; } setup=&draw->setup; setup->move.x=setup->move.y=setup->move.z=0; setup->sway.x=setup->sway.y=setup->sway.z=0.0f; model_calc_draw_bone_position(mdl,setup,pose_idx,bone_idx,&fire_pnt->x,&fire_pnt->y,&fire_pnt->z); if (draw->flip_x) fire_pnt->x=-fire_pnt->x; fire_pnt->x+=draw->pnt.x; fire_pnt->y+=draw->pnt.y; fire_pnt->z+=draw->pnt.z; if (draw->no_rot.on) gl_project_fix_rotation(&fire_pnt->x,&fire_pnt->y,&fire_pnt->z); // get 'barrel' bone offset (draw bones already calced above) bone_idx=model_find_bone(mdl,weap->proj.barrel_bone_tag); if (bone_idx==-1) { if (err_str!=NULL) strcpy(err_str,"Weapon has missing or no barrel bone"); return(FALSE); } model_get_draw_bone_position(setup,bone_idx,&barrel_pnt.x,&barrel_pnt.y,&barrel_pnt.z); if (draw->flip_x) barrel_pnt.x=-barrel_pnt.x; barrel_pnt.x+=draw->pnt.x; barrel_pnt.y+=draw->pnt.y; barrel_pnt.z+=draw->pnt.z; if (draw->no_rot.on) gl_project_fix_rotation(&barrel_pnt.x,&barrel_pnt.y,&barrel_pnt.z); // angles between them dist=distance_2D_get(0,0,(fire_pnt->x-barrel_pnt.x),(fire_pnt->z-barrel_pnt.z)); fire_ang->x=-(180.0f-angle_find(0,0,(fire_pnt->y-barrel_pnt.y),dist)); fire_ang->y=angle_find(barrel_pnt.x,barrel_pnt.z,fire_pnt->x,fire_pnt->z); fire_ang->z=0.0f; return(TRUE); }