/* * Portions of this file are copyright Rebirth contributors and licensed as * described in COPYING.txt. * Portions of this file are copyright Parallax Software and licensed * according to the Parallax license below. * See COPYING.txt for license details. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Created from version 1.11 of main\wall.c * */ #include #include #include #include #include "wall.h" #include "editor/medwall.h" #include "inferno.h" #include "editor/editor.h" #include "editor/esegment.h" #include "segment.h" #include "dxxerror.h" #include "event.h" #include "gameseg.h" #include "textures.h" #include "screens.h" #include "switch.h" #include "editor/eswitch.h" #include "texmerge.h" #include "medrobot.h" #include "timer.h" #include "cntrlcen.h" #include "key.h" #include "ehostage.h" #include "centers.h" #include "piggy.h" #include "kdefs.h" #include "u_mem.h" #include "compiler-exchange.h" #include "compiler-make_unique.h" #include "compiler-range_for.h" #include "highest_valid.h" #include "partial_range.h" static int wall_add_to_side(const vsegptridx_t segp, int side, sbyte type); //------------------------------------------------------------------------- // Variables for this module... //------------------------------------------------------------------------- static UI_DIALOG *MainWindow = NULL; namespace { struct wall_dialog { std::unique_ptr wallViewBox; std::unique_ptr quitButton; array, 3> doorFlag; array, 4> keyFlag; int old_wall_num; fix64 time; int framenum; }; static int Current_door_type=1; struct count_wall { short wallnum; segnum_t segnum; short sidenum; }; } static int wall_dialog_handler(UI_DIALOG *dlg,const d_event &event, wall_dialog *wd); //--------------------------------------------------------------------- // Add a wall (removable 2 sided) static int add_wall(const vsegptridx_t seg, short side) { if (Num_walls < MAX_WALLS-2) if (IS_CHILD(seg->children[side])) { if (seg->sides[side].wall_num == wall_none) { seg->sides[side].wall_num = Num_walls; Num_walls++; } auto csegp = vsegptridx(seg->children[side]); auto Connectside = find_connect_side(seg, csegp); if (csegp->sides[Connectside].wall_num == wall_none) { 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; } static int wall_assign_door(int door_type) { if (Cursegp->sides[Curside].wall_num == wall_none) { editor_status("Cannot assign door. No wall at Curside."); return 0; } if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR && Walls[Cursegp->sides[Curside].wall_num].type != WALL_BLASTABLE) { editor_status("Cannot assign door. No door at Curside."); return 0; } Current_door_type = door_type; const auto &&csegp = vsegptr(Cursegp->children[Curside]); auto Connectside = find_connect_side(Cursegp, csegp); Walls[Cursegp->sides[Curside].wall_num].clip_num = door_type; Walls[csegp->sides[Connectside].wall_num].clip_num = door_type; if (WallAnims[door_type].flags & WCF_TMAP1) { Cursegp->sides[Curside].tmap_num = WallAnims[door_type].frames[0]; csegp->sides[Connectside].tmap_num = WallAnims[door_type].frames[0]; Cursegp->sides[Curside].tmap_num2 = 0; csegp->sides[Connectside].tmap_num2 = 0; } else { Cursegp->sides[Curside].tmap_num2 = WallAnims[door_type].frames[0]; csegp->sides[Connectside].tmap_num2 = WallAnims[door_type].frames[0]; } Update_flags |= UF_WORLD_CHANGED; return 1; } int wall_add_blastable() { return wall_add_to_side(Cursegp, Curside, WALL_BLASTABLE); } int wall_add_door() { return wall_add_to_side(Cursegp, Curside, WALL_DOOR); } int wall_add_closed_wall() { return wall_add_to_side(Cursegp, Curside, WALL_CLOSED); } int wall_add_external_wall() { if (Cursegp->children[Curside] == segment_exit) { 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 wall_add_illusion() { return wall_add_to_side(Cursegp, Curside, WALL_ILLUSION); } static int GotoPrevWall() { int current_wall; if (Cursegp->sides[Curside].wall_num == wall_none) current_wall = Num_walls; else current_wall = Cursegp->sides[Curside].wall_num; current_wall--; if (current_wall < 0) current_wall = Num_walls-1; if (current_wall >= Num_walls) current_wall = Num_walls-1; if (Walls[current_wall].segnum == segment_none) { return 0; } if (Walls[current_wall].sidenum == side_none) { return 0; } Cursegp = segptridx(Walls[current_wall].segnum); Curside = Walls[current_wall].sidenum; return 1; } static int GotoNextWall() { int current_wall; current_wall = Cursegp->sides[Curside].wall_num; // It's ok to be -1 because it will immediately become 0 current_wall++; if (current_wall >= Num_walls) current_wall = 0; if (current_wall < 0) current_wall = 0; if (Walls[current_wall].segnum == segment_none) { return 0; } if (Walls[current_wall].sidenum == side_none) { return 0; } Cursegp = segptridx(Walls[current_wall].segnum); Curside = Walls[current_wall].sidenum; return 1; } static int PrevWall() { int wall_type; if (Cursegp->sides[Curside].wall_num == wall_none) { editor_status("Cannot assign new wall. No wall on curside."); return 0; } wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num; if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) { do { wall_type--; if (wall_type < 0) wall_type = Num_wall_anims-1; if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num) Error("Cannot find clip for door."); } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE); } else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) { do { wall_type--; if (wall_type < 0) wall_type = Num_wall_anims-1; if (wall_type == Walls[Cursegp->sides[Curside].wall_num].clip_num) Error("Cannot find clip for blastable wall."); } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE)); } wall_assign_door(wall_type); Update_flags |= UF_WORLD_CHANGED; return 1; } static int NextWall() { int wall_type; if (Cursegp->sides[Curside].wall_num == wall_none) { editor_status("Cannot assign new wall. No wall on curside."); return 0; } wall_type = Walls[Cursegp->sides[Curside].wall_num].clip_num; if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) { do { wall_type++; if (wall_type >= Num_wall_anims) { wall_type = 0; if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1) Error("Cannot find clip for door."); } } while (WallAnims[wall_type].num_frames == -1 || WallAnims[wall_type].flags & WCF_BLASTABLE); } else if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_BLASTABLE) { do { wall_type++; if (wall_type >= Num_wall_anims) { wall_type = 0; if (Walls[Cursegp->sides[Curside].wall_num].clip_num==-1) Error("Cannot find clip for blastable wall."); } } while (WallAnims[wall_type].num_frames == -1 || !(WallAnims[wall_type].flags & WCF_BLASTABLE)); } wall_assign_door(wall_type); Update_flags |= UF_WORLD_CHANGED; return 1; } //------------------------------------------------------------------------- // Called from the editor... does one instance of the wall dialog box //------------------------------------------------------------------------- int do_wall_dialog() { // Only open 1 instance of this window... if ( MainWindow != NULL ) return 0; auto wd = make_unique(); wd->framenum = 0; // Close other windows. close_all_windows(); // Open a window with a quit button MainWindow = ui_create_dialog(TMAPBOX_X+20, TMAPBOX_Y+20, 765-TMAPBOX_X, 545-TMAPBOX_Y, DF_DIALOG, wall_dialog_handler, std::move(wd)); return 1; } static int wall_dialog_created(UI_DIALOG *const w, wall_dialog *const wd) { wd->quitButton = ui_add_gadget_button(w, 20, 252, 48, 40, "Done", NULL); // These are the checkboxes for each door flag. int i = 80; wd->doorFlag[0] = ui_add_gadget_checkbox(w, 22, i, 16, 16, 0, "Locked"); i += 24; wd->doorFlag[1] = ui_add_gadget_checkbox(w, 22, i, 16, 16, 0, "Auto"); i += 24; wd->doorFlag[2] = ui_add_gadget_checkbox(w, 22, i, 16, 16, 0, "Illusion OFF"); i += 24; wd->keyFlag[0] = ui_add_gadget_radio(w, 22, i, 16, 16, 0, "NONE"); i += 24; wd->keyFlag[1] = ui_add_gadget_radio(w, 22, i, 16, 16, 0, "Blue"); i += 24; wd->keyFlag[2] = ui_add_gadget_radio(w, 22, i, 16, 16, 0, "Red"); i += 24; wd->keyFlag[3] = ui_add_gadget_radio(w, 22, i, 16, 16, 0, "Yellow"); i += 24; // The little box the wall will appear in. wd->wallViewBox = ui_add_gadget_userbox(w, 155, 5, 64, 64); // A bunch of buttons... i = 80; ui_add_gadget_button(w, 155, i, 70, 22, "<< Clip", PrevWall); ui_add_gadget_button(w, 155+70, i, 70, 22, "Clip >>", NextWall);i += 25; ui_add_gadget_button(w, 155, i, 140, 22, "Add Blastable", wall_add_blastable); i += 25; ui_add_gadget_button(w, 155, i, 140, 22, "Add Door", wall_add_door ); i += 25; ui_add_gadget_button(w, 155, i, 140, 22, "Add Illusory", wall_add_illusion); i += 25; ui_add_gadget_button(w, 155, i, 140, 22, "Add Closed Wall", wall_add_closed_wall); i+=25; ui_add_gadget_button(w, 155, i, 70, 22, "<< Prev", GotoPrevWall); ui_add_gadget_button(w, 155+70, i, 70, 22, "Next >>", GotoNextWall);i += 25; ui_add_gadget_button(w, 155, i, 140, 22, "Remove Wall", wall_remove); i += 25; ui_add_gadget_button(w, 155, i, 140, 22, "Bind to Trigger", bind_wall_to_trigger); i += 25; ui_add_gadget_button(w, 155, i, 140, 22, "Bind to Control", bind_wall_to_control_center); i+=25; wd->old_wall_num = -2; // Set to some dummy value so everything works ok on the first frame. return 1; } void close_wall_window() { if (likely(MainWindow)) ui_close_dialog(exchange(MainWindow, nullptr)); } int wall_dialog_handler(UI_DIALOG *dlg,const d_event &event, wall_dialog *wd) { switch(event.type) { case EVENT_WINDOW_CREATED: return wall_dialog_created(dlg, wd); case EVENT_WINDOW_CLOSE: std::default_delete()(wd); return 0; default: break; } sbyte type; fix DeltaTime; fix64 Temp; int keypress = 0; int rval = 0; if (event.type == EVENT_KEY_COMMAND) keypress = event_key_get(event); Assert(MainWindow != NULL); //------------------------------------------------------------ // Call the ui code.. //------------------------------------------------------------ ui_button_any_drawn = 0; //------------------------------------------------------------ // If we change walls, we need to reset the ui code for all // of the checkboxes that control the wall flags. //------------------------------------------------------------ if (wd->old_wall_num != Cursegp->sides[Curside].wall_num) { if ( Cursegp->sides[Curside].wall_num != wall_none) { wall *w = &Walls[Cursegp->sides[Curside].wall_num]; ui_checkbox_check(wd->doorFlag[0].get(), w->flags & WALL_DOOR_LOCKED); ui_checkbox_check(wd->doorFlag[1].get(), w->flags & WALL_DOOR_AUTO); ui_checkbox_check(wd->doorFlag[2].get(), w->flags & WALL_ILLUSION_OFF); ui_radio_set_value(wd->keyFlag[0].get(), w->keys & KEY_NONE); ui_radio_set_value(wd->keyFlag[1].get(), w->keys & KEY_BLUE); ui_radio_set_value(wd->keyFlag[2].get(), w->keys & KEY_RED); ui_radio_set_value(wd->keyFlag[3].get(), w->keys & KEY_GOLD); } } //------------------------------------------------------------ // If any of the checkboxes that control the wallflags are set, then // update the corresponding wall flag. //------------------------------------------------------------ if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_DOOR) { if (GADGET_PRESSED(wd->doorFlag[0].get())) { if ( wd->doorFlag[0]->flag == 1 ) Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_LOCKED; else Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_LOCKED; rval = 1; } else if (GADGET_PRESSED(wd->doorFlag[1].get())) { if ( wd->doorFlag[1]->flag == 1 ) Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_DOOR_AUTO; else Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_DOOR_AUTO; rval = 1; } //------------------------------------------------------------ // If any of the radio buttons that control the mode are set, then // update the corresponding key. //------------------------------------------------------------ for ( int i=0; i < 4; i++ ) { if (GADGET_PRESSED(wd->keyFlag[i].get())) { Walls[Cursegp->sides[Curside].wall_num].keys = 1<doorFlag, 2u)) ui_checkbox_check(i.get(), 0); range_for (auto &i, wd->keyFlag) ui_radio_set_value(i.get(), 0); } if (Walls[Cursegp->sides[Curside].wall_num].type == WALL_ILLUSION) { if (GADGET_PRESSED(wd->doorFlag[2].get())) { if ( wd->doorFlag[2]->flag == 1 ) Walls[Cursegp->sides[Curside].wall_num].flags |= WALL_ILLUSION_OFF; else Walls[Cursegp->sides[Curside].wall_num].flags &= ~WALL_ILLUSION_OFF; rval = 1; } } else for ( int i=2; i < 3; i++ ) if (wd->doorFlag[i]->flag == 1) { wd->doorFlag[i]->flag = 0; // Tells ui that this button isn't checked wd->doorFlag[i]->status = 1; // Tells ui to redraw button } //------------------------------------------------------------ // Draw the wall in the little 64x64 box //------------------------------------------------------------ if (event.type == EVENT_UI_DIALOG_DRAW) { // A simple frame time counter for animating the walls... Temp = timer_query(); DeltaTime = Temp - wd->time; gr_set_current_canvas( wd->wallViewBox->canvas ); if (Cursegp->sides[Curside].wall_num != wall_none) { type = Walls[Cursegp->sides[Curside].wall_num].type; if ((type == WALL_DOOR) || (type == WALL_BLASTABLE)) { if (DeltaTime > ((F1_0*200)/1000)) { wd->framenum++; wd->time = Temp; } if (wd->framenum >= WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].num_frames) wd->framenum=0; PIGGY_PAGE_IN(Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[wd->framenum]]); gr_ubitmap(GameBitmaps[Textures[WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].frames[wd->framenum]].index]); } else { if (type == WALL_OPEN) gr_clear_canvas( CBLACK ); else { if (Cursegp->sides[Curside].tmap_num2 > 0) gr_ubitmap(texmerge_get_cached_bitmap( Cursegp->sides[Curside].tmap_num, Cursegp->sides[Curside].tmap_num2)); else { PIGGY_PAGE_IN(Textures[Cursegp->sides[Curside].tmap_num]); gr_ubitmap(GameBitmaps[Textures[Cursegp->sides[Curside].tmap_num].index]); } } } } else gr_clear_canvas( CGREY ); } //------------------------------------------------------------ // If anything changes in the ui system, redraw all the text that // identifies this wall. //------------------------------------------------------------ if (event.type == EVENT_UI_DIALOG_DRAW) { if ( Cursegp->sides[Curside].wall_num != wall_none ) { ui_dprintf_at( MainWindow, 12, 6, "Wall: %hi ", static_cast(Cursegp->sides[Curside].wall_num)); switch (Walls[Cursegp->sides[Curside].wall_num].type) { case WALL_NORMAL: ui_dprintf_at( MainWindow, 12, 23, " Type: Normal " ); break; case WALL_BLASTABLE: ui_dprintf_at( MainWindow, 12, 23, " Type: Blastable" ); break; case WALL_DOOR: ui_dprintf_at( MainWindow, 12, 23, " Type: Door " ); ui_dputs_at( MainWindow, 223, 6, &WallAnims[Walls[Cursegp->sides[Curside].wall_num].clip_num].filename[0]); break; case WALL_ILLUSION: ui_dprintf_at( MainWindow, 12, 23, " Type: Illusion " ); break; case WALL_OPEN: ui_dprintf_at( MainWindow, 12, 23, " Type: Open " ); break; case WALL_CLOSED: ui_dprintf_at( MainWindow, 12, 23, " Type: Closed " ); break; default: ui_dprintf_at( MainWindow, 12, 23, " Type: Unknown " ); break; } if (Walls[Cursegp->sides[Curside].wall_num].type != WALL_DOOR) ui_dprintf_at( MainWindow, 223, 6, " " ); ui_dprintf_at( MainWindow, 12, 40, " Clip: %d ", Walls[Cursegp->sides[Curside].wall_num].clip_num ); ui_dprintf_at( MainWindow, 12, 57, " Trigger: %d ", Walls[Cursegp->sides[Curside].wall_num].trigger ); } else { ui_dprintf_at( MainWindow, 12, 6, "Wall: none "); ui_dprintf_at( MainWindow, 12, 23, " Type: none "); ui_dprintf_at( MainWindow, 12, 40, " Clip: none "); ui_dprintf_at( MainWindow, 12, 57, " Trigger: none "); } } if (ui_button_any_drawn || (wd->old_wall_num != Cursegp->sides[Curside].wall_num) ) Update_flags |= UF_WORLD_CHANGED; if (GADGET_PRESSED(wd->quitButton.get()) || keypress == KEY_ESC) { close_wall_window(); return 1; } wd->old_wall_num = Cursegp->sides[Curside].wall_num; return rval; } //--------------------------------------------------------------------- // Restore all walls to original status (closed doors, repaired walls) int wall_restore_all() { range_for (auto &w, partial_range(Walls, Num_walls)) { if (w.flags & WALL_BLASTED) { w.hps = WALL_HPS; w.flags &= ~WALL_BLASTED; } if (w.flags & WALL_DOOR_OPENED) w.flags &= ~WALL_DOOR_OPENED; if (w.flags & WALL_DOOR_OPENING) w.flags &= ~WALL_DOOR_OPENING; } for (int i=0;ichildren[side]) && IS_CHILD(seg->sides[side].wall_num)) { const auto &&csegp = vsegptr(seg->children[side]); auto 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 != wall_none) Walls[Walls[lower_wallnum].linked_wall].linked_wall = wall_none; if (Walls[lower_wallnum+1].linked_wall != wall_none) Walls[Walls[lower_wallnum+1].linked_wall].linked_wall = wall_none; for (int w=lower_wallnum;w(s)); if (segp->segnum != segment_none) for (int w=0;wsides[w].wall_num > lower_wallnum+1) segp->sides[w].wall_num -= 2; } // Destroy any links to the deleted wall. range_for (auto &t, partial_range(Triggers, Num_triggers)) for (int l=0;l < t.num_links;l++) if (t.seg[l] == seg && t.side[l] == side) { for (int t1=0;t1 < t.num_links-1;t1++) { t.seg[t1] = t.seg[t1+1]; t.side[t1] = t.side[t1+1]; } t.num_links--; } // Destroy control center links as well. for (int l=0;lsides[side].wall_num = wall_none; csegp->sides[Connectside].wall_num = wall_none; Update_flags |= UF_WORLD_CHANGED; return 1; } editor_status( "Can't remove wall. No wall present."); return 0; } //--------------------------------------------------------------------- // Remove a special wall. int wall_remove() { return wall_remove_side(Cursegp, Curside); } //--------------------------------------------------------------------- // Add a wall to curside static int wall_add_to_side(const vsegptridx_t segp, int side, sbyte type) { if (add_wall(segp, side)) { auto csegp = vsegptridx(segp->children[side]); auto connectside = find_connect_side(segp, csegp); Walls[segp->sides[side].wall_num].segnum = segp; Walls[csegp->sides[connectside].wall_num].segnum = csegp; Walls[segp->sides[side].wall_num].sidenum = side; Walls[csegp->sides[connectside].wall_num].sidenum = connectside; Walls[segp->sides[side].wall_num].flags = 0; Walls[csegp->sides[connectside].wall_num].flags = 0; Walls[segp->sides[side].wall_num].type = type; Walls[csegp->sides[connectside].wall_num].type = type; // Walls[segp->sides[side].wall_num].trigger = -1; // Walls[csegp->sides[connectside].wall_num].trigger = -1; Walls[segp->sides[side].wall_num].clip_num = -1; Walls[csegp->sides[connectside].wall_num].clip_num = -1; Walls[segp->sides[side].wall_num].keys = KEY_NONE; Walls[csegp->sides[connectside].wall_num].keys = KEY_NONE; if (type == WALL_BLASTABLE) { Walls[segp->sides[side].wall_num].hps = WALL_HPS; Walls[csegp->sides[connectside].wall_num].hps = WALL_HPS; //Walls[segp->sides[side].wall_num].clip_num = 0; //Walls[csegp->sides[connectside].wall_num].clip_num = 0; } if (type != WALL_DOOR) { segp->sides[side].tmap_num2 = 0; csegp->sides[connectside].tmap_num2 = 0; } if (type == WALL_DOOR) { Walls[segp->sides[side].wall_num].flags |= WALL_DOOR_AUTO; Walls[csegp->sides[connectside].wall_num].flags |= WALL_DOOR_AUTO; Walls[segp->sides[side].wall_num].clip_num = Current_door_type; Walls[csegp->sides[connectside].wall_num].clip_num = Current_door_type; } //Update_flags |= UF_WORLD_CHANGED; //return 1; // return NextWall(); //assign a clip num return wall_assign_door(Current_door_type); } else { editor_status( "Cannot add wall here, no children" ); return 0; } } //--------------------------------------------------------------------- // Add a wall to markedside int wall_add_to_markedside(sbyte type) { if (add_wall(Markedsegp, Markedside)) { int wall_num, cwall_num; const auto &&csegp = vsegptridx(Markedsegp->children[Markedside]); auto Connectside = find_connect_side(Markedsegp, csegp); wall_num = Markedsegp->sides[Markedside].wall_num; cwall_num = csegp->sides[Connectside].wall_num; Walls[wall_num].segnum = Markedsegp; Walls[cwall_num].segnum = csegp; Walls[wall_num].sidenum = Markedside; Walls[cwall_num].sidenum = Connectside; Walls[wall_num].flags = 0; Walls[cwall_num].flags = 0; Walls[wall_num].type = type; Walls[cwall_num].type = type; Walls[wall_num].trigger = trigger_none; Walls[cwall_num].trigger = trigger_none; Walls[wall_num].clip_num = -1; Walls[cwall_num].clip_num = -1; Walls[wall_num].keys = KEY_NONE; Walls[cwall_num].keys = KEY_NONE; if (type == WALL_BLASTABLE) { Walls[wall_num].hps = WALL_HPS; Walls[cwall_num].hps = WALL_HPS; Walls[wall_num].clip_num = 0; Walls[cwall_num].clip_num = 0; } if (type != WALL_DOOR) { Markedsegp->sides[Markedside].tmap_num2 = 0; csegp->sides[Connectside].tmap_num2 = 0; } Update_flags |= UF_WORLD_CHANGED; return 1; } else { editor_status( "Cannot add wall here, no children" ); return 0; } } int bind_wall_to_control_center() { int link_num; if (Cursegp->sides[Curside].wall_num == wall_none) { editor_status("No wall at Curside."); return 0; } link_num = ControlCenterTriggers.num_links; for (int i=0;isides[Curside].wall_num != wall_none) w1 = &Walls[Cursegp->sides[Curside].wall_num]; if (Markedsegp->sides[Markedside].wall_num != wall_none) w2 = &Walls[Markedsegp->sides[Markedside].wall_num]; if (!w1 || w1->type != WALL_DOOR) { editor_status("Curseg/curside is not a door"); return 0; } if (!w2 || w2->type != WALL_DOOR) { editor_status("Markedseg/markedside is not a door"); return 0; } if (w1->linked_wall != wall_none) editor_status("Curseg/curside is already linked"); if (w2->linked_wall != wall_none) editor_status("Markedseg/markedside is already linked"); w1->linked_wall = Markedsegp->sides[Markedside].wall_num; w2->linked_wall = Cursegp->sides[Curside].wall_num; return 1; } int wall_unlink_door() { wall *w1=NULL; if (Cursegp->sides[Curside].wall_num != wall_none) w1 = &Walls[Cursegp->sides[Curside].wall_num]; if (!w1 || w1->type != WALL_DOOR) { editor_status("Curseg/curside is not a door"); return 0; } if (w1->linked_wall == wall_none) editor_status("Curseg/curside is not linked"); Assert(Walls[w1->linked_wall].linked_wall == w1-Walls); Walls[w1->linked_wall].linked_wall = wall_none; w1->linked_wall = wall_none; return 1; } #define DIAGNOSTIC_MESSAGE_MAX 150 int check_walls() { int wall_count, trigger_count; count_wall CountedWalls[MAX_WALLS]; char Message[DIAGNOSTIC_MESSAGE_MAX]; int matcen_num; wall_count = 0; range_for (const auto seg, highest_valid(Segments)) { const auto &&segp = vsegptr(static_cast(seg)); if (segp->segnum != segment_none) { // Check fuelcenters matcen_num = segp->matcen_num; if (matcen_num == 0) if (RobotCenters[0].segnum != seg) { segp->matcen_num = -1; } if (matcen_num > -1) if (RobotCenters[matcen_num].segnum != seg) { RobotCenters[matcen_num].segnum = seg; } for (int side=0;sidesides[side].wall_num != wall_none) { CountedWalls[wall_count].wallnum = segp->sides[side].wall_num; CountedWalls[wall_count].segnum = seg; CountedWalls[wall_count].sidenum = side; wall_count++; } } } if (wall_count != Num_walls) { sprintf( Message, "Num_walls is bogus\nDo you wish to correct it?\n"); if (ui_messagebox( -2, -2, 2, Message, "Yes", "No" )==1) { Num_walls = wall_count; editor_status_fmt("Num_walls set to %d\n", Num_walls); } } // Check validity of Walls array. for (int w=0; w(seg)); for (int side=0;sidesides[side].wall_num = wall_none; } Num_walls=0; Num_triggers=0; return 1; } return 0; } // ------------------------------------------------------------------------------------------------ static void copy_old_wall_data_to_new(int owall, int nwall) { Walls[nwall].flags = Walls[owall].flags; Walls[nwall].type = Walls[owall].type; Walls[nwall].clip_num = Walls[owall].clip_num; Walls[nwall].keys = Walls[owall].keys; Walls[nwall].hps = Walls[owall].hps; Walls[nwall].state = Walls[owall].state; Walls[nwall].linked_wall = wall_none; Walls[nwall].trigger = trigger_none; if (Walls[owall].trigger != trigger_none) { editor_status("Warning: Trigger not copied in group copy."); } } //typedef struct trigger { // sbyte type; // short flags; // fix value; // fix time; // sbyte link_num; // short num_links; // short seg[MAX_WALLS_PER_LINK]; // short side[MAX_WALLS_PER_LINK]; // } trigger; // ------------------------------------------------------------------------------------------------ void copy_group_walls(int old_group, int new_group) { group::segment_array_type_t::const_iterator bo = GroupList[old_group].segments.begin(); group::segment_array_type_t::const_iterator bn = GroupList[new_group].segments.begin(); group::segment_array_type_t::const_iterator eo = GroupList[old_group].segments.end(); int old_seg, new_seg; for (; bo != eo; ++bo, ++bn) { old_seg = *bo; new_seg = *bn; for (int j=0; j(i)); if (segp->segnum != segment_none) for (int j=0; jsides[j].wall_num; if (wall_num != wall_none) { if (wall_flags[wall_num] != 0) { if (!Validate_walls) return; Int3(); // Error! Your mine has been invalidated! // Do not continue! Do not save! // Remember your last action and Contact Mike! // To continue, set the variable Validate_walls to 1 by doing: // /Validate_walls = 1 // Then do the usual /eip++;g } if ((Walls[wall_num].segnum != i) || (Walls[wall_num].sidenum != j)) { if (!Validate_walls) return; Int3(); // Error! Your mine has been invalidated! // Do not continue! Do not save! // Remember your last action and Contact Mike! // To continue, set the variable Validate_walls to 1 by doing: // /Validate_walls = 1 // Then do the usual /eip++;g } wall_flags[wall_num] = 1; } } } }