/* * 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 . */ // WorldObjectsGenericDialog.cpp : implementation file // #include #include "mfc_compatibility.h" #include "editor.h" #include "WorldObjectsGenericDialog.h" #include "PhysicsDlg.h" #include "AISettingsDlg.h" #include "objinfo.h" #include "polymodel.h" #include "AnimStatesDialog.h" #include "EditLineDialog.h" #include "genericpage.h" #include "RobotEditWeaponsDialog.h" #include "GenericLightDialog.h" #include "robotfire.h" #include "ddio.h" #include "soundload.h" #include "objinit.h" #include "gametexture.h" #include "vclip.h" #include "QuickCompile.h" #include "mem.h" #include "mono.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CWorldObjectsGenericDialog dialog // Data for copy/paste object object_info Copy_object; CWorldObjectsGenericDialog::CWorldObjectsGenericDialog(CWnd *pParent /*=NULL*/) : CDialog(CWorldObjectsGenericDialog::IDD, pParent) { //{{AFX_DATA_INIT(CWorldObjectsGenericDialog) m_type_name = _T(""); m_current = 0; m_sInvenDescription = _T(""); m_sInvenIconName = _T(""); //}}AFX_DATA_INIT } void CWorldObjectsGenericDialog::DoDataExchange(CDataExchange *pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CWorldObjectsGenericDialog) DDX_Control(pDX, IDC_GENERIC_AMBIENT_SOUND_COMBO, m_ambient_sound_combo); DDX_Control(pDX, IDC_GENERIC_EXPLOSION_SOUND_COMBO, m_explosion_sound_combo); DDX_Text(pDX, IDC_GENERIC_TYPE_NAME, m_type_name); DDX_Text(pDX, IDC_GENERIC_ID_EDIT, m_current); DDX_Text(pDX, IDC_GENERIC_INVEN_DESCRIPTION, m_sInvenDescription); DDV_MaxChars(pDX, m_sInvenDescription, 180); DDX_Text(pDX, IDC_GENERIC_INVEN_ICONNAME, m_sInvenIconName); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CWorldObjectsGenericDialog, CDialog) //{{AFX_MSG_MAP(CWorldObjectsGenericDialog) ON_BN_CLICKED(IDC_GENERIC_EDIT_AI, OnGenericEditAI) ON_BN_CLICKED(IDC_GENERIC_EDIT_PHYSICS, OnGenericEditPhysics) ON_BN_CLICKED(IDC_GENERIC_USES_AI, OnGenericUsesAI) ON_BN_CLICKED(IDC_GENERIC_USES_PHYSICS, OnGenericUsesPhysics) ON_BN_CLICKED(IDC_GENERIC_ADD_NEW, OnGenericAddNew) ON_BN_CLICKED(IDC_GENERIC_CHECKED_OUT, OnGenericCheckedOut) ON_BN_CLICKED(IDC_GENERIC_CHECKIN, OnGenericCheckIn) ON_BN_CLICKED(IDC_GENERIC_DEFINE_ANIMSTATES, OnGenericDefineAnimStates) ON_BN_CLICKED(IDC_GENERIC_DELETE, OnGenericDelete) ON_BN_CLICKED(IDC_GENERIC_LOCK, OnGenericLock) ON_BN_CLICKED(IDC_GENERIC_NEXT, OnGenericNext) ON_BN_CLICKED(IDC_GENERIC_PREV, OnGenericPrev) ON_BN_CLICKED(IDC_GENERIC_CHANGE_MODEL, OnGenericChangeModel) ON_BN_CLICKED(IDC_GENERIC_CHANGE_NAME, OnGenericChangeName) ON_WM_TIMER() ON_CBN_SELENDOK(IDC_GENERIC_NAME_PULLDOWN, OnSelendokGenericNamePulldown) ON_EN_KILLFOCUS(IDC_GENERIC_SIZE_EDIT, OnKillfocusGenericSizeEdit) ON_BN_CLICKED(IDC_GENERIC_COPY, OnGenericCopy) ON_BN_CLICKED(IDC_GENERIC_PASTE, OnGenericPaste) ON_EN_KILLFOCUS(IDC_GENERIC_SCRIPT_ID_EDIT, OnKillfocusGenericScriptIDEdit) ON_BN_CLICKED(IDC_GENERIC_UNDO_LOCK, OnGenericUndoLock) ON_BN_CLICKED(IDC_GENERIC_DESTROYABLE, OnGenericDestroyable) ON_EN_KILLFOCUS(IDC_GENERIC_HITPOINT_EDIT, OnKillfocusGenericHitpointEdit) ON_WM_DESTROY() ON_BN_CLICKED(IDC_GENERIC_WEAPON_INFO_BUTTON, OnGenericWeaponInfoButton) ON_BN_CLICKED(IDC_GENERIC_LIGHT_BUTTON, OnGenericLightButton) ON_BN_CLICKED(IDC_DEFAULT_RADIUS_BUTTON, OnDefaultRadiusButton) ON_BN_CLICKED(IDC_SELSCRIPT, OnSelScript) ON_BN_CLICKED(IDC_GENERIC_CONCUSSIVE_CHECK, OnGenericConcussiveCheck) ON_EN_KILLFOCUS(IDC_GENERIC_IMPACT_DAMAGE_EDIT, OnKillfocusGenericImpactDamageEdit) ON_EN_KILLFOCUS(IDC_GENERIC_IMPACT_SIZE_EDIT, OnKillfocusGenericImpactSizeEdit) ON_BN_CLICKED(IDC_NOLOD, OnNolod) ON_BN_CLICKED(IDC_HIRES_RADIO, OnHiresRadio) ON_BN_CLICKED(IDC_MEDRES_RADIO, OnMedresRadio) ON_BN_CLICKED(IDC_LORES_RADIO, OnLoresRadio) ON_EN_KILLFOCUS(IDC_GENERIC_IMPACT_TIME_EDIT, OnKillfocusGenericImpactTimeEdit) ON_CBN_SELENDOK(IDC_GENERIC_EXPLOSION_SOUND_COMBO, OnSelendokGenericExplosionSoundCombo) ON_CBN_SELENDOK(IDC_GENERIC_AMBIENT_SOUND_COMBO, OnSelendokGenericAmbientSoundCombo) ON_EN_KILLFOCUS(IDC_GENERIC_INVEN_DESCRIPTION, OnKillfocusGenericInvenDescription) ON_EN_KILLFOCUS(IDC_GENERIC_INVEN_ICONNAME, OnKillfocusGenericInvenIconname) ON_BN_CLICKED(IDC_OVERRIDE, OnOverride) ON_BN_CLICKED(IDC_GENERIC_INVEN_SELECTABLE, OnGenericInvenSelectable) ON_BN_CLICKED(IDC_GENERIC_INVEN_NONUSEABLE, OnGenericInvenNonuseable) ON_EN_KILLFOCUS(IDC_LOD_DISTANCE_EDIT, OnKillfocusLodDistanceEdit) ON_BN_CLICKED(IDC_INVTYPE_GAME, OnInvtypeGame) ON_BN_CLICKED(IDC_INVTYPE_MISSION, OnInvtypeMission) ON_BN_CLICKED(IDC_INVEN_NOREMOVE, OnInvenNoremove) ON_BN_CLICKED(IDC_INVEN_VISWHENUSED, OnInvenViswhenused) ON_CBN_SELENDOK(IDC_DEATH_POWERUP1_PULLDOWN, OnSelendokDeathPowerup1Pulldown) ON_EN_KILLFOCUS(IDC_DEATH_POWERUP1_NUM_EDIT, OnKillfocusDeathPowerup1NumEdit) ON_EN_KILLFOCUS(IDC_DEATH_POWERUP1_PERCENT_EDIT, OnKillfocusDeathPowerup1PercentEdit) ON_EN_KILLFOCUS(IDC_DEATH_POWERUP2_NUM_EDIT, OnKillfocusDeathPowerup2NumEdit) ON_EN_KILLFOCUS(IDC_DEATH_POWERUP2_PERCENT_EDIT, OnKillfocusDeathPowerup2PercentEdit) ON_CBN_SELENDOK(IDC_DEATH_POWERUP2_PULLDOWN, OnSelendokDeathPowerup2Pulldown) ON_BN_CLICKED(IDC_DEATH_POWERUP_USE2_IF_HAVE1_CHECK, OnDeathPowerupUse2IfHave1Check) ON_BN_CLICKED(IDC_GENERIC_DEATH_SPEW_2_IF_ZERO_1, OnGenericDeathSpew2IfZero1) ON_EN_KILLFOCUS(IDC_SCRIPTNAME, OnKillfocusScriptname) ON_BN_CLICKED(IDC_COMPILEMODULE, OnCompilemodule) ON_EN_KILLFOCUS(IDC_SCRIPT_OVERRIDE, OnKillfocusScriptOverride) ON_BN_CLICKED(IDC_GENERIC_AI_SCRIPTED_DEATH, OnGenericAiScriptedDeath) ON_EN_KILLFOCUS(IDC_RESPAWN_SCALAR_EDIT, OnKillfocusRespawnScalarEdit) ON_BN_CLICKED(IDC_GENERIC_DEATHS, OnGenericDeaths) ON_EN_KILLFOCUS(IDC_GENERIC_SCORE_EDIT, OnKillfocusGenericScoreEdit) ON_EN_KILLFOCUS(IDC_GENERIC_AMMO_EDIT, OnKillfocusGenericAmmoEdit) ON_BN_CLICKED(IDC_OBJ_CEILING_CHECK, OnObjCeilingCheck) ON_BN_CLICKED(IDC_OBJECT_FLY_THROUGH_RENDERED_PORTALS, OnObjectFlyThroughRenderedPortals) ON_BN_CLICKED(IDC_NSC_BUTTON, OnNscButton) ON_BN_CLICKED(IDC_DSMPBD_CHECK, OnDsmpbdCheck) ON_BN_CLICKED(IDC_GENERIC_AMBIENT, OnGenericAmbient) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CWorldObjectsGenericDialog message handlers void CWorldObjectsGenericDialog::EnableDisableAll(bool flag) { ((CButton *)GetDlgItem(IDC_GENERIC_USES_AI))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_USES_PHYSICS))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_CHECKED_OUT))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_CHECKIN))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_DEFINE_ANIMSTATES))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_DELETE))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_LOCK))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_UNDO_LOCK))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_NEXT))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_PREV))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_EDIT_PHYSICS))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_EDIT_AI))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_COPY))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_CHANGE_NAME))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_CHANGE_MODEL))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_SIZE_EDIT))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_DESTROYABLE))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_AI_SCRIPTED_DEATH))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_OBJ_CEILING_CHECK))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_HITPOINT_EDIT))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_SCORE_EDIT))->EnableWindow(flag); ((CButton *)GetDlgItem(IDC_GENERIC_AMMO_EDIT))->EnableWindow(flag); } // Returns true if the specified object is locked bool CWorldObjectsGenericDialog::IsLocked(int n) { return (mng_FindTrackLock(Object_info[n].name, PAGETYPE_GENERIC) != -1); } // Returns the number of locked items of the current type int CWorldObjectsGenericDialog::CountLockedItems() { int lock_count = 0; int first, n; first = n = GetObjectID(m_type); if (first == -1) return 0; do { if (IsLocked(n)) lock_count++; n = GetNextObjectID(n); } while (n != first); return lock_count; } #define NULL_NAME "" void CWorldObjectsGenericDialog::UpdateDialog() { CEdit *ebox; CButton *bbox; int first, n; char txt[100]; int i; if (m_current == -1) { // ebox=(CEdit *) GetDlgItem (IDC_GENERIC_NAME_EDIT); // ebox->SetWindowText ("NONE"); EnableDisableAll(0); // Show paste button if you have the network, and there's an object in the copy buffer ((CButton *)GetDlgItem(IDC_GENERIC_PASTE))->EnableWindow(Network_up && (Copy_object.type != OBJ_NONE)); return; } EnableDisableAll(1); ebox = (CEdit *)GetDlgItem(IDC_GENERIC_MODEL_NAME_EDIT); PageInPolymodel(Object_info[m_current].render_handle); if (m_lod == 0) ebox->SetWindowText(Poly_models[Object_info[m_current].render_handle].name); else if (m_lod == 1) { if (Object_info[m_current].med_render_handle == -1) ebox->SetWindowText("No model defined"); else ebox->SetWindowText(Poly_models[Object_info[m_current].med_render_handle].name); } else { if (Object_info[m_current].lo_render_handle == -1) ebox->SetWindowText("No model defined"); else ebox->SetWindowText(Poly_models[Object_info[m_current].lo_render_handle].name); } // Do LOD distance edit box ebox = (CEdit *)GetDlgItem(IDC_LOD_DISTANCE_EDIT); if (m_lod == 0) ebox->SetWindowText("0"); else if (m_lod == 1) { sprintf(txt, "%f", Object_info[m_current].med_lod_distance); ebox->SetWindowText(txt); } else { sprintf(txt, "%f", Object_info[m_current].lo_lod_distance); ebox->SetWindowText(txt); } int poly_handle; if (m_lod == 0) poly_handle = Object_info[m_current].render_handle; else if (m_lod == 1) poly_handle = Object_info[m_current].med_render_handle; else poly_handle = Object_info[m_current].lo_render_handle; if (poly_handle == -1) sprintf(txt, "Num polys: NA"); else { PageInPolymodel(poly_handle); sprintf(txt, "Num polys: %d", CountFacesInPolymodel(&Poly_models[poly_handle])); } ebox = (CEdit *)GetDlgItem(IDC_NUM_POLYS); ebox->SetWindowText(txt); // Print out texture RAM usage ebox = (CEdit *)GetDlgItem(IDC_TEXTURE_RAM_TEXT); if (poly_handle == -1) sprintf(txt, "Texture RAM: NA"); else { int tram = GetTextureUsageForPolymodel(poly_handle); sprintf(txt, "Texture RAM: %dK", tram / 1000); } ebox->SetWindowText(txt); ebox = (CEdit *)GetDlgItem(IDC_RESPAWN_SCALAR_EDIT); sprintf(txt, "%f", Object_info[m_current].respawn_scalar); ebox->SetWindowText(txt); ebox = (CEdit *)GetDlgItem(IDC_GENERIC_IMPACT_SIZE_EDIT); sprintf(txt, "%f", Object_info[m_current].impact_size); ebox->SetWindowText(txt); ebox = (CEdit *)GetDlgItem(IDC_GENERIC_IMPACT_TIME_EDIT); sprintf(txt, "%f", Object_info[m_current].impact_time); ebox->SetWindowText(txt); ebox = (CEdit *)GetDlgItem(IDC_GENERIC_IMPACT_DAMAGE_EDIT); sprintf(txt, "%f", Object_info[m_current].damage); ebox->SetWindowText(txt); ebox = (CEdit *)GetDlgItem(IDC_DEATH_POWERUP1_NUM_EDIT); sprintf(txt, "%d", Object_info[m_current].dspew_number[0]); ebox->SetWindowText(txt); ebox = (CEdit *)GetDlgItem(IDC_DEATH_POWERUP2_NUM_EDIT); sprintf(txt, "%d", Object_info[m_current].dspew_number[1]); ebox->SetWindowText(txt); ebox = (CEdit *)GetDlgItem(IDC_DEATH_POWERUP1_PERCENT_EDIT); sprintf(txt, "%f", Object_info[m_current].dspew_percent[0] * 100.0f); ebox->SetWindowText(txt); ebox = (CEdit *)GetDlgItem(IDC_DEATH_POWERUP2_PERCENT_EDIT); sprintf(txt, "%f", Object_info[m_current].dspew_percent[1] * 100.0f); ebox->SetWindowText(txt); bbox = (CButton *)GetDlgItem(IDC_GENERIC_USES_PHYSICS); bbox->SetCheck(Object_info[m_current].flags & OIF_USES_PHYSICS); ((CButton *)GetDlgItem(IDC_GENERIC_EDIT_PHYSICS))->EnableWindow(Object_info[m_current].flags & OIF_USES_PHYSICS); bbox = (CButton *)GetDlgItem(IDC_DEATH_POWERUP_USE2_IF_HAVE1_CHECK); bbox->SetCheck(Object_info[m_current].f_dspew & DSF_ONLY_IF_PLAYER_HAS_OBJ_1); bbox = (CButton *)GetDlgItem(IDC_GENERIC_DEATH_SPEW_2_IF_ZERO_1); bbox->SetCheck(Object_info[m_current].f_dspew & DSF_ONLY_IF_NO_1); // Update the sound combo boxes m_explosion_sound_combo.SetSelected(Object_info[m_current].sounds[GSI_EXPLODE]); m_ambient_sound_combo.SetSelected(Object_info[m_current].sounds[GSI_AMBIENT]); SendDlgItemMessage(IDC_DEATH_POWERUP1_PULLDOWN, CB_RESETCONTENT, 0, 0); SendDlgItemMessage(IDC_DEATH_POWERUP1_PULLDOWN, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)NULL_NAME); for (i = 0; i < MAX_OBJECT_IDS; i++) { if (Object_info[i].type != OBJ_NONE) SendDlgItemMessage(IDC_DEATH_POWERUP1_PULLDOWN, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)Object_info[i].name); } if (Object_info[m_current].dspew[0] >= 0 && Object_info[m_current].dspew[0] < MAX_OBJECT_IDS && Object_info[Object_info[m_current].dspew[0]].type != OBJ_NONE) SendDlgItemMessage(IDC_DEATH_POWERUP1_PULLDOWN, CB_SELECTSTRING, 0, (LPARAM)(LPCTSTR)Object_info[Object_info[m_current].dspew[0]].name); else SendDlgItemMessage(IDC_DEATH_POWERUP1_PULLDOWN, CB_SELECTSTRING, 0, (LPARAM)(LPCTSTR)NULL_NAME); SendDlgItemMessage(IDC_DEATH_POWERUP2_PULLDOWN, CB_RESETCONTENT, 0, 0); SendDlgItemMessage(IDC_DEATH_POWERUP2_PULLDOWN, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)NULL_NAME); for (i = 0; i < MAX_OBJECT_IDS; i++) { if (Object_info[i].type != OBJ_NONE) SendDlgItemMessage(IDC_DEATH_POWERUP2_PULLDOWN, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)Object_info[i].name); } if (Object_info[m_current].dspew[1] >= 0 && Object_info[m_current].dspew[1] < MAX_OBJECT_IDS && Object_info[Object_info[m_current].dspew[1]].type != OBJ_NONE) SendDlgItemMessage(IDC_DEATH_POWERUP2_PULLDOWN, CB_SELECTSTRING, 0, (LPARAM)(LPCTSTR)Object_info[Object_info[m_current].dspew[1]].name); else SendDlgItemMessage(IDC_DEATH_POWERUP2_PULLDOWN, CB_SELECTSTRING, 0, (LPARAM)(LPCTSTR)NULL_NAME); // Edit AI box bbox = (CButton *)GetDlgItem(IDC_GENERIC_USES_AI); bbox->SetCheck(Object_info[m_current].flags & OIF_CONTROL_AI); ((CButton *)GetDlgItem(IDC_GENERIC_EDIT_AI))->EnableWindow(Object_info[m_current].flags & OIF_CONTROL_AI); // Weapon Info box ((CButton *)GetDlgItem(IDC_GENERIC_WEAPON_INFO_BUTTON)) ->EnableWindow(Poly_models[Object_info[m_current].render_handle].num_wbs > 0); // Update the size in the edit box sprintf(txt, "%.2f", Object_info[m_current].size); ((CEdit *)GetDlgItem(IDC_GENERIC_SIZE_EDIT))->SetWindowText(txt); // Edit hitpoint box bbox = (CButton *)GetDlgItem(IDC_GENERIC_DESTROYABLE); bbox->SetCheck(Object_info[m_current].flags & OIF_DESTROYABLE); ((CButton *)GetDlgItem(IDC_GENERIC_HITPOINT_EDIT))->EnableWindow(Object_info[m_current].flags & OIF_DESTROYABLE); ((CButton *)GetDlgItem(IDC_GENERIC_SCORE_EDIT))->EnableWindow(Object_info[m_current].flags & OIF_DESTROYABLE); bbox = (CButton *)GetDlgItem(IDC_GENERIC_AI_SCRIPTED_DEATH); bbox->SetCheck(Object_info[m_current].flags & OIF_AI_SCRIPTED_DEATH); bbox = (CButton *)GetDlgItem(IDC_OBJ_CEILING_CHECK); bbox->SetCheck(Object_info[m_current].flags & OIF_DO_CEILING_CHECK); bbox = (CButton *)GetDlgItem(IDC_OBJECT_FLY_THROUGH_RENDERED_PORTALS); bbox->SetCheck(Object_info[m_current].flags & OIF_IGNORE_FORCEFIELDS_AND_GLASS); bbox = (CButton *)GetDlgItem(IDC_NSC_BUTTON); bbox->SetCheck(Object_info[m_current].flags & OIF_NO_DIFF_SCALE_DAMAGE); bbox = (CButton *)GetDlgItem(IDC_DSMPBD_CHECK); bbox->SetCheck(Object_info[m_current].flags & OIF_NO_DIFF_SCALE_MOVE); bbox = (CButton *)GetDlgItem(IDC_GENERIC_AMBIENT); bbox->SetCheck(Object_info[m_current].flags & OIF_AMBIENT_OBJECT); // Update the hit points in the edit box sprintf(txt, (Object_info[m_current].flags & OIF_DESTROYABLE) ? "%d" : "", Object_info[m_current].hit_points); ((CEdit *)GetDlgItem(IDC_GENERIC_HITPOINT_EDIT))->SetWindowText(txt); // Update the score in the edit box sprintf(txt, (Object_info[m_current].flags & OIF_DESTROYABLE) ? "%d" : "", Object_info[m_current].score); ((CEdit *)GetDlgItem(IDC_GENERIC_SCORE_EDIT))->SetWindowText(txt); // Update ammo control sprintf(txt, "%d", Object_info[m_current].ammo_count); ((CEdit *)GetDlgItem(IDC_GENERIC_AMMO_EDIT))->SetWindowText(txt); ((CButton *)GetDlgItem(IDC_GENERIC_AMMO_TEXT))->EnableWindow(Object_info[m_current].type == OBJ_POWERUP); ((CButton *)GetDlgItem(IDC_GENERIC_AMMO_EDIT))->EnableWindow(Object_info[m_current].type == OBJ_POWERUP); // Show script handle // sprintf(txt,(Object_info[m_current].script_handle==-1)?"None":"%d",Object_info[m_current].script_handle); // ((CEdit *) GetDlgItem(IDC_GENERIC_SCRIPT_ID_EDIT))->SetWindowText(txt); // Enabled show checked out button if there are items checked out ((CButton *)GetDlgItem(IDC_GENERIC_CHECKED_OUT))->EnableWindow(m_locked_count > 0); // Show the current ID sprintf(txt, "%d", m_current); ((CEdit *)GetDlgItem(IDC_GENERIC_ID_EDIT))->SetWindowText(txt); // Show paste button if you have the network, and there's an object in the copy buffer ((CButton *)GetDlgItem(IDC_GENERIC_PASTE))->EnableWindow(Network_up && (Copy_object.type != OBJ_NONE)); // Show delete button if page is locked ((CButton *)GetDlgItem(IDC_GENERIC_DELETE))->EnableWindow(IsLocked(m_current)); // Show lock button if network is up, and item not already locked ((CButton *)GetDlgItem(IDC_GENERIC_LOCK))->EnableWindow(Network_up && !IsLocked(m_current)); // Show checkin button if network is up, and item is locked ((CButton *)GetDlgItem(IDC_GENERIC_CHECKIN))->EnableWindow(Network_up && IsLocked(m_current)); // Show undo lock button if network is up, and item is locked ((CButton *)GetDlgItem(IDC_GENERIC_UNDO_LOCK))->EnableWindow(Network_up && IsLocked(m_current)); // Show add new button if network is up ((CButton *)GetDlgItem(IDC_GENERIC_ADD_NEW))->EnableWindow(Network_up); // Reset name pulldown list SendDlgItemMessage(IDC_GENERIC_NAME_PULLDOWN, CB_RESETCONTENT, 0, 0); first = n = GetObjectID(m_type); if (first != -1) { do { SendDlgItemMessage(IDC_GENERIC_NAME_PULLDOWN, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)Object_info[n].name); n = GetNextObjectID(n); } while (n != first); n = SendDlgItemMessage(IDC_GENERIC_NAME_PULLDOWN, CB_FINDSTRINGEXACT, 0, (LPARAM)(LPCTSTR)Object_info[m_current].name); ASSERT(n != CB_ERR); SendDlgItemMessage(IDC_GENERIC_NAME_PULLDOWN, CB_SETCURSEL, n, 0); } // Reset script edit box ebox = (CEdit *)GetDlgItem(IDC_SCRIPTNAME); if (!Object_info[m_current].module_name[0]) ebox->SetWindowText("null"); else ebox->SetWindowText(Object_info[m_current].module_name); ebox = (CEdit *)GetDlgItem(IDC_SCRIPT_OVERRIDE); if (!Object_info[m_current].script_name_override[0]) ebox->SetWindowText("null"); else ebox->SetWindowText(Object_info[m_current].script_name_override); bbox = (CButton *)GetDlgItem(IDC_GENERIC_INVEN_SELECTABLE); bbox->SetCheck(Object_info[m_current].flags & OIF_INVEN_SELECTABLE); bbox = (CButton *)GetDlgItem(IDC_GENERIC_INVEN_NONUSEABLE); bbox->SetCheck(Object_info[m_current].flags & OIF_INVEN_NONUSEABLE); bbox = (CButton *)GetDlgItem(IDC_INVEN_NOREMOVE); bbox->SetCheck(Object_info[m_current].flags & OIF_INVEN_NOREMOVE); bbox = (CButton *)GetDlgItem(IDC_INVEN_VISWHENUSED); bbox->SetCheck(Object_info[m_current].flags & OIF_INVEN_VISWHENUSED); if (Object_info[m_current].flags & OIF_INVEN_TYPE_MISSION) { bbox = (CButton *)GetDlgItem(IDC_INVTYPE_MISSION); bbox->SetCheck(true); bbox = (CButton *)GetDlgItem(IDC_INVTYPE_GAME); bbox->SetCheck(false); } else { bbox = (CButton *)GetDlgItem(IDC_INVTYPE_GAME); bbox->SetCheck(true); bbox = (CButton *)GetDlgItem(IDC_INVTYPE_MISSION); bbox->SetCheck(false); } ebox = (CEdit *)GetDlgItem(IDC_GENERIC_INVEN_DESCRIPTION); if (!Object_info[m_current].description) ebox->SetWindowText(""); else ebox->SetWindowText(Object_info[m_current].description); ebox = (CEdit *)GetDlgItem(IDC_GENERIC_INVEN_ICONNAME); if (!Object_info[m_current].icon_name[0]) ebox->SetWindowText(""); else ebox->SetWindowText(Object_info[m_current].icon_name); ebox = (CEdit *)GetDlgItem(IDC_NOLOD); if (m_lod == 0) ebox->EnableWindow(FALSE); else if (m_lod == 1) { if (Object_info[m_current].med_render_handle == -1) ebox->EnableWindow(FALSE); else ebox->EnableWindow(TRUE); } else { if (Object_info[m_current].lo_render_handle == -1) ebox->EnableWindow(FALSE); else ebox->EnableWindow(TRUE); } bbox = (CButton *)GetDlgItem(IDC_HIRES_RADIO); bbox->SetCheck(m_lod == 0); bbox = (CButton *)GetDlgItem(IDC_MEDRES_RADIO); bbox->SetCheck(m_lod == 1); bbox = (CButton *)GetDlgItem(IDC_LORES_RADIO); bbox->SetCheck(m_lod == 2); // Update the picture UpdateObjectView(); } BOOL CWorldObjectsGenericDialog::OnInitDialog() { static bool first_time = 1; m_type_name = Object_type_names[m_type]; m_lod = 0; Copy_object.description = NULL; CDialog::OnInitDialog(); // Start the timer CWnd::SetTimer(1, 50, NULL); // Make sure we have a valid object if (Object_info[m_current].type != m_type) m_current = GetObjectID(m_type); // Find out how many locked items m_locked_count = CountLockedItems(); // Init copy/paste if (first_time) { Copy_object.type = OBJ_NONE; first_time = 0; } CEdit *edit = (CEdit *)GetDlgItem(IDC_GENERIC_INVEN_DESCRIPTION); edit->LimitText(0); // Initialize sound combo boxes m_explosion_sound_combo.Init(Object_info[m_current].sounds[GSI_EXPLODE]); m_ambient_sound_combo.Init(Object_info[m_current].sounds[GSI_AMBIENT]); // Update all the fields UpdateDialog(); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CWorldObjectsGenericDialog::OnGenericEditAI() { CAISettingsDlg dlg(Object_info[m_current].ai_info); dlg.DoModal(); } void CWorldObjectsGenericDialog::OnGenericEditPhysics() { CPhysicsDlg dlg(&Object_info[m_current].phys_info); dlg.DoModal(); } void CWorldObjectsGenericDialog::OnGenericUsesAI() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_GENERIC_USES_AI); if (btn->GetCheck()) Object_info[m_current].flags |= OIF_CONTROL_AI; else Object_info[m_current].flags &= ~OIF_CONTROL_AI; ((CButton *)GetDlgItem(IDC_GENERIC_EDIT_AI))->EnableWindow(Object_info[m_current].flags & OIF_CONTROL_AI); } void CWorldObjectsGenericDialog::OnGenericUsesPhysics() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_GENERIC_USES_PHYSICS); if (btn->GetCheck()) Object_info[m_current].flags |= OIF_USES_PHYSICS; else Object_info[m_current].flags &= ~OIF_USES_PHYSICS; ((CButton *)GetDlgItem(IDC_GENERIC_EDIT_PHYSICS))->EnableWindow(Object_info[m_current].flags & OIF_USES_PHYSICS); } // Gets a name from the user, making sure it's unique // Returns true if got new name, false if cancelled. // the data in buf not changed if cancel is pressed bool InputObjectName(char *buf, int len, char *title, char *prompt, CWnd *wnd) { if (len > (PAGENAME_LEN - 1)) len = PAGENAME_LEN - 1; char *tempbuf = mem_rmalloc(len); strncpy(tempbuf, buf, len - 1); tempbuf[len - 1] = '\0'; try_again: if (!InputString(tempbuf, len, title, prompt, wnd)) { mem_free(tempbuf); return 0; } if (FindObjectIDName(tempbuf) != -1) { OutrageMessageBox("The name you specified is already in use. Enter another name."); goto try_again; } strcpy(buf, tempbuf); mem_free(tempbuf); return 1; } void CWorldObjectsGenericDialog::OnGenericAddNew() { char filename[256], dir[256], fname[256], ext[32]; char cur_name[100], *t; int img_handle; int object_handle; int c = 1, finding_name = 1; ASSERT(Network_up); // Get the filename of the representing image CString filter = "Descent III files (*.pof,*.oof)|*.pof;*.oof||"; if (!OpenFileDialog(this, (LPCTSTR)filter, filename, Current_model_dir, sizeof(Current_model_dir))) return; ddio_SplitPath(filename, dir, fname, ext); std::filesystem::path tmp = ChangePolyModelName(filename); strcpy(cur_name, tmp.u8string().c_str()); if ((FindPolyModelName(fname)) != -1) { OutrageMessageBox("You must rename your model to something else because there is already a model with that name!"); return; } // Okay, we selected a file. Lets do what needs to be done here. img_handle = LoadPolyModel(filename, 0); if (img_handle < 0) { OutrageMessageBox("Couldn't open that model file."); return; } // Get a default name strcpy(cur_name, fname); // Start with the filename t = strchr(cur_name, '.'); // Strip the extention if (!t) t = cur_name + strlen(cur_name); *t = 0; do { // Make sure the name not already in use int c = 0; if (FindObjectIDName(cur_name) == -1) break; *t = 0; sprintf(cur_name, "%s%d", cur_name, ++c); } while (1); cur_name[0] = toupper(cur_name[0]); // make first char uppercase // Get the object name from the user retry_name: if (!InputObjectName(cur_name, sizeof(cur_name), "Object name", "Enter a name for your object:", this)) return; if (FindObjectIDName(cur_name) != -1) { OutrageMessageBox("That name is taken, please choose another."); goto retry_name; } // Alloc an object and give a name not already taken by some other object object_handle = AllocObjectID(m_type, true, true, true); if (object_handle == -1) { OutrageMessageBox("Cannot add object: There are no free object slots."); return; } strcpy(Object_info[object_handle].name, cur_name); Object_info[object_handle].render_handle = img_handle; // figure out size of object ComputeDefaultSize(Object_info[object_handle].type, img_handle, &Object_info[object_handle].size); // Init some stuff Object_info[object_handle].flags = OIF_DESTROYABLE; Object_info[object_handle].hit_points = 100; memset(&Object_info[object_handle].lighting_info, 0, sizeof(light_info)); Object_info[object_handle].lighting_info.timebits = 0xFFFFFFFF; if (m_type == OBJ_BUILDING) Object_info[object_handle].lighting_info.lighting_render_type = LRT_LIGHTMAPS; else Object_info[object_handle].lighting_info.lighting_render_type = LRT_GOURAUD; // Finally, save a local copy of the model/anim and alloc a tracklock mprintf(0, "Making a copy of this model locally...\n"); std::filesystem::path destname = LocalModelsDir / Poly_models[Object_info[object_handle].render_handle].name; cf_CopyFile(destname, filename); mng_AllocTrackLock(cur_name, PAGETYPE_GENERIC); m_current = object_handle; RemapStaticIDs(); UpdateDialog(); } void CWorldObjectsGenericDialog::OnGenericCheckedOut() { char str[10000]; int total = 0; mng_DisplayLockList(TableUser); sprintf(str, "User %s has these objects held locally:\n\n", TableUser); for (int i = 0; i < MAX_TRACKLOCKS; i++) { if (GlobalTrackLocks[i].used && GlobalTrackLocks[i].pagetype == PAGETYPE_GENERIC) { int n = FindObjectIDName(GlobalTrackLocks[i].name); ASSERT(n != -1); if (Object_info[n].type == m_type) { // found one of our type strcat(str, " "); strcat(str, GlobalTrackLocks[i].name); strcat(str, "\n"); total++; } } } if (total != 0) // Display list MessageBox(str, "Textures", MB_OK); } void CWorldObjectsGenericDialog::OnGenericCheckIn() { mngs_Pagelock temp_pl; int r; if (m_current == -1) return; if (!mng_MakeLocker()) return; // Make sure we own this object strcpy(temp_pl.name, Object_info[m_current].name); temp_pl.pagetype = PAGETYPE_GENERIC; r = mng_CheckIfPageOwned(&temp_pl, TableUser); if (r < 0) OutrageMessageBox(ErrorString); else if (r == 0) OutrageMessageBox(InfoString); else { // Change the pagelock state to UNLOCKED strcpy(temp_pl.holder, "UNLOCKED"); if (!mng_ReplacePagelock(temp_pl.name, &temp_pl)) { MessageBox(ErrorString, "Error!"); mng_EraseLocker(); return; } else { // Now actually replace the copy on the net with our local one if (!mng_ReplacePage(Object_info[m_current].name, Object_info[m_current].name, m_current, PAGETYPE_GENERIC, 0)) OutrageMessageBox(ErrorString); else { // Save this object anim/model to the network for all std::filesystem::path srcname = LocalModelsDir / Poly_models[Object_info[m_current].render_handle].name; std::filesystem::path destname = NetModelsDir / Poly_models[Object_info[m_current].render_handle].name; cf_CopyFile(destname, srcname); if (Object_info[m_current].med_render_handle != -1) { srcname = LocalModelsDir / Poly_models[Object_info[m_current].med_render_handle].name; destname = NetModelsDir / Poly_models[Object_info[m_current].med_render_handle].name; cf_CopyFile(destname, srcname); } if (Object_info[m_current].lo_render_handle != -1) { srcname = LocalModelsDir / Poly_models[Object_info[m_current].lo_render_handle].name; destname = NetModelsDir / Poly_models[Object_info[m_current].lo_render_handle].name; cf_CopyFile(destname, srcname); } OutrageMessageBox("Object checked in."); // Delete it from local pagefile if it is there int dret = mng_DeletePage(Object_info[m_current].name, PAGETYPE_GENERIC, 1); ASSERT(dret == 1); mng_EraseLocker(); // Free the tracklock int p = mng_FindTrackLock(Object_info[m_current].name, PAGETYPE_GENERIC); ASSERT(p != -1); mng_FreeTrackLock(p); UpdateDialog(); } } } UpdateDialog(); } void CWorldObjectsGenericDialog::OnGenericDefineAnimStates() { if (m_current == -1) return; CAnimStatesDialog dlg(Object_info[m_current].render_handle, Object_info[m_current].anim); if (dlg.DoModal() == IDOK) // Copy back into object dlg.GetAnimData(Object_info[m_current].anim); } void CWorldObjectsGenericDialog::OnGenericDelete() { int answer, tl; mngs_Pagelock pl; int old_current; if (m_current == -1) return; // Check to see if we even have it locked if ((tl = mng_FindTrackLock(Object_info[m_current].name, PAGETYPE_GENERIC)) == -1) { OutrageMessageBox("This object is not yours to delete. Lock first."); return; } // Make sure it is to be deleted answer = MessageBox("Are you sure you want to delete this object?", Object_info[m_current].name, MB_YESNO); if (answer == IDNO) return; if (!mng_MakeLocker()) return; strcpy(pl.name, Object_info[m_current].name); pl.pagetype = PAGETYPE_GENERIC; // Check to see if this is a local object only. If so, only delete it locally if (mng_CheckIfPageOwned(&pl, TableUser) != 1) { mng_FreeTrackLock(tl); if (!mng_DeletePage(Object_info[m_current].name, PAGETYPE_GENERIC, 1)) { mprintf(0, ErrorString); Int3(); } } else // if it is network, delete it from both the net and local drives { mng_FreeTrackLock(tl); mng_DeletePage(Object_info[m_current].name, PAGETYPE_GENERIC, 0); mng_DeletePage(Object_info[m_current].name, PAGETYPE_GENERIC, 1); mng_DeletePagelock(Object_info[m_current].name, PAGETYPE_GENERIC); } // Advance to the next object old_current = m_current; m_current = GetNextObjectID(m_current); if (m_current == old_current) m_current = -1; FreePolyModel(Object_info[old_current].render_handle); if (Object_info[old_current].med_render_handle != -1) FreePolyModel(Object_info[old_current].med_render_handle); if (Object_info[old_current].lo_render_handle != -1) FreePolyModel(Object_info[old_current].lo_render_handle); FreeObjectID(old_current); mng_EraseLocker(); OutrageMessageBox("Object deleted."); RemapStaticIDs(); UpdateDialog(); } void CWorldObjectsGenericDialog::OnGenericLock() { mngs_Pagelock temp_pl; mngs_generic_page page; int r; if (m_current == -1) return; if (!mng_MakeLocker()) return; // Make sure it can be locked strcpy(temp_pl.name, Object_info[m_current].name); temp_pl.pagetype = PAGETYPE_GENERIC; r = mng_CheckIfPageLocked(&temp_pl); if (r == 2) { int answer; answer = OutrageMessageBox(MBOX_YESNO, "This page is not even in the table file, or the database maybe corrupt. " "Override to 'Unlocked'? (Select NO if you don't know what you're doing)"); if (answer == IDYES) { strcpy(temp_pl.holder, "UNLOCKED"); if (!mng_ReplacePagelock(temp_pl.name, &temp_pl)) MessageBox(ErrorString, "Error!"); } } else if (r < 0) OutrageMessageBox(ErrorString); else if (r == 1) OutrageMessageBox(InfoString); else { // Everything is ok. Tell the network we're locking it and get a copy to // our local drive strcpy(temp_pl.holder, TableUser); if (!mng_ReplacePagelock(temp_pl.name, &temp_pl)) { MessageBox(ErrorString, "Error!"); mng_EraseLocker(); return; } else { // Search thru the net pagefile and get a new copy in RAM in case anyone // changed it since we started the editor if (mng_FindSpecificGenericPage(temp_pl.name, &page)) { if (mng_AssignGenericPageToObjInfo(&page, m_current)) { if (!mng_ReplacePage(Object_info[m_current].name, Object_info[m_current].name, m_current, PAGETYPE_GENERIC, 1)) { OutrageMessageBox("There was problem writing that page locally!"); mng_EraseLocker(); return; } OutrageMessageBox("Object locked."); } else OutrageMessageBox( "There was a problem loading this object. You might encounter problems in dealing with it. Good luck!"); mng_AllocTrackLock(Object_info[m_current].name, PAGETYPE_GENERIC); UpdateDialog(); } else OutrageMessageBox("Couldn't find that object in the table file!"); } } mng_EraseLocker(); UpdateDialog(); } void CWorldObjectsGenericDialog::OnGenericNext() { m_current = GetNextObjectID(m_current); m_lod = 0; UpdateDialog(); } void CWorldObjectsGenericDialog::OnGenericPrev() { m_current = GetPrevObjectID(m_current); m_lod = 0; UpdateDialog(); } void CWorldObjectsGenericDialog::OnGenericChangeModel() { char filename[255]; char curname[255]; char fname[255]; char dir[255]; char ext[100]; int img_handle; int c = 1, finding_name = 1; int model = 0; // Get the filename of the representing image CString filter = "Descent III files (*.pof,*.oof)|*.pof;*.oof||"; if (!OpenFileDialog(this, (LPCTSTR)filter, filename, Current_model_dir, sizeof(Current_model_dir))) return; std::filesystem::path tmp = ChangePolyModelName(filename); strcpy(curname, tmp.u8string().c_str()); ddio_SplitPath(filename, dir, fname, ext); if ((FindPolyModelName(curname)) != -1) { int answer = MessageBox("There is already a model in memory with this name. Are you sure you want to replace it?", fname, MB_YESNO); if (answer == IDNO) return; } // Okay, we selected a file. Lets do what needs to be done here. img_handle = LoadPolyModel(filename, 0); if (img_handle < 0) { OutrageMessageBox("Couldn't open that animation/model file."); return; } if (m_lod == 0) { ChangeOldModelsForObjects(Object_info[m_current].render_handle, img_handle); FreePolyModel(Object_info[m_current].render_handle); Object_info[m_current].render_handle = img_handle; } else if (m_lod == 1) { if (Object_info[m_current].med_render_handle != -1) FreePolyModel(Object_info[m_current].med_render_handle); Object_info[m_current].med_render_handle = img_handle; } else { if (Object_info[m_current].lo_render_handle != -1) FreePolyModel(Object_info[m_current].lo_render_handle); Object_info[m_current].lo_render_handle = img_handle; } // A new model might induce a new weapon stucture if (OutrageMessageBox(MBOX_YESNO, "Would you like to clear the weapon battery info?") == IDYES) { WBClearInfo(Object_info[m_current].static_wb); } // Finally, save a local copy of the model sprintf(curname, "%s\\%s", LocalModelsDir.u8string().c_str(), Poly_models[img_handle].name); cf_CopyFile(curname, filename); UpdateDialog(); } void CWorldObjectsGenericDialog::OnGenericChangeName() { char name[PAGENAME_LEN]; mngs_Pagelock pl; // Make sure we have this ship locked, if not reset name and bail int p = mng_FindTrackLock(Object_info[m_current].name, PAGETYPE_GENERIC); if (p == -1) { OutrageMessageBox("You must lock this object if you wish to change its name."); return; } // Get new name retry_name: strcpy(name, Object_info[m_current].name); if (!InputObjectName(name, sizeof(name), "Object name", "Enter a new name for this object:", this)) return; if (FindObjectIDName(name) != -1) { OutrageMessageBox("That name is taken, please choose another."); goto retry_name; } if (!mng_MakeLocker()) return; // Check to see if this page exists on the network. If so, we have to // rename it so we can prevent havoc strcpy(pl.name, Object_info[m_current].name); pl.pagetype = PAGETYPE_GENERIC; int ret = mng_CheckIfPageOwned(&pl, TableUser); if (ret < 0) OutrageMessageBox(ErrorString); else if (ret == 1) mng_RenamePage(Object_info[m_current].name, name, PAGETYPE_GENERIC); else if (ret == 2) { // This page has never been checked in, replace only local copy char oldname[PAGENAME_LEN]; strcpy(oldname, Object_info[m_current].name); strcpy(Object_info[m_current].name, name); mng_ReplacePage(oldname, Object_info[m_current].name, m_current, PAGETYPE_GENERIC, 1); } else if (ret == 0) { OutrageMessageBox("You don't own this page. Get Jason now!"); mng_FreeTrackLock(p); return; } // Finally, copy our new name to the appropriate arrays strcpy(GlobalTrackLocks[p].name, name); strcpy(Object_info[m_current].name, name); mng_EraseLocker(); RemapStaticIDs(); // check to see if current has been remapped if (Object_info[m_current].type != m_type) m_current = GetObjectID(m_type); UpdateDialog(); } #define NUM_ANIM_FRAMES 30 void CWorldObjectsGenericDialog::UpdateObjectView(void) { CWnd *objwnd; RECT rect; int x, y, bm_handle, w, h; static int frame = 0, spin_frame = 0; static int last_object = -1; static int last_render_handle = -1; static int object_dir = 0; if (m_current == -1) return; if (object_dir == 0) { frame++; if (frame == NUM_ANIM_FRAMES) { frame = NUM_ANIM_FRAMES - 1; object_dir = 1; } } else { frame--; if (frame == -1) { frame = 0; object_dir = 0; } } objwnd = GetDlgItem(IDC_GENERIC_OBJECTVIEW); objwnd->GetWindowRect(&rect); ScreenToClient(&rect); Desktop_surf->attach_to_window((unsigned)m_hWnd); w = rect.right - rect.left; h = rect.bottom - rect.top; int render_handle; if (m_lod == 0) render_handle = Object_info[m_current].render_handle; else if (m_lod == 1) render_handle = Object_info[m_current].med_render_handle; else render_handle = Object_info[m_current].lo_render_handle; if (last_object != m_current || last_render_handle != render_handle) { Desktop_surf->clear(rect.left, rect.top, w, h); last_object = m_current; last_render_handle = render_handle; } bm_handle = render_handle; if (bm_handle == -1) return; vector zero_vector; vector view_vector = {0, 0, -20}; matrix id_matrix, rot_matrix; poly_model *pm = GetPolymodelPointer(bm_handle); vm_MakeZero(&zero_vector); vm_MakeIdentity(&id_matrix); float norm_angles[256]; float keyframe = pm->frame_min + (pm->frame_max - pm->frame_min) * ((float)frame / (float)NUM_ANIM_FRAMES); SetNormalizedTimeAnim(keyframe, norm_angles, pm); spin_frame++; vm_AnglesToMatrix(&rot_matrix, 0, spin_frame * 400, 0); view_vector.z = -(fabs(pm->maxs.z - pm->mins.z) * 2); m_ObjectSurf.create(128, 128, BPP_16); grViewport *vport = new grViewport(&m_ObjectSurf); StartEditorFrame(vport, &view_vector, &id_matrix, D3_DEFAULT_ZOOM); DrawPolygonModel(&zero_vector, &rot_matrix, bm_handle, norm_angles, 0, 1.0, 1.0, 1.0); EndEditorFrame(); x = rect.left + ((rect.right - rect.left) / 2) - m_ObjectSurf.width() / 2; y = rect.top + ((rect.bottom - rect.top) / 2) - m_ObjectSurf.height() / 2; Desktop_surf->blt(x, y, &m_ObjectSurf); delete vport; m_ObjectSurf.free(); } void CWorldObjectsGenericDialog::OnTimer(UINT nIDEvent) { UpdateObjectView(); CDialog::OnTimer(nIDEvent); } void CWorldObjectsGenericDialog::OnSelendokGenericNamePulldown() { int i, cur; char name[200]; cur = SendDlgItemMessage(IDC_GENERIC_NAME_PULLDOWN, CB_GETCURSEL, 0, 0); SendDlgItemMessage(IDC_GENERIC_NAME_PULLDOWN, CB_GETLBTEXT, cur, (LPARAM)(LPCTSTR)name); i = FindObjectIDName(name); if (i == -1) { mprintf(0, "Possible corrupted object list, but probably nothing."); } else { ASSERT(Object_info[i].type == m_type); m_current = i; } UpdateDialog(); } void CWorldObjectsGenericDialog::OnKillfocusGenericSizeEdit() { char str[20]; ((CEdit *)GetDlgItem(IDC_GENERIC_SIZE_EDIT))->GetWindowText(str, 20); Object_info[m_current].size = atof(str); } void CWorldObjectsGenericDialog::OnKillfocusGenericScriptIDEdit() { /* char str[20]; ((CEdit *) GetDlgItem(IDC_GENERIC_SCRIPT_ID_EDIT))->GetWindowText(str,20); strcpy(Object_info[m_current].script_name, str); */ } void CWorldObjectsGenericDialog::OnGenericCopy() { if (m_current != -1) { if (Copy_object.description) { mem_free(Copy_object.description); } Copy_object = Object_info[m_current]; Copy_object.description = NULL; if (!Object_info[m_current].description) Copy_object.description = mem_strdup(""); else Copy_object.description = mem_strdup(Object_info[m_current].description); } UpdateDialog(); } void CWorldObjectsGenericDialog::OnGenericPaste() { char temp_name[PAGENAME_LEN + 10]; // need to add some space for the "CopyxOf" int n; ASSERT(Network_up); ASSERT(Copy_object.type != OBJ_NONE); if (Copy_object.type != m_type) { if (OutrageMessageBox(MBOX_YESNO, "You are about to paste a %s object as a %s. Is this OK?", Object_type_names[Copy_object.type], Object_type_names[m_type]) != IDYES) return; } // Get the name of the new object strcpy(temp_name, Copy_object.name); if (FindObjectIDName(temp_name) != -1) { int c = 2; sprintf(temp_name, "CopyOf%s", Copy_object.name); do { // Make sure the name not already in use if (FindObjectIDName(temp_name) == -1) break; sprintf(temp_name, "Copy%dOf%s", c, Copy_object.name); c++; } while (1); } if (!InputObjectName(temp_name, sizeof(temp_name), "Object name", "Enter a name for your object:", this)) // bail return; // Get a slot for this object n = AllocObjectID(m_type, true, true, true); if (n == -1) { OutrageMessageBox("Cannot paste object: There are no free object slots."); return; } // Copy into new slot Object_info[n] = Copy_object; Object_info[n].description = Copy_object.description; Copy_object.description = NULL; // Set type and name Object_info[n].type = m_type; strcpy(Object_info[n].name, temp_name); // Increment the used count of the polymodels Poly_models[Object_info[m_current].render_handle].used++; if (Object_info[m_current].med_render_handle != -1) Poly_models[Object_info[m_current].med_render_handle].used++; if (Object_info[m_current].lo_render_handle != -1) Poly_models[Object_info[m_current].lo_render_handle].used++; // Make this the current item m_current = n; // Add this to paging system mng_AllocTrackLock(Object_info[n].name, PAGETYPE_GENERIC); // I'm not sure if this belongs here RemapStaticIDs(); UpdateDialog(); } // When closing, save all our checked out objects locally so we know // what stuff to flag as "checked out" the next time we start up void CWorldObjectsGenericDialog::SaveGenericsOnClose() { int i, t; if (!Network_up) return; // don't save a damn thing if the network is down for (i = 0; i < MAX_TRACKLOCKS; i++) { if (GlobalTrackLocks[i].used == 1 && GlobalTrackLocks[i].pagetype == PAGETYPE_GENERIC) { t = FindObjectIDName(GlobalTrackLocks[i].name); ASSERT(t != -1); mng_ReplacePage(Object_info[t].name, Object_info[t].name, t, PAGETYPE_GENERIC, 1); } } } void CWorldObjectsGenericDialog::OnDestroy() { CDialog::OnDestroy(); if (Copy_object.description) { mem_free(Copy_object.description); Copy_object.description = NULL; } SaveGenericsOnClose(); ObjReInitAll(); } BOOL CWorldObjectsGenericDialog::DestroyWindow() { return CDialog::DestroyWindow(); } void CWorldObjectsGenericDialog::OnGenericUndoLock() { int tl; mngs_Pagelock pl; mngs_generic_page page; if (m_current == -1) return; // Should have this item locked if ((tl = mng_FindTrackLock(Object_info[m_current].name, PAGETYPE_GENERIC)) == -1) return; // Make sure it is to be deleted if (OutrageMessageBox(MBOX_YESNO, "Are you sure you want to undo your lock and lose any changes you may have made?") != IDYES) return; if (!mng_MakeLocker()) return; strcpy(pl.name, Object_info[m_current].name); pl.pagetype = PAGETYPE_GENERIC; mng_FreeTrackLock(tl); // Delete local page if (!mng_DeletePage(Object_info[m_current].name, PAGETYPE_GENERIC, 1)) { mprintf(0, ErrorString); Int3(); } // Get old data from net if (!mng_FindSpecificGenericPage(pl.name, &page)) Int3(); // Copy old get into our local array if (!mng_AssignGenericPageToObjInfo(&page, m_current)) Int3(); // We're done mng_EraseLocker(); // Update the display UpdateDialog(); } void CWorldObjectsGenericDialog::OnGenericDestroyable() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_GENERIC_DESTROYABLE); if (btn->GetCheck()) Object_info[m_current].flags |= OIF_DESTROYABLE; else Object_info[m_current].flags &= ~OIF_DESTROYABLE; ((CButton *)GetDlgItem(IDC_GENERIC_HITPOINT_EDIT))->EnableWindow(Object_info[m_current].flags & OIF_DESTROYABLE); ((CButton *)GetDlgItem(IDC_GENERIC_SCORE_EDIT))->EnableWindow(Object_info[m_current].flags & OIF_DESTROYABLE); } void CWorldObjectsGenericDialog::OnKillfocusGenericHitpointEdit() { char str[20]; ((CEdit *)GetDlgItem(IDC_GENERIC_HITPOINT_EDIT))->GetWindowText(str, 20); Object_info[m_current].hit_points = atoi(str); } void CWorldObjectsGenericDialog::OnGenericWeaponInfoButton() { RobotEditWeaponsDialog dlg(Object_info[m_current].static_wb, GetPolymodelPointer(Object_info[m_current].render_handle)); if (dlg.DoModal() == IDOK) dlg.GetData(); } void CWorldObjectsGenericDialog::OnGenericLightButton() { if (m_current == -1) return; CGenericLightDialog dlg(&Object_info[m_current].lighting_info); dlg.DoModal(); UpdateDialog(); } void CWorldObjectsGenericDialog::OnDefaultRadiusButton() { ComputeDefaultSize(Object_info[m_current].type, Object_info[m_current].render_handle, &Object_info[m_current].size); UpdateDialog(); } void CWorldObjectsGenericDialog::OnSelScript() { CString filter = "D3 Compiled Scripts (*.dll)|*.dll||"; char filename[_MAX_PATH]; char pathname[_MAX_PATH], name[_MAX_PATH]; strcpy(pathname, LocalScriptDir); if (!OpenFileDialog(this, (LPCTSTR)filter, filename, pathname, sizeof(pathname))) return; ddio_SplitPath(filename, NULL, name, NULL); sprintf(filename, "%s.dll", name); strcpy(Object_info[m_current].module_name, filename); UpdateDialog(); /* // TODO: Add your control notification handler code here CScriptSelect dlg(REF_OBJTYPE); if (dlg.DoModal() == IDOK) { strcpy(Object_info[m_current].script_name, (LPCSTR)dlg.m_ScriptName); UpdateDialog(); } */ } void CWorldObjectsGenericDialog::OnGenericConcussiveCheck() { // TODO: Add your control notification handler code here } void CWorldObjectsGenericDialog::OnKillfocusGenericImpactDamageEdit() { CEdit *ebox; char str[20]; ebox = (CEdit *)GetDlgItem(IDC_GENERIC_IMPACT_DAMAGE_EDIT); ebox->GetWindowText(str, 20); Object_info[m_current].damage = atof(str); UpdateDialog(); } void CWorldObjectsGenericDialog::OnKillfocusGenericImpactSizeEdit() { CEdit *ebox; char str[20]; ebox = (CEdit *)GetDlgItem(IDC_GENERIC_IMPACT_SIZE_EDIT); ebox->GetWindowText(str, 20); Object_info[m_current].impact_size = atof(str); UpdateDialog(); } void CWorldObjectsGenericDialog::OnNolod() { // TODO: Add your control notification handler code here if (m_lod == 0) { MessageBox("You must have a hi-res model."); return; } else if (m_lod == 1) { FreePolyModel(Object_info[m_current].med_render_handle); Object_info[m_current].med_render_handle = -1; } else { FreePolyModel(Object_info[m_current].lo_render_handle); Object_info[m_current].lo_render_handle = -1; } UpdateDialog(); } void CWorldObjectsGenericDialog::OnHiresRadio() { m_lod = 0; UpdateDialog(); } void CWorldObjectsGenericDialog::OnMedresRadio() { m_lod = 1; UpdateDialog(); } void CWorldObjectsGenericDialog::OnLoresRadio() { m_lod = 2; UpdateDialog(); } void CWorldObjectsGenericDialog::OnKillfocusGenericImpactTimeEdit() { CEdit *ebox; char str[20]; ebox = (CEdit *)GetDlgItem(IDC_GENERIC_IMPACT_TIME_EDIT); ebox->GetWindowText(str, 20); Object_info[m_current].impact_time = atof(str); UpdateDialog(); } void CWorldObjectsGenericDialog::OnSelendokGenericExplosionSoundCombo() { Object_info[m_current].sounds[GSI_EXPLODE] = m_explosion_sound_combo.GetSelected(); } void CWorldObjectsGenericDialog::OnSelendokGenericAmbientSoundCombo() { Object_info[m_current].sounds[GSI_AMBIENT] = m_ambient_sound_combo.GetSelected(); } void CWorldObjectsGenericDialog::OnKillfocusGenericInvenDescription() { CEdit *ebox; char str[255]; ebox = (CEdit *)GetDlgItem(IDC_GENERIC_INVEN_DESCRIPTION); ebox->GetWindowText(str, 180); if (Object_info[m_current].description) { mem_free(Object_info[m_current].description); Object_info[m_current].description = NULL; } if ((strlen(str) > 0) && (strcmp(str, ""))) { Object_info[m_current].description = mem_strdup(str); } else { ebox->SetWindowText(""); } UpdateDialog(); } void CWorldObjectsGenericDialog::OnKillfocusGenericInvenIconname() { CEdit *ebox; char str[255]; ebox = (CEdit *)GetDlgItem(IDC_GENERIC_INVEN_ICONNAME); ebox->GetWindowText(str, 180); strcpy(Object_info[m_current].icon_name, str); UpdateDialog(); } void CWorldObjectsGenericDialog::OnOverride() { int n = m_current; mngs_Pagelock temp_pl; strcpy(temp_pl.name, Object_info[n].name); temp_pl.pagetype = PAGETYPE_GENERIC; mng_OverrideToUnlocked(&temp_pl); } void CWorldObjectsGenericDialog::OnGenericInvenSelectable() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_GENERIC_INVEN_SELECTABLE); if (btn->GetCheck()) Object_info[m_current].flags |= OIF_INVEN_SELECTABLE; else Object_info[m_current].flags &= ~OIF_INVEN_SELECTABLE; } void CWorldObjectsGenericDialog::OnGenericInvenNonuseable() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_GENERIC_INVEN_NONUSEABLE); if (btn->GetCheck()) Object_info[m_current].flags |= OIF_INVEN_NONUSEABLE; else Object_info[m_current].flags &= ~OIF_INVEN_NONUSEABLE; } void CWorldObjectsGenericDialog::OnKillfocusLodDistanceEdit() { CEdit *ebox; char str[255]; float dist; ebox = (CEdit *)GetDlgItem(IDC_LOD_DISTANCE_EDIT); ebox->GetWindowText(str, 180); dist = atof(str); if (dist < 0) return; if (m_lod == 1) { Object_info[m_current].med_lod_distance = dist; } else if (m_lod == 2) { Object_info[m_current].lo_lod_distance = dist; } UpdateDialog(); } void CWorldObjectsGenericDialog::OnInvtypeGame() { Object_info[m_current].flags &= ~OIF_INVEN_TYPE_MISSION; UpdateDialog(); } void CWorldObjectsGenericDialog::OnInvtypeMission() { Object_info[m_current].flags |= OIF_INVEN_TYPE_MISSION; UpdateDialog(); } void CWorldObjectsGenericDialog::OnInvenNoremove() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_INVEN_NOREMOVE); if (btn->GetCheck()) Object_info[m_current].flags |= OIF_INVEN_NOREMOVE; else Object_info[m_current].flags &= ~OIF_INVEN_NOREMOVE; } void CWorldObjectsGenericDialog::OnInvenViswhenused() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_INVEN_VISWHENUSED); if (btn->GetCheck()) Object_info[m_current].flags |= OIF_INVEN_VISWHENUSED; else Object_info[m_current].flags &= ~OIF_INVEN_VISWHENUSED; } void CWorldObjectsGenericDialog::OnSelendokDeathPowerup1Pulldown() { int cur; char name[200]; cur = SendDlgItemMessage(IDC_DEATH_POWERUP1_PULLDOWN, CB_GETCURSEL, 0, 0); SendDlgItemMessage(IDC_DEATH_POWERUP1_PULLDOWN, CB_GETLBTEXT, cur, (LPARAM)(LPCTSTR)name); Object_info[m_current].dspew[0] = FindObjectIDName(name); UpdateDialog(); } void CWorldObjectsGenericDialog::OnKillfocusDeathPowerup1NumEdit() { CEdit *ebox; char str[20]; ebox = (CEdit *)GetDlgItem(IDC_DEATH_POWERUP1_NUM_EDIT); ebox->GetWindowText(str, 20); Object_info[m_current].dspew_number[0] = atoi(str); UpdateDialog(); } void CWorldObjectsGenericDialog::OnKillfocusDeathPowerup1PercentEdit() { CEdit *ebox; char str[20]; ebox = (CEdit *)GetDlgItem(IDC_DEATH_POWERUP1_PERCENT_EDIT); ebox->GetWindowText(str, 20); Object_info[m_current].dspew_percent[0] = atof(str) / 100.0f; UpdateDialog(); } void CWorldObjectsGenericDialog::OnKillfocusDeathPowerup2NumEdit() { CEdit *ebox; char str[20]; ebox = (CEdit *)GetDlgItem(IDC_DEATH_POWERUP2_NUM_EDIT); ebox->GetWindowText(str, 20); Object_info[m_current].dspew_number[1] = atoi(str); UpdateDialog(); } void CWorldObjectsGenericDialog::OnKillfocusDeathPowerup2PercentEdit() { CEdit *ebox; char str[20]; ebox = (CEdit *)GetDlgItem(IDC_DEATH_POWERUP2_PERCENT_EDIT); ebox->GetWindowText(str, 20); Object_info[m_current].dspew_percent[1] = atof(str) / 100.0f; UpdateDialog(); } void CWorldObjectsGenericDialog::OnSelendokDeathPowerup2Pulldown() { int cur; char name[200]; cur = SendDlgItemMessage(IDC_DEATH_POWERUP2_PULLDOWN, CB_GETCURSEL, 0, 0); SendDlgItemMessage(IDC_DEATH_POWERUP2_PULLDOWN, CB_GETLBTEXT, cur, (LPARAM)(LPCTSTR)name); Object_info[m_current].dspew[1] = FindObjectIDName(name); UpdateDialog(); } void CWorldObjectsGenericDialog::OnDeathPowerupUse2IfHave1Check() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_DEATH_POWERUP_USE2_IF_HAVE1_CHECK); if (btn->GetCheck()) Object_info[m_current].f_dspew |= DSF_ONLY_IF_PLAYER_HAS_OBJ_1; else Object_info[m_current].f_dspew &= ~DSF_ONLY_IF_PLAYER_HAS_OBJ_1; UpdateDialog(); } void CWorldObjectsGenericDialog::OnGenericDeathSpew2IfZero1() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_GENERIC_DEATH_SPEW_2_IF_ZERO_1); if (btn->GetCheck()) Object_info[m_current].f_dspew |= DSF_ONLY_IF_NO_1; else Object_info[m_current].f_dspew &= ~DSF_ONLY_IF_NO_1; UpdateDialog(); } int CWorldObjectsGenericDialog::GetTextureUsageForPolymodel(int modelnum) { poly_model *pm = &Poly_models[modelnum]; int total = 0; uint8_t already_used[100]; memset(already_used, 0, 100); ASSERT(pm && pm->used != 0); for (int i = 0; i < pm->n_models; i++) { bsp_info *sm = &pm->submodel[i]; for (int t = 0; t < sm->num_faces; t++) { polyface *fp = &sm->faces[t]; if (fp->texnum != -1 && !already_used[fp->texnum]) { already_used[fp->texnum] = 1; int texnum = pm->textures[fp->texnum]; texture *texp = &GameTextures[texnum]; if (texnum == 0) continue; // don't count error texture if (texp->used) { if (texp->flags & TF_ANIMATED) { vclip *vc = &GameVClips[texp->bm_handle]; for (int j = 0; j < vc->num_frames; j++) { int bm_handle = vc->frames[j]; int mem_this_tex = bm_w(bm_handle, 0) * bm_h(bm_handle, 0); if (bm_mipped(bm_handle)) mem_this_tex += (mem_this_tex / 3); mem_this_tex *= 2; total += mem_this_tex; } } else { int mem_this_tex = bm_w(texp->bm_handle, 0) * bm_h(texp->bm_handle, 0); if (bm_mipped(texp->bm_handle)) mem_this_tex += (mem_this_tex / 3); mem_this_tex *= 2; total += mem_this_tex; } } } } } return total; } void CWorldObjectsGenericDialog::OnKillfocusScriptname() { char str[MAX_MODULENAME_LEN]; ((CEdit *)GetDlgItem(IDC_SCRIPTNAME))->GetWindowText(str, MAX_MODULENAME_LEN); if (!strcmp(str, "null")) { Object_info[m_current].module_name[0] = '\0'; UpdateDialog(); return; } strcpy(Object_info[m_current].module_name, str); UpdateDialog(); } void CWorldObjectsGenericDialog::OnCompilemodule() { CQuickCompile dlg(Object_info[m_current].module_name); dlg.DoModal(); switch (dlg.ret_value) { case -1: // does not exist break; case 0: // failed compile break; case 1: // success break; }; } void CWorldObjectsGenericDialog::OnKillfocusScriptOverride() { char str[PAGENAME_LEN]; ((CEdit *)GetDlgItem(IDC_SCRIPT_OVERRIDE))->GetWindowText(str, PAGENAME_LEN); if (!strcmp(str, "null")) { Object_info[m_current].script_name_override[0] = '\0'; UpdateDialog(); return; } strncpy(Object_info[m_current].script_name_override, str, PAGENAME_LEN - 1); Object_info[m_current].script_name_override[PAGENAME_LEN - 1] = '\0'; UpdateDialog(); } void CWorldObjectsGenericDialog::OnGenericAiScriptedDeath() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_GENERIC_AI_SCRIPTED_DEATH); if (btn->GetCheck()) Object_info[m_current].flags |= OIF_AI_SCRIPTED_DEATH; else Object_info[m_current].flags &= ~OIF_AI_SCRIPTED_DEATH; } void CWorldObjectsGenericDialog::OnKillfocusRespawnScalarEdit() { CEdit *ebox; char str[20]; float val; ebox = (CEdit *)GetDlgItem(IDC_RESPAWN_SCALAR_EDIT); ebox->GetWindowText(str, 20); val = atof(str); if (val < -1) val = -1; if (val > 10000) val = 10000; Object_info[m_current].respawn_scalar = val; UpdateDialog(); } #include "GenericDeathDialog.h" void CWorldObjectsGenericDialog::OnGenericDeaths() { CGenericDeathDialog dlg(&Object_info[m_current]); dlg.DoModal(); } void CWorldObjectsGenericDialog::OnKillfocusGenericScoreEdit() { char str[20]; ((CEdit *)GetDlgItem(IDC_GENERIC_SCORE_EDIT))->GetWindowText(str, 20); Object_info[m_current].score = atoi(str); } void CWorldObjectsGenericDialog::OnKillfocusGenericAmmoEdit() { char str[20]; ((CEdit *)GetDlgItem(IDC_GENERIC_AMMO_EDIT))->GetWindowText(str, 20); Object_info[m_current].ammo_count = atoi(str); } void CWorldObjectsGenericDialog::OnObjCeilingCheck() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_OBJ_CEILING_CHECK); if (btn->GetCheck()) Object_info[m_current].flags |= OIF_DO_CEILING_CHECK; else Object_info[m_current].flags &= ~OIF_DO_CEILING_CHECK; } void CWorldObjectsGenericDialog::OnObjectFlyThroughRenderedPortals() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_OBJECT_FLY_THROUGH_RENDERED_PORTALS); if (btn->GetCheck()) Object_info[m_current].flags |= OIF_IGNORE_FORCEFIELDS_AND_GLASS; else Object_info[m_current].flags &= ~OIF_IGNORE_FORCEFIELDS_AND_GLASS; } void CWorldObjectsGenericDialog::OnNscButton() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_NSC_BUTTON); if (btn->GetCheck()) Object_info[m_current].flags |= OIF_NO_DIFF_SCALE_DAMAGE; else Object_info[m_current].flags &= ~OIF_NO_DIFF_SCALE_DAMAGE; } void CWorldObjectsGenericDialog::OnDsmpbdCheck() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_DSMPBD_CHECK); if (btn->GetCheck()) Object_info[m_current].flags |= OIF_NO_DIFF_SCALE_MOVE; else Object_info[m_current].flags &= ~OIF_NO_DIFF_SCALE_MOVE; } void CWorldObjectsGenericDialog::OnGenericAmbient() { CButton *btn; btn = (CButton *)GetDlgItem(IDC_GENERIC_AMBIENT); if (btn->GetCheck()) Object_info[m_current].flags |= OIF_AMBIENT_OBJECT; else Object_info[m_current].flags &= ~OIF_AMBIENT_OBJECT; }