/*
* 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;
}