/* * 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/WorldObjectsDoorDialog.cpp $ * $Revision: 1.1.1.1 $ * $Date: 2003-08-26 03:57:39 $ * $Author: kevinb $ * * WorldObjectsDoorDialog.cpp : implementation file * * $Log: not supported by cvs2svn $ * * 26 2/04/99 2:05p Matt * Added blastable doors * * 25 1/21/99 11:15p Jeff * pulled out some structs and defines from header files and moved them * into seperate header files so that multiplayer dlls don't require major * game headers, just those new headers. Side effect is a shorter build * time. Also cleaned up some header file #includes that weren't needed. * This affected polymodel.h, object.h, player.h, vecmat.h, room.h, * manage.h and multi.h * * 24 1/08/99 2:56p Samir * Ripped out OSIRIS1. * * 23 12/21/98 5:27p Jeff * added osiris module information to door page. Fixed up dialogs for * objects and doors for script interface (added a browse button) * * 22 11/06/98 12:34p Jason * more speedups for manage system * * 21 10/14/98 12:08p Jason * fixed some long standing name problems * * 20 10/08/98 4:24p Kevin * Changed code to comply with memory library usage. Always use mem_malloc * , mem_free and mem_strdup * * 19 6/23/98 2:43p Matt * Changed calls to OutrageMessageBox() & Debug_MessageBox() to deal with * int return value (instead of bool). * * 18 6/15/98 4:00p Jason * replaced monochromatic polymodel lighting with rgb lighting * * 17 5/22/98 8:50p Matt * Added sounds for doors * * 16 4/17/98 1:53p Matt * Reinitialize all objects when leaving the editor dialogs for generic * objects (robots, powerps), doors, and player ships. * * 15 4/06/98 4:53p Jason * got pageable polymodels working correctly with editor * * 14 4/02/98 3:54p Jason * first pass in getting polymodel paging to work * * 13 2/02/98 7:07p Matt * Added support for doors that can be seen through even when closed * * 12 1/25/98 5:17p Matt * Changed the door dialog to be more like the generic dialog * * 11 1/23/98 5:39p Matt * Added validity checking for door models. * * 10 12/19/97 11:25a Samir * g3_StartFrame and g3_EndFrame replaced by EditorStartFrame and * EditorEndFrame * * 9 12/01/97 6:06p Samir * Implemented new FileDialog tracker system. * * 8 10/06/97 3:24p Jason * fixed checkin problem * * 7 10/06/97 1:01p Jason * made doors work with scripts (sort of) * * 6 9/11/97 5:38p Jason * initial door coding for room engine * * 5 8/08/97 2:25p Matt * Took out error messages which are now handled by mng_MakeLocker() * * 4 8/07/97 12:42p Jason * fixed potential memory problem * * 3 7/24/97 6:11p Matt * Created symbolic constant for default zoom, and used it every place * that specifies zoom * * $NoKeywords: $ */ #include "stdafx.h" #include "editor.h" #include "WorldObjectsDoorDialog.h" #include "manage.h" #include "doorpage.h" #include "mono.h" #include "vclip.h" #include "polymodel.h" #include "door.h" #include "ddio.h" #include "EditLineDialog.h" #include "objinit.h" #include "soundload.h" #include "mem.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CWorldObjectsDoorDialog dialog CWorldObjectsDoorDialog::CWorldObjectsDoorDialog(CWnd* pParent /*=NULL*/) : CDialog(CWorldObjectsDoorDialog::IDD, pParent) { //{{AFX_DATA_INIT(CWorldObjectsDoorDialog) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT } void CWorldObjectsDoorDialog::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CWorldObjectsDoorDialog) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CWorldObjectsDoorDialog, CDialog) //{{AFX_MSG_MAP(CWorldObjectsDoorDialog) ON_BN_CLICKED(IDC_ADD_DOOR, OnAddDoor) ON_BN_CLICKED(IDC_CHECKIN_DOOR, OnCheckinDoor) ON_EN_KILLFOCUS(IDC_CLOSE_TIME, OnKillfocusCloseTime) ON_BN_CLICKED(IDC_DELETE_DOOR, OnDeleteDoor) ON_BN_CLICKED(IDC_DOOR_NEXT, OnDoorNext) ON_EN_KILLFOCUS(IDC_DOOR_OPEN_TIME, OnKillfocusDoorOpenTime) ON_BN_CLICKED(IDC_DOOR_PREV, OnDoorPrev) ON_EN_KILLFOCUS(IDC_DOOR_STAYS_OPEN, OnKillfocusDoorStaysOpen) ON_BN_CLICKED(IDC_DOORS_OUT, OnDoorsOut) ON_BN_CLICKED(IDC_LOAD_DOOR_MODEL, OnLoadDoorModel) ON_BN_CLICKED(IDC_LOCK_DOOR, OnLockDoor) ON_WM_TIMER() ON_CBN_SELENDOK(IDC_DOOR_PULLDOWN, OnSelendokDoorPulldown) ON_WM_HELPINFO() ON_BN_CLICKED(IDC_DOOR_CHANGE_NAME, OnDoorChangeName) ON_BN_CLICKED(IDC_TRANSPARENCY, OnTransparency) ON_WM_DESTROY() ON_CBN_SELENDOK(IDC_DOOR_CLOSE_SOUND, OnSelendokDoorCloseSound) ON_CBN_SELENDOK(IDC_DOOR_OPEN_SOUND, OnSelendokDoorOpenSound) ON_BN_CLICKED(IDC_BROWSE, OnBrowse) ON_EN_KILLFOCUS(IDC_SCRIPTNAME, OnKillfocusScriptname) ON_BN_CLICKED(IDC_DOOR_BLASTABLE, OnDoorBlastable) ON_EN_KILLFOCUS(IDC_DOOR_HITPOINTS_EDIT, OnKillfocusDoorHitpointsEdit) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CWorldObjectsDoorDialog message handlers #include "room.h" //Makes sure a door model is ok. If not ok, brings up messagebox to tell the user //Parameter: handle - the handle for the polymodel //Returns: true if ok, else false bool VerifyDoorModel(int handle) { poly_model *pm = GetPolymodelPointer (handle); int s; bool found_frontface=0,found_shell=0; for (s=0;sn_models;s++) { bsp_info *sm = &pm->submodel[s]; if (sm->flags & SOF_FRONTFACE) { if (sm->num_faces != 1) { OutrageMessageBox("Invalid door model: Frontface has %d faces; must have 1.",sm->num_faces); return 0; } if (sm->num_children != 0) { OutrageMessageBox("Invalid door model: Frontface cannot have submodels."); return 0; } found_frontface = 1; } if (sm->flags & SOF_SHELL) { if (sm->num_children != 0) { OutrageMessageBox("Invalid door model: Shell cannot have submodels."); return 0; } //check polygons in the shell. we do this by copying the poly face into a room room check_room; face check_face; check_room.verts = sm->verts; check_room.faces = &check_face; for (int f=0;fnum_faces;f++) { polyface *polyface = &sm->faces[f]; //copy polygon face into the room face check_face.num_verts = polyface->nverts; check_face.face_verts = polyface->vertnums; if (! ComputeFaceNormal(&check_room,0)) { OutrageMessageBox("Invalid door model: Face %d in shell has bad normal.",f); return 0; } } found_shell = 1; } } if (! found_frontface) { OutrageMessageBox("Invalid door model: Missing Frontface."); return 0; } if (! found_shell) { OutrageMessageBox("Invalid door model: Missing Shell."); return 0; } return 1; } void CWorldObjectsDoorDialog::OnAddDoor() { char filename[256], pathname[256], dir[256], ext[32]; char cur_name[100]; int img_handle; int door_handle; int c=1,finding_name=1; if (!Network_up) { OutrageMessageBox ("Sorry babe, the network is down. This action is a no-no.\n"); return; } // Get the filename of the representing image CString filter = "Descent III files (*.pof,*.oof)|*.pof;*.oof||"; if (!OpenFileDialog(this, (LPCSTR)filter, pathname, Current_model_dir, sizeof(Current_model_dir))) return; // Okay, we selected a file. Lets do what needs to be done here. img_handle=LoadDoorImage (pathname,0); ddio_SplitPath(pathname, dir, filename, ext); if (! VerifyDoorModel(img_handle)) { FreePolyModel(img_handle); return; } if (img_handle<0) { OutrageMessageBox ("Couldn't open that model file."); return; } // Alloc a door and give a name not already taken by some other door door_handle=AllocDoor(); while (finding_name) { if (c==1) sprintf (cur_name,"%s",filename); else sprintf (cur_name,"%s%d",filename,c); if (FindDoorName (cur_name)!=-1) c++; else finding_name=0; } strcpy (Doors[door_handle].name,cur_name); Doors[door_handle].model_handle=img_handle; // Finally, save a local copy of the model/anim and alloc a tracklock mprintf ((0,"Making a copy of this model locally...\n")); char destname[100]; sprintf (destname,"%s\\%s",LocalModelsDir,Poly_models[Doors[door_handle].model_handle].name); if (stricmp (destname,pathname)) // only copy if they are different cf_CopyFile (destname,pathname); mng_AllocTrackLock (cur_name,PAGETYPE_DOOR); D3EditState.current_door=door_handle; UpdateDialog (); } #define NULL_NAME "" void CWorldObjectsDoorDialog::UpdateDialog() { CEdit *ebox; CButton *bbox; int n=D3EditState.current_door; char str[50]; if (Num_doors<1) { bbox=(CButton *) GetDlgItem (IDC_DOOR_NEXT); bbox->EnableWindow (FALSE); bbox=(CButton *) GetDlgItem (IDC_DOOR_PREV); bbox->EnableWindow (FALSE); return; } else { bbox=(CButton *) GetDlgItem (IDC_DOOR_NEXT); bbox->EnableWindow (TRUE); bbox=(CButton *) GetDlgItem (IDC_DOOR_PREV); bbox->EnableWindow (TRUE); } if (!Doors[n].used) n=D3EditState.current_door=GetNextDoor(n); // ebox=(CEdit *) GetDlgItem (IDC_DOOR_NAME_EDIT); // ebox->SetWindowText (Doors[n].name); bbox = (CButton *)GetDlgItem(IDC_TRANSPARENCY); bbox->SetCheck(Doors[n].flags & DF_SEETHROUGH); bool blastable = ((Doors[n].flags & DF_BLASTABLE) != 0); bbox = (CButton *)GetDlgItem(IDC_DOOR_BLASTABLE); bbox->SetCheck(blastable); ebox=(CEdit *) GetDlgItem (IDC_DOOR_MODEL_NAME_EDIT); ebox->SetWindowText (Poly_models[Doors[n].model_handle].name); ebox=(CEdit *) GetDlgItem (IDC_DOOR_OPEN_TIME); sprintf (str,"%f",Doors[n].total_open_time); ebox->SetWindowText (str); ebox=(CEdit *) GetDlgItem (IDC_DOOR_STAYS_OPEN); sprintf (str,"%f",Doors[n].total_time_open); ebox->SetWindowText (str); ebox=(CEdit *) GetDlgItem (IDC_CLOSE_TIME); sprintf (str,"%f",Doors[n].total_close_time); ebox->SetWindowText (str); //Update hitpoint editing controls GetDlgItem(IDC_DOOR_HITPOINTS_TEXT)->EnableWindow(blastable); ebox=(CEdit *) GetDlgItem (IDC_DOOR_HITPOINTS_EDIT); sprintf(str,"%d",Doors[n].hit_points); ebox->SetWindowText(str); ebox->EnableWindow(blastable); bbox=(CButton *) GetDlgItem (IDC_CHECKIN_DOOR); if (mng_FindTrackLock (Doors[n].name,PAGETYPE_DOOR)==-1) { bbox->EnableWindow (FALSE); bbox=(CButton *) GetDlgItem (IDC_LOCK_DOOR); bbox->EnableWindow (TRUE); } else { bbox->EnableWindow (TRUE); bbox=(CButton *) GetDlgItem (IDC_LOCK_DOOR); bbox->EnableWindow (FALSE); } SendDlgItemMessage( IDC_DOOR_PULLDOWN, CB_RESETCONTENT,0,0); for (int i=0;iSetWindowText("null"); else ebox->SetWindowText(Doors[n].module_name); //Update sounds lists SendDlgItemMessage( IDC_DOOR_OPEN_SOUND, CB_RESETCONTENT,0,0); SendDlgItemMessage( IDC_DOOR_OPEN_SOUND, CB_ADDSTRING,0,(LPARAM) (LPCTSTR) NULL_NAME); for (i=0;iGetWindowRect(&rect); ScreenToClient(&rect); Desktop_surf->attach_to_window((unsigned)m_hWnd); w=rect.right-rect.left; h=rect.bottom-rect.top; if (last_door!=n || last_model_handle!=Doors[n].model_handle) { Desktop_surf->clear(rect.left,rect.top,w,h); last_door=n; last_model_handle=Doors[n].model_handle; } bm_handle=GetDoorImage (n); 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[30]; for (int i=0;i<30;i++) norm_angles[i]=(float)frame/(float)NUM_ANIM_FRAMES; spin_frame++; vm_AnglesToMatrix (&rot_matrix,0,spin_frame*400,0); m_DoorSurf.create(128, 128, BPP_16); grViewport *vport=new grViewport (&m_DoorSurf); 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_DoorSurf.width()/2; y = rect.top + ((rect.bottom-rect.top)/2) - m_DoorSurf.height()/2; Desktop_surf->blt(x, y, &m_DoorSurf); delete vport; m_DoorSurf.free(); } void CWorldObjectsDoorDialog::OnCheckinDoor() { int n=D3EditState.current_door; mngs_Pagelock temp_pl; int r; if (Num_doors<1) return; if (!mng_MakeLocker()) return; // Make sure we own this door strcpy (temp_pl.name,Doors[n].name); temp_pl.pagetype=PAGETYPE_DOOR; 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 (Doors[n].name,Doors[n].name,n,PAGETYPE_DOOR,0)) OutrageMessageBox (ErrorString); else { // Save this door anim/model to the network for all char destname[100],srcname[100]; sprintf (srcname,"%s\\%s",LocalModelsDir,Poly_models[Doors[n].model_handle].name); sprintf (destname,"%s\\%s",NetModelsDir,Poly_models[Doors[n].model_handle].name); cf_CopyFile (destname,srcname); OutrageMessageBox ("Door checked in."); // Delete it from local pagefile if its there int dret=mng_DeletePage (Doors[n].name,PAGETYPE_DOOR,1); ASSERT (dret==1); mng_EraseLocker(); // Free the tracklock int p=mng_FindTrackLock (Doors[n].name,PAGETYPE_DOOR); ASSERT (p!=-1); mng_FreeTrackLock (p); UpdateDialog (); } } } mng_EraseLocker(); } void CWorldObjectsDoorDialog::OnKillfocusCloseTime() { CEdit *ebox; char str[20]; int n=D3EditState.current_door; ebox=(CEdit *) GetDlgItem (IDC_CLOSE_TIME); ebox->GetWindowText (str,20); Doors[n].total_close_time=atof (str); } void CWorldObjectsDoorDialog::OnDeleteDoor() { int answer,tl; mngs_Pagelock pl; int n=D3EditState.current_door; if (Num_doors<1) return; // Check to see if we even have it locked if ((tl=mng_FindTrackLock (Doors[n].name,PAGETYPE_DOOR))==-1) { OutrageMessageBox ("This door is not yours to delete. Lock first."); return; } //Make sure its to be deleted answer=MessageBox ("Are you sure you want to delete this door?",Doors[n].name,MB_YESNO); if (answer==IDNO) return; if (!mng_MakeLocker()) return; strcpy (pl.name,Doors[n].name); pl.pagetype=PAGETYPE_DOOR; // Check to see if this is a local door only. If so, only delete it locally if (mng_CheckIfPageOwned (&pl,TableUser)!=1) { mng_FreeTrackLock (tl); if (!mng_DeletePage (Doors[n].name,PAGETYPE_DOOR,1)) { mprintf ((0,ErrorString)); Int3(); } } else // if its network, delete it from both the net and local drives { mng_FreeTrackLock (tl); mng_DeletePage (Doors[n].name,PAGETYPE_DOOR,1); mng_DeletePage (Doors[n].name,PAGETYPE_DOOR,0); mng_DeletePagelock (Doors[n].name,PAGETYPE_DOOR); } // Advance to the next door D3EditState.current_door=GetNextDoor (n); FreePolyModel (Doors[n].model_handle); FreeDoor (n); mng_EraseLocker(); OutrageMessageBox ("Door deleted."); UpdateDialog (); } //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 InputDoorName(char *buf,int len,char *title,char *prompt,CWnd *wnd) { char *tempbuf = (char *) mem_malloc(len); strcpy(tempbuf,buf); try_again: if (! InputString(tempbuf,len,title,prompt,wnd)) { mem_free(tempbuf); return 0; } if (FindDoorName(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 CWorldObjectsDoorDialog::OnDoorChangeName() { int n=D3EditState.current_door; char name[PAGENAME_LEN]; mngs_Pagelock pl; // Make sure we have this door locked, if not reset name and bail int p=mng_FindTrackLock (Doors[n].name,PAGETYPE_DOOR); if (p==-1) { OutrageMessageBox ("You must lock this door if you wish to change its name."); return; } //Get new name strcpy(name,Doors[n].name); if (! InputDoorName(name,sizeof(name),"Door name","Enter a new name for this door:",this)) return; 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,Doors[n].name); pl.pagetype=PAGETYPE_DOOR; int ret=mng_CheckIfPageOwned (&pl,TableUser); if (ret<0) OutrageMessageBox (ErrorString); else if (ret==1) mng_RenamePage (Doors[n].name,name,PAGETYPE_DOOR); else if (ret==2) { // This page has never been checked in, replace only local copy char oldname[PAGENAME_LEN]; strcpy (oldname,Doors[n].name); strcpy (Doors[n].name,name); mng_ReplacePage (oldname,Doors[n].name,n,PAGETYPE_DOOR,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 (Doors[n].name,name); UpdateDialog(); mng_EraseLocker(); } void CWorldObjectsDoorDialog::OnDoorNext() { D3EditState.current_door=GetNextDoor(D3EditState.current_door); UpdateDialog(); } void CWorldObjectsDoorDialog::OnKillfocusDoorOpenTime() { CEdit *ebox; char str[20]; int n=D3EditState.current_door; ebox=(CEdit *) GetDlgItem (IDC_DOOR_OPEN_TIME); ebox->GetWindowText (str,20); Doors[n].total_open_time=atof (str); } void CWorldObjectsDoorDialog::OnDoorPrev() { D3EditState.current_door=GetPrevDoor(D3EditState.current_door); UpdateDialog(); } void CWorldObjectsDoorDialog::OnKillfocusDoorStaysOpen() { // TODO: Add your control notification handler code here CEdit *ebox; char str[20]; int n=D3EditState.current_door; ebox=(CEdit *) GetDlgItem (IDC_DOOR_STAYS_OPEN); ebox->GetWindowText (str,20); Doors[n].total_time_open=atof (str); } void CWorldObjectsDoorDialog::OnDoorsOut() { char str[10000]; int total=0; mng_DisplayLockList (TableUser); sprintf (str,"User %s has these doors held locally:\n\n",TableUser); for (int i=0;iGetCheck()) Doors[n].flags |= DF_SEETHROUGH; else Doors[n].flags &= ~DF_SEETHROUGH; } void CWorldObjectsDoorDialog::OnDestroy() { CDialog::OnDestroy(); ObjReInitAll(); } void CWorldObjectsDoorDialog::OnSelendokDoorOpenSound() { int cur; char name[200]; int n=D3EditState.current_door; cur=SendDlgItemMessage( IDC_DOOR_OPEN_SOUND, CB_GETCURSEL,0,0); SendDlgItemMessage( IDC_DOOR_OPEN_SOUND, CB_GETLBTEXT,cur,(LPARAM) (LPCTSTR)name); Doors[n].open_sound = FindSoundName(name); } void CWorldObjectsDoorDialog::OnSelendokDoorCloseSound() { int cur; char name[200]; int n=D3EditState.current_door; cur=SendDlgItemMessage( IDC_DOOR_CLOSE_SOUND, CB_GETCURSEL,0,0); SendDlgItemMessage( IDC_DOOR_CLOSE_SOUND, CB_GETLBTEXT,cur,(LPARAM) (LPCTSTR)name); Doors[n].close_sound = FindSoundName(name); } void CWorldObjectsDoorDialog::OnBrowse() { 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); int n = D3EditState.current_door; strcpy(Doors[n].module_name,filename); UpdateDialog(); } void CWorldObjectsDoorDialog::OnKillfocusScriptname() { char str[MAX_MODULENAME_LEN]; ((CEdit *) GetDlgItem(IDC_SCRIPTNAME))->GetWindowText(str,MAX_MODULENAME_LEN); strcpy(Doors[D3EditState.current_door].module_name, str); UpdateDialog(); } void CWorldObjectsDoorDialog::OnDoorBlastable() { int n=D3EditState.current_door; CButton *btn; btn = (CButton *)GetDlgItem(IDC_DOOR_BLASTABLE); if (btn->GetCheck()) Doors[n].flags |= DF_BLASTABLE; else Doors[n].flags &= ~DF_BLASTABLE; UpdateDialog(); } void CWorldObjectsDoorDialog::OnKillfocusDoorHitpointsEdit() { char str[256]; int n=D3EditState.current_door; CEdit *ebox=(CEdit *) GetDlgItem (IDC_DOOR_HITPOINTS_EDIT); ebox->GetWindowText(str,sizeof(str)); Doors[n].hit_points = atoi(str); UpdateDialog(); }