/* * Descent 3 * Copyright (C) 2024 Parallax Software * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . --- HISTORICAL COMMENTS FOLLOW --- * $Logfile: /DescentIII/Main/editor/ObjectDialog.cpp $ * $Revision: 1.1.1.1 $ * $Date: 2003-08-26 03:57:38 $ * $Author: kevinb $ * * Object keypad dialog * * $Log: not supported by cvs2svn $ * * 46 5/08/99 1:39a Matt * Added a function to delete all objects of a certain type, and support * for placing and attaching groups to the terrain. * * 45 4/05/99 3:34p Matt * Cleaned up player start flags * * 44 4/02/99 12:58p Chris * Change object now preserves names * * 43 3/27/99 12:52p Chris * The editor object placement code now allows objects to be pushed into * wall (when a toggle box is checked) * * 42 2/18/99 2:09p Luke * Checking in for Matt * * 41 2/05/99 1:25p Matt * Show more info on the status line when an object is selected * * 40 2/03/99 1:58a Matt * Fixed small bug * * 39 2/03/99 1:20a Matt * Made the object combo box on the object tab sort, and replaced the * listbox of pictures with a big picture of the current item. * * 38 1/27/99 11:03a Samir * added rotate 90 button to object dialog. * * 37 1/19/99 6:53p Matt * Fixed a problem when the viewer was instantaneously moved from inside * to ourside or vise-versa. * * 36 1/15/99 7:52p Chris * Updated ObjSetPos() to include a f_update_attach_children flag * * 35 10/22/98 11:01a Chris * Added object regrounding * * 34 10/08/98 7:17p Chris * Added object swap types * * 33 8/24/98 12:24p Jason * added waypoints and player start position flags * * 32 6/15/98 4:00p Jason * replaced monochromatic polymodel lighting with rgb lighting * * 31 5/18/98 2:56p Matt * Added code to readjust all ground object (for after the terrain has * moved). * * 30 5/06/98 4:02p Sean * * 29 5/06/98 1:55p Sean * * 28 5/06/98 1:49p Sean * fixed dumb bug with my last rev * * 27 5/06/98 12:34p Jason * Added next object in terrain stuff * * 26 4/02/98 3:54p Jason * first pass in getting polymodel paging to work * * 25 3/30/98 6:20p Matt * Renamed ResetObject() to be ObjReInitAll() * * 24 2/24/98 11:19a Samir * objects should look better in listbox. * * 23 2/05/98 11:25a Samir * Maybe this will work to fix ListNextItem problems. * * 22 1/30/98 6:05p Matt * Got Next Object in object keypad working, and made a routine to set the * current editor object. * * 21 1/18/98 9:07p Matt * New parms for ResetObjects() * * 20 1/07/98 6:39p Jason * Fixed player object number stuff * * 19 12/19/97 11:26a Samir * Oops. * * 18 12/19/97 11:25a Samir * g3_StartFrame and g3_EndFrame replaced by EditorStartFrame and * EditorEndFrame * * 17 12/01/97 3:20p Samir * No Int3 when trying to place objects outside the mine. * * 16 9/17/97 1:26p Samir * BIG SEGMENT RIPOUT * * 15 9/15/97 11:55a Samir * Fixed playership adding. * * 14 9/02/97 3:02p Samir * fixed bug. accidentally set wrong variable for axis movement. * * 13 8/29/97 2:49p Samir * Added new object movement features. * * 12 8/25/97 7:39p Samir * Using new GrListBox from old editorPictListBox * * 11 8/18/97 12:09p Matt * Fixed a stupid bug, and added some error checking and handling * * 10 8/13/97 9:50a Matt * Changed highlighted object to draw with magenta box around it * * 9 8/12/97 10:57p Matt * Made object page work for the generic object types (robot, powerup, * building, clutter) * * 8 8/11/97 1:53p Matt * Ripped out robot & powerup pages, and added generic page * * 7 8/06/97 11:11a Mark * Took out Int3 for 'untested' draw code in DrawItem. - Samir * * 6 7/24/97 7:18p Matt * Cleaned up code that draws robots & powerups * * 5 7/24/97 6:11p Matt * Created symbolic constant for default zoom, and used it every place * that specifies zoom * * 4 7/24/97 4:21p Matt * On object keypad, only list this object types the the designer can * place * * 3 7/24/97 2:54p Matt * Got rid of some member variables that kept track of current robot, * powerup, & object type, and used variables in D3EditState instead. * * 2 7/22/97 7:08p Matt * Cleaned up D3EditState, moving some vars in and some out, and renaming * and changing a few others * * 35 6/04/97 11:56a Samir * Added PowerupProp Dialog. * * 34 6/03/97 4:55p Mark * * 34 6/03/97 4:50p Jeff * added Context Sensitive Help * * 33 5/01/97 12:33p Jason * added reset objects function * * 32 5/01/97 11:16a Samir * No Int3 in Object type selection * * 26 4/02/97 6:25p Samir * Fixed screwup with decrease heading function. * * 25 4/02/97 12:22p Samir * Fixed object box scroll problems by keeping an array of item starts for * each obj_type and fixed problem of placing a bad robot (door) when * first placing objects. * * 14 3/13/97 6:17p Jason * changed door/polymodel prototype * * 13 3/03/97 5:56p Jason * changed function name to be more generic * GetPowerupBitmap -> GetPowerupImage * * 12 2/26/97 3:35p Mark * * 11 2/25/97 4:35p Samir * Selecting from combo box sets pictoral list box selection. * * 10 2/21/97 6:25p Samir * Object palette works (shitty scaling of powerups.) * * 9 2/20/97 4:26p Mark * * 8 2/19/97 5:26p Samir * When setting focus on objID listbox, update its contents. * * 7 2/19/97 2:16p Samir * Added RunKeypadFunction handler. * * 6 2/18/97 12:47p Samir * Able to select object types and ids from keypad. * * 5 2/17/97 6:19p Samir * Added place object and move left,right,for, back functionality. * * 4 1/27/97 11:38a Samir * Added horizontal scrolling of keypad modeless dialog. * * $NoKeywords: $ */ #include "stdafx.h" #include "editor.h" #include "ObjectDialog.h" #include "ObjMoveManager.h" #include "HObject.h" #include "polymodel.h" #include "object.h" #include "ship.h" #include "objinfo.h" #include "multi.h" #include "objinit.h" #include "room.h" #include "d3edit.h" #include "physics.h" #include "door.h" #include "mem.h" #include "PowerupPropDialog.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// //List of object types & names for the editor int edit_object_types[] = { OBJ_ROBOT, OBJ_POWERUP, OBJ_BUILDING, OBJ_CLUTTER, OBJ_PLAYER }; char *edit_objtype_names[] = { "Robot","Powerup","Building","Clutter","Player ship" }; int Swap_source_id = -1; int Swap_dest_id = -1; int Reground_id = -1; bool f_allow_objects_to_be_pushed_through_walls = false; void DrawItemModel(grHardwareSurface *surf,int model_num); #define NUM_EDIT_OBJTYPES (sizeof(edit_object_types) / sizeof(*edit_object_types)) ///////////////////////////////////////////////////////////////////////////// // CObjectDialog dialog CObjectDialog::CObjectDialog(CWnd* pParent /*=NULL*/) : CKeypadDialog(CObjectDialog::IDD, pParent) { //{{AFX_DATA_INIT(CObjectDialog) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT } void CObjectDialog::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CObjectDialog) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } void CObjectDialog::UpdateIDList() { InitObjIDComboBox((CComboBox *)GetDlgItem(IDC_COMBO_OBJID)); } void CObjectDialog::PlaceObject() { OnObjectPlaceObject(); } void CObjectDialog::DeleteObject() { OnObjPadDelobj(); } BEGIN_MESSAGE_MAP(CObjectDialog, CDialog) //{{AFX_MSG_MAP(CObjectDialog) ON_WM_SIZE() ON_WM_VSCROLL() ON_WM_HSCROLL() ON_BN_CLICKED(IDC_OBJPAD_PLACEOBJ, OnObjectPlaceObject) ON_CBN_SELCHANGE(IDC_COMBO_OBJTYPE, OnSelchangeComboObjType) ON_CBN_SELCHANGE(IDC_COMBO_OBJID, OnSelchangeComboObjID) ON_BN_CLICKED(IDC_OBJ_DELOBJ, OnObjPadDelobj) ON_BN_CLICKED(IDC_OBJPAD_NEXTOBJ, OnObjpadNextobj) ON_CBN_SETFOCUS(IDC_COMBO_OBJID, OnSetfocusComboObjID) ON_BN_CLICKED(IDC_OBJECTPAD_GROUP, OnObjectpadGroup) ON_BN_CLICKED(IDC_OBJ_CONT_PREVIEW, OnObjContPreview) ON_WM_PAINT() ON_WM_LBUTTONDOWN() ON_BN_CLICKED(IDC_OBJPAD_FLAGOBJMULTI, OnObjpadFlagobjmulti) ON_BN_CLICKED(IDC_OBJPAD_FLIPOBJ, OnObjpadFlipobj) ON_BN_CLICKED(IDC_OBJPAD_SETDEFAULT, OnObjpadSetdefault) ON_WM_DESTROY() ON_BN_CLICKED(IDC_RESET_OBJECTS, OnResetObjects) ON_WM_HELPINFO() ON_BN_CLICKED(IDC_OBJPAD_PROPERTIES, OnObjpadProperties) ON_CBN_SELCHANGE(IDC_COORDSYS_SELECT, OnSelChangeCoordSysSelect) ON_BN_CLICKED(IDC_OBJMOVEX, OnObjmoveX) ON_BN_CLICKED(IDC_OBJMOVEY, OnObjmoveY) ON_BN_CLICKED(IDC_OBJMOVEXY, OnObjmoveXY) ON_BN_CLICKED(IDC_OBJMOVEZ, OnObjmoveZ) ON_BN_CLICKED(IDC_OBJMOVEP, OnObjmoveP) ON_BN_CLICKED(IDC_OBJMOVEH, OnObjmoveH) ON_BN_CLICKED(IDC_OBJMOVEB, OnObjmoveB) ON_BN_CLICKED(IDC_OBJMOVEPH, OnObjmovePH) ON_BN_CLICKED(IDC_OBJPAD_RESET_ALL_OBJ_HEIGHTS, OnObjpadResetAllObjHeights) ON_BN_CLICKED(IDC_OBJPAD_RESET_CUROBJ_HEIGHT, OnObjpadResetCurobjHeight) ON_BN_CLICKED(IDC_PREV_START_POSITON, OnPrevStartPositon) ON_BN_CLICKED(IDC_NEXT_START_POS, OnNextStartPos) ON_BN_CLICKED(IDC_JUMP_TO_START_POS, OnJumpToStartPos) ON_BN_CLICKED(IDC_RED_CHECK, OnRedCheck) ON_BN_CLICKED(IDC_BLUE_CHECK, OnBlueCheck) ON_BN_CLICKED(IDC_GREEN_CHECK, OnGreenCheck) ON_BN_CLICKED(IDC_YELLOW_CHECK, OnYellowCheck) ON_CBN_SELENDOK(IDC_SWAP_SOURCE_COMBO, OnSelendokSwapSourceCombo) ON_CBN_SELENDOK(IDC_SWAP_DEST_COMBO, OnSelendokSwapDestCombo) ON_BN_CLICKED(IDC_OBJECT_SWAP_BUTTON, OnObjectSwapButton) ON_CBN_SELENDOK(IDC_REGROUND_COMBO, OnSelendokRegroundCombo) ON_BN_CLICKED(IDC_REGROUND_BUTTON, OnRegroundButton) ON_BN_CLICKED(IDC_OBJ_ROT90, OnObjRot90) ON_BN_CLICKED(IDC_OBJECT_PUSHTHROUGHWALLS, OnObjectPushthroughwalls) ON_BN_CLICKED(IDC_OBJPAD_DELETEALL, OnObjpadDeleteAll) //}}AFX_MSG_MAP END_MESSAGE_MAP() //Current player isn't saved, so just keep it locally int current_player = 0; //Sets the current index of the given type void SetCurrentIndex(int index) { switch (D3EditState.current_obj_type) { case OBJ_ROBOT: D3EditState.current_robot = index; break; case OBJ_POWERUP: D3EditState.current_powerup = index; break; case OBJ_CLUTTER: D3EditState.current_clutter = index; break; case OBJ_BUILDING: D3EditState.current_building = index; break; case OBJ_PLAYER: current_player = index; break; default: Int3(); } } //Returns the current index of the given type int GetCurrentIndex() { int type = D3EditState.current_obj_type; int current; switch (type) { case OBJ_ROBOT: current = D3EditState.current_robot; break; case OBJ_POWERUP: current = D3EditState.current_powerup; break; case OBJ_CLUTTER: current = D3EditState.current_clutter; break; case OBJ_BUILDING: current = D3EditState.current_building; break; case OBJ_PLAYER: return current_player; break; default: Int3(); } if (Object_info[current].type != type) { //current is of wrong type current = GetObjectID(type); //...so get a new current SetCurrentIndex(current); } return current; } ///////////////////////////////////////////////////////////////////////////// // CObjectDialog message handlers void CObjectDialog::InitObjIDComboBox(CComboBox *box) { int i,first,n; box->ResetContent(); //Add names of object IDs of current object type switch (D3EditState.current_obj_type) { case OBJ_ROBOT: case OBJ_POWERUP: case OBJ_CLUTTER: case OBJ_BUILDING: first = GetObjectID(D3EditState.current_obj_type); if (first == -1) break; if (GetCurrentIndex() == -1) SetCurrentIndex(first); n = first; do { int index = box->AddString(Object_info[n].name); box->SetItemData(index,n); if (n == GetCurrentIndex()) box->SetCurSel(index); n = GetNextObjectID(n); } while (n != first); break; case OBJ_PLAYER: for (i = 0; i < MAX_SHIPS; i++) { if (Ships[i].used) { int index = box->AddString(Ships[i].name); box->SetItemData(index,i); if (i == D3EditState.current_ship) box->SetCurSel(index); } } break; } } void CObjectDialog::InitObjTypeComboBox(CComboBox *box) { box->ResetContent(); for (int i = 0; i < NUM_EDIT_OBJTYPES; i++) { if (box->AddString(edit_objtype_names[i]) < 0) Int3(); if (edit_object_types[i] == D3EditState.current_obj_type) box->SetCurSel(i); } } BOOL CObjectDialog::OnInitDialog() { CComboBox *box; int current; CDialog::OnInitDialog(); //Init types combo box InitObjTypeComboBox((CComboBox *)GetDlgItem(IDC_COMBO_OBJTYPE)); //Init IDs combo box InitObjIDComboBox((CComboBox *)GetDlgItem(IDC_COMBO_OBJID)); //Get index of current item current = GetCurrentIndex(); ASSERT(current != -1); // set selection in object movement combobox and move axis. box = (CComboBox *)GetDlgItem(IDC_COORDSYS_SELECT); if (D3EditState.object_move_mode == REL_OBJECT) box->SelectString(-1,"Local"); else if (D3EditState.object_move_mode == REL_VIEWER) box->SelectString(-1,"Viewer"); else { D3EditState.object_move_mode= REL_OBJECT; box->SelectString(-1,"Local"); } ObjMoveManager.SetMoveAxis(D3EditState.object_move_axis); CButton *btn = NULL; switch (D3EditState.object_move_axis) { case OBJMOVEAXIS_X: btn = (CButton*)GetDlgItem(IDC_OBJMOVEX); break; case OBJMOVEAXIS_Y: btn = (CButton*)GetDlgItem(IDC_OBJMOVEY); break; case OBJMOVEAXIS_Z: btn = (CButton*)GetDlgItem(IDC_OBJMOVEZ); break; case OBJMOVEAXIS_XY: btn = (CButton*)GetDlgItem(IDC_OBJMOVEXY); break; case OBJMOVEAXIS_P: btn = (CButton*)GetDlgItem(IDC_OBJMOVEP); break; case OBJMOVEAXIS_H: btn = (CButton*)GetDlgItem(IDC_OBJMOVEH); break; case OBJMOVEAXIS_B: btn = (CButton*)GetDlgItem(IDC_OBJMOVEB); break; case OBJMOVEAXIS_PH: btn = (CButton*)GetDlgItem(IDC_OBJMOVEPH); break; default: Int3(); // THIS SHOULD NEVER HAPPEN - samir } btn->SetCheck(1); m_current_start_pos=0; UpdateDialog(); // Done. return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CObjectDialog::OnDestroy() { CDialog::OnDestroy(); } void CObjectDialog::OnSize(UINT nType, int cx, int cy) { CKeypadDialog::OnSize(nType, cx, cy); } void CObjectDialog::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { CKeypadDialog::OnVScroll(nSBCode, nPos, pScrollBar); } void CObjectDialog::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { CKeypadDialog::OnHScroll(nSBCode, nPos, pScrollBar); } void CObjectDialog::OnPaint() { CPaintDC dc(this); // device context for painting if (!m_Active) return; UpdateIDList(); // this is here to update the object ids in case of any changes ASSERT(GetCurrentIndex() != -1); //Draw picture of current item DrawPicture(GetDlgItem(IDC_OBJ_PALETTE)); } void CObjectDialog::OnLButtonDown(UINT nFlags, CPoint point) { CDialog::OnLButtonDown(nFlags, point); } void CObjectDialog::UpdateDialog() { CEdit *box; char str[255]; int cur=m_current_start_pos; int i; sprintf (str,"Current start position: %d",cur); box = (CEdit *)GetDlgItem(IDC_START_POS_TEXT); box->SetWindowText (str); CheckDlgButton (IDC_RED_CHECK,Players[cur].startpos_flags & PSPF_RED); CheckDlgButton (IDC_BLUE_CHECK,Players[cur].startpos_flags & PSPF_BLUE); CheckDlgButton (IDC_GREEN_CHECK,Players[cur].startpos_flags & PSPF_GREEN); CheckDlgButton (IDC_YELLOW_CHECK,Players[cur].startpos_flags & PSPF_YELLOW); SendDlgItemMessage( IDC_SWAP_SOURCE_COMBO, CB_RESETCONTENT,0,0); SendDlgItemMessage( IDC_SWAP_DEST_COMBO, CB_RESETCONTENT,0,0); SendDlgItemMessage( IDC_REGROUND_COMBO, CB_RESETCONTENT,0,0); for (i=0;i= 0 && Swap_source_id < MAX_OBJECT_IDS && Object_info[Swap_source_id].type != OBJ_NONE) SendDlgItemMessage( IDC_SWAP_SOURCE_COMBO, CB_SELECTSTRING,0,(LPARAM) (LPCTSTR) Object_info[Swap_source_id].name); else SendDlgItemMessage( IDC_SWAP_SOURCE_COMBO, CB_SELECTSTRING,0,(LPARAM) (LPCTSTR) "None"); if(Swap_dest_id >= 0 && Swap_dest_id < MAX_OBJECT_IDS && Object_info[Swap_dest_id].type != OBJ_NONE) SendDlgItemMessage( IDC_SWAP_DEST_COMBO, CB_SELECTSTRING,0,(LPARAM) (LPCTSTR) Object_info[Swap_dest_id].name); else SendDlgItemMessage( IDC_SWAP_DEST_COMBO, CB_SELECTSTRING,0,(LPARAM) (LPCTSTR) "None"); if(Reground_id >= 0 && Reground_id < MAX_OBJECT_IDS && Object_info[Reground_id].type != OBJ_NONE) SendDlgItemMessage( IDC_REGROUND_COMBO, CB_SELECTSTRING,0,(LPARAM) (LPCTSTR) Object_info[Reground_id].name); else SendDlgItemMessage( IDC_REGROUND_COMBO, CB_SELECTSTRING,0,(LPARAM) (LPCTSTR) "None"); } void CObjectDialog::DrawPicture(CWnd *wnd) { RECT box_rect; int width,height,model_num; grHardwareSurface hw_surf; if (!Editor_active) return; // initialize graphic objects wnd->GetClientRect(&box_rect); width = box_rect.right - box_rect.left; height = box_rect.bottom - box_rect.top; Desktop_surf->attach_to_window((unsigned) wnd->m_hWnd); hw_surf.create(width,height,BPP_16); switch (D3EditState.current_obj_type) { case OBJ_CLUTTER: case OBJ_BUILDING: case OBJ_POWERUP: case OBJ_ROBOT: model_num = GetObjectImage(GetCurrentIndex()); break; case OBJ_PLAYER: model_num = GetShipImage(GetCurrentIndex()); break; default: Int3(); } DrawItemModel(&hw_surf,model_num); } // Keypad functions! void CObjectDialog::OnObjmoveX() { D3EditState.object_move_axis = OBJMOVEAXIS_X; ObjMoveManager.SetMoveAxis(D3EditState.object_move_axis); } void CObjectDialog::OnObjmoveY() { D3EditState.object_move_axis = OBJMOVEAXIS_Y; ObjMoveManager.SetMoveAxis(D3EditState.object_move_axis); } void CObjectDialog::OnObjmoveXY() { D3EditState.object_move_axis = OBJMOVEAXIS_XY; ObjMoveManager.SetMoveAxis(D3EditState.object_move_axis); } void CObjectDialog::OnObjmoveZ() { D3EditState.object_move_axis = OBJMOVEAXIS_Z; ObjMoveManager.SetMoveAxis(D3EditState.object_move_axis); } void CObjectDialog::OnObjmoveP() { D3EditState.object_move_axis = OBJMOVEAXIS_P; ObjMoveManager.SetMoveAxis(D3EditState.object_move_axis); } void CObjectDialog::OnObjmoveH() { D3EditState.object_move_axis = OBJMOVEAXIS_H; ObjMoveManager.SetMoveAxis(D3EditState.object_move_axis); } void CObjectDialog::OnObjmoveB() { D3EditState.object_move_axis = OBJMOVEAXIS_B; ObjMoveManager.SetMoveAxis(D3EditState.object_move_axis); } void CObjectDialog::OnObjmovePH() { D3EditState.object_move_axis = OBJMOVEAXIS_PH; ObjMoveManager.SetMoveAxis(D3EditState.object_move_axis); } int CObjectDialog::GetFreePlayerIndex() { uint8_t slots[MAX_NET_PLAYERS]; memset (slots,0,MAX_NET_PLAYERS); for (int i=0;i<=Highest_object_index;i++) { if (Objects[i].type==OBJ_PLAYER) { // Get Jason if these asserts fail ASSERT (slots[Objects[i].id]==0); ASSERT (Objects[i].id -1); if (!HObjectPlace(D3EditState.current_obj_type, objid)) { mprintf(0, "Attempt to place object outside mine failed!\n"); } } void CObjectDialog::OnSelchangeComboObjType() { // make sure to save the old item start value. int old_obj_type = D3EditState.current_obj_type; D3EditState.current_obj_type = edit_object_types[((CComboBox *)GetDlgItem(IDC_COMBO_OBJTYPE))->GetCurSel()]; InitObjIDComboBox((CComboBox *)GetDlgItem(IDC_COMBO_OBJID)); ASSERT(GetCurrentIndex() != -1); //Draw picture of current item DrawPicture(GetDlgItem(IDC_OBJ_PALETTE)); } void CObjectDialog::OnSelchangeComboObjID() { CComboBox *box = (CComboBox *)GetDlgItem(IDC_COMBO_OBJID); switch (D3EditState.current_obj_type) { case OBJ_ROBOT: case OBJ_POWERUP: case OBJ_BUILDING: case OBJ_CLUTTER: { int id = box->GetItemData(box->GetCurSel()); ASSERT(Object_info[id].type == D3EditState.current_obj_type); SetCurrentIndex(id); break; } case OBJ_PLAYER: { char text[32]; int i,j; box->GetLBText(box->GetCurSel(), text); j = 0; for (i=0;itype]; obj_name = objp->name ? objp->name : ""; if (IS_GENERIC(objp->type)) id_name = Object_info[objp->id].name; else if (objp->type == OBJ_DOOR) id_name = Doors[objp->id].name; if (id_name) EditorStatus("Object %d selected. Type = %s:%s, Name = %s",objnum,type_name,id_name,obj_name); else EditorStatus("Object %d selected. Type = %s, Name = %s",objnum,type_name,obj_name); State_changed = 1; } void CObjectDialog::OnObjpadNextobj() { int next; // If on the terrain, advance to the next object if (Editor_view_mode==VM_TERRAIN && OBJECT_OUTSIDE(&Objects[Cur_object_index])) { next=-1; int done=0; for (int i=Cur_object_index+1;i<=Highest_object_index && !done;i++) { object *obj=&Objects[i]; if (obj->type!=OBJ_NONE && OBJECT_OUTSIDE (obj) && obj->type!=OBJ_ROOM) { next=i; done=1; } } if (!done) { // Start counting from zero for (int i=0;i<=Cur_object_index && !done;i++) { object *obj=&Objects[i]; if (obj->type!=OBJ_NONE && OBJECT_OUTSIDE (obj) && obj->type!=OBJ_ROOM) { next=i; done=1; } } if (next == -1) { EditorStatus("There are no other objects on the terrain"); return; } } SelectObject(next); return; } if (Objects[Cur_object_index].roomnum != ROOMNUM(Curroomp)) { next = Curroomp->objects; if (next == -1) { EditorStatus("There are no objects in the current room"); return; } } else { next = Objects[Cur_object_index].next; if (next == -1) { next = Curroomp->objects; if (next == Cur_object_index) { EditorStatus("There are no other objects in this room"); return; } } } SelectObject(next); } void CObjectDialog::OnSetfocusComboObjID() { InitObjIDComboBox((CComboBox *)GetDlgItem(IDC_COMBO_OBJID)); } void CObjectDialog::OnObjectpadGroup() { // TODO: Add your control notification handler code here } void CObjectDialog::OnObjContPreview() { // TODO: Add your control notification handler code here } void CObjectDialog::OnObjpadFlagobjmulti() { // TODO: Add your control notification handler code here } void CObjectDialog::OnObjpadFlipobj() { // TODO: Add your control notification handler code here HObjectFlip(); } void CObjectDialog::OnObjpadSetdefault() { // TODO: Add your control notification handler code here HObjectSetDefault(); } void CObjectDialog::OnResetObjects() { ObjReInitAll(); OutrageMessageBox ("All objects reset!"); } BOOL CObjectDialog::OnHelpInfo(HELPINFO* pHelpInfo) { // TODO: Add your message handler code here and/or call default WinHelp(HID_OBJECTTAB,HELP_CONTEXT); return TRUE; //return CDialog::OnHelpInfo(pHelpInfo); } // This function will allow you to edit individual properties for the current selected object. void CObjectDialog::OnObjpadProperties() { if (Cur_object_index == -1) { OutrageMessageBox("Must select an object before editing it's properties."); return; } theApp.pause(); switch (Objects[Cur_object_index].type) { case OBJ_POWERUP: { CPowerupPropDialog dlg; dlg.DoModal(); break; } } theApp.resume(); } ///////////////////////////////////////////////////////////////////// // New Object Movement Control implementation void CObjectDialog::OnSelChangeCoordSysSelect() { CComboBox *cbox = (CComboBox *)GetDlgItem(IDC_COORDSYS_SELECT); char seltext[8]; cbox->GetLBText(cbox->GetCurSel(), seltext); if (stricmp(seltext, "local") == 0) { D3EditState.object_move_mode = REL_OBJECT; } else if (stricmp(seltext, "viewer") == 0) { D3EditState.object_move_mode = REL_VIEWER; } else if (stricmp(seltext, "world") == 0) { D3EditState.object_move_mode = REL_VIEWER; } } void DrawItemModel(grHardwareSurface *surf,int model_num) { vector zero_vector={0,0,0}; vector view_pos={0,0,0}; matrix id_matrix,rot_matrix; poly_model *pm = GetPolymodelPointer(model_num); //Calculate viewer position vector maxs = pm->maxs, mins = pm->mins; view_pos.x = -(mins.x + maxs.x) / 2; view_pos.y = (mins.y + maxs.y) / 2; maxs.x += view_pos.x; maxs.y -= view_pos.y; maxs.z = 0; view_pos.z = -2.5 * vm_GetMagnitude(&maxs); //Set viewer and object orientations vm_MakeIdentity(&id_matrix); vm_AnglesToMatrix(&rot_matrix,0,32768,0); //Set up surface & vuewport surf->clear(); grViewport *vport = new grViewport(surf); vport->clear(); //Draw to our surface StartEditorFrame(vport,&view_pos,&id_matrix,D3_DEFAULT_ZOOM); DrawPolygonModel(&zero_vector,&rot_matrix,model_num,NULL,0,1.0,1.0,1.0); EndEditorFrame(); //Copy to the screen Desktop_surf->blt(0,0,surf); //Delete our viewport delete vport; } void CObjectDialog::OnObjpadResetCurobjHeight() { if (Cur_object_index == -1) { OutrageMessageBox("You must have a current object for this operation."); return; } object *objp = &Objects[Cur_object_index]; //Make sure object is outside if (! OBJECT_OUTSIDE(objp)) { OutrageMessageBox("The object must be on the terrain this operation."); return; } //Make sure object has a ground plane if (! ((objp->render_type == RT_POLYOBJ) && ((GetPolymodelPointer(objp->rtype.pobj_info.model_num))->n_ground))) { OutrageMessageBox("The object must have a ground plane for this operation."); return; } ResetGroundObject(objp); } void CObjectDialog::OnObjpadResetAllObjHeights() { object *objp; int i; int n_moved = 0; for (i=0,objp=Objects;i<=Highest_object_index;i++,objp++) { //Make sure object is outside if (! OBJECT_OUTSIDE(objp)) continue; //Make sure object has a ground plane if (! ((objp->render_type == RT_POLYOBJ) && ((GetPolymodelPointer(objp->rtype.pobj_info.model_num))->n_ground))) continue; //Do it ResetGroundObject(objp); n_moved++; } EditorStatus("%d objects adjusted.",n_moved); } void CObjectDialog::OnPrevStartPositon() { if (m_current_start_pos==0) m_current_start_pos=MAX_PLAYERS-1; else m_current_start_pos--; UpdateDialog(); } void CObjectDialog::OnNextStartPos() { m_current_start_pos++; if (m_current_start_pos>=MAX_PLAYERS) m_current_start_pos=0; UpdateDialog(); } void CObjectDialog::OnJumpToStartPos() { char str[255]; int found_obj=-1; int highest=-1; for (int i=0;i<=Highest_object_index && found_obj==-1;i++) { if (Objects[i].type==OBJ_PLAYER) { if (Objects[i].id>highest) highest=Objects[i].id; if(Objects[i].id==m_current_start_pos) { found_obj=i; } } } if (found_obj==-1) { sprintf (str,"There was no player defined for this start position. The highest numbered player is #%d.",highest); OutrageMessageBox (str); } else { MoveViewer(&Objects[found_obj].pos,Objects[found_obj].roomnum,&Objects[found_obj].orient); TV_changed=1; } } void CObjectDialog::OnRedCheck() { int cur=m_current_start_pos; int c=IsDlgButtonChecked(IDC_RED_CHECK); if (c) Players[cur].startpos_flags |=PSPF_RED; else Players[cur].startpos_flags &=~PSPF_RED; } void CObjectDialog::OnBlueCheck() { int cur=m_current_start_pos; int c=IsDlgButtonChecked(IDC_BLUE_CHECK); if (c) Players[cur].startpos_flags |=PSPF_BLUE; else Players[cur].startpos_flags &=~PSPF_BLUE; } void CObjectDialog::OnGreenCheck() { int cur=m_current_start_pos; int c=IsDlgButtonChecked(IDC_GREEN_CHECK); if (c) Players[cur].startpos_flags |=PSPF_GREEN; else Players[cur].startpos_flags &=~PSPF_GREEN; } void CObjectDialog::OnYellowCheck() { int cur=m_current_start_pos; int c=IsDlgButtonChecked(IDC_YELLOW_CHECK); if (c) Players[cur].startpos_flags |=PSPF_YELLOW; else Players[cur].startpos_flags &=~PSPF_YELLOW; } void CObjectDialog::OnSelendokSwapSourceCombo() { int cur; char name[200]; cur=SendDlgItemMessage( IDC_SWAP_SOURCE_COMBO, CB_GETCURSEL,0,0); SendDlgItemMessage( IDC_SWAP_SOURCE_COMBO, CB_GETLBTEXT,cur,(LPARAM) (LPCTSTR)name); Swap_source_id = FindObjectIDName(name); UpdateDialog(); } void CObjectDialog::OnSelendokSwapDestCombo() { int cur; char name[200]; cur=SendDlgItemMessage( IDC_SWAP_DEST_COMBO, CB_GETCURSEL,0,0); SendDlgItemMessage( IDC_SWAP_DEST_COMBO, CB_GETLBTEXT,cur,(LPARAM) (LPCTSTR)name); Swap_dest_id = FindObjectIDName(name); UpdateDialog(); } void CObjectDialog::OnObjectSwapButton() { int i; int cur; char name[200]; cur=SendDlgItemMessage( IDC_SWAP_SOURCE_COMBO, CB_GETCURSEL,0,0); SendDlgItemMessage( IDC_SWAP_SOURCE_COMBO, CB_GETLBTEXT,cur,(LPARAM) (LPCTSTR)name); int s_id = FindObjectIDName(name); cur=SendDlgItemMessage( IDC_SWAP_DEST_COMBO, CB_GETCURSEL,0,0); SendDlgItemMessage( IDC_SWAP_DEST_COMBO, CB_GETLBTEXT,cur,(LPARAM) (LPCTSTR)name); int d_id = FindObjectIDName(name); if(s_id >= 0 && d_id >= 0) { for(i = 0; i <= Highest_object_index; i++) { if(Objects[i].type == OBJ_ROBOT || Objects[i].type == OBJ_CLUTTER || Objects[i].type == OBJ_POWERUP || Objects[i].type == OBJ_BUILDING) { if(Objects[i].id == s_id) { vector pos = Objects[i].pos; matrix orient = Objects[i].orient; int room = Objects[i].roomnum; int parent = Objects[i].parent_handle; char temp_name[256]; temp_name[0] = '\0'; if(Objects[i].name) { strcpy(temp_name, Objects[i].name); } ObjDelete(i); int o_index = ObjCreate(Object_info[d_id].type, d_id, room, &pos, &orient, parent); if(temp_name[0] != '\0') { Objects[o_index].name = (char *)mem_malloc(strlen(temp_name) + 1); strcpy(Objects[o_index].name, temp_name); } } } } } World_changed = 1; UpdateDialog(); } void CObjectDialog::OnSelendokRegroundCombo() { int cur; char name[200]; cur=SendDlgItemMessage( IDC_REGROUND_COMBO, CB_GETCURSEL,0,0); SendDlgItemMessage( IDC_REGROUND_COMBO, CB_GETLBTEXT,cur,(LPARAM) (LPCTSTR)name); Reground_id = FindObjectIDName(name); UpdateDialog(); } void CObjectDialog::OnRegroundButton() { if(Reground_id >= 0 && Object_info[Reground_id].type != OBJ_NONE) { int i; for(i = 0; i <= Highest_object_index; i++) { vector gp; object *obj = &Objects[i]; if(obj->type == OBJ_ROBOT || obj->type == OBJ_CLUTTER || obj->type == OBJ_POWERUP || obj->type == OBJ_BUILDING) { if(obj->id == Reground_id && PhysCalcGround(&gp, NULL, &Objects[i], 0)) { fvi_info hit_info; fvi_query fq; int fate; vector start = obj->pos + obj->size * 0.8f * obj->orient.uvec; vector end = obj->pos - obj->size * 2.0f * obj->orient.uvec; fq.p0 = &start; fq.p1 = &end; fq.startroom = obj->roomnum; fq.rad = 0.0f; fq.flags = FQ_CHECK_OBJS | FQ_IGNORE_POWERUPS | FQ_IGNORE_WEAPONS | FQ_IGNORE_MOVING_OBJECTS; fq.thisobjnum = OBJNUM(obj); fq.ignore_obj_list = NULL; fate = fvi_FindIntersection(&fq, &hit_info); if(fate != HIT_NONE) { float ps; float pr; float diff; ps = (gp - obj->pos) * obj->orient.uvec; pr = (hit_info.hit_pnt - obj->pos) * obj->orient.uvec; if(ps != pr) { diff = ps - pr; obj->pos -= diff * obj->orient.uvec; ObjSetPos(obj, &obj->pos, obj->roomnum, NULL,false); World_changed = 1; } } } } } } UpdateDialog(); } extern bool RotateObject(int objnum, angle p, angle h, angle b); void CObjectDialog::OnObjRot90() { angle p=0,b=0,h=0; switch (D3EditState.object_move_axis) { case OBJMOVEAXIS_P: p = 0x4000; break; case OBJMOVEAXIS_H: h = 0x4000; break; case OBJMOVEAXIS_B: b = 0x4000; break; case OBJMOVEAXIS_PH: p = 0x4000; h = 0x4000; break; default: return; } RotateObject(Cur_object_index, p,h,b); } void CObjectDialog::OnObjectPushthroughwalls() { if(f_allow_objects_to_be_pushed_through_walls) f_allow_objects_to_be_pushed_through_walls = false; else f_allow_objects_to_be_pushed_through_walls = true; } void CObjectDialog::OnObjpadDeleteAll() { if (Cur_object_index == -1) return; object *objp = &Objects[Cur_object_index]; if (objp->type == OBJ_PLAYER) { OutrageMessageBox("You cannot use this function on player objects."); return; } int type = objp->type, id = objp->id; if (type == OBJ_DOOR) { if (OutrageMessageBox(MBOX_YESNO,"It's very, very bad to delete a door object. Are you sure you want to delete all instances of the \"%s\" door?",Doors[id].name) != IDYES) return; } else { //Not a door char *objid_name; if (IS_GENERIC(type)) objid_name = Object_info[id].name; else objid_name = ""; if (OutrageMessageBox(MBOX_YESNO,"Are you sure you want to delete all %s objects of type \"%s\" in the mine?",Object_type_names[type],objid_name) != IDYES) return; } int count = 0; for (int objnum=0;objnum<=Highest_object_index;objnum++) { if ((Objects[objnum].type == type) && (Objects[objnum].id == id)) { ObjDelete(objnum); count++; } } EditorStatus("%d objects deleted.",count); World_changed = 1; }