// -------------------------------------------------------------------------------------- // Select next segment. // If there is a connection on the current side, then choose that segment. // If there is no connecting segment on the current side, try any segment. __attribute_warn_unused_result static std::pair<vsegptridx_t, uint_fast32_t> get_next_segment_side(const vsegptridx_t curseg_num, uint_fast32_t curside) { const auto side_child = curseg_num->children[curside]; if (IS_CHILD(side_child)) { const auto &&newseg_num = curseg_num.absolute_sibling(side_child); // Find out what side we came in through and favor side opposite that const auto newside = Side_opposite[find_connect_side(curseg_num, newseg_num)]; // If there is nothing attached on the side opposite to what we came in (*newside), pick any other side if (!IS_CHILD(newseg_num->children[newside])) for (uint_fast32_t s = 0; s != MAX_SIDES_PER_SEGMENT; ++s) { const auto cseg = newseg_num->children[s]; if (cseg != curseg_num && IS_CHILD(cseg)) return {newseg_num, s}; } return {newseg_num, newside}; } else { return {curseg_num, curside}; } }
// --------------------------------------------------------------------------------------------------- // Do chase mode. // View current segment (Cursegp) from the previous segment. void set_chase_matrix(segment *sp) { int v; vms_vector forvec = ZERO_VECTOR, upvec; vms_vector tv = ZERO_VECTOR; segment *psp; // move back two segments, if possible, else move back one, if possible, else use current if (IS_CHILD(sp->children[WFRONT])) { psp = &Segments[sp->children[WFRONT]]; if (IS_CHILD(psp->children[WFRONT])) psp = &Segments[psp->children[WFRONT]]; } else psp = sp; for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) vm_vec_add2(&forvec,&Vertices[sp->verts[v]]); vm_vec_scale(&forvec,F1_0/MAX_VERTICES_PER_SEGMENT); for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) vm_vec_add2(&tv,&Vertices[psp->verts[v]]); vm_vec_scale(&tv,F1_0/MAX_VERTICES_PER_SEGMENT); Ed_view_target = forvec; vm_vec_sub2(&forvec,&tv); extract_up_vector_from_segment(psp,&upvec); if (!((forvec.x == 0) && (forvec.y == 0) && (forvec.z == 0))) vm_vector_2_matrix(&LargeView.ev_matrix,&forvec,&upvec,NULL); }
//--------------------------------------------------------------------- // Add a wall (removable 2 sided) int add_wall(segment *seg, short side) { int Connectside; segment *csegp; if (Num_walls < MAX_WALLS-2) if (IS_CHILD(seg->children[side])) { if (seg->sides[side].wall_num == -1) { seg->sides[side].wall_num = Num_walls; Num_walls++; } csegp = &Segments[seg->children[side]]; Connectside = find_connect_side(seg, csegp); if (csegp->sides[Connectside].wall_num == -1) { csegp->sides[Connectside].wall_num = Num_walls; Num_walls++; } create_removable_wall( seg, side, CurrentTexture ); create_removable_wall( csegp, Connectside, CurrentTexture ); return 1; } return 0; }
// -------------- Create all sloppy joints within CurrentGroup ------------------ int CreateSloppyAdjacentJointsGroup() { int adj_side; int done_been_a_change = 0; range_for(const auto &gs, GroupList[current_group].segments) { auto segp = vsegptridx(gs); for (int sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) if (!IS_CHILD(segp->children[sidenum])) { segptridx_t adj_sp = segment_none; if (med_find_closest_threshold_segment_side(segp, sidenum, adj_sp, &adj_side, 5*F1_0)) { if (adj_sp->group == segp->group) { if (segp->children[sidenum] != adj_sp) if (!med_form_joint(segp, sidenum, adj_sp,adj_side)) done_been_a_change = 1; } } } } if (done_been_a_change) { Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; autosave_mine(mine_filename); diagnostic_message("Sloppy Joint segment formed."); undo_status[Autosave_count] = "Sloppy Joint segment undone."; warn_if_concave_segments(); } return 1; }
// ---------------------------------------------------------------------------------------------------------------- // Recursively parse mine structure, drawing segments. void draw_mine_sub(int segnum,int depth) { segment *mine_ptr; if (Been_visited[segnum]) return; // If segment already drawn, return. Been_visited[segnum] = 1; // Say that this segment has been drawn. mine_ptr = &Segments[segnum]; // If this segment is active, process it, else skip it. if (mine_ptr->segnum != -1) { int side; if (Search_mode) check_segment(mine_ptr); else add_edges(mine_ptr); //add this segments edges to list if (depth != 0) { for (side=0; side<MAX_SIDES_PER_SEGMENT; side++) { if (IS_CHILD(mine_ptr->children[side])) { if (mine_ptr->sides[side].wall_num != -1) draw_special_wall(mine_ptr, side); draw_mine_sub(mine_ptr->children[side],depth-1); } } } } }
//----------------------------------------------------------------- // Adds a specific trigger flag to Markedsegp/Markedside if it is possible. // Automatically adds flag to Connectside if possible unless it is a control trigger. // Returns 1 if trigger flag added. // Returns 0 if trigger flag cannot be added. int trigger_flag_Markedside(short flag, int value) { int trigger_num; //, ctrigger_num; int wall_num; if (!Markedsegp) { editor_status("No Markedside."); return 0; } // If no child on Markedside return if (!IS_CHILD(Markedsegp->children[Markedside])) return 0; // If no wall just return wall_num = Markedsegp->sides[Markedside].wall_num; if (!value && wall_num == -1) return 0; trigger_num = value ? add_trigger(Markedsegp, Markedside) : Walls[wall_num].trigger; if (trigger_num == -1) { editor_status(value ? "Cannot add trigger at Markedside." : "No trigger at Markedside."); return 0; } if (value) Triggers[trigger_num].flags |= flag; else Triggers[trigger_num].flags &= ~flag; return 1; }
int trigger_remove_flag_from_Markedside(short flag) { int trigger_num; //, ctrigger_num; int wall_num; if (!Markedsegp) { editor_status("No Markedside."); return 0; } // If no child on Markedside return if (!IS_CHILD(Markedsegp->children[Markedside])) return 0; // If no wall just return wall_num = Markedsegp->sides[Markedside].wall_num; if (wall_num == -1) return 0; trigger_num = Walls[wall_num].trigger; // If flag is already cleared, then don't change anything. if ( trigger_num == -1 ) { editor_status("No trigger at Markedside."); return 0; } if (!Triggers[trigger_num].flags & flag) return 1; Triggers[trigger_num].flags &= ~flag; return 1; }
// -------------- Create all sloppy joints within CurrentGroup ------------------ int CreateSloppyAdjacentJointsGroup() { int adj_side; segment *adj_sp; int num_segs = GroupList[current_group].num_segments; short *segs = GroupList[current_group].segments; segment *segp; int done_been_a_change = 0; int segind, sidenum; for (segind=0; segind<num_segs; segind++) { segp = &Segments[segs[segind]]; for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) if (!IS_CHILD(segp->children[sidenum])) if (med_find_closest_threshold_segment_side(segp, sidenum, &adj_sp, &adj_side, 5*F1_0)) { if (adj_sp->group == segp->group) { if (segp->children[sidenum] != adj_sp-Segments) if (!med_form_joint(segp, sidenum, adj_sp,adj_side)) done_been_a_change = 1; } } } if (done_been_a_change) { Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; autosave_mine(mine_filename); diagnostic_message("Sloppy Joint segment formed."); strcpy(undo_status[Autosave_count], "Sloppy Joint segment undone."); warn_if_concave_segments(); } return 1; }
__attribute_warn_unused_result static vsegptridx_t get_previous_segment(const vsegptridx_t curseg_num, const uint_fast32_t curside) { const auto side_child = curseg_num->children[Side_opposite[curside]]; if (IS_CHILD(side_child)) return curseg_num.absolute_sibling(side_child); // no segment on opposite face, connect to anything return get_any_attached_segment(curseg_num, curside); }
// ----------------------------------------------------------------------------- // Increase the size of Cursegp in dimension dimension by amount int segsize_common(int dimension, fix amount) { int i; int propagated[MAX_SIDES_PER_SEGMENT]; vms_vector uvec, rvec, fvec, scalevec; Degenerate_segment_found = 0; med_scale_segment_new(Cursegp, dimension, amount); med_extract_up_vector_from_segment_side(Cursegp, Curside, &uvec); med_extract_right_vector_from_segment_side(Cursegp, Curside, &rvec); extract_forward_vector_from_segment(Cursegp, &fvec); scalevec.x = vm_vec_mag(&rvec); scalevec.y = vm_vec_mag(&uvec); scalevec.z = vm_vec_mag(&fvec); if (Degenerate_segment_found) { Degenerate_segment_found = 0; // mprintf(0, "Applying scale would create degenerate segments. Aborting scale.\n"); editor_status("Applying scale would create degenerate segments. Aborting scale."); med_scale_segment_new(Cursegp, dimension, -amount); return 1; } med_create_new_segment(&scalevec); // For all segments to which Cursegp is connected, propagate tmap (uv coordinates) from the connected // segment back to Cursegp. This will meaningfully propagate uv coordinates to all sides which havve // an incident edge. It will also do some sides more than once. And it is probably just not what you want. for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) propagated[i] = 0; for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) if (IS_CHILD(Cursegp->children[i])) { int s; for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) propagated[s]++; propagated[Side_opposite[i]]--; med_propagate_tmaps_to_segments(&Segments[Cursegp->children[i]],Cursegp,1); } // Now, for all sides that were not adjacent to another side, and therefore did not get tmaps // propagated to them, treat as a back side. for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) if (!propagated[i]) { med_propagate_tmaps_to_back_side(Cursegp, i, 1); } // New stuff, assign default texture to all affected sides. Update_flags |= UF_WORLD_CHANGED; mine_changed = 1; return 1; }
// --------------------------------------------------------------------------------------- // Select previous segment. // If there is a connection on the side opposite to the current side, then choose that segment. // If there is no connecting segment on the opposite face, try any segment. void get_previous_segment(int curseg_num, int curside,int *newseg_num, int *newside) { int s; *newseg_num = curseg_num; if (IS_CHILD(Segments[curseg_num].children[(int)Side_opposite[curside]])) *newseg_num = Segments[curseg_num].children[(int)Side_opposite[curside]]; else // no segment on opposite face, connect to anything for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) if ((s != curside) && IS_CHILD(Segments[curseg_num].children[s])) *newseg_num = Segments[curseg_num].children[s]; // Now make Curside point at the segment we just left (unless we couldn't leave it). if (*newseg_num != curseg_num) *newside = find_connect_side(&Segments[curseg_num],&Segments[*newseg_num]); else *newside = curside; }
// ----------------------------------------------------------------------------- // Return true if ok for buddy to talk, else return false. // Buddy is allowed to talk if the segment he is in does not contain a blastable wall that has not been blasted // AND he has never yet, since being initialized for level, been allowed to talk. int BuddyMayTalk(void) { int i; segment *segp; if (gameData.objs.objects[gameData.escort.nObjNum].type != OBJ_ROBOT) { gameData.escort.bMayTalk = 0; return 0; } if (gameData.escort.bMayTalk) return 1; if ((gameData.objs.objects[gameData.escort.nObjNum].type == OBJ_ROBOT) && (gameData.escort.nObjNum <= gameData.objs.nLastObject) && !gameData.bots.pInfo[gameData.objs.objects[gameData.escort.nObjNum].id].companion) { for (i=0; i<=gameData.objs.nLastObject; i++) if (gameData.bots.pInfo[gameData.objs.objects[i].id].companion) break; if (i > gameData.objs.nLastObject) return 0; else gameData.escort.nObjNum = i; } segp = gameData.segs.segments + gameData.objs.objects[gameData.escort.nObjNum].segnum; for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) { short wall_num = WallNumP (segp, (short) i); if (IS_WALL (wall_num)) { if ((gameData.walls.walls[wall_num].type == WALL_BLASTABLE) && !(gameData.walls.walls[wall_num].flags & WALL_BLASTED)) return 0; } // Check one level deeper. if (IS_CHILD(segp->children[i])) { int j; segment *csegp = &gameData.segs.segments[segp->children[i]]; for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) { short wall2 = WallNumP (csegp, (short) j); if (IS_WALL (wall2)) { if ((gameData.walls.walls[wall2].type == WALL_BLASTABLE) && !(gameData.walls.walls[wall2].flags & WALL_BLASTED)) return 0; } } } } gameData.escort.bMayTalk = 1; return 1; }
__attribute_warn_unused_result static vsegptridx_t get_any_attached_segment(const vsegptridx_t curseg_num, const uint_fast32_t skipside) { for (uint_fast32_t s = 0; s != MAX_SIDES_PER_SEGMENT; ++s) { if (unlikely(s == skipside)) continue; const auto child = curseg_num->children[s]; if (IS_CHILD(child)) return curseg_num.absolute_sibling(child); } return curseg_num; }
// -------------------------------------------------------------------------------------- // Select next segment. // If there is a connection on the current side, then choose that segment. // If there is no connecting segment on the current side, try any segment. void get_next_segment(int curseg_num, int curside, int *newseg_num, int *newside) { int s; if (IS_CHILD(Segments[curseg_num].children[curside])) { *newseg_num = Segments[curseg_num].children[Curside]; // Find out what side we came in through and favor side opposite that *newside = Side_opposite[find_connect_side(&Segments[curseg_num],&Segments[*newseg_num])]; // If there is nothing attached on the side opposite to what we came in (*newside), pick any other side if (!IS_CHILD(Segments[*newseg_num].children[*newside])) for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) if ((Segments[*newseg_num].children[s] != curseg_num) && IS_CHILD(Segments[*newseg_num].children[s])) *newside = s; } else { *newseg_num = curseg_num; *newside = curside; } }
int wall_add_external_wall() { if (Cursegp->children[Curside] == -2) { editor_status( "Wall is already external!" ); return 1; } if (IS_CHILD(Cursegp->children[Curside])) { editor_status( "Cannot add external wall here - seg has children" ); return 0; } Cursegp->children[Curside] = -2; return 1; }
int GenerateCurve() { if ( (Markedsegp != 0) && !IS_CHILD(Markedsegp->children[Markedside])) { r1scale = r4scale = F1_0*20; autosave_mine( mine_filename ); diagnostic_message("Curve Generated."); Update_flags |= UF_WORLD_CHANGED; curve = generate_curve(r1scale, r4scale); mine_changed = 1; if (curve == 1) { strcpy(undo_status[Autosave_count], "Curve Generation UNDONE.\n"); } if (curve == 0) diagnostic_message("Cannot generate curve -- check Current segment."); } else diagnostic_message("Cannot generate curve -- check Marked segment."); warn_if_concave_segments(); return 1; }
// ----------------------------------------------------------------------------- // Create a breadth-first list of segments reachable from current segment. // max_segs is maximum number of segments to search. Use MAX_SEGMENTS to search all. // On exit, *length <= max_segs. // Input: // start_seg // Output: // bfs_list: array of shorts, each reachable segment. Includes start segment. // length: number of elements in bfs_list void CreateBfsList(int start_seg, short bfs_list[], int *length, int max_segs) { int head, tail; sbyte bVisited[MAX_SEGMENTS]; #if 1 memset (bVisited, 0, MAX_SEGMENTS * sizeof (sbyte)); #else for (i=0; i<MAX_SEGMENTS; i++) bVisited[i] = 0; #endif head = 0; tail = 0; bfs_list[head++] = start_seg; bVisited[start_seg] = 1; while ((head != tail) && (head < max_segs)) { int i; short curseg; segment *cursegp; curseg = bfs_list[tail++]; cursegp = gameData.segs.segments + curseg; for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) { int connected_seg = cursegp->children[i]; if (!IS_CHILD (connected_seg)) continue; if (bVisited[connected_seg]) continue; if (!SegmentIsReachable(curseg, (short) i)) continue; bfs_list[head++] = connected_seg; if (head >= max_segs) break; bVisited[connected_seg] = 1; Assert(head < MAX_SEGMENTS); } } *length = head; }
void run_test() { int n; pid_t pid; n = NUM_PROC; while(n-- > 0) { pid = x_fork(); if(IS_CHILD(pid)) { // do something; test_routine(); exit(0); } } n = NUM_PROC; while(n-- > 0) { pid = x_wait(NULL); //printf("Done: %d\n", pid); } }
//----------------------------------------------------------------- // Adds a specific trigger flag to Markedsegp/Markedside if it is possible. // Automatically adds flag to Connectside if possible unless it is a control trigger. // Returns 1 if trigger flag added. // Returns 0 if trigger flag cannot be added. int trigger_add_to_Markedside(short flag) { int trigger_num; //, ctrigger_num; if (!Markedsegp) { editor_status("No Markedside."); return 0; } // If no child on Markedside return if (!IS_CHILD(Markedsegp->children[Markedside])) return 0; trigger_num = add_trigger(Markedsegp, Markedside); if (trigger_num == -1) { editor_status("Cannot add trigger at Markedside."); return 0; } Triggers[trigger_num].flags |= flag; return 1; }
int trigger_dialog_handler(UI_DIALOG *dlg, d_event *event, trigger_dialog *t) { int i; short Markedwall, trigger_num; int keypress = 0; int rval = 0; Assert(MainWindow != NULL); if (!Markedsegp) { close_trigger_window(); return 0; } //------------------------------------------------------------ // Call the ui code.. //------------------------------------------------------------ ui_button_any_drawn = 0; if (event->type == EVENT_KEY_COMMAND) keypress = event_key_get(event); //------------------------------------------------------------ // If we change walls, we need to reset the ui code for all // of the checkboxes that control the wall flags. //------------------------------------------------------------ Markedwall = Markedsegp->sides[Markedside].wall_num; if (Markedwall != -1) trigger_num = Walls[Markedwall].trigger; else trigger_num = -1; if (t->old_trigger_num != trigger_num) { if (trigger_num != -1) { trigger *trig = &Triggers[trigger_num]; ui_checkbox_check(t->triggerFlag[0], trig->flags & TRIGGER_CONTROL_DOORS); ui_checkbox_check(t->triggerFlag[1], trig->flags & TRIGGER_SHIELD_DAMAGE); ui_checkbox_check(t->triggerFlag[2], trig->flags & TRIGGER_ENERGY_DRAIN); ui_checkbox_check(t->triggerFlag[3], trig->flags & TRIGGER_EXIT); ui_checkbox_check(t->triggerFlag[4], trig->flags & TRIGGER_ONE_SHOT); ui_checkbox_check(t->triggerFlag[5], trig->flags & TRIGGER_ILLUSION_ON); ui_checkbox_check(t->triggerFlag[6], trig->flags & TRIGGER_ILLUSION_OFF); ui_checkbox_check(t->triggerFlag[7], trig->flags & TRIGGER_ON); ui_checkbox_check(t->triggerFlag[8], trig->flags & TRIGGER_MATCEN); ui_checkbox_check(t->triggerFlag[9], trig->flags & TRIGGER_SECRET_EXIT); } } //------------------------------------------------------------ // If any of the checkboxes that control the wallflags are set, then // update the cooresponding wall flag. //------------------------------------------------------------ if (IS_CHILD(Markedsegp->children[Markedside])) { rval = 1; if (GADGET_PRESSED(t->triggerFlag[0])) trigger_flag_Markedside(TRIGGER_CONTROL_DOORS, t->triggerFlag[0]->flag); else if (GADGET_PRESSED(t->triggerFlag[1])) trigger_flag_Markedside(TRIGGER_SHIELD_DAMAGE, t->triggerFlag[1]->flag); else if (GADGET_PRESSED(t->triggerFlag[2])) trigger_flag_Markedside(TRIGGER_ENERGY_DRAIN, t->triggerFlag[2]->flag); else if (GADGET_PRESSED(t->triggerFlag[3])) trigger_flag_Markedside(TRIGGER_EXIT, t->triggerFlag[3]->flag); else if (GADGET_PRESSED(t->triggerFlag[4])) trigger_flag_Markedside(TRIGGER_ONE_SHOT, t->triggerFlag[4]->flag); else if (GADGET_PRESSED(t->triggerFlag[5])) trigger_flag_Markedside(TRIGGER_ILLUSION_ON, t->triggerFlag[5]->flag); else if (GADGET_PRESSED(t->triggerFlag[6])) trigger_flag_Markedside(TRIGGER_ILLUSION_OFF, t->triggerFlag[6]->flag); else if (GADGET_PRESSED(t->triggerFlag[7])) trigger_flag_Markedside(TRIGGER_ON, t->triggerFlag[7]->flag); else if (GADGET_PRESSED(t->triggerFlag[8])) trigger_flag_Markedside(TRIGGER_MATCEN, t->triggerFlag[8]->flag); else if (GADGET_PRESSED(t->triggerFlag[9])) trigger_flag_Markedside(TRIGGER_SECRET_EXIT, t->triggerFlag[9]->flag); else rval = 0; } else for (i = 0; i < NUM_TRIGGER_FLAGS; i++ ) ui_checkbox_check(t->triggerFlag[i], 0); //------------------------------------------------------------ // Draw the wall in the little 64x64 box //------------------------------------------------------------ if (event->type == EVENT_UI_DIALOG_DRAW) { gr_set_current_canvas( t->wallViewBox->canvas ); if ((Markedsegp->sides[Markedside].wall_num == -1) || (Walls[Markedsegp->sides[Markedside].wall_num].trigger) == -1) gr_clear_canvas( CBLACK ); else { if (Markedsegp->sides[Markedside].tmap_num2 > 0) { gr_ubitmap(0,0, texmerge_get_cached_bitmap( Markedsegp->sides[Markedside].tmap_num, Markedsegp->sides[Markedside].tmap_num2)); } else { if (Markedsegp->sides[Markedside].tmap_num > 0) { PIGGY_PAGE_IN(Textures[Markedsegp->sides[Markedside].tmap_num]); gr_ubitmap(0,0, &GameBitmaps[Textures[Markedsegp->sides[Markedside].tmap_num].index]); } else gr_clear_canvas( CGREY ); } } } //------------------------------------------------------------ // If anything changes in the ui system, redraw all the text that // identifies this robot. //------------------------------------------------------------ if (event->type == EVENT_UI_DIALOG_DRAW) { if ( Markedsegp->sides[Markedside].wall_num > -1 ) { ui_dprintf_at( MainWindow, 12, 6, "Trigger: %d ", trigger_num); } else { ui_dprintf_at( MainWindow, 12, 6, "Trigger: none "); } } if (ui_button_any_drawn || (t->old_trigger_num != trigger_num) ) Update_flags |= UF_WORLD_CHANGED; if (event->type == EVENT_WINDOW_CLOSE) { d_free(t); MainWindow = NULL; return 0; } if ( GADGET_PRESSED(t->quitButton) || (keypress==KEY_ESC)) { close_trigger_window(); return 1; } t->old_trigger_num = trigger_num; return rval; }
void do_trigger_window() { int i; short Markedwall, trigger_num; if ( MainWindow == NULL ) return; if (!Markedsegp) { close_trigger_window(); return; } //------------------------------------------------------------ // Call the ui code.. //------------------------------------------------------------ ui_button_any_drawn = 0; ui_window_do_gadgets(MainWindow); //------------------------------------------------------------ // If we change walls, we need to reset the ui code for all // of the checkboxes that control the wall flags. //------------------------------------------------------------ Markedwall = Markedsegp->sides[Markedside].wall_num; if (Markedwall != -1) trigger_num = Walls[Markedwall].trigger; else trigger_num = -1; if (old_trigger_num != trigger_num ) { for ( i=0; i < NUM_TRIGGER_FLAGS; i++ ) { TriggerFlag[i]->flag = 0; // Tells ui that this button isn't checked TriggerFlag[i]->status = 1; // Tells ui to redraw button } if (trigger_num != -1) { if (Triggers[trigger_num].flags & TRIGGER_CONTROL_DOORS) TriggerFlag[0]->flag = 1; if (Triggers[trigger_num].flags & TRIGGER_SHIELD_DAMAGE) TriggerFlag[1]->flag = 1; if (Triggers[trigger_num].flags & TRIGGER_ENERGY_DRAIN) TriggerFlag[2]->flag = 1; if (Triggers[trigger_num].flags & TRIGGER_EXIT) TriggerFlag[3]->flag = 1; if (Triggers[trigger_num].flags & TRIGGER_ONE_SHOT) TriggerFlag[4]->flag = 1; if (Triggers[trigger_num].flags & TRIGGER_ILLUSION_ON) TriggerFlag[5]->flag = 1; if (Triggers[trigger_num].flags & TRIGGER_ILLUSION_OFF) TriggerFlag[6]->flag = 1; if (Triggers[trigger_num].flags & TRIGGER_ON) TriggerFlag[7]->flag = 1; if (Triggers[trigger_num].flags & TRIGGER_MATCEN) TriggerFlag[8]->flag = 1; if (Triggers[trigger_num].flags & TRIGGER_SECRET_EXIT) TriggerFlag[9]->flag = 1; } } //------------------------------------------------------------ // If any of the checkboxes that control the wallflags are set, then // update the cooresponding wall flag. //------------------------------------------------------------ if (IS_CHILD(Markedsegp->children[Markedside])) { if (TriggerFlag[0]->flag == 1) trigger_add_to_Markedside(TRIGGER_CONTROL_DOORS); else trigger_remove_flag_from_Markedside(TRIGGER_CONTROL_DOORS); if (TriggerFlag[1]->flag == 1) trigger_add_to_Markedside(TRIGGER_SHIELD_DAMAGE); else trigger_remove_flag_from_Markedside(TRIGGER_SHIELD_DAMAGE); if (TriggerFlag[2]->flag == 1) trigger_add_to_Markedside(TRIGGER_ENERGY_DRAIN); else trigger_remove_flag_from_Markedside(TRIGGER_ENERGY_DRAIN); if (TriggerFlag[3]->flag == 1) trigger_add_to_Markedside(TRIGGER_EXIT); else trigger_remove_flag_from_Markedside(TRIGGER_EXIT); if (TriggerFlag[4]->flag == 1) trigger_add_to_Markedside(TRIGGER_ONE_SHOT); else trigger_remove_flag_from_Markedside(TRIGGER_ONE_SHOT); if (TriggerFlag[5]->flag == 1) trigger_add_to_Markedside(TRIGGER_ILLUSION_ON); else trigger_remove_flag_from_Markedside(TRIGGER_ILLUSION_ON); if (TriggerFlag[6]->flag == 1) trigger_add_to_Markedside(TRIGGER_ILLUSION_OFF); else trigger_remove_flag_from_Markedside(TRIGGER_ILLUSION_OFF); if (TriggerFlag[7]->flag == 1) trigger_add_to_Markedside(TRIGGER_ON); else trigger_remove_flag_from_Markedside(TRIGGER_ON); if (TriggerFlag[8]->flag == 1) trigger_add_to_Markedside(TRIGGER_MATCEN); else trigger_remove_flag_from_Markedside(TRIGGER_MATCEN); if (TriggerFlag[9]->flag == 1) trigger_add_to_Markedside(TRIGGER_SECRET_EXIT); else trigger_remove_flag_from_Markedside(TRIGGER_SECRET_EXIT); } else for ( i=0; i < NUM_TRIGGER_FLAGS; i++ ) if (TriggerFlag[i]->flag == 1) { TriggerFlag[i]->flag = 0; // Tells ui that this button isn't checked TriggerFlag[i]->status = 1; // Tells ui to redraw button } //------------------------------------------------------------ // Draw the wall in the little 64x64 box //------------------------------------------------------------ gr_set_current_canvas( WallViewBox->canvas ); if ((Markedsegp->sides[Markedside].wall_num == -1) || (Walls[Markedsegp->sides[Markedside].wall_num].trigger) == -1) gr_clear_canvas( CBLACK ); else { if (Markedsegp->sides[Markedside].tmap_num2 > 0) { gr_ubitmap(0,0, texmerge_get_cached_bitmap( Markedsegp->sides[Markedside].tmap_num, Markedsegp->sides[Markedside].tmap_num2)); } else { if (Markedsegp->sides[Markedside].tmap_num > 0) { PIGGY_PAGE_IN(Textures[Markedsegp->sides[Markedside].tmap_num]); gr_ubitmap(0,0, &GameBitmaps[Textures[Markedsegp->sides[Markedside].tmap_num].index]); } else gr_clear_canvas( CGREY ); } } //------------------------------------------------------------ // If anything changes in the ui system, redraw all the text that // identifies this robot. //------------------------------------------------------------ if (ui_button_any_drawn || (old_trigger_num != trigger_num) ) { if ( Markedsegp->sides[Markedside].wall_num > -1 ) { ui_wprintf_at( MainWindow, 12, 6, "Trigger: %d ", trigger_num); } else { ui_wprintf_at( MainWindow, 12, 6, "Trigger: none "); } Update_flags |= UF_WORLD_CHANGED; } if ( QuitButton->pressed || (last_keypress==KEY_ESC)) { close_trigger_window(); return; } old_trigger_num = trigger_num; }
int main(void) { int in[2]; int out[2]; pid_t pid; printf("type 'quit' for exit\n\n"); x_pipe(in); x_pipe(out); pid = x_fork(); if(IS_CHILD(pid)) { x_dup2(in[READ], STDIN_FD); x_dup2(out[WRITE], STDOUT_FD); x_close(in[READ]); x_close(in[WRITE]); x_close(out[READ]); x_close(out[WRITE]); execl("/usr/bin/bc", "runbc", NULL); perror("execl"); exit(1); } else if(IS_PARENT(pid)) { char buf[BUFSIZE + 1]; fd_set rfds; int count; int flag = 1; x_close(in[READ]); x_close(out[WRITE]); while(13) { FD_ZERO(&rfds); FD_SET(STDIN_FD, &rfds); FD_SET(out[READ], &rfds); count = 0; x_select(out[READ] + 1, &rfds, NULL, NULL, NULL); if(FD_ISSET(out[READ], &rfds)) { // read messages from BC count = x_read(out[READ], buf, BUFSIZE); if(count) { x_write(STDOUT_FD, buf, count); } else { break; } } if(FD_ISSET(STDIN_FD, &rfds) && flag) { // send commands to BC count = x_read(STDIN_FD, buf, BUFSIZE); if(count) { x_write(in[WRITE], buf, count); } else { x_write(in[WRITE], "quit\n", 6); flag = 0; } } } x_waitpid(pid, NULL, 0); x_close(in[WRITE]); x_close(out[READ]); } return 0; }
//--------------------------------------------------------------------- // Remove a specific side. int wall_remove_side(segment *seg, short side) { int Connectside; segment *csegp; int lower_wallnum; int w, s, t, l, t1; if (IS_CHILD(seg->children[side]) && IS_CHILD(seg->sides[side].wall_num)) { csegp = &Segments[seg->children[side]]; Connectside = find_connect_side(seg, csegp); remove_trigger(seg, side); remove_trigger(csegp, Connectside); // Remove walls 'wall_num' and connecting side 'wall_num' // from Walls array. lower_wallnum = seg->sides[side].wall_num; if (csegp->sides[Connectside].wall_num < lower_wallnum) lower_wallnum = csegp->sides[Connectside].wall_num; if (Walls[lower_wallnum].linked_wall != -1) Walls[Walls[lower_wallnum].linked_wall].linked_wall = -1; if (Walls[lower_wallnum+1].linked_wall != -1) Walls[Walls[lower_wallnum+1].linked_wall].linked_wall = -1; for (w=lower_wallnum;w<Num_walls-2;w++) Walls[w] = Walls[w+2]; Num_walls -= 2; for (s=0;s<=Highest_segment_index;s++) if (Segments[s].segnum != -1) for (w=0;w<MAX_SIDES_PER_SEGMENT;w++) if (Segments[s].sides[w].wall_num > lower_wallnum+1) Segments[s].sides[w].wall_num -= 2; // Destroy any links to the deleted wall. for (t=0;t<Num_triggers;t++) for (l=0;l<Triggers[t].num_links;l++) if ((Triggers[t].seg[l] == seg-Segments) && (Triggers[t].side[l] == side)) { for (t1=0;t1<Triggers[t].num_links-1;t1++) { Triggers[t].seg[t1] = Triggers[t].seg[t1+1]; Triggers[t].side[t1] = Triggers[t].side[t1+1]; } Triggers[t].num_links--; } // Destroy control center links as well. for (l=0;l<ControlCenterTriggers.num_links;l++) if ((ControlCenterTriggers.seg[l] == seg-Segments) && (ControlCenterTriggers.side[l] == side)) { for (t1=0;t1<ControlCenterTriggers.num_links-1;t1++) { ControlCenterTriggers.seg[t1] = ControlCenterTriggers.seg[t1+1]; ControlCenterTriggers.side[t1] = ControlCenterTriggers.side[t1+1]; } ControlCenterTriggers.num_links--; } seg->sides[side].wall_num = -1; csegp->sides[Connectside].wall_num = -1; Update_flags |= UF_WORLD_CHANGED; return 1; } editor_status( "Can't remove wall. No wall present."); return 0; }
// ----------------------------------------------------------------------------- //do whatever this thing does in a frame void DoReactorFrame (object *objP) { int nBestGun; // If a boss level, then gameData.reactor.bPresent will be 0. if (!gameData.reactor.bPresent) return; #ifndef NDEBUG if (!gameStates.app.cheats.bRobotsFiring || (gameStates.app.bGameSuspended & SUSP_ROBOTS)) return; #else if (!gameStates.app.cheats.bRobotsFiring) return; #endif if (!(gameData.reactor.bHit || gameData.reactor.bSeenPlayer)) { if (!(gameData.app.nFrameCount % 8)) { // Do every so often... vms_vector vec_to_player; fix dist_to_player; int i; segment *segp = &gameData.segs.segments[objP->segnum]; // This is a hack. Since the control center is not processed by // ai_do_frame, it doesn't know to deal with cloaked dudes. It // seems to work in single-player mode because it is actually using // the value of Believed_player_position that was set by the last // person to go through ai_do_frame. But since a no-robots game // never goes through ai_do_frame, I'm making it so the control // center can spot cloaked dudes. if (gameData.app.nGameMode & GM_MULTI) gameData.ai.vBelievedPlayerPos = gameData.objs.objects[gameData.multi.players[gameData.multi.nLocalPlayer].objnum].pos; // Hack for special control centers which are isolated and not reachable because the // real control center is inside the boss. for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) if (IS_CHILD (segp->children[i])) break; if (i == MAX_SIDES_PER_SEGMENT) return; VmVecSub (&vec_to_player, &gameData.objs.console->pos, &objP->pos); dist_to_player = VmVecNormalizeQuick (&vec_to_player); if (dist_to_player < F1_0*200) { gameData.reactor.bSeenPlayer = ObjectCanSeePlayer (objP, &objP->pos, 0, &vec_to_player); gameData.reactor.nNextFireTime = 0; } } return; } // Periodically, make the reactor fall asleep if player not visible. if (gameData.reactor.bHit || gameData.reactor.bSeenPlayer) { if ((Last_time_cc_vis_check + F1_0*5 < gameData.time.xGame) || (Last_time_cc_vis_check > gameData.time.xGame)) { vms_vector vec_to_player; fix dist_to_player; VmVecSub (&vec_to_player, &gameData.objs.console->pos, &objP->pos); dist_to_player = VmVecNormalizeQuick (&vec_to_player); Last_time_cc_vis_check = gameData.time.xGame; if (dist_to_player < F1_0*120) { gameData.reactor.bSeenPlayer = ObjectCanSeePlayer (objP, &objP->pos, 0, &vec_to_player); if (!gameData.reactor.bSeenPlayer) gameData.reactor.bHit = 0; } } } if ((gameData.reactor.nNextFireTime < 0) && !(gameStates.app.bPlayerIsDead && (gameData.time.xGame > gameStates.app.nPlayerTimeOfDeath+F1_0*2))) { if (gameData.multi.players[gameData.multi.nLocalPlayer].flags & PLAYER_FLAGS_CLOAKED) nBestGun = CalcBestReactorGun (N_controlcen_guns, Gun_pos, Gun_dir, &gameData.ai.vBelievedPlayerPos); else nBestGun = CalcBestReactorGun (N_controlcen_guns, Gun_pos, Gun_dir, &gameData.objs.console->pos); if (nBestGun != -1) { int rand_prob, count; vms_vector vec_to_goal; fix dist_to_player; fix delta_fire_time; if (gameData.multi.players[gameData.multi.nLocalPlayer].flags & PLAYER_FLAGS_CLOAKED) { VmVecSub (&vec_to_goal, &gameData.ai.vBelievedPlayerPos, &Gun_pos[nBestGun]); dist_to_player = VmVecNormalizeQuick (&vec_to_goal); } else { VmVecSub (&vec_to_goal, &gameData.objs.console->pos, &Gun_pos[nBestGun]); dist_to_player = VmVecNormalizeQuick (&vec_to_goal); } if (dist_to_player > F1_0*300) { gameData.reactor.bHit = 0; gameData.reactor.bSeenPlayer = 0; return; } #ifdef NETWORK if (gameData.app.nGameMode & GM_MULTI) MultiSendCtrlcenFire (&vec_to_goal, nBestGun, OBJ_IDX (objP)); #endif CreateNewLaserEasy (&vec_to_goal, &Gun_pos[nBestGun], OBJ_IDX (objP), CONTROLCEN_WEAPON_NUM, 1); // some of time, based on level, fire another thing, not directly at player, so it might hit him if he's constantly moving. rand_prob = F1_0/ (abs (gameData.missions.nCurrentLevel)/4+2); count = 0; while ((d_rand () > rand_prob) && (count < 4)) { vms_vector randvec; MakeRandomVector (&randvec); VmVecScaleInc (&vec_to_goal, &randvec, F1_0/6); VmVecNormalizeQuick (&vec_to_goal); #ifdef NETWORK if (gameData.app.nGameMode & GM_MULTI) MultiSendCtrlcenFire (&vec_to_goal, nBestGun, OBJ_IDX (objP)); #endif CreateNewLaserEasy (&vec_to_goal, &Gun_pos[nBestGun], OBJ_IDX (objP), CONTROLCEN_WEAPON_NUM, 0); count++; } delta_fire_time = (NDL - gameStates.app.nDifficultyLevel) * F1_0/4; if (gameStates.app.nDifficultyLevel == 0) delta_fire_time += F1_0/2; if (gameData.app.nGameMode & GM_MULTI) // slow down rate of fire in multi player delta_fire_time *= 2; gameData.reactor.nNextFireTime = delta_fire_time; } } else gameData.reactor.nNextFireTime -= gameData.time.xFrame; }
// ----------------------------------------------------------------------------------------------------------- // Create a path from objP->info.position.vPos to the center of nEndSeg. // Return a list of (segment_num, point_locations) at pointSegP // Return number of points in *numPoints. // if nMaxDepth == -1, then there is no maximum depth. // If unable to create path, return -1, else return 0. // If randomFlag !0, then introduce randomness into path by looking at sides in random order. This means // that a path between two segments won't always be the same, unless it is unique.p. // If bSafeMode is set, then additional points are added to "make sure" that points are reachable.p. I would // like to say that it ensures that the CObject can move between the points, but that would require knowing what // the CObject is (which isn't passed, right?) and making fvi calls (slow, right?). So, consider it the more_or_less_safeFlag. // If nEndSeg == -2, then end seg will never be found and this routine will drop out due to depth (xProbably called by CreateNSegmentPath). int CreatePathPoints (CObject *objP, int nStartSeg, int nEndSeg, tPointSeg *pointSegP, short *numPoints, int nMaxDepth, int bRandom, int bSafeMode, int nAvoidSeg) { short nCurSeg; short nSide, hSide; int qTail = 0, qHead = 0; int h, i, j; sbyte bVisited [MAX_SEGMENTS_D2X]; segQueueEntry segmentQ [MAX_SEGMENTS_D2X]; short depth [MAX_SEGMENTS_D2X]; int nCurDepth; sbyte randomXlate [MAX_SIDES_PER_SEGMENT]; tPointSeg *origPointSegs = pointSegP; int lNumPoints; CSegment *segP; CFixVector vCenter; int nParentSeg, nDestSeg; tFVIQuery fq; tFVIData hitData; int hitType; int bAvoidPlayer; #if PATH_VALIDATION ValidateAllPaths (); #endif if ((objP->info.nType == OBJ_ROBOT) && (objP->cType.aiInfo.behavior == AIB_RUN_FROM) && (nAvoidSeg != -32767)) { bRandom = 1; nAvoidSeg = gameData.objs.consoleP->info.nSegment; } bAvoidPlayer = gameData.objs.consoleP->info.nSegment == nAvoidSeg; if (nMaxDepth == -1) nMaxDepth = MAX_PATH_LENGTH; lNumPoints = 0; memset (bVisited, 0, sizeof (bVisited [0]) * gameData.segs.nSegments); memset (depth, 0, sizeof (depth [0]) * gameData.segs.nSegments); // If there is a CSegment we're not allowed to visit, mark it. if (nAvoidSeg != -1) { Assert (nAvoidSeg <= gameData.segs.nLastSegment); if ((nStartSeg != nAvoidSeg) && (nEndSeg != nAvoidSeg)) { bVisited [nAvoidSeg] = 1; depth [nAvoidSeg] = 0; } } nCurSeg = nStartSeg; bVisited [nCurSeg] = 1; nCurDepth = 0; #if DBG if (objP->Index () == nDbgObj) nDbgObj = nDbgObj; #endif if (bRandom) CreateRandomXlate (randomXlate); nCurSeg = nStartSeg; bVisited [nCurSeg] = 1; while (nCurSeg != nEndSeg) { segP = SEGMENTS + nCurSeg; if (bRandom && (d_rand () < 8192)) //create a different xlate at random time intervals CreateRandomXlate (randomXlate); for (nSide = 0; nSide < MAX_SIDES_PER_SEGMENT; nSide++) { hSide = bRandom ? randomXlate [nSide] : nSide; if (!IS_CHILD (segP->m_children [hSide])) continue; if (!((segP->IsDoorWay (hSide, NULL) & WID_FLY_FLAG) || (AIDoorIsOpenable (objP, segP, hSide)))) continue; nDestSeg = segP->m_children [hSide]; if (bVisited [nDestSeg]) continue; if (bAvoidPlayer && ((nCurSeg == nAvoidSeg) || (nDestSeg == nAvoidSeg))) { vCenter = segP->SideCenter (hSide); fq.p0 = &objP->info.position.vPos; fq.startSeg = objP->info.nSegment; fq.p1 = &vCenter; fq.radP0 = fq.radP1 = objP->info.xSize; fq.thisObjNum = objP->Index (); fq.ignoreObjList = NULL; fq.flags = 0; fq.bCheckVisibility = false; hitType = FindVectorIntersection (&fq, &hitData); if (hitType != HIT_NONE) continue; } if (nDestSeg < 0) continue; if (nCurSeg < 0) continue; segmentQ [qTail].start = nCurSeg; segmentQ [qTail].end = nDestSeg; segmentQ [qTail].nConnSide = (ubyte) hSide; bVisited [nDestSeg] = 1; depth [qTail++] = nCurDepth + 1; if (depth [qTail-1] == nMaxDepth) { nEndSeg = segmentQ [qTail-1].end; goto pathTooLong; } // end if (depth [... } // for (nSide.p... if (qHead >= qTail) { // Couldn't get to goal, return a path as far as we got, which is probably acceptable to the unparticular caller. nEndSeg = segmentQ [qTail-1].end; break; } nCurSeg = segmentQ [qHead].end; nCurDepth = depth [qHead]; qHead++; pathTooLong: ; } // while (nCurSeg ... // Set qTail to the CSegment which ends at the goal. while (segmentQ [--qTail].end != nEndSeg) if (qTail < 0) { *numPoints = lNumPoints; return -1; } for (i = qTail; i >= 0; ) { nParentSeg = segmentQ [i].start; lNumPoints++; if (nParentSeg == nStartSeg) break; while (segmentQ [--i].end != nParentSeg) Assert (i >= 0); } if (bSafeMode && ((pointSegP - gameData.ai.routeSegs) + 2 * lNumPoints + 1 >= LEVEL_POINT_SEGS)) { // Ouch! Cannot insert center points in path. So return unsafe path. #if TRACE console.printf (CON_DBG, "Resetting all paths because of bSafeMode.p.\n"); #endif AIResetAllPaths (); *numPoints = lNumPoints; return -1; } pointSegP->nSegment = nStartSeg; pointSegP->point = SEGMENTS [nStartSeg].Center (); if (bSafeMode) lNumPoints *= 2; j = lNumPoints++; h = bSafeMode + 1; for (i = qTail; i >= 0; j -= h) { nDestSeg = segmentQ [i].end; nParentSeg = segmentQ [i].start; pointSegP [j].nSegment = nDestSeg; pointSegP [j].point = SEGMENTS [nDestSeg].Center (); pointSegP [j].nConnSide = segmentQ [i].nConnSide; if (nParentSeg == nStartSeg) break; while (segmentQ [--i].end != nParentSeg) Assert (qTail >= 0); } if (bSafeMode) { for (i = 0; i < lNumPoints - 1; i = j) { j = i + 2; InsertTransitPoint (pointSegP + i + 1, pointSegP + i, pointSegP + j, pointSegP [j].nConnSide); } lNumPoints = OptimizePath (pointSegP, lNumPoints); } pointSegP += lNumPoints; #if PATH_VALIDATION ValidatePath (2, origPointSegs, lNumPoints); #endif #if PATH_VALIDATION ValidatePath (3, origPointSegs, lNumPoints); #endif // -- MK, 10/30/95 -- This code causes apparent discontinuities in the path, moving a point // into a new CSegment. It is not necessarily bad, but it makes it hard to track down actual // discontinuity xProblems. if ((objP->info.nType == OBJ_ROBOT) && ROBOTINFO (objP->info.nId).companion) MoveTowardsOutside (origPointSegs, &lNumPoints, objP, 0); #if PATH_VALIDATION ValidatePath (4, origPointSegs, lNumPoints); #endif *numPoints = lNumPoints; return 0; }
// ----------------------------------------------------------------------------- //do whatever this thing does in a frame void do_controlcen_frame(object *obj) { int best_gun_num; // If a boss level, then Control_center_present will be 0. if (!Control_center_present) return; #ifndef NDEBUG if (!Robot_firing_enabled || (Game_suspended & SUSP_ROBOTS)) return; #else if (!Robot_firing_enabled) return; #endif if (!(Control_center_been_hit || Control_center_player_been_seen)) { if (!(FrameCount % 8)) { // Do every so often... vms_vector vec_to_player; fix dist_to_player; int i; segment *segp = &Segments[obj->segnum]; // This is a hack. Since the control center is not processed by // ai_do_frame, it doesn't know to deal with cloaked dudes. It // seems to work in single-player mode because it is actually using // the value of Believed_player_position that was set by the last // person to go through ai_do_frame. But since a no-robots game // never goes through ai_do_frame, I'm making it so the control // center can spot cloaked dudes. if (Game_mode & GM_MULTI) Believed_player_pos = Objects[Players[Player_num].objnum].pos; // Hack for special control centers which are isolated and not reachable because the // real control center is inside the boss. for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) if (IS_CHILD(segp->children[i])) break; if (i == MAX_SIDES_PER_SEGMENT) return; vm_vec_sub(&vec_to_player, &ConsoleObject->pos, &obj->pos); dist_to_player = vm_vec_normalize_quick(&vec_to_player); if (dist_to_player < F1_0*200) { Control_center_player_been_seen = player_is_visible_from_object(obj, &obj->pos, 0, &vec_to_player); Control_center_next_fire_time = 0; } } return; } // Periodically, make the reactor fall asleep if player not visible. if (Control_center_been_hit || Control_center_player_been_seen) { if ((Last_time_cc_vis_check + F1_0*5 < GameTime) || (Last_time_cc_vis_check > GameTime)) { vms_vector vec_to_player; fix dist_to_player; vm_vec_sub(&vec_to_player, &ConsoleObject->pos, &obj->pos); dist_to_player = vm_vec_normalize_quick(&vec_to_player); Last_time_cc_vis_check = GameTime; if (dist_to_player < F1_0*120) { Control_center_player_been_seen = player_is_visible_from_object(obj, &obj->pos, 0, &vec_to_player); if (!Control_center_player_been_seen) Control_center_been_hit = 0; } } } if ((Control_center_next_fire_time < 0) && !(Player_is_dead && (GameTime > Player_time_of_death+F1_0*2))) { if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) best_gun_num = calc_best_gun(N_controlcen_guns, Gun_pos, Gun_dir, &Believed_player_pos); else best_gun_num = calc_best_gun(N_controlcen_guns, Gun_pos, Gun_dir, &ConsoleObject->pos); if (best_gun_num != -1) { int rand_prob, count; vms_vector vec_to_goal; fix dist_to_player; fix delta_fire_time; if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) { vm_vec_sub(&vec_to_goal, &Believed_player_pos, &Gun_pos[best_gun_num]); dist_to_player = vm_vec_normalize_quick(&vec_to_goal); } else { vm_vec_sub(&vec_to_goal, &ConsoleObject->pos, &Gun_pos[best_gun_num]); dist_to_player = vm_vec_normalize_quick(&vec_to_goal); } if (dist_to_player > F1_0*300) { Control_center_been_hit = 0; Control_center_player_been_seen = 0; return; } #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_controlcen_fire(&vec_to_goal, best_gun_num, obj-Objects); #endif Laser_create_new_easy( &vec_to_goal, &Gun_pos[best_gun_num], obj-Objects, CONTROLCEN_WEAPON_NUM, 1); // some of time, based on level, fire another thing, not directly at player, so it might hit him if he's constantly moving. rand_prob = F1_0/(abs(Current_level_num)/4+2); count = 0; while ((rand() > rand_prob) && (count < 4)) { vms_vector randvec; make_random_vector(&randvec); vm_vec_scale_add2(&vec_to_goal, &randvec, F1_0/6); vm_vec_normalize_quick(&vec_to_goal); #ifdef NETWORK if (Game_mode & GM_MULTI) multi_send_controlcen_fire(&vec_to_goal, best_gun_num, obj-Objects); #endif Laser_create_new_easy( &vec_to_goal, &Gun_pos[best_gun_num], obj-Objects, CONTROLCEN_WEAPON_NUM, 0); count++; } delta_fire_time = (NDL - Difficulty_level) * F1_0/4; if (Difficulty_level == 0) delta_fire_time += F1_0/2; if (Game_mode & GM_MULTI) // slow down rate of fire in multi player delta_fire_time *= 2; Control_center_next_fire_time = delta_fire_time; } } else Control_center_next_fire_time -= FrameTime; }
// ----------------------------------------------------------------------------- //do whatever this thing does in a frame void DoReactorFrame (CObject *objP) { int nBestGun, i; tReactorStates *rStatP; // If a boss level, then gameData.reactor.bPresent will be 0. if (!gameData.reactor.bPresent) return; i = FindReactor (objP); if (i < 0) return; rStatP = gameData.reactor.states + i; #if DBG if (!gameStates.app.cheats.bRobotsFiring || (gameStates.app.bGameSuspended & SUSP_ROBOTS)) return; #else if (!gameStates.app.cheats.bRobotsFiring) return; #endif if (!(rStatP->bHit || rStatP->bSeenPlayer)) { if (gameStates.app.tick40fps.bTick) { // Do ever so often... CFixVector vecToPlayer; fix xDistToPlayer; int i; CSegment *segP = SEGMENTS + objP->info.nSegment; // This is a hack. Since the control center is not processed by // ai_do_frame, it doesn't know how to deal with cloaked dudes. It // seems to work in single-CPlayerData mode because it is actually using // the value of Believed_player_position that was set by the last // person to go through ai_do_frame. But since a no-robots game // never goes through ai_do_frame, I'm making it so the control // center can spot cloaked dudes. if (IsMultiGame) gameData.ai.target.vBelievedPos = OBJPOS (OBJECTS + LOCALPLAYER.nObject)->vPos; // Hack for special control centers which are isolated and not reachable because the // real control center is inside the boss. for (i = 0; i < MAX_SIDES_PER_SEGMENT; i++) if (IS_CHILD (segP->m_children [i])) break; if (i == MAX_SIDES_PER_SEGMENT) return; vecToPlayer = OBJPOS (gameData.objs.consoleP)->vPos - objP->info.position.vPos; xDistToPlayer = CFixVector::Normalize (vecToPlayer); if (xDistToPlayer < I2X (200)) { rStatP->bSeenPlayer = AICanSeeTarget (objP, &objP->info.position.vPos, 0, &vecToPlayer); rStatP->nNextFireTime = 0; } } return; } // Periodically, make the reactor fall asleep if CPlayerData not visible. if (rStatP->bHit || rStatP->bSeenPlayer) { if ((rStatP->xLastVisCheckTime + I2X (5) < gameData.time.xGame) || (rStatP->xLastVisCheckTime > gameData.time.xGame)) { CFixVector vecToPlayer; fix xDistToPlayer; vecToPlayer = gameData.objs.consoleP->info.position.vPos - objP->info.position.vPos; xDistToPlayer = CFixVector::Normalize (vecToPlayer); rStatP->xLastVisCheckTime = gameData.time.xGame; if (xDistToPlayer < I2X (120)) { rStatP->bSeenPlayer = AICanSeeTarget (objP, &objP->info.position.vPos, 0, &vecToPlayer); if (!rStatP->bSeenPlayer) rStatP->bHit = 0; } } } if ((rStatP->nNextFireTime < 0) && !(gameStates.app.bPlayerIsDead && (gameData.time.xGame > gameStates.app.nPlayerTimeOfDeath + I2X (2)))) { nBestGun = CalcBestReactorGun (gameData.reactor.props [objP->info.nId].nGuns, rStatP->vGunPos, rStatP->vGunDir, (LOCALPLAYER.flags & PLAYER_FLAGS_CLOAKED) ? &gameData.ai.target.vBelievedPos : &gameData.objs.consoleP->info.position.vPos); if (nBestGun != -1) { int nRandProb, count; CFixVector vecToGoal; fix xDistToPlayer; fix xDeltaFireTime; if (LOCALPLAYER.flags & PLAYER_FLAGS_CLOAKED) { vecToGoal = gameData.ai.target.vBelievedPos - rStatP->vGunPos[nBestGun]; xDistToPlayer = CFixVector::Normalize (vecToGoal); } else { vecToGoal = gameData.objs.consoleP->info.position.vPos - rStatP->vGunPos [nBestGun]; xDistToPlayer = CFixVector::Normalize (vecToGoal); } if (xDistToPlayer > I2X (300)) { rStatP->bHit = 0; rStatP->bSeenPlayer = 0; return; } if (gameData.app.nGameMode & GM_MULTI) MultiSendCtrlcenFire (&vecToGoal, nBestGun, objP->Index ()); CreateNewLaserEasy (&vecToGoal, &rStatP->vGunPos [nBestGun], objP->Index (), CONTROLCEN_WEAPON_NUM, 1); // some of time, based on level, fire another thing, not directly at CPlayerData, so it might hit him if he's constantly moving. nRandProb = I2X (1) / (abs (gameData.missions.nCurrentLevel) / 4 + 2); count = 0; while ((d_rand () > nRandProb) && (count < 4)) { CFixVector vRand; vRand = CFixVector::Random(); vecToGoal += vRand * (I2X (1)/6); CFixVector::Normalize (vecToGoal); if (IsMultiGame) MultiSendCtrlcenFire (&vecToGoal, nBestGun, objP->Index ()); CreateNewLaserEasy (&vecToGoal, &rStatP->vGunPos [nBestGun], objP->Index (), CONTROLCEN_WEAPON_NUM, 0); count++; } xDeltaFireTime = I2X (NDL - gameStates.app.nDifficultyLevel) / 4; if (gameStates.app.nDifficultyLevel == 0) xDeltaFireTime += (fix) (I2X (1) / 2 * gameStates.gameplay.slowmo [0].fSpeed); if (IsMultiGame) // slow down rate of fire in multi player xDeltaFireTime *= 2; rStatP->nNextFireTime = xDeltaFireTime; } } else rStatP->nNextFireTime -= gameData.physics.xTime; }
// ----------------------------------------------------------------------------- //do whatever this thing does in a frame void DoReactorFrame (tObject *objP) { int nBestGun, i; tReactorStates *rStatP; // If a boss level, then gameData.reactor.bPresent will be 0. if (!gameData.reactor.bPresent) return; i = FindReactor (objP); if (i < 0) return; rStatP = gameData.reactor.states + i; #ifdef _DEBUG if (!gameStates.app.cheats.bRobotsFiring || (gameStates.app.bGameSuspended & SUSP_ROBOTS)) return; #else if (!gameStates.app.cheats.bRobotsFiring) return; #endif if (!(rStatP->bHit || rStatP->bSeenPlayer)) { if (gameStates.app.tick40fps.bTick) { // Do ever so often... vmsVector vecToPlayer; fix xDistToPlayer; int i; tSegment *segP = gameData.segs.segments + objP->nSegment; // This is a hack. Since the control center is not processed by // ai_do_frame, it doesn't know how to deal with cloaked dudes. It // seems to work in single-tPlayer mode because it is actually using // the value of Believed_player_position that was set by the last // person to go through ai_do_frame. But since a no-robots game // never goes through ai_do_frame, I'm making it so the control // center can spot cloaked dudes. if (IsMultiGame) gameData.ai.vBelievedPlayerPos = gameData.objs.objects [LOCALPLAYER.nObject].position.vPos; // Hack for special control centers which are isolated and not reachable because the // real control center is inside the boss. for (i = 0; i < MAX_SIDES_PER_SEGMENT; i++) if (IS_CHILD (segP->children [i])) break; if (i == MAX_SIDES_PER_SEGMENT) return; VmVecSub (&vecToPlayer, &gameData.objs.console->position.vPos, &objP->position.vPos); xDistToPlayer = VmVecNormalizeQuick (&vecToPlayer); if (xDistToPlayer < F1_0 * 200) { rStatP->bSeenPlayer = ObjectCanSeePlayer (objP, &objP->position.vPos, 0, &vecToPlayer); rStatP->nNextFireTime = 0; } } return; } // Periodically, make the reactor fall asleep if tPlayer not visible. if (rStatP->bHit || rStatP->bSeenPlayer) { if ((rStatP->xLastVisCheckTime + F1_0 * 5 < gameData.time.xGame) || (rStatP->xLastVisCheckTime > gameData.time.xGame)) { vmsVector vecToPlayer; fix xDistToPlayer; VmVecSub (&vecToPlayer, &gameData.objs.console->position.vPos, &objP->position.vPos); xDistToPlayer = VmVecNormalizeQuick (&vecToPlayer); rStatP->xLastVisCheckTime = gameData.time.xGame; if (xDistToPlayer < F1_0 * 120) { rStatP->bSeenPlayer = ObjectCanSeePlayer (objP, &objP->position.vPos, 0, &vecToPlayer); if (!rStatP->bSeenPlayer) rStatP->bHit = 0; } } } if ((rStatP->nNextFireTime < 0) && !(gameStates.app.bPlayerIsDead && (gameData.time.xGame > gameStates.app.nPlayerTimeOfDeath + F1_0 * 2))) { if (LOCALPLAYER.flags & PLAYER_FLAGS_CLOAKED) nBestGun = CalcBestReactorGun (gameData.reactor.props [objP->id].nGuns, rStatP->vGunPos, rStatP->vGunDir, &gameData.ai.vBelievedPlayerPos); else nBestGun = CalcBestReactorGun (gameData.reactor.props [objP->id].nGuns, rStatP->vGunPos, rStatP->vGunDir, &gameData.objs.console->position.vPos); if (nBestGun != -1) { int nRandProb, count; vmsVector vecToGoal; fix xDistToPlayer; fix xDeltaFireTime; if (LOCALPLAYER.flags & PLAYER_FLAGS_CLOAKED) { VmVecSub (&vecToGoal, &gameData.ai.vBelievedPlayerPos, &rStatP->vGunPos [nBestGun]); xDistToPlayer = VmVecNormalizeQuick (&vecToGoal); } else { VmVecSub (&vecToGoal, &gameData.objs.console->position.vPos, &rStatP->vGunPos [nBestGun]); xDistToPlayer = VmVecNormalizeQuick (&vecToGoal); } if (xDistToPlayer > F1_0 * 300) { rStatP->bHit = 0; rStatP->bSeenPlayer = 0; return; } if (gameData.app.nGameMode & GM_MULTI) MultiSendCtrlcenFire (&vecToGoal, nBestGun, OBJ_IDX (objP)); CreateNewLaserEasy (&vecToGoal, &rStatP->vGunPos[nBestGun], OBJ_IDX (objP), CONTROLCEN_WEAPON_NUM, 1); // some of time, based on level, fire another thing, not directly at tPlayer, so it might hit him if he's constantly moving. nRandProb = F1_0 / (abs (gameData.missions.nCurrentLevel) / 4 + 2); count = 0; while ((d_rand () > nRandProb) && (count < 4)) { vmsVector vRand; MakeRandomVector (&vRand); VmVecScaleInc (&vecToGoal, &vRand, F1_0/6); VmVecNormalizeQuick (&vecToGoal); if (IsMultiGame) MultiSendCtrlcenFire (&vecToGoal, nBestGun, OBJ_IDX (objP)); CreateNewLaserEasy (&vecToGoal, &rStatP->vGunPos[nBestGun], OBJ_IDX (objP), CONTROLCEN_WEAPON_NUM, 0); count++; } xDeltaFireTime = (NDL - gameStates.app.nDifficultyLevel) * F1_0/4; if (gameStates.app.nDifficultyLevel == 0) xDeltaFireTime += (fix) (F1_0 / 2 * gameStates.gameplay.slowmo [0].fSpeed); if (IsMultiGame) // slow down rate of fire in multi player xDeltaFireTime *= 2; rStatP->nNextFireTime = xDeltaFireTime; } } else rStatP->nNextFireTime -= gameData.physics.xTime; }
// ----------------------------------------------------------------------------------------------------------- // Return true if door can be flown through by a suitable nType robot. // Brains, avoid robots, companions can open doors. // objP == NULL means treat as buddy. int AIDoorIsOpenable (CObject *objP, CSegment *segP, short nSide) { CWall *wallP; if (!IS_CHILD (segP->m_children [nSide])) return 0; //trap -2 (exit CSide) if (!(wallP = segP->Wall (nSide))) return 1; //d:\temp\dm_testthen say it can't be opened // The mighty console CObject can open all doors (for purposes of determining paths). if (objP == gameData.objs.consoleP) { if (wallP->nType == WALL_DOOR) return 1; } if ((objP == NULL) || (ROBOTINFO (objP->info.nId).companion == 1)) { int ailp_mode; if (wallP->flags & WALL_BUDDY_PROOF) { if ((wallP->nType == WALL_DOOR) && (wallP->state == WALL_DOOR_CLOSED)) return 0; else if (wallP->nType == WALL_CLOSED) return 0; else if ((wallP->nType == WALL_ILLUSION) && !(wallP->flags & WALL_ILLUSION_OFF)) return 0; } if (wallP->keys != KEY_NONE) { if (wallP->keys == KEY_BLUE) return (LOCALPLAYER.flags & PLAYER_FLAGS_BLUE_KEY); else if (wallP->keys == KEY_GOLD) return (LOCALPLAYER.flags & PLAYER_FLAGS_GOLD_KEY); else if (wallP->keys == KEY_RED) return (LOCALPLAYER.flags & PLAYER_FLAGS_RED_KEY); } if (wallP->nType == WALL_CLOSED) return 0; if (wallP->nType != WALL_DOOR) /*&& (wallP->nType != WALL_CLOSED))*/ return 1; // If Buddy is returning to CPlayerData, don't let him think he can get through triggered doors. // It's only valid to think that if the CPlayerData is going to get him through. But if he's // going to the CPlayerData, the CPlayerData is probably on the opposite CSide. if (objP) ailp_mode = gameData.ai.localInfo [objP->Index ()].mode; else if (gameData.escort.nObjNum >= 0) ailp_mode = gameData.ai.localInfo [gameData.escort.nObjNum].mode; else ailp_mode = 0; // -- if (Buddy_got_stuck) { if (ailp_mode == AIM_GOTO_PLAYER) { if ((wallP->nType == WALL_BLASTABLE) && (wallP->state != WALL_BLASTED)) return 0; if (wallP->nType == WALL_CLOSED) return 0; if (wallP->nType == WALL_DOOR) { if ((wallP->flags & WALL_DOOR_LOCKED) && (wallP->state == WALL_DOOR_CLOSED)) return 0; } } // -- } if ((ailp_mode != AIM_GOTO_PLAYER) && (wallP->controllingTrigger != -1)) { int nClip = wallP->nClip; if (nClip == -1) return 1; else if (gameData.walls.animP [nClip].flags & WCF_HIDDEN) { if (wallP->state == WALL_DOOR_CLOSED) return 0; else return 1; } else return 1; } if (wallP->nType == WALL_DOOR) { if (wallP->nType == WALL_BLASTABLE) return 1; else { int nClip = wallP->nClip; if (nClip == -1) return 1; // Buddy allowed to go through secret doors to get to player. else if ((ailp_mode != AIM_GOTO_PLAYER) && (gameData.walls.animP [nClip].flags & WCF_HIDDEN)) { if (wallP->state == WALL_DOOR_CLOSED) return 0; else return 1; } else return 1; } } } else if ((objP->info.nId == ROBOT_BRAIN) || (objP->cType.aiInfo.behavior == AIB_RUN_FROM) || (objP->cType.aiInfo.behavior == AIB_SNIPE)) { if (wallP) { if ((wallP->nType == WALL_DOOR) && (wallP->keys == KEY_NONE) && !(wallP->flags & WALL_DOOR_LOCKED)) return 1; else if (wallP->keys != KEY_NONE) { // Allow bots to open doors to which CPlayerData has keys. if (wallP->keys & LOCALPLAYER.flags) return 1; } } } return 0; }