mirror of
https://github.com/thug1src/thug.git
synced 2024-12-02 12:56:45 +00:00
3815 lines
103 KiB
C++
3815 lines
103 KiB
C++
#include <core/defines.h>
|
|
#include <gel/mainloop.h>
|
|
#include <gel/objtrack.h>
|
|
#include <gel/event.h>
|
|
#include <gel/scripting/checksum.h>
|
|
#include <gel/scripting/script.h>
|
|
#include <gel/scripting/struct.h>
|
|
#include <gel/scripting/array.h>
|
|
#include <gel/scripting/symboltable.h>
|
|
#include <gel/scripting/utils.h>
|
|
#include <gel/scripting/component.h>
|
|
#include <gel/object/compositeobjectmanager.h>
|
|
#include <sk/ParkEditor2/ParkEd.h>
|
|
#include <sk/scripting/cfuncs.h>
|
|
#include <sk/modules/FrontEnd/FrontEnd.h>
|
|
#include <gfx/nxviewman.h>
|
|
#include <gfx/2D/ScreenElemMan.h>
|
|
#include <gfx/2D/TextElement.h>
|
|
#include <gel/components/cameracomponent.h>
|
|
#include <sk/components/raileditorcomponent.h>
|
|
#include <sk/components/goaleditorcomponent.h>
|
|
|
|
#include <sk/modules/skate/skate.h>
|
|
|
|
#include <sk/ParkEditor2/clipboard.h>
|
|
#include <core/string/stringutils.h>
|
|
|
|
//#define DONT_USE_CURSOR_META
|
|
|
|
namespace Ed
|
|
{
|
|
|
|
|
|
|
|
|
|
const float CParkEditor::vMAX_CAM_DIST = 1500.0f;
|
|
const float CParkEditor::vMIN_CAM_DIST = 500.0f;
|
|
const float CParkEditor::vCAM_DIST_INC = 16.0f;
|
|
const float CParkEditor::vCAM_TARGET_ELEVATION = 300.0f;
|
|
|
|
DefineSingletonClass( CParkEditor, "Park editor module" );
|
|
|
|
|
|
|
|
|
|
CParkEditor::CParkEditor() :
|
|
mp_park_manager(true)
|
|
{
|
|
m_logic_task = new Tsk::Task< CParkEditor > ( CParkEditor::s_logic_code, *this );
|
|
m_display_task = new Tsk::Task< CParkEditor > ( CParkEditor::s_display_code, *this, Tsk::BaseTask::Node::vDISPLAY_TASK_PRIORITY_CPARKEDITOR_DISPLAY );
|
|
m_input_handler = new Inp::Handler< CParkEditor > ( 0, CParkEditor::s_input_logic_code, *this);
|
|
|
|
m_movement_vel = 480.0f; //8.0f; // default movement velocity in inches per second
|
|
m_rotate_vel = 120.0f; // 120 degrees per second. In 3 seconds you should complete 1 revolution
|
|
|
|
mp_camera = NULL;
|
|
m_camDist = 1400.0f;
|
|
m_camAngle = 0.0f; //225.0f;
|
|
m_camAngleVert = 10.0f;
|
|
|
|
m_cursor_state = vMOVEMENT;
|
|
m_state = vINACTIVE;
|
|
m_paused = false;
|
|
|
|
mp_cursor = NULL;
|
|
mp_menu_manager = NULL;
|
|
|
|
m_pct_resources_used = 1.0f;
|
|
m_last_main_heap_free=0;
|
|
|
|
m_tod_script=0;
|
|
|
|
mp_play_mode_gap_manager=NULL;
|
|
|
|
m_allow_defrag=false;
|
|
|
|
RegisterWithTracker(NULL);
|
|
}
|
|
|
|
|
|
|
|
|
|
CParkEditor::~CParkEditor()
|
|
{
|
|
}
|
|
|
|
|
|
|
|
|
|
void CParkEditor::Initialize(bool editMode)
|
|
{
|
|
ParkEd("CParkEditor::Initialize()");
|
|
//printf("CParkEditor::Initialize\n");
|
|
|
|
mp_park_manager->Initialize();
|
|
|
|
if (editMode && !mp_cursor)
|
|
{
|
|
mp_cursor = new CCursor();
|
|
mp_menu_manager = new CUpperMenuManager();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void CParkEditor::Rebuild(bool justRebuildFloor, bool clearMap, bool makeCursor)
|
|
{
|
|
ParkEd("CParkEditor::Rebuild(justRebuildFloor = %d, clearMap = %d)", justRebuildFloor, clearMap);
|
|
|
|
if (justRebuildFloor)
|
|
{
|
|
mp_park_manager->RebuildFloor();
|
|
}
|
|
else
|
|
{
|
|
if (mp_cursor)
|
|
delete mp_cursor;
|
|
mp_cursor = NULL;
|
|
mp_park_manager->RebuildWholePark(clearMap);
|
|
}
|
|
|
|
if (makeCursor && !mp_cursor)
|
|
{
|
|
mp_cursor = new CCursor();
|
|
}
|
|
|
|
// Fix to TT1437, where the 1P restart piece was able to be placed outside the map if X pressed really quickly
|
|
// just after nuking a park.
|
|
if (mp_cursor)
|
|
{
|
|
mp_cursor->ForceInBounds();
|
|
}
|
|
|
|
// Regenerate the node array when the park is rebuilt (usually only happens when we are going to play the level)
|
|
mp_park_manager->RebuildNodeArray();
|
|
|
|
// and re register the gaps so that any old gaps are removed from the career.
|
|
CGapManager::sInstance()->RegisterGapsWithSkaterCareer();
|
|
}
|
|
|
|
|
|
|
|
|
|
void CParkEditor::SetState(EEditorState desiredState)
|
|
{
|
|
ParkEd("CParkEditor::SetState(desiredState = %d)", desiredState);
|
|
|
|
if (desiredState != vKEEP_SAME_STATE)
|
|
{
|
|
m_state = desiredState;
|
|
}
|
|
|
|
// this prevents menu input from placing a piece
|
|
m_commands.ClearAll();
|
|
if (mp_cursor)
|
|
mp_cursor->SetVisibility(m_state == vEDITING);
|
|
|
|
if (desiredState == vTEST_PLAY || desiredState == vREGULAR_PLAY)
|
|
{
|
|
// XXX
|
|
Ryan("$$$MakeEditorStuffVisible(false)\n");
|
|
MakeEditorStuffVisible(false);
|
|
|
|
CGapManager::sInstance()->RegisterGapsWithSkaterCareer();
|
|
}
|
|
else
|
|
{
|
|
// XXX
|
|
Ryan("$$$MakeEditorStuffVisible(true)\n");
|
|
MakeEditorStuffVisible(true);
|
|
}
|
|
|
|
Spt::SingletonPtr<Mdl::FrontEnd> p_front_end;
|
|
if (desiredState == vEDITING)
|
|
{
|
|
Mdl::Skate::Instance()->CleanupForParkEditor();
|
|
|
|
p_front_end->SetAutoRepeatTimes(320, 100);
|
|
mp_park_manager->HighlightMetasWithGaps(false, NULL);
|
|
}
|
|
else
|
|
{
|
|
// same as above, but what the hell
|
|
p_front_end->SetAutoRepeatTimes(320, 50);
|
|
}
|
|
update_analog_stick_menu_control_state();
|
|
}
|
|
|
|
|
|
|
|
|
|
void CParkEditor::MakeEditorStuffVisible(bool visible)
|
|
{
|
|
ParkEd("MakeEditorStuffVisible(visible = %d)", visible);
|
|
|
|
// it would be nice to sort out the encapsulation sometime...
|
|
Ed::CParkManager::Instance()->GetGenerator()->HighlightAllPieces(false);
|
|
Ed::CParkManager::Instance()->GetGenerator()->SetGapPiecesVisible(visible);
|
|
Ed::CParkManager::Instance()->GetGenerator()->SetRestartPiecesVisible(visible);
|
|
|
|
if (visible)
|
|
{
|
|
Script::RunScript("pause_trick_text");
|
|
Script::RunScript("GoalManager_HidePoints");
|
|
Script::RunScript("GoalManager_HideGoalPoints");
|
|
Script::RunScript("SK4_Hide_Death_Message");
|
|
}
|
|
else
|
|
{
|
|
Script::RunScript("unpause_trick_text");
|
|
Script::RunScript("GoalManager_ShowPoints");
|
|
Script::RunScript("GoalManager_ShowGoalPoints");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void CParkEditor::AccessDisk(bool save, int fileSlot, bool blockRebuild)
|
|
{
|
|
ParkEd("CParkEditor::AccessDisk()");
|
|
|
|
if (save)
|
|
{
|
|
CParkManager::sInstance()->AccessDisk(true, fileSlot);
|
|
}
|
|
else
|
|
{
|
|
int old_theme = CParkManager::sInstance()->GetTheme();
|
|
|
|
if (m_state != vINACTIVE && !blockRebuild)
|
|
{
|
|
// need to destroy cursor geometry now, otherwise code will think park has changed
|
|
Dbg_Assert(mp_cursor);
|
|
mp_cursor->DestroyGeometry();
|
|
}
|
|
if (mp_cursor)
|
|
{
|
|
mp_cursor->DestroyAnyClipboardCursors();
|
|
}
|
|
|
|
CParkManager::sInstance()->AccessDisk(false, fileSlot);
|
|
if (m_state != vINACTIVE && !blockRebuild)
|
|
{
|
|
if (CParkManager::sInstance()->GetTheme() != old_theme)
|
|
{
|
|
Script::CStruct params;
|
|
params.AddChecksum("level", CRCD(0xe8b4b836,"Load_Sk5Ed"));
|
|
|
|
Script::RunScript("change_level", ¶ms);
|
|
}
|
|
else
|
|
{
|
|
CParkManager::sInstance()->RebuildWholePark(false);
|
|
mp_cursor->ChangePieceInSet(0);
|
|
mp_park_manager->HighlightMetasWithGaps(false, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void CParkEditor::PostMemoryCardLoad(uint8 * p_map_buffer, int oldTheme)
|
|
{
|
|
bool needs_rebuild = (m_state == vEDITING || m_state == vTEST_PLAY);
|
|
|
|
if (needs_rebuild)
|
|
{
|
|
// need to destroy cursor geometry now, otherwise code will think park has changed
|
|
Dbg_Assert(mp_cursor);
|
|
mp_cursor->DestroyGeometry();
|
|
}
|
|
// PATCH: Copy buffer back over itself to set the flags
|
|
Ed::CParkManager::Instance()->SetCompressedMapBuffer(p_map_buffer);
|
|
if (needs_rebuild)
|
|
{
|
|
// XXX
|
|
Ryan("old theme %d, new theme %d\n", oldTheme, CParkManager::sInstance()->GetTheme());
|
|
if (CParkManager::sInstance()->GetTheme() != oldTheme)
|
|
{
|
|
Script::CStruct params;
|
|
params.AddChecksum("level", CRCD(0xe8b4b836,"Load_Sk5Ed"));
|
|
|
|
Script::RunScript("change_level", ¶ms);
|
|
}
|
|
else
|
|
{
|
|
CParkManager::sInstance()->RebuildWholePark(false);
|
|
mp_cursor->ChangePieceInSet(0);
|
|
mp_park_manager->HighlightMetasWithGaps(false, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// K: Added to allow cleanup of the park editor heap during play
|
|
void CParkEditor::DeleteCursor()
|
|
{
|
|
if (mp_cursor)
|
|
{
|
|
delete mp_cursor;
|
|
mp_cursor=NULL;
|
|
}
|
|
}
|
|
|
|
// Creates a copy of the gap manager on the script heap.
|
|
// CGapManager::sInstance() will still return the original gap manager afterwards however.
|
|
// This function is needed because to free up memory before playing a park, everything on the
|
|
// park editor heap is deleted and then the heap is deleted, and the original gap manager is on that heap.
|
|
// So a copy is made for play mode, since the gap manager is needed when a gap fires.
|
|
void CParkEditor::CreatePlayModeGapManager()
|
|
{
|
|
Dbg_MsgAssert(mp_play_mode_gap_manager==NULL,("Expected mp_play_mode_gap_manager to be NULL"));
|
|
Ed::CGapManager *p_original_gap_manager = CGapManager::sInstance();
|
|
|
|
Mem::Manager::sHandle().PushContext(Mem::Manager::sHandle().ScriptHeap());
|
|
mp_play_mode_gap_manager=new Ed::CGapManager(NULL);
|
|
|
|
// Use the overloaded assignement operator to make the copy.
|
|
*mp_play_mode_gap_manager = *p_original_gap_manager;
|
|
|
|
Mem::Manager::sHandle().PopContext();
|
|
|
|
|
|
// The constructor of CGapManager sets the sp_instance pointer, so set it back to the original so that
|
|
// things don't get confused.
|
|
p_original_gap_manager->SetInstance();
|
|
}
|
|
|
|
void CParkEditor::SwitchToPlayModeGapManager()
|
|
{
|
|
Dbg_MsgAssert(CGapManager::sInstanceNoAssert() == NULL,("Expected CGapManager::sInstance() to be NULL"));
|
|
Dbg_MsgAssert(mp_play_mode_gap_manager,("NULL mp_play_mode_gap_manager"));
|
|
mp_play_mode_gap_manager->SetInstance();
|
|
}
|
|
|
|
void CParkEditor::DeletePlayModeGapManager()
|
|
{
|
|
if (mp_play_mode_gap_manager)
|
|
{
|
|
delete mp_play_mode_gap_manager;
|
|
mp_play_mode_gap_manager=NULL;
|
|
}
|
|
Dbg_MsgAssert(CGapManager::sInstanceNoAssert() == NULL,("Expected CGapManager::sInstance() to be NULL"));
|
|
}
|
|
|
|
void CParkEditor::PlayModeGapManagerChecks()
|
|
{
|
|
//printf("CGapManager::sInstance = 0x%08x\n",CGapManager::sInstanceNoAssert());
|
|
//printf("mp_play_mode_gap_manager = 0x%08x\n",mp_play_mode_gap_manager);
|
|
}
|
|
|
|
void CParkEditor::Cleanup()
|
|
{
|
|
ParkEd("CParkEditor::Cleanup()");
|
|
|
|
m_state = vINACTIVE;
|
|
if (mp_cursor)
|
|
{
|
|
delete mp_cursor;
|
|
mp_cursor = NULL;
|
|
}
|
|
if (mp_menu_manager)
|
|
{
|
|
delete mp_menu_manager;
|
|
mp_menu_manager = NULL;
|
|
}
|
|
|
|
mp_park_manager->Destroy(CParkGenerator::DESTROY_PIECES_AND_SECTORS);
|
|
|
|
Obj::CRailEditorComponent::sUpdateSuperSectorsAfterDeletingRailSectors = false;
|
|
Obj::GetRailEditor()->DestroyRailGeometry();
|
|
Obj::GetRailEditor()->DestroyPostGeometry();
|
|
Obj::CRailEditorComponent::sUpdateSuperSectorsAfterDeletingRailSectors = true;
|
|
|
|
printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ DEATH OR GLORY 2 $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n");
|
|
}
|
|
|
|
void CParkEditor::SetAppropriateCamera()
|
|
{
|
|
if (mp_cursor && mp_cursor->InRailPlacementMode())
|
|
{
|
|
CFuncs::SetActiveCamera(CRCD(0x5b509ad3,"raileditor"), 0, false);
|
|
}
|
|
else
|
|
{
|
|
CFuncs::SetActiveCamera(CRCD(0x64716bee,"parked_cam"), 0, false);
|
|
}
|
|
}
|
|
|
|
void CParkEditor::do_piece_select_commands()
|
|
{
|
|
if (m_commands.TestMask(mPREV_SET))
|
|
{
|
|
mp_cursor->ChangeSet(-1);
|
|
turn_on_or_update_piece_menu();
|
|
Obj::CTracker* p_tracker = Obj::CTracker::Instance();
|
|
p_tracker->LaunchEvent(Script::GenerateCRC("parked_menu_up"), Script::GenerateCRC("set_menu_container"));
|
|
//mp_menu_manager->SetSourceMeta(mp_cursor->GetChecksum());
|
|
}
|
|
if (m_commands.TestMask(mNEXT_SET))
|
|
{
|
|
mp_cursor->ChangeSet(1);
|
|
turn_on_or_update_piece_menu();
|
|
Obj::CTracker* p_tracker = Obj::CTracker::Instance();
|
|
p_tracker->LaunchEvent(Script::GenerateCRC("parked_menu_down"), Script::GenerateCRC("set_menu_container"));
|
|
//mp_menu_manager->SetSourceMeta(mp_cursor->GetChecksum());
|
|
}
|
|
if (m_commands.TestMask(mPREV_PIECE))
|
|
{
|
|
mp_cursor->ChangePieceInSet(-1);
|
|
turn_on_or_update_piece_menu();
|
|
Obj::CTracker* p_tracker = Obj::CTracker::Instance();
|
|
p_tracker->LaunchEvent(Script::GenerateCRC("parked_menu_left"), Script::GenerateCRC("piece_menu_container"));
|
|
//mp_menu_manager->SetSourceMeta(mp_cursor->GetChecksum());
|
|
}
|
|
if (m_commands.TestMask(mNEXT_PIECE))
|
|
{
|
|
mp_cursor->ChangePieceInSet(1);
|
|
turn_on_or_update_piece_menu();
|
|
Obj::CTracker* p_tracker = Obj::CTracker::Instance();
|
|
p_tracker->LaunchEvent(Script::GenerateCRC("parked_menu_right"), Script::GenerateCRC("piece_menu_container"));
|
|
//mp_menu_manager->SetSourceMeta(mp_cursor->GetChecksum());
|
|
}
|
|
}
|
|
|
|
void CParkEditor::regular_command_logic()
|
|
{
|
|
Dbg_MsgAssert(mp_cursor,("NULL mp_cursor"));
|
|
|
|
Mth::Matrix cam_matrix;
|
|
cam_matrix.Ident();
|
|
cam_matrix.SetPos(Mth::Vector(0.0f, 0.0f, m_camDist, 1.0f));
|
|
cam_matrix.RotateX(Mth::DegToRad(-m_camAngleVert));
|
|
cam_matrix.RotateY(Mth::DegToRad(m_camAngle));
|
|
cam_matrix.Translate(Mth::Vector(mp_cursor->m_pos[X], vCAM_TARGET_ELEVATION, mp_cursor->m_pos[Z], 0.0f));
|
|
|
|
Obj::CCompositeObject * p_obj = (Obj::CCompositeObject *) Obj::CCompositeObjectManager::Instance()->GetObjectByID(CRCD(0x64716bee,"parked_cam"));
|
|
if (p_obj)
|
|
{
|
|
//printf("Setting cam pos\n");
|
|
//CFuncs::SetActiveCamera(CRCD(0x64716bee,"parked_cam"), 0, false);
|
|
|
|
//Obj::CCameraComponent * p_cam_comp = GetCameraComponentFromObject(p_obj);
|
|
p_obj->SetPos(cam_matrix[Mth::POS]);
|
|
p_obj->SetMatrix(cam_matrix);
|
|
}
|
|
|
|
|
|
if (!m_paused)
|
|
{
|
|
// XXX
|
|
//Ryan("enraged monkey\n");
|
|
|
|
// We unhighlight the meta-pieces intersecting the cursor before
|
|
// we change or move it.
|
|
if (!mp_cursor->InAreaSelectMode())
|
|
{
|
|
mp_cursor->HighlightIntersectingMetas(false);
|
|
}
|
|
|
|
Tmr::Time current_time = Tmr::GetTime();
|
|
float elapsed_seconds = (int) (current_time - m_last_time) / 1000.0f;
|
|
m_last_time = current_time;
|
|
|
|
static const float scale = ( 1.0f / ( 128.0f - Inp::vANALOGUE_TOL ));
|
|
|
|
m_leftStick.m_Y =
|
|
( m_leftStick.m_Y > Inp::vANALOGUE_TOL ) ? ( m_leftStick.m_Y - Inp::vANALOGUE_TOL ) * scale :
|
|
( m_leftStick.m_Y < -Inp::vANALOGUE_TOL ) ? ( m_leftStick.m_Y + Inp::vANALOGUE_TOL ) * scale : 0.0f;
|
|
m_leftStick.m_X =
|
|
( m_leftStick.m_X > Inp::vANALOGUE_TOL ) ? ( m_leftStick.m_X - Inp::vANALOGUE_TOL ) * scale :
|
|
( m_leftStick.m_X < -Inp::vANALOGUE_TOL ) ? ( m_leftStick.m_X + Inp::vANALOGUE_TOL ) * scale : 0.0f;
|
|
|
|
float rel_shift_x = m_leftStick.m_X * elapsed_seconds * m_movement_vel;
|
|
float rel_shift_z = m_leftStick.m_Y * elapsed_seconds * m_movement_vel;
|
|
float angle_rad = m_camAngle * Mth::PI / 180.0f;
|
|
float shift_x = cosf(angle_rad) * rel_shift_x + sinf(angle_rad) * rel_shift_z;
|
|
float shift_z = cosf(angle_rad) * rel_shift_z - sinf(angle_rad) * rel_shift_x;
|
|
|
|
m_rightStick.m_Y =
|
|
( m_rightStick.m_Y > Inp::vANALOGUE_TOL ) ? ( m_rightStick.m_Y - Inp::vANALOGUE_TOL ) * scale :
|
|
( m_rightStick.m_Y < -Inp::vANALOGUE_TOL ) ? ( m_rightStick.m_Y + Inp::vANALOGUE_TOL ) * scale : 0.0f;
|
|
m_rightStick.m_X =
|
|
( m_rightStick.m_X > Inp::vANALOGUE_TOL ) ? ( m_rightStick.m_X - Inp::vANALOGUE_TOL ) * scale :
|
|
( m_rightStick.m_X < -Inp::vANALOGUE_TOL ) ? ( m_rightStick.m_X + Inp::vANALOGUE_TOL ) * scale : 0.0f;
|
|
|
|
#ifdef __PLAT_NGC__DAN
|
|
if ( !( m_commands.TestMask(mZOOM_CAMERA_IN) ) )
|
|
#endif // __PLAT_NGC__
|
|
{
|
|
m_camAngle += m_rightStick.m_X * elapsed_seconds * m_rotate_vel;
|
|
}
|
|
if (m_camAngle < 0) m_camAngle += 360.0f;
|
|
else if (m_camAngle >= 360.0) m_camAngle -= 360.0f;
|
|
#ifdef __PLAT_NGC__DAN
|
|
if ( !( m_commands.TestMask(mZOOM_CAMERA_IN) ) )
|
|
#endif // __PLAT_NGC__
|
|
{
|
|
m_camAngleVert -= m_rightStick.m_Y * elapsed_seconds * m_rotate_vel;
|
|
}
|
|
if (m_camAngleVert < 10.0f) m_camAngleVert = 10.0f;
|
|
else if (m_camAngleVert > 90.0) m_camAngleVert = 90.0f;
|
|
|
|
/*
|
|
PlayEdPlaceSound for placing items (might have wrong sound hooked up right now)
|
|
PlayEdEraseSound for removing items
|
|
PlayRaiseGroundSound for raising
|
|
PlayLowerGroundSound for lowering
|
|
PlayRotatePieceSound for rotating both directions
|
|
*/
|
|
|
|
int rot_inc = 0;
|
|
if (m_commands.TestMask(mROTATE_CW))
|
|
{
|
|
Script::RunScript("PlayRotatePieceSound");
|
|
if (mp_cursor->InGapMode())
|
|
mp_cursor->AdjustGap(-1, 0, 0);
|
|
else
|
|
rot_inc = -1;
|
|
}
|
|
if (m_commands.TestMask(mROTATE_CCW))
|
|
{
|
|
Script::RunScript("PlayRotatePieceSound");
|
|
if (mp_cursor->InGapMode())
|
|
mp_cursor->AdjustGap(-1, 0, 0);
|
|
else
|
|
rot_inc = 1;
|
|
}
|
|
if (m_commands.TestMask(mPLACE_PIECE))
|
|
{
|
|
if (mp_cursor->InGapMode())
|
|
{
|
|
bool success = mp_cursor->AttemptGap();
|
|
if ((success || mp_cursor->IsSittingOnGap()) && !mp_cursor->HalfFinishedGap())
|
|
{
|
|
Script::RunScript("PlayEdPlaceSound");
|
|
// XXX
|
|
Ryan("the hell, you say\n");
|
|
Script::RunScript("parked_setup_gap_menu");
|
|
}
|
|
else
|
|
Script::RunScript("PlayEdBuzzSound");
|
|
|
|
m_allow_defrag=true;
|
|
}
|
|
else if (mp_cursor->InAreaSelectMode())
|
|
{
|
|
switch (mp_cursor->AttemptAreaSelect())
|
|
{
|
|
case 1:
|
|
// Maybe have a different sound for the first corner ?
|
|
Script::RunScript("PlayEdPlaceSound");
|
|
break;
|
|
case 2:
|
|
Script::RunScript("PlayEdPlaceSound");
|
|
Script::RunScript("parked_setup_area_select_menu");
|
|
break;
|
|
default:
|
|
Script::RunScript("PlayEdBuzzSound");
|
|
break;
|
|
}
|
|
// Note: Not setting m_allow_defrag here, because otherwise it may defrag
|
|
// as soon as the user places one of the area corners, which becomes a pain
|
|
// especially if trying to select a set of pieces to delete to free up memory.
|
|
}
|
|
else if (mp_cursor->InPasteMode())
|
|
{
|
|
mp_cursor->PasteCurrentClipboard();
|
|
m_allow_defrag=true;
|
|
}
|
|
else
|
|
{
|
|
if (mp_cursor->AttemptStamp())
|
|
Script::RunScript("PlayEdPlaceSound");
|
|
else
|
|
Script::RunScript("PlayEdBuzzSound");
|
|
m_allow_defrag=true;
|
|
}
|
|
}
|
|
if (m_commands.TestMask(mREMOVE_PIECE))
|
|
{
|
|
if (mp_cursor->InGapMode())
|
|
{
|
|
if (mp_cursor->AttemptRemoveGap())
|
|
{
|
|
Script::RunScript("PlayEdEraseSound");
|
|
}
|
|
else
|
|
Script::RunScript("PlayEdBuzzSound");
|
|
}
|
|
else if (mp_cursor->InAreaSelectMode())
|
|
{
|
|
mp_cursor->ClearAreaSelection();
|
|
m_allow_defrag=true;
|
|
}
|
|
else
|
|
{
|
|
if (mp_cursor->AttemptRemove())
|
|
{
|
|
Script::RunScript("PlayEdEraseSound");
|
|
}
|
|
else
|
|
{
|
|
Script::RunScript("PlayEdBuzzSound");
|
|
}
|
|
m_allow_defrag=true;
|
|
}
|
|
// and re register the gaps so that any old gaps are removed from the career.
|
|
CGapManager::sInstance()->RegisterGapsWithSkaterCareer();
|
|
}
|
|
|
|
do_piece_select_commands();
|
|
|
|
if (m_commands.TestMask(mRAISE_FLOOR))
|
|
{
|
|
if (!mp_cursor->InGapMode())
|
|
{
|
|
if (mp_cursor->ChangeFloorHeight(1))
|
|
Script::RunScript("PlayRaiseGroundSound");
|
|
else
|
|
Script::RunScript("PlayEdBuzzSound");
|
|
}
|
|
m_allow_defrag=true;
|
|
}
|
|
if (m_commands.TestMask(mLOWER_FLOOR))
|
|
{
|
|
if (!mp_cursor->InGapMode())
|
|
{
|
|
if (mp_cursor->ChangeFloorHeight(-1))
|
|
Script::RunScript("PlayLowerGroundSound");
|
|
else
|
|
Script::RunScript("PlayEdBuzzSound");
|
|
}
|
|
m_allow_defrag=true;
|
|
}
|
|
|
|
#ifdef __PLAT_NGC__DAN
|
|
if ( m_commands.TestMask(mZOOM_CAMERA_IN) )
|
|
{
|
|
// Use y component of stick to zoom camera in or out.
|
|
m_camDist += vCAM_DIST_INC * m_rightStick.m_Y;
|
|
if (m_camDist > vMAX_CAM_DIST)
|
|
m_camDist = vMAX_CAM_DIST;
|
|
if (m_camDist < vMIN_CAM_DIST)
|
|
m_camDist = vMIN_CAM_DIST;
|
|
}
|
|
#else
|
|
if (m_commands.TestMask(mZOOM_CAMERA_OUT) && !mp_cursor->InGapMode())
|
|
{
|
|
m_camDist += vCAM_DIST_INC;
|
|
if (m_camDist > vMAX_CAM_DIST)
|
|
m_camDist = vMAX_CAM_DIST;
|
|
}
|
|
if (m_commands.TestMask(mZOOM_CAMERA_IN) && !mp_cursor->InGapMode())
|
|
{
|
|
m_camDist -= vCAM_DIST_INC;
|
|
if (m_camDist < vMIN_CAM_DIST)
|
|
m_camDist = vMIN_CAM_DIST;
|
|
}
|
|
#endif // __PLAT_NGC__
|
|
|
|
if (m_commands.TestMask(mINCREASE_GAP_LEFT))
|
|
{
|
|
if (mp_cursor->InGapMode())
|
|
mp_cursor->AdjustGap(0, 1, 0);
|
|
}
|
|
if (m_commands.TestMask(mINCREASE_GAP_RIGHT))
|
|
{
|
|
if (mp_cursor->InGapMode())
|
|
mp_cursor->AdjustGap(0, 0, 1);
|
|
}
|
|
if (m_commands.TestMask(mDECREASE_GAP_LEFT))
|
|
{
|
|
if (mp_cursor->InGapMode())
|
|
mp_cursor->AdjustGap(0, -1, 0);
|
|
}
|
|
if (m_commands.TestMask(mDECREASE_GAP_RIGHT))
|
|
{
|
|
if (mp_cursor->InGapMode())
|
|
mp_cursor->AdjustGap(0, 0, -1);
|
|
}
|
|
|
|
|
|
// If an operation has occurred that has modified collidable geometry,
|
|
// run through all the existing created-rails and update their posts so that they
|
|
// maintain ground contact.
|
|
if (m_commands.TestMask(mPLACE_PIECE) ||
|
|
m_commands.TestMask(mREMOVE_PIECE) ||
|
|
m_commands.TestMask(mRAISE_FLOOR) ||
|
|
m_commands.TestMask(mLOWER_FLOOR))
|
|
{
|
|
Obj::CRailEditorComponent *p_rail_editor=Obj::GetRailEditor();
|
|
p_rail_editor->AdjustYs();
|
|
p_rail_editor->UpdateRailGeometry();
|
|
p_rail_editor->UpdatePostGeometry();
|
|
|
|
Obj::GetGoalEditor()->RefreshGoalPositionsUsingCollisionCheck();
|
|
}
|
|
|
|
mp_cursor->Update(shift_x, shift_z, rot_inc);
|
|
//printf("cursor position: (%.2f,%.2f)\n", mp_cursor->m_target_pos[X], mp_cursor->m_target_pos[Z]);
|
|
|
|
if (mp_cursor->InAreaSelectMode())
|
|
{
|
|
mp_cursor->RefreshSelectionArea();
|
|
}
|
|
else if (mp_cursor->InRailPlacementMode())
|
|
{
|
|
mp_cursor->DestroyGeometry();
|
|
}
|
|
else
|
|
{
|
|
// Highlight the pieces intersecting the cursor after it has changed or moved
|
|
mp_cursor->HighlightIntersectingMetas(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CParkEditor::rail_placement_logic()
|
|
{
|
|
Dbg_MsgAssert(mp_cursor,("NULL mp_cursor"));
|
|
|
|
if (!m_paused)
|
|
{
|
|
do_piece_select_commands();
|
|
}
|
|
}
|
|
|
|
void CParkEditor::Update()
|
|
{
|
|
if (!m_paused)
|
|
{
|
|
if (m_state == vEDITING)
|
|
{
|
|
Script::CStruct params;
|
|
params.AddChecksum(NONAME, Script::GenerateCRC("hide"));
|
|
CFuncs::ScriptPauseSkaters(¶ms, NULL);
|
|
}
|
|
else if (m_state == vTEST_PLAY)
|
|
{
|
|
CFuncs::ScriptUnPauseSkaters(NULL, NULL);
|
|
}
|
|
}
|
|
|
|
if (m_state == vEDITING && mp_cursor)
|
|
{
|
|
if (!m_paused)
|
|
{
|
|
if (mp_cursor->InRailPlacementMode())
|
|
{
|
|
if (Obj::GetRailEditor()->IsSuspended())
|
|
{
|
|
Script::RunScript(CRCD(0x2c3b17ea,"SwitchOnRailEditor"));
|
|
}
|
|
|
|
rail_placement_logic();
|
|
|
|
if (!mp_cursor->InRailPlacementMode())
|
|
{
|
|
Script::RunScript(CRCD(0x32428a49,"SwitchOffRailEditor"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!Obj::GetRailEditor()->IsSuspended())
|
|
{
|
|
Script::RunScript(CRCD(0x32428a49,"SwitchOffRailEditor"));
|
|
}
|
|
regular_command_logic();
|
|
if (mp_cursor->InRailPlacementMode())
|
|
{
|
|
Script::RunScript(CRCD(0x2c3b17ea,"SwitchOnRailEditor"));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!m_paused)
|
|
{
|
|
CParkGenerator *p_generator = mp_park_manager->GetGenerator();
|
|
CParkGenerator::MemUsageInfo usage_info = p_generator->GetResourceUsageInfo();
|
|
|
|
#ifdef __NOPT_ASSERT__
|
|
if (Script::GetInteger(CRCD(0xcc55a87b,"show_parked_main_heap_free")))
|
|
{
|
|
printf("usage_info.mMainHeapFree = %d usage_info.mParkHeapFree=%d\n",usage_info.mMainHeapFree,usage_info.mParkHeapFree);
|
|
}
|
|
#endif
|
|
|
|
|
|
if (usage_info.mMainHeapFree >= 0)
|
|
{
|
|
m_pct_resources_used=1.0f-((float)usage_info.mMainHeapFree)/((float)p_generator->GetResourceSize("main_heap_base"));
|
|
}
|
|
else
|
|
{
|
|
#ifdef __NOPT_ASSERT__
|
|
printf("Memory overflow! Gone over the end of the gauge by %d bytes\n",-usage_info.mMainHeapFree);
|
|
#endif
|
|
m_pct_resources_used=1.0f;
|
|
}
|
|
|
|
Mem::Heap *p_bottom_up_heap = Mem::Manager::sHandle().BottomUpHeap();
|
|
Mem::Heap *p_top_down_heap = Mem::Manager::sHandle().TopDownHeap();
|
|
#ifdef __NOPT_ASSERT__
|
|
if (Script::GetInteger(CRCD(0xe2ca7dfc,"show_actual_heap_status")))
|
|
{
|
|
printf("Bottom up = %d Top down = %d\n",p_bottom_up_heap->mFreeMem.m_count,p_top_down_heap->mp_region->MemAvailable());
|
|
}
|
|
#endif
|
|
|
|
// top_down_pct is a metric based on the amount of top down heap available. The reason for the 2.0 is to
|
|
// make the top_down_pct be >= 1.0 if there is less than TOP_DOWN_REQUIRED_MARGIN available, and < 1.0
|
|
// if there is more than that available.
|
|
float top_down_pct=2.0f-(((float)p_top_down_heap->mp_region->MemAvailable()) / ((float)TOP_DOWN_REQUIRED_MARGIN));
|
|
if (top_down_pct > m_pct_resources_used)
|
|
{
|
|
m_pct_resources_used = top_down_pct;
|
|
}
|
|
|
|
|
|
float park_heap_pct=1.0f-((float)usage_info.mParkHeapFree)/((float)p_generator->GetResourceSize("park_heap_base"));
|
|
if (park_heap_pct > m_pct_resources_used)
|
|
{
|
|
m_pct_resources_used=park_heap_pct;
|
|
}
|
|
|
|
m_last_main_heap_free=usage_info.mMainHeapFree;
|
|
|
|
//printf("2: m_pct_resources_used = %f\n",m_pct_resources_used);
|
|
|
|
//float rail_point_pct = (float) usage_info.mTotalRailPoints / (float) (p_generator->GetResourceSize("out_railpoint_pool") - 25);
|
|
int component_use_est = usage_info.mTotalClonedPieces * 7 + usage_info.mTotalRailPoints * 9 + usage_info.mTotalLinkedRailPoints;
|
|
int base_component_use = p_generator->GetResourceSize("component_use_base");
|
|
float component_pct = (float) (component_use_est - base_component_use) / (float) (p_generator->GetResourceSize("max_components") - base_component_use);
|
|
if (m_pct_resources_used < component_pct)
|
|
m_pct_resources_used = component_pct;
|
|
//printf("component_use_est=%d\n",component_use_est);
|
|
//ParkEd("3: m_pct_resources_used=%f",m_pct_resources_used);
|
|
|
|
int vector_use_est = usage_info.mTotalClonedPieces * 2 + usage_info.mTotalRailPoints * 2;
|
|
int base_vector_use = p_generator->GetResourceSize("vector_use_base");
|
|
float vector_pct = (float) (vector_use_est - base_vector_use) / (float) (p_generator->GetResourceSize("max_vectors") - base_vector_use);
|
|
if (m_pct_resources_used < vector_pct)
|
|
m_pct_resources_used = vector_pct;
|
|
//printf("vector_use_est=%d\n",vector_use_est);
|
|
//ParkEd("4: m_pct_resources_used=%f",m_pct_resources_used);
|
|
//printf("3: m_pct_resources_used = %f\n",m_pct_resources_used);
|
|
|
|
float pieces_pct=(float)mp_park_manager->GetDMAPieceCount() / (float)p_generator->GetResourceSize("max_dma_pieces");
|
|
if (pieces_pct > m_pct_resources_used)
|
|
{
|
|
m_pct_resources_used = pieces_pct;
|
|
}
|
|
|
|
//printf("4: m_pct_resources_used = %f IsParkFull=%d\n",m_pct_resources_used,IsParkFull());
|
|
|
|
float shown_pct_resources_used = m_pct_resources_used;
|
|
if (shown_pct_resources_used < 0.0f) shown_pct_resources_used = 0.0f;
|
|
else if (shown_pct_resources_used > 1.0f) shown_pct_resources_used = 1.0f;
|
|
|
|
|
|
|
|
bool do_defragment=false;
|
|
|
|
// Don't defrag if in rail placement mode, cos the resulting mode switch causes an assert.
|
|
if (mp_cursor->InRailPlacementMode())
|
|
{
|
|
m_allow_defrag=false;
|
|
}
|
|
// m_allow_defrag is a flag that gets set by any operation that may have increased
|
|
// memory usage, such as placing a piece, or raising the ground.
|
|
// It is required to prevent an infinite loop of defrags which could occur if defrags
|
|
// were allowed every frame.
|
|
|
|
if (shown_pct_resources_used >= 1.0f && p_top_down_heap->mp_region->MemAvailable() < TOP_DOWN_REQUIRED_MARGIN)
|
|
{
|
|
// We're in trouble, there may not be enough top down heap for UpdateSuperSectors
|
|
// to execute. This can happen if trying to raise a large chunk of ground.
|
|
if (p_bottom_up_heap->mFreeMem.m_count + p_top_down_heap->mp_region->MemAvailable() > (TOP_DOWN_REQUIRED_MARGIN + TOP_DOWN_REQUIRED_MARGIN_LEEWAY))
|
|
{
|
|
// ... but there would be more than enough if all the fragments could be utilised,
|
|
// so do a defragment to see if that helps.
|
|
if (m_allow_defrag)
|
|
{
|
|
do_defragment=true;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// The old logic from THPS4, which would only defrag if this flag was set.
|
|
/*
|
|
if (usage_info.mIsFragmented)
|
|
{
|
|
if (m_allow_defrag)
|
|
{
|
|
do_defragment=true;
|
|
}
|
|
}
|
|
*/
|
|
|
|
m_allow_defrag=false;
|
|
|
|
if (do_defragment)
|
|
{
|
|
#ifdef __PLAT_NGC__
|
|
// The regular defragment script often does not fully cure the fragmentation, which
|
|
// is a problem on the NGC because of its lower memory. So do a full reload instead.
|
|
Script::SpawnScript(CRCD(0x57c05a9a,"reload_park"));
|
|
#else
|
|
// XXX
|
|
Ryan("defragging, memory free (largest block) is %d\n", usage_info.mMainHeapFree);
|
|
SetPaused(true);
|
|
// run a script to defragment memory
|
|
#ifdef __NOPT_ASSERT__
|
|
Script::CScript *p_script=Script::SpawnScript("parked_defragment_memory");
|
|
p_script->SetCommentString("Spawned by CParkEditor::Update()");
|
|
#else
|
|
Script::SpawnScript("parked_defragment_memory");
|
|
#endif
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
// percent_bar_colored_part
|
|
Front::CScreenElementManager* p_elem_man = Front::CScreenElementManager::Instance();
|
|
Front::CScreenElement *p_pct_bar = p_elem_man->GetElement(CRCD(0xcd9c729a, "percent_bar_colored_part"), Front::CScreenElementManager::DONT_ASSERT).Convert();
|
|
if (p_pct_bar)
|
|
p_pct_bar->SetScale(shown_pct_resources_used, 1.0f, false, Front::CScreenElement::FORCE_INSTANT);
|
|
|
|
if (Script::GetInteger(CRCD(0x7a9c1acd,"parked_show_memory_stats")))
|
|
{
|
|
Script::RunScript(CRCD(0xb935948d,"CreateMemStatsScreenElements"));
|
|
|
|
Front::CScreenElementManager* p_elem_man = Front::CScreenElementManager::Instance();
|
|
Front::CTextElement *p_park_free_elem = (Front::CTextElement *) p_elem_man->GetElement(CRCD(0xa5a33eb9, "parked_mem_stats_park_free"), Front::CScreenElementManager::ASSERT).Convert();
|
|
char park_free_text[128];
|
|
sprintf(park_free_text, "park heap free:\\c2 %s", Str::PrintThousands(usage_info.mParkHeapFree));
|
|
p_park_free_elem->SetText(park_free_text);
|
|
|
|
Front::CTextElement *p_main_free_elem = (Front::CTextElement *) p_elem_man->GetElement(CRCD(0xcd38c218, "parked_mem_stats_main_free"), Front::CScreenElementManager::ASSERT).Convert();
|
|
char main_free_text[128];
|
|
if (usage_info.mIsFragmented)
|
|
sprintf(main_free_text, "main heap free:\\c2 %s \\c1FRAG", Str::PrintThousands(usage_info.mMainHeapFree));
|
|
else
|
|
sprintf(main_free_text, "main heap free:\\c2 %s", Str::PrintThousands(usage_info.mMainHeapFree));
|
|
p_main_free_elem->SetText(main_free_text);
|
|
|
|
Front::CTextElement *p_last_op_elem = (Front::CTextElement *) p_elem_man->GetElement(CRCD(0x9dd4532f, "parked_mem_stats_last_op"), Front::CScreenElementManager::ASSERT).Convert();
|
|
char last_op_text[128];
|
|
sprintf(last_op_text, "last op size:\\c2 %d", usage_info.mMainHeapUsed - usage_info.mLastMainUsed);
|
|
p_last_op_elem->SetText(last_op_text);
|
|
|
|
Front::CTextElement *p_other_elem = (Front::CTextElement *) p_elem_man->GetElement(CRCD(0xb42704a3, "parked_mem_stats_other"), Front::CScreenElementManager::ASSERT).Convert();
|
|
char other_text[128];
|
|
sprintf(other_text, "components free:\\c2 %d %d",
|
|
p_generator->GetResourceSize("max_components") - component_use_est - base_component_use,
|
|
p_generator->GetResourceSize("max_vectors") - vector_use_est - base_vector_use);
|
|
p_other_elem->SetText(other_text);
|
|
|
|
Front::CTextElement *p_pct_elem = (Front::CTextElement *) p_elem_man->GetElement(CRCD(0x65f2394f, "parked_mem_stats_pct"), Front::CScreenElementManager::ASSERT).Convert();
|
|
char pct_text[128];
|
|
sprintf(pct_text, "pct:\\c3 %.2f", m_pct_resources_used * 100.0f);
|
|
p_pct_elem->SetText(pct_text);
|
|
|
|
Front::CTextElement *p_pieces_remaining_elem = (Front::CTextElement *) p_elem_man->GetElement(CRCD(0x3da56dac, "parked_mem_pieces_remaining"), Front::CScreenElementManager::ASSERT).Convert();
|
|
char pieces_remaining_text[128];
|
|
sprintf(pieces_remaining_text, "pieces remaining:\\c2 %d", p_generator->GetResourceSize("max_dma_pieces") - mp_park_manager->GetDMAPieceCount());
|
|
p_pieces_remaining_elem->SetText(pieces_remaining_text);
|
|
|
|
Front::CTextElement *p_main_used_elem = (Front::CTextElement *) p_elem_man->GetElement(CRCD(0xf95160c8, "parked_mem_stats_main_used"), Front::CScreenElementManager::ASSERT).Convert();
|
|
char main_used_text[128];
|
|
sprintf(main_used_text, "main heap used:\\c2 %s", Str::PrintThousands(usage_info.mMainHeapUsed));
|
|
p_main_used_elem->SetText(main_used_text);
|
|
}
|
|
else
|
|
{
|
|
Script::RunScript(CRCD(0x7a449180,"DestroyMemStatsScreenElements"));
|
|
}
|
|
|
|
// Update the clipboard usage bar.
|
|
/*
|
|
Front::CScreenElement *p_clipboard_percent_bar = p_elem_man->GetElement(CRCD(0xf07100ce,"clipboard_percent_bar_colored_part"), Front::CScreenElementManager::DONT_ASSERT).Convert();
|
|
if (p_clipboard_percent_bar)
|
|
{
|
|
p_clipboard_percent_bar->SetScale(mp_park_manager->GetClipboardProportionUsed(), 1.0f, false, Front::CScreenElement::FORCE_INSTANT);
|
|
}
|
|
*/
|
|
} // end if (!m_paused)
|
|
}
|
|
else
|
|
{
|
|
m_commands.ClearAll();
|
|
}
|
|
}
|
|
|
|
void CParkEditor::SwitchMenuPieceToMostRecentClipboard()
|
|
{
|
|
CCursor::sInstance()->SwitchMenuPieceToMostRecentClipboard();
|
|
|
|
turn_on_or_update_piece_menu();
|
|
Obj::CTracker* p_tracker = Obj::CTracker::Instance();
|
|
p_tracker->LaunchEvent(Script::GenerateCRC("parked_menu_up"), Script::GenerateCRC("set_menu_container"));
|
|
}
|
|
|
|
// Returns true if there is enough memory to copy or paste an area of the given size.
|
|
bool CParkEditor::RoomToCopyOrPaste(int w, int l)
|
|
{
|
|
#ifdef __PLAT_NGC__
|
|
Mem::Heap *p_top_down_heap = Mem::Manager::sHandle().TopDownHeap();
|
|
if (p_top_down_heap->mp_region->MemAvailable() < TOP_DOWN_REQUIRED_MARGIN)
|
|
{
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
// Assumes that in the worst case 1 cell uses up 40K, for example when a bunch of fountain pieces are raised
|
|
// to the maximum height.
|
|
return w * l * 40000 < m_last_main_heap_free;
|
|
}
|
|
|
|
void CParkEditor::SetPaused(bool paused)
|
|
{
|
|
// XXX
|
|
Ryan("some fucker has made my pause state = %d\n", paused);
|
|
m_paused = paused;
|
|
|
|
if (mp_menu_manager)
|
|
{
|
|
if (paused)
|
|
{
|
|
Script::RunScript("parked_kill_wait_message");
|
|
mp_menu_manager->Disable();
|
|
}
|
|
else
|
|
{
|
|
mp_menu_manager->Enable();
|
|
turn_on_or_update_piece_menu();
|
|
}
|
|
}
|
|
|
|
if (mp_cursor)
|
|
{
|
|
if (mp_cursor->InRailPlacementMode())
|
|
{
|
|
mp_cursor->SetVisibility(false);
|
|
}
|
|
else
|
|
{
|
|
if (paused)
|
|
{
|
|
mp_cursor->SetVisibility(false);
|
|
}
|
|
else
|
|
{
|
|
mp_cursor->SetVisibility(true);
|
|
}
|
|
}
|
|
mp_cursor->RefreshHelperText();
|
|
}
|
|
|
|
update_analog_stick_menu_control_state();
|
|
}
|
|
|
|
|
|
|
|
|
|
void CParkEditor::turn_on_or_update_piece_menu()
|
|
{
|
|
int menu_set_number;
|
|
int set_num = mp_cursor->GetSelectedSet(&menu_set_number);
|
|
// XXX
|
|
Ryan("piece set number is %d\n", set_num);
|
|
Dbg_Assert(mp_menu_manager);
|
|
mp_menu_manager->SetPieceSet(&mp_park_manager->GetPieceSet(set_num), set_num, menu_set_number);
|
|
|
|
if (mp_cursor)
|
|
{
|
|
mp_cursor->RefreshHelperText();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void CParkEditor::update_analog_stick_menu_control_state()
|
|
{
|
|
Spt::SingletonPtr<Mdl::FrontEnd> p_front_end;
|
|
if (m_state == vEDITING && !m_paused)
|
|
{
|
|
p_front_end->SetAnalogStickActiveForMenus(false);
|
|
}
|
|
else
|
|
p_front_end->SetAnalogStickActiveForMenus(true);
|
|
}
|
|
|
|
|
|
|
|
|
|
void CParkEditor::pass_event_to_listener(Obj::CEvent *pEvent)
|
|
{
|
|
if (m_state != vEDITING || !mp_cursor || m_paused)
|
|
return;
|
|
|
|
uint32 type = pEvent->GetType();
|
|
uint32 target = pEvent->GetTarget();
|
|
|
|
if (target != CRCD(0x56a1eae3, "root_window"))
|
|
return;
|
|
|
|
#ifdef __PLAT_NGC__
|
|
if ( m_commands.TestMask( mINCREASE_GAP_RIGHT ) ) return;
|
|
if ( m_commands.TestMask( mDECREASE_GAP_RIGHT ) ) return;
|
|
if ( m_commands.TestMask( mINCREASE_GAP_LEFT ) ) return;
|
|
if ( m_commands.TestMask( mDECREASE_GAP_LEFT ) ) return;
|
|
#endif // __PLAT_NGC__
|
|
|
|
switch(type)
|
|
{
|
|
case Obj::CEvent::TYPE_PAD_UP:
|
|
m_commands.SetMask( mPREV_SET );
|
|
break;
|
|
case Obj::CEvent::TYPE_PAD_DOWN:
|
|
m_commands.SetMask( mNEXT_SET );
|
|
break;
|
|
case Obj::CEvent::TYPE_PAD_LEFT:
|
|
m_commands.SetMask( mPREV_PIECE );
|
|
break;
|
|
case Obj::CEvent::TYPE_PAD_RIGHT:
|
|
m_commands.SetMask( mNEXT_PIECE );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
//Ryan("I got an event!!\n");
|
|
}
|
|
|
|
|
|
|
|
|
|
void CParkEditor::v_start_cb()
|
|
{
|
|
|
|
Ryan("CParkEditor2::v_start_cb\n");
|
|
|
|
Mlp::Manager * mlp_manager = Mlp::Manager::Instance();
|
|
mlp_manager->AddLogicTask ( *m_logic_task );
|
|
Inp::Manager * inp_manager = Inp::Manager::Instance();
|
|
inp_manager->AddHandler( *m_input_handler );
|
|
mlp_manager->AddDisplayTask ( *m_display_task );
|
|
}
|
|
|
|
|
|
|
|
|
|
void CParkEditor::v_stop_cb()
|
|
{
|
|
Ryan("CParkEditor2::v_stop_cb\n");
|
|
|
|
m_logic_task->Remove();
|
|
m_input_handler->Remove();
|
|
}
|
|
|
|
|
|
|
|
|
|
void CParkEditor::s_input_logic_code ( const Inp::Handler < CParkEditor >& handler )
|
|
{
|
|
CParkEditor &mdl = handler.GetData();
|
|
// first clear last frame's data
|
|
mdl.m_commands.ClearAll();
|
|
|
|
//if (!mdl.mp_map || mdl.GameGoingOrOutsideEditor() || mdl.InMenu() || !mdl.m_initialized) return;
|
|
|
|
// translate m_Input data to module-specific commands
|
|
mdl.m_rightStick.m_X = handler.m_Input->m_Event[Inp::Data::vA_RIGHT_X] - 128;
|
|
mdl.m_rightStick.m_Y = handler.m_Input->m_Event[Inp::Data::vA_RIGHT_Y] - 128;
|
|
mdl.m_leftStick.m_X = handler.m_Input->m_Event[Inp::Data::vA_LEFT_X] - 128;
|
|
mdl.m_leftStick.m_Y = handler.m_Input->m_Event[Inp::Data::vA_LEFT_Y] - 128;
|
|
|
|
#ifdef __PLAT_NGC__
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_TRIANGLE )
|
|
{
|
|
mdl.m_commands.SetMask( mROTATE_CCW );
|
|
}
|
|
#else
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_SQUARE )
|
|
{
|
|
mdl.m_commands.SetMask( mROTATE_CCW );
|
|
}
|
|
#endif // __PLAT_NGC__
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_CIRCLE )
|
|
{
|
|
mdl.m_commands.SetMask( mROTATE_CW );
|
|
}
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_X )
|
|
{
|
|
mdl.m_commands.SetMask( mPLACE_PIECE );
|
|
}
|
|
#ifdef __PLAT_NGC__
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_SQUARE )
|
|
{
|
|
mdl.m_commands.SetMask( mREMOVE_PIECE );
|
|
}
|
|
#else
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_TRIANGLE )
|
|
{
|
|
mdl.m_commands.SetMask( mREMOVE_PIECE );
|
|
}
|
|
#endif // __PLAT_NGC__
|
|
#ifdef __PLAT_NGC__
|
|
if( !(handler.m_Input->m_Buttons & Inp::Data::mD_Z) )
|
|
{
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_L1 )
|
|
{
|
|
mdl.m_commands.SetMask( mRAISE_FLOOR );
|
|
}
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_R1 )
|
|
{
|
|
mdl.m_commands.SetMask( mLOWER_FLOOR );
|
|
}
|
|
}
|
|
#else
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_L1 )
|
|
{
|
|
mdl.m_commands.SetMask( mRAISE_FLOOR );
|
|
}
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_L2 )
|
|
{
|
|
mdl.m_commands.SetMask( mLOWER_FLOOR );
|
|
}
|
|
#endif // __PLAT_NGC__
|
|
#ifdef __PLAT_NGC__
|
|
if( ( handler.m_Input->m_Makes & Inp::Data::mD_UP ) && ( handler.m_Input->m_Buttons & Inp::Data::mD_R1 ) )
|
|
{
|
|
mdl.m_commands.SetMask( mINCREASE_GAP_RIGHT );
|
|
}
|
|
if( ( handler.m_Input->m_Makes & Inp::Data::mD_DOWN ) && ( handler.m_Input->m_Buttons & Inp::Data::mD_R1 ) )
|
|
{
|
|
mdl.m_commands.SetMask( mDECREASE_GAP_RIGHT );
|
|
}
|
|
if( ( handler.m_Input->m_Makes & Inp::Data::mD_UP ) && ( handler.m_Input->m_Buttons & Inp::Data::mD_L1 ) )
|
|
{
|
|
mdl.m_commands.SetMask( mINCREASE_GAP_LEFT );
|
|
}
|
|
if( ( handler.m_Input->m_Makes & Inp::Data::mD_DOWN ) && ( handler.m_Input->m_Buttons & Inp::Data::mD_L1 ) )
|
|
{
|
|
mdl.m_commands.SetMask( mDECREASE_GAP_LEFT );
|
|
}
|
|
#else
|
|
#ifdef __PLAT_XBOX__
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_L1 )
|
|
{
|
|
mdl.m_commands.SetMask( mINCREASE_GAP_RIGHT );
|
|
}
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_L2 )
|
|
{
|
|
mdl.m_commands.SetMask( mDECREASE_GAP_RIGHT );
|
|
}
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_BLACK )
|
|
{
|
|
mdl.m_commands.SetMask( mINCREASE_GAP_LEFT );
|
|
}
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_WHITE )
|
|
{
|
|
mdl.m_commands.SetMask( mDECREASE_GAP_LEFT );
|
|
}
|
|
#else
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_R1 )
|
|
{
|
|
mdl.m_commands.SetMask( mINCREASE_GAP_RIGHT );
|
|
}
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_R2 )
|
|
{
|
|
mdl.m_commands.SetMask( mDECREASE_GAP_RIGHT );
|
|
}
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_L1 )
|
|
{
|
|
mdl.m_commands.SetMask( mINCREASE_GAP_LEFT );
|
|
}
|
|
if( handler.m_Input->m_Makes & Inp::Data::mD_L2 )
|
|
{
|
|
mdl.m_commands.SetMask( mDECREASE_GAP_LEFT );
|
|
}
|
|
#endif
|
|
|
|
#endif // __PLAT_NGC__
|
|
#ifdef __PLAT_NGC__
|
|
if( handler.m_Input->m_Buttons & Inp::Data::mD_Z )
|
|
{
|
|
if( handler.m_Input->m_Buttons & Inp::Data::mD_L1 )
|
|
{
|
|
mdl.m_commands.SetMask( mZOOM_CAMERA_IN );
|
|
}
|
|
if( handler.m_Input->m_Buttons & Inp::Data::mD_R1 )
|
|
{
|
|
mdl.m_commands.SetMask( mZOOM_CAMERA_OUT );
|
|
}
|
|
}
|
|
#else
|
|
#ifdef __PLAT_XBOX__
|
|
if( handler.m_Input->m_Buttons & Inp::Data::mD_BLACK )
|
|
{
|
|
mdl.m_commands.SetMask( mZOOM_CAMERA_OUT );
|
|
}
|
|
if( handler.m_Input->m_Buttons & Inp::Data::mD_WHITE )
|
|
{
|
|
mdl.m_commands.SetMask( mZOOM_CAMERA_IN );
|
|
}
|
|
#else
|
|
if( handler.m_Input->m_Buttons & Inp::Data::mD_R1 )
|
|
{
|
|
mdl.m_commands.SetMask( mZOOM_CAMERA_OUT );
|
|
}
|
|
if( handler.m_Input->m_Buttons & Inp::Data::mD_R2 )
|
|
{
|
|
mdl.m_commands.SetMask( mZOOM_CAMERA_IN );
|
|
}
|
|
#endif // __PLAT_XBOX__
|
|
#endif // __PLAT_NGC__
|
|
}
|
|
|
|
|
|
|
|
|
|
void CParkEditor::s_logic_code ( const Tsk::Task< CParkEditor >& task )
|
|
{
|
|
|
|
|
|
CParkEditor &mdl = task.GetData();
|
|
//if (mdl.mp_commandParams)
|
|
// mdl.runCommand();
|
|
//if (!mdl.mp_map || mdl.GameGoingOrOutsideEditor() || !mdl.m_initialized) return;
|
|
|
|
/*
|
|
// put skater up in air HACK
|
|
Mdl::Skate* skate_mod = Mdl::Skate::Instance();
|
|
Obj::CSkater *pSkater = skate_mod->GetLocalSkater();
|
|
if (pSkater)
|
|
pSkater->m_pos.Set(4000.0f, 4000.0f, 0.0f);
|
|
*/
|
|
|
|
Tmr::Time elapsed_time;
|
|
static Tmr::Time last_time = 0;
|
|
|
|
elapsed_time = Tmr::ElapsedTime( last_time );
|
|
last_time = last_time + elapsed_time;
|
|
|
|
mdl.Update();
|
|
}
|
|
|
|
|
|
|
|
|
|
void CParkEditor::s_display_code ( const Tsk::Task< CParkEditor >& task )
|
|
{
|
|
//CParkEditor &mdl = task.GetData();
|
|
//if (!mdl.mp_map || mdl.GameGoingOrOutsideEditor() || !mdl.m_initialized) return;
|
|
|
|
//mdl.Draw();
|
|
}
|
|
|
|
void CParkEditor::BindParkEditorToController( int controller )
|
|
{
|
|
Spt::SingletonPtr< Inp::Manager > inp_manager;
|
|
inp_manager->ReassignHandler( *m_input_handler, controller );
|
|
}
|
|
|
|
Mth::Vector& CParkEditor::GetCursorPos()
|
|
{
|
|
Dbg_MsgAssert(mp_cursor,("NULL mp_cursor"));
|
|
return mp_cursor->m_pos;
|
|
}
|
|
|
|
void CParkEditor::DestroyClipboardsWhichAreTooBigToFit()
|
|
{
|
|
if (mp_cursor)
|
|
{
|
|
mp_cursor->DestroyClipboardsWhichAreTooBigToFit();
|
|
}
|
|
}
|
|
|
|
void CParkEditor::SetTimeOfDayScript(uint32 tod_script)
|
|
{
|
|
m_tod_script=tod_script;
|
|
}
|
|
|
|
CCursor *CCursor::sp_instance = NULL;
|
|
const float CCursor::MOTION_PCT_INC = .15f;
|
|
const float CCursor::ROT_DEG_INC = 15.0f;
|
|
|
|
|
|
|
|
|
|
CCursor::CCursor() :
|
|
m_cell_dims(0, 0, 0),
|
|
m_target_pos(0.0f, 0.0f, 0.0f),
|
|
m_pos(0.0f, 0.0f, 0.0f),
|
|
m_hard_rot(Mth::ROT_0),
|
|
m_target_rot(0.0f),
|
|
m_rot(0.0f),
|
|
mp_meta(NULL)
|
|
{
|
|
m_num_corners_selected=0;
|
|
m_initialised_highlight=false;
|
|
|
|
mp_clipboards=NULL;
|
|
mp_current_clipboard=NULL;
|
|
|
|
m_hard_rot = Mth::ROT_0;
|
|
|
|
m_motion_pct = 1.0f;
|
|
|
|
m_selected_set = 0;
|
|
m_menu_set_number = 0;
|
|
|
|
m_current_gap.numCompleteHalves = 0;
|
|
m_current_gap.mCancelFlags=0;
|
|
|
|
m_mode = NONE;
|
|
|
|
CParkManager::CPieceSet &piece_set = m_manager->GetPieceSet(m_selected_set, &m_menu_set_number);
|
|
set_source_meta(piece_set.mEntryTab[piece_set.mSelectedEntry].mNameCrc);
|
|
|
|
m_gap_suffix_counter=1;
|
|
|
|
sp_instance = this;
|
|
}
|
|
|
|
CCursor::~CCursor()
|
|
{
|
|
#ifndef DONT_USE_CURSOR_META
|
|
if (mp_meta)
|
|
{
|
|
mp_meta->MarkUnlocked();
|
|
m_manager->DestroyConcreteMeta(mp_meta, CParkManager::mDONT_DESTROY_PIECES_ABOVE);
|
|
}
|
|
|
|
#endif
|
|
|
|
destroy_clipboards();
|
|
|
|
sp_instance = NULL;
|
|
}
|
|
|
|
// K: Added to test something
|
|
void CCursor::DeleteMeta()
|
|
{
|
|
if (mp_meta)
|
|
{
|
|
delete mp_meta;
|
|
mp_meta=NULL;
|
|
}
|
|
}
|
|
|
|
void CCursor::destroy_clipboards()
|
|
{
|
|
CClipboard *p_clipboard=mp_clipboards;
|
|
while (p_clipboard)
|
|
{
|
|
CClipboard *p_next=p_clipboard->mpNext;
|
|
delete p_clipboard;
|
|
p_clipboard=p_next;
|
|
}
|
|
mp_current_clipboard=NULL;
|
|
}
|
|
|
|
// Called when the park is resized.
|
|
void CCursor::DestroyClipboardsWhichAreTooBigToFit()
|
|
{
|
|
CClipboard *p_last=NULL;
|
|
CClipboard *p_clipboard=mp_clipboards;
|
|
while (p_clipboard)
|
|
{
|
|
CClipboard *p_next=p_clipboard->mpNext;
|
|
|
|
GridDims area;
|
|
p_clipboard->GetArea(this,&area);
|
|
|
|
if (area.GetW() > m_manager->GetParkNearBounds().GetW() ||
|
|
area.GetW() > m_manager->GetParkNearBounds().GetL() ||
|
|
area.GetL() > m_manager->GetParkNearBounds().GetW() ||
|
|
area.GetL() > m_manager->GetParkNearBounds().GetL())
|
|
{
|
|
if (p_last)
|
|
{
|
|
p_last->mpNext=p_next;
|
|
}
|
|
if (p_clipboard==mp_clipboards)
|
|
{
|
|
mp_clipboards=p_next;
|
|
}
|
|
|
|
delete p_clipboard;
|
|
p_clipboard=p_next;
|
|
}
|
|
else
|
|
{
|
|
p_last=p_clipboard;
|
|
p_clipboard=p_next;
|
|
}
|
|
}
|
|
|
|
mp_current_clipboard=mp_clipboards;
|
|
|
|
// Refresh since mp_current_clipboard has changed.
|
|
ChangePieceInSet(0);
|
|
}
|
|
|
|
void CCursor::DestroyGeometry()
|
|
{
|
|
if (mp_meta)
|
|
{
|
|
mp_meta->MarkUnlocked();
|
|
m_manager->DestroyConcreteMeta(mp_meta, CParkManager::mDONT_DESTROY_PIECES_ABOVE);
|
|
mp_meta = NULL;
|
|
}
|
|
}
|
|
|
|
void CCursor::DestroyAnyClipboardCursors()
|
|
{
|
|
CClipboard *p_clipboard=mp_clipboards;
|
|
while (p_clipboard)
|
|
{
|
|
p_clipboard->DestroyMetas();
|
|
p_clipboard=p_clipboard->mpNext;
|
|
}
|
|
}
|
|
|
|
void CCursor::Update(float shiftX, float shiftZ, int rotInc)
|
|
{
|
|
/*
|
|
==================================================
|
|
ROTATION SECTION
|
|
==================================================
|
|
*/
|
|
|
|
if (rotInc > 0)
|
|
{
|
|
m_hard_rot = Mth::ERot90((m_hard_rot + 1) & 3);
|
|
m_target_rot += 90.0f;
|
|
if (m_target_rot > 360.0f)
|
|
{
|
|
m_target_rot -= 360.0f;
|
|
m_rot -= 360.0f;
|
|
}
|
|
m_cell_dims.SetWHL(m_cell_dims.GetL(), m_cell_dims.GetH(), m_cell_dims.GetW());
|
|
}
|
|
else if (rotInc < 0)
|
|
{
|
|
m_hard_rot = Mth::ERot90((m_hard_rot - 1) & 3);
|
|
m_target_rot -= 90.0f;
|
|
if (m_target_rot < 0.0f)
|
|
{
|
|
m_target_rot += 360.0f;
|
|
m_rot += 360.0f;
|
|
}
|
|
m_cell_dims.SetWHL(m_cell_dims.GetL(), m_cell_dims.GetH(), m_cell_dims.GetW());
|
|
}
|
|
|
|
/*
|
|
==================================================
|
|
CELL POSITIONING SECTION
|
|
==================================================
|
|
*/
|
|
|
|
const float near_zero = .0001f;
|
|
//const float tolerance = .5f;
|
|
|
|
float shift_x_squared = shiftX * shiftX;
|
|
float shift_z_squared = shiftZ * shiftZ;
|
|
|
|
bool actual_shift = (shift_x_squared > near_zero * near_zero || shift_z_squared > near_zero * near_zero);
|
|
|
|
// can't shift to new cell if cursor currently in motion
|
|
if (actual_shift && m_motion_pct <= 0.0f)
|
|
{
|
|
if (shift_z_squared > 5.8284f * shift_x_squared)
|
|
{
|
|
if (shiftZ < 0.0f)
|
|
change_cell_pos(0, -1);
|
|
else
|
|
change_cell_pos(0, 1);
|
|
m_motion_pct = 1.0f;
|
|
}
|
|
else if (shift_x_squared > 5.8284f * shift_z_squared)
|
|
{
|
|
if (shiftX < 0.0f)
|
|
change_cell_pos(-1, 0);
|
|
else
|
|
change_cell_pos(1, 0);
|
|
m_motion_pct = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
if (shiftZ < 0.0f)
|
|
change_cell_pos(0, -1);
|
|
else
|
|
change_cell_pos(0, 1);
|
|
|
|
if (shiftX < 0.0f)
|
|
change_cell_pos(-1, 0);
|
|
else
|
|
change_cell_pos(1, 0);
|
|
m_motion_pct = 1.0f;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
change_cell_pos(0, 0);
|
|
}
|
|
|
|
#if 0
|
|
printf("cell (%d,%d), shown (%.2f,%.2f)\n",
|
|
m_cell_dims.GetX(), m_cell_dims.GetZ(),
|
|
m_pos[X], m_pos[Z]);
|
|
#endif
|
|
|
|
/*
|
|
==================================================
|
|
ANIMATION SECTION
|
|
==================================================
|
|
*/
|
|
|
|
//m_cell_dims.PrintContents();
|
|
|
|
// derive m_target_pos from m_cell_dims
|
|
|
|
Mth::Vector world_dims;
|
|
m_target_pos = m_manager->GridCoordinatesToWorld(m_cell_dims, &world_dims);
|
|
m_target_pos[X] += world_dims[X] / 2.0f;
|
|
m_target_pos[Z] += world_dims[Z] / 2.0f;
|
|
|
|
if (m_motion_pct > 0.0f)
|
|
{
|
|
m_pos[X] += (m_target_pos[X] - m_pos[X]) * MOTION_PCT_INC / m_motion_pct;
|
|
m_pos[Z] += (m_target_pos[Z] - m_pos[Z]) * MOTION_PCT_INC / m_motion_pct;
|
|
m_pos[Y] = m_target_pos[Y];
|
|
m_motion_pct -= MOTION_PCT_INC;
|
|
if (m_motion_pct < 0.0f) m_motion_pct = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
m_pos = m_target_pos;
|
|
m_motion_pct = 0.0f;
|
|
}
|
|
|
|
if (m_rot < m_target_rot)
|
|
{
|
|
m_rot += ROT_DEG_INC;
|
|
if (m_rot > m_target_rot)
|
|
m_rot = m_target_rot;
|
|
}
|
|
else if (m_rot > m_target_rot)
|
|
{
|
|
m_rot -= ROT_DEG_INC;
|
|
if (m_rot < m_target_rot)
|
|
m_rot = m_target_rot;
|
|
}
|
|
|
|
/*
|
|
Script::CStruct *p_params=new Script::CStruct;
|
|
p_params->AddVector(CRCD(0x7f261953,"pos"),m_pos[X],m_pos[Y],m_pos[Z]);
|
|
Script::RunScript(CRCD(0x9796fc9f,"ParkEdCursorPos"),p_params);
|
|
delete p_params;
|
|
*/
|
|
|
|
#ifndef DONT_USE_CURSOR_META
|
|
// Mick: TT#3804
|
|
// Adding the vector fixes Z-Fighting between cursor and identical piece
|
|
if (m_mode==PASTE)
|
|
{
|
|
if (mp_current_clipboard)
|
|
{
|
|
//printf("m_clipboard_y=%d\n",m_clipboard_y);
|
|
mp_current_clipboard->ShowMetas(m_pos + Mth::Vector(-1.5f,+1.5f,-1.5f), m_rot, m_clipboard_y);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DestroyAnyClipboardCursors();
|
|
if (m_mode != RAIL_PLACEMENT)
|
|
{
|
|
Dbg_Assert(mp_meta);
|
|
mp_meta->SetSoftRot(m_pos + Mth::Vector(-1.5f,+1.5f,-1.5f), m_rot); // Mick: Changed to move up, so water does not vanish on GC
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
bool CCursor::AttemptStamp()
|
|
{
|
|
Dbg_Assert(mp_meta);
|
|
ParkEd("CCursor::AttemptStamp()");
|
|
|
|
if (!m_manager->CanPlacePiecesIn(m_cell_dims))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// If we are trying to put down a restart point then we need to see if there are
|
|
// any free slots avaiable
|
|
CParkGenerator::RestartType restart_type = m_manager->IsRestartPiece(mp_meta->GetNameChecksum());
|
|
if (restart_type != CParkGenerator::vEMPTY)
|
|
{
|
|
//printf("Attempting to stamp a restart piece type %d\n", restart_type);
|
|
if (! m_manager->GetGenerator()->FreeRestartExists(restart_type))
|
|
{
|
|
// no free slots for this restart point
|
|
printf ("No free slots exist for this type of restart point\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#ifndef DONT_USE_CURSOR_META
|
|
CAbstractMetaPiece *p_abstract = m_manager->GetAbstractMeta(mp_meta->GetNameChecksum());
|
|
Dbg_MsgAssert(p_abstract, ("couldn't find abstract piece %s", Script::FindChecksumName(mp_meta->GetNameChecksum())));
|
|
CConcreteMetaPiece *p_concrete = m_manager->CreateConcreteMeta(p_abstract);
|
|
p_concrete->SetRot(m_hard_rot);
|
|
m_manager->AddMetaPieceToPark(m_cell_dims, p_concrete);
|
|
#endif
|
|
|
|
m_manager->RebuildFloor();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CCursor::AttemptRemove()
|
|
{
|
|
ParkEd("CCursor::AttemptRemove()");
|
|
|
|
GridDims area;
|
|
if (m_mode==PASTE)
|
|
{
|
|
if (mp_current_clipboard)
|
|
{
|
|
mp_current_clipboard->GetArea(this,&area);
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
area=m_cell_dims;
|
|
}
|
|
|
|
return m_manager->DestroyMetasInArea(area);
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
A callback called by CParkManager::DestroyConcreteMeta()
|
|
*/
|
|
void CCursor::InformOfMetapieceDeletion(CConcreteMetaPiece *pMeta)
|
|
{
|
|
int gap_half;
|
|
GridDims meta_area = pMeta->GetArea();
|
|
CGapManager::GapDescriptor *p_gap_desc = m_manager->GetGapDescriptor(meta_area, &gap_half);
|
|
if (p_gap_desc && is_gap_descriptor_same_as_current(p_gap_desc))
|
|
m_current_gap.numCompleteHalves = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CCursor::AttemptGap()
|
|
{
|
|
Spt::SingletonPtr<CParkEditor> p_editor;
|
|
if (p_editor->IsParkFull())
|
|
return false;
|
|
|
|
CMapListTemp meta_list = m_manager->GetMetaPiecesAt(m_cell_dims);
|
|
if (meta_list.IsEmpty())
|
|
{
|
|
// XXX
|
|
Ryan("no gap for you!!!!\n");
|
|
return false;
|
|
}
|
|
CConcreteMetaPiece *p_meta = meta_list.GetList()->GetConcreteMeta();
|
|
// XXX
|
|
Ryan("attempting gap at: ");
|
|
m_cell_dims.PrintContents();
|
|
|
|
int half;
|
|
CGapManager::GapDescriptor *pDesc = m_manager->GetGapDescriptor(m_cell_dims, &half);
|
|
if (pDesc)
|
|
{
|
|
// gap already attached at this location
|
|
if (m_current_gap.numCompleteHalves == 1)
|
|
{
|
|
// user already working on gap, so fail
|
|
return false;
|
|
}
|
|
}
|
|
else if (p_meta)
|
|
{
|
|
// metapiece found at this location without gap attached
|
|
if (m_current_gap.numCompleteHalves == 1)
|
|
// remove gap half placed so far. It'll get rebuilt later.
|
|
m_manager->RemoveGap(m_current_gap);
|
|
else
|
|
// make sure not 2
|
|
m_current_gap.numCompleteHalves = 0;
|
|
|
|
int active_gap_half = m_current_gap.numCompleteHalves;
|
|
|
|
GridDims gap_area = p_meta->GetArea();
|
|
|
|
// start gap
|
|
m_current_gap.loc[active_gap_half] = gap_area;
|
|
m_current_gap.rot[active_gap_half] = 0;
|
|
m_current_gap.leftExtent[active_gap_half] = 0;
|
|
m_current_gap.rightExtent[active_gap_half] = 0;
|
|
m_current_gap.score = 100;
|
|
m_current_gap.numCompleteHalves = active_gap_half + 1;
|
|
m_current_gap.tabIndex = -1;
|
|
|
|
if (active_gap_half == 0)
|
|
{
|
|
// new gap, so give default name
|
|
if (m_gap_suffix_counter > 1)
|
|
{
|
|
// K: Make sure the default names are different otherwise when registered in the
|
|
// CSkaterCareer it will not get added cos it will think it is the same gap
|
|
// as the last.
|
|
sprintf(m_current_gap.text, "gap%d",m_gap_suffix_counter);
|
|
}
|
|
else
|
|
{
|
|
strcpy(m_current_gap.text, "gap");
|
|
}
|
|
++m_gap_suffix_counter;
|
|
}
|
|
|
|
if (!m_manager->AddGap(m_current_gap))
|
|
{
|
|
m_current_gap.numCompleteHalves = 0;
|
|
return false;
|
|
}
|
|
m_manager->RebuildFloor();
|
|
if (m_current_gap.numCompleteHalves > 0)
|
|
m_manager->HighlightMetasWithGaps(true, &m_current_gap);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CCursor::AttemptRemoveGap()
|
|
{
|
|
if (m_current_gap.numCompleteHalves == 1)
|
|
{
|
|
// remove gap being worked on
|
|
m_manager->RemoveGap(m_current_gap);
|
|
m_current_gap.numCompleteHalves = 0;
|
|
m_manager->RebuildFloor();
|
|
return true;
|
|
}
|
|
|
|
int half;
|
|
CGapManager::GapDescriptor *pDesc = m_manager->GetGapDescriptor(m_cell_dims, &half);
|
|
if (pDesc)
|
|
{
|
|
// remove gap at this position
|
|
m_manager->RemoveGap(*pDesc);
|
|
m_manager->RebuildFloor();
|
|
m_manager->HighlightMetasWithGaps(true, NULL);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CCursor::AdjustGap(int rot, int leftChange, int rightChange)
|
|
{
|
|
// grab gap at this location
|
|
int half;
|
|
CGapManager::GapDescriptor *p_desc = m_manager->GetGapDescriptor(m_cell_dims, &half);
|
|
if (!p_desc)
|
|
{
|
|
// no gap, so leave
|
|
return false;
|
|
}
|
|
|
|
if (!is_gap_descriptor_same_as_current(p_desc))
|
|
// we are currently working on a gap and it's not the same as the one at this location, so fail
|
|
return false;
|
|
|
|
CGapManager::GapDescriptor desc_temp = *p_desc;
|
|
bool needs_change = false;
|
|
|
|
if (rot != 0)
|
|
{
|
|
desc_temp.rot[half] -= rot;
|
|
desc_temp.leftExtent[half] = 0;
|
|
desc_temp.rightExtent[half] = 0;
|
|
needs_change = true;
|
|
}
|
|
|
|
if (leftChange != 0)
|
|
{
|
|
desc_temp.leftExtent[half] += leftChange;
|
|
if (desc_temp.leftExtent[half] < 0)
|
|
desc_temp.leftExtent[half] = 0;
|
|
else if (desc_temp.leftExtent[half] > 6)
|
|
desc_temp.leftExtent[half] = 6;
|
|
needs_change = true;
|
|
}
|
|
|
|
if (rightChange != 0)
|
|
{
|
|
desc_temp.rightExtent[half] += rightChange;
|
|
if (desc_temp.rightExtent[half] < 0)
|
|
desc_temp.rightExtent[half] = 0;
|
|
if (desc_temp.rightExtent[half] > 6)
|
|
desc_temp.rightExtent[half] = 6;
|
|
needs_change = true;
|
|
}
|
|
|
|
if (needs_change)
|
|
{
|
|
m_manager->RemoveGap(*p_desc);
|
|
desc_temp.rot[half] &= 3;
|
|
|
|
GridDims park_bounds = m_manager->GetParkNearBounds();
|
|
|
|
// make sure gap boundaries are within map
|
|
if (desc_temp.rot[half] == 0)
|
|
{
|
|
if (desc_temp.loc[half].GetZ() - desc_temp.rightExtent[half] < park_bounds.GetZ())
|
|
desc_temp.rightExtent[half]--;
|
|
if (desc_temp.loc[half].GetZ() + desc_temp.loc[half].GetL() + desc_temp.leftExtent[half] > park_bounds.GetZ() + park_bounds.GetL())
|
|
desc_temp.leftExtent[half]--;
|
|
}
|
|
else if (desc_temp.rot[half] == 2)
|
|
{
|
|
if (desc_temp.loc[half].GetZ() - desc_temp.leftExtent[half] < park_bounds.GetZ())
|
|
desc_temp.leftExtent[half]--;
|
|
if (desc_temp.loc[half].GetZ() + desc_temp.loc[half].GetL() + desc_temp.rightExtent[half] > park_bounds.GetZ() + park_bounds.GetL())
|
|
desc_temp.rightExtent[half]--;
|
|
}
|
|
else if (desc_temp.rot[half] == 1)
|
|
{
|
|
if (desc_temp.loc[half].GetX() - desc_temp.rightExtent[half] < park_bounds.GetX())
|
|
desc_temp.rightExtent[half]--;
|
|
if (desc_temp.loc[half].GetX() + desc_temp.loc[half].GetW() + desc_temp.leftExtent[half] > park_bounds.GetX() + park_bounds.GetW())
|
|
desc_temp.leftExtent[half]--;
|
|
}
|
|
else if (desc_temp.rot[half] == 3)
|
|
{
|
|
if (desc_temp.loc[half].GetX() - desc_temp.leftExtent[half] < park_bounds.GetX())
|
|
desc_temp.leftExtent[half]--;
|
|
if (desc_temp.loc[half].GetX() + desc_temp.loc[half].GetW() + desc_temp.rightExtent[half] > park_bounds.GetX() + park_bounds.GetW())
|
|
desc_temp.rightExtent[half]--;
|
|
}
|
|
|
|
// XXX
|
|
for (half = 0; half < 2; half++)
|
|
Ryan("gap details for half %d (%d,%d,%d),(%d,%d,%d) left=%d right=%d\n", half,
|
|
desc_temp.loc[half].GetX(), desc_temp.loc[half].GetY(), desc_temp.loc[half].GetZ(),
|
|
desc_temp.loc[half].GetW(), desc_temp.loc[half].GetH(), desc_temp.loc[half].GetL(),
|
|
desc_temp.leftExtent[half], desc_temp.rightExtent[half]);
|
|
|
|
m_manager->AddGap(desc_temp);
|
|
m_manager->RebuildFloor();
|
|
|
|
if (m_current_gap.numCompleteHalves == 1)
|
|
{
|
|
m_current_gap = desc_temp;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
void CCursor::SetGapNameAndScore(const char *pGapName, int score)
|
|
{
|
|
if (pGapName)
|
|
{
|
|
Dbg_MsgAssert(strlen(pGapName) <= 31, ("too many characters in gap name"));
|
|
if (*pGapName == '\0')
|
|
strcpy(m_current_gap.text, "x");
|
|
else
|
|
strcpy(m_current_gap.text, pGapName);
|
|
}
|
|
if (score >= 0)
|
|
{
|
|
m_current_gap.score = score;
|
|
}
|
|
Dbg_Assert(m_current_gap.tabIndex >= 0);
|
|
CGapManager::sInstance()->SetGapInfo(m_current_gap.tabIndex, m_current_gap);
|
|
}
|
|
|
|
void CCursor::SetGapCancelFlags(Script::CStruct *p_cancelFlags)
|
|
{
|
|
if (!p_cancelFlags)
|
|
{
|
|
return;
|
|
}
|
|
|
|
uint32 cancel_flags=0;
|
|
Script::CComponent *p_comp=p_cancelFlags->GetNextComponent();
|
|
while (p_comp)
|
|
{
|
|
Dbg_MsgAssert(p_comp->mNameChecksum==0 && p_comp->mType==ESYMBOLTYPE_NAME,("Gap cancel flag structure must contain only names"));
|
|
cancel_flags |= Script::GetInteger(p_comp->mChecksum);
|
|
p_comp=p_cancelFlags->GetNextComponent(p_comp);
|
|
}
|
|
|
|
m_current_gap.mCancelFlags=cancel_flags;
|
|
|
|
Dbg_Assert(m_current_gap.tabIndex >= 0);
|
|
CGapManager::sInstance()->SetGapInfo(m_current_gap.tabIndex, m_current_gap);
|
|
}
|
|
|
|
|
|
const char *CCursor::GetGapName()
|
|
{
|
|
return m_current_gap.text;
|
|
}
|
|
|
|
|
|
int CCursor::AttemptAreaSelect()
|
|
{
|
|
Dbg_MsgAssert(m_mode==AREA_SELECT,("Called AttemptAreaSelect() with m_mode!=AREA_SELECT"));
|
|
Dbg_MsgAssert(m_num_corners_selected<=2,("Bad m_num_corners_selected of %d",m_num_corners_selected));
|
|
|
|
if (m_num_corners_selected==0)
|
|
{
|
|
mp_area_corners[0]=m_cell_dims;
|
|
mp_area_corners[1]=m_cell_dims;
|
|
m_num_corners_selected=1;
|
|
ForceSelectionAreaHighlightRefresh();
|
|
}
|
|
else if (m_num_corners_selected==1)
|
|
{
|
|
GridDims area;
|
|
GetAreaSelectDims(&area);
|
|
if (area.GetW() <= CLIPBOARD_MAX_W && area.GetL() <= CLIPBOARD_MAX_L)
|
|
{
|
|
m_num_corners_selected=2;
|
|
}
|
|
}
|
|
|
|
return m_num_corners_selected;
|
|
}
|
|
|
|
void CCursor::ClearAreaSelection()
|
|
{
|
|
GridDims area;
|
|
GetAreaSelectDims(&area);
|
|
|
|
m_manager->HighlightMetasInArea(area,false);
|
|
|
|
m_num_corners_selected=0;
|
|
m_initialised_highlight=false;
|
|
}
|
|
|
|
void CCursor::ContinueAreaSelection()
|
|
{
|
|
m_num_corners_selected=1;
|
|
// Need to force it to re-highlight the selection area next time around
|
|
// because when quitting the paused menu something resets all the highlights.
|
|
ForceSelectionAreaHighlightRefresh();
|
|
}
|
|
|
|
void CCursor::DeleteSelectedPieces()
|
|
{
|
|
if (!m_num_corners_selected)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GridDims dims;
|
|
GetAreaSelectDims(&dims);
|
|
|
|
// First true means do not destroy any flags or restarts
|
|
// Second true means only destroy if completely within the area.
|
|
m_manager->DestroyMetasInArea(dims, true, true);
|
|
|
|
ContinueAreaSelection();
|
|
}
|
|
|
|
void CCursor::ResetSelectedHeights()
|
|
{
|
|
if (!m_num_corners_selected)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GridDims dims;
|
|
GetAreaSelectDims(&dims);
|
|
|
|
m_manager->ResetFloorHeights(dims);
|
|
|
|
ContinueAreaSelection();
|
|
}
|
|
|
|
void CCursor::get_selected_area_coords(uint8 *p_x1, uint8 *p_z1, uint8 *p_x2, uint8 *p_z2)
|
|
{
|
|
uint8 x1=mp_area_corners[0].GetX();
|
|
uint8 z1=mp_area_corners[0].GetZ();
|
|
uint8 x2=mp_area_corners[1].GetX();
|
|
uint8 z2=mp_area_corners[1].GetZ();
|
|
|
|
if (x2 < x1)
|
|
{
|
|
uint8 temp=x1;
|
|
x1=x2;
|
|
x2=temp;
|
|
}
|
|
|
|
if (z2 < z1)
|
|
{
|
|
uint8 temp=z1;
|
|
z1=z2;
|
|
z2=temp;
|
|
}
|
|
|
|
*p_x1=x1;
|
|
*p_z1=z1;
|
|
*p_x2=x2;
|
|
*p_z2=z2;
|
|
}
|
|
|
|
void CCursor::GetAreaSelectDims(GridDims *p_dims)
|
|
{
|
|
if (m_num_corners_selected==0)
|
|
{
|
|
p_dims->SetXYZ(0,0,0);
|
|
p_dims->SetWHL(0,0,0);
|
|
return;
|
|
}
|
|
|
|
uint8 x1,z1,x2,z2;
|
|
get_selected_area_coords(&x1,&z1,&x2,&z2);
|
|
|
|
p_dims->SetXYZ(x1,0,z1);
|
|
p_dims->SetWHL(x2-x1+1,1,z2-z1+1);
|
|
}
|
|
|
|
bool CCursor::DestroyMetasInCurrentArea()
|
|
{
|
|
GridDims area;
|
|
GetAreaSelectDims(&area);
|
|
|
|
return CParkManager::sInstance()->DestroyMetasInArea(area);
|
|
}
|
|
|
|
void CCursor::DeleteOldestClipboard()
|
|
{
|
|
// Find p_last, the last clipboard in the list.
|
|
CClipboard *p_clip=mp_clipboards;
|
|
CClipboard *p_last=NULL;
|
|
CClipboard *p_next_to_last=NULL;
|
|
while (p_clip)
|
|
{
|
|
p_next_to_last=p_last;
|
|
p_last=p_clip;
|
|
|
|
p_clip=p_clip->mpNext;
|
|
}
|
|
if (!p_last)
|
|
{
|
|
// Cannot do anything because there are no clipboards to delete
|
|
return;
|
|
}
|
|
|
|
delete p_last;
|
|
|
|
if (p_next_to_last)
|
|
{
|
|
p_next_to_last->mpNext=NULL;
|
|
}
|
|
else
|
|
{
|
|
mp_clipboards=NULL;
|
|
}
|
|
}
|
|
|
|
bool CCursor::SelectionAreaTooBigToCopy()
|
|
{
|
|
GridDims area;
|
|
GetAreaSelectDims(&area);
|
|
|
|
if (area.GetW() > CLIPBOARD_MAX_W || area.GetL() > CLIPBOARD_MAX_L)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
Spt::SingletonPtr<CParkEditor> p_editor;
|
|
if (!p_editor->RoomToCopyOrPaste(area.GetW(), area.GetL()))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool CCursor::CopySelectionToClipboard()
|
|
{
|
|
if (SelectionAreaTooBigToCopy())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
GridDims area;
|
|
GetAreaSelectDims(&area);
|
|
|
|
// TODO TODO TODO
|
|
// If not enough rail points to copy the rails, check to see if any of the existing clipboards contain
|
|
// rails. If so, delete enough of them to free up enough points. If still not enough points, bail out.
|
|
// If enough, carry on with the next loop.
|
|
Mth::Vector corner_pos;
|
|
Mth::Vector area_dims;
|
|
corner_pos=Ed::CParkManager::Instance()->GridCoordinatesToWorld(area,&area_dims);
|
|
int num_rail_points_needed=Obj::GetRailEditor()->CountPointsInArea(corner_pos[X], corner_pos[Z],
|
|
corner_pos[X]+area_dims[X], corner_pos[Z]+area_dims[Z]);
|
|
if (num_rail_points_needed > Obj::GetRailEditor()->GetNumFreePoints())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
if (GetNumClipboards()==MAX_CLIPBOARDS)
|
|
{
|
|
// All the CClipboard's in the pool have already been allocated.
|
|
|
|
// Find the oldest clipboard and delete it.
|
|
DeleteOldestClipboard();
|
|
|
|
// That will have freed up space for one more CClipboard
|
|
// so the new CClipboard below should not assert.
|
|
// If it does then something strange is going on, like MAX_CLIPBOARDS is 0 or something.
|
|
}
|
|
|
|
CClipboard *p_clipboard=new CClipboard;
|
|
|
|
|
|
|
|
// CopySelectionToClipboard will use up CClipboardEntry's, of which there are only
|
|
// a certain number allocated in a pool.
|
|
// So CopySelectionToClipboard may fail, even though the CClipboard pool may not be full.
|
|
|
|
// Keep deleting old clipboards until CopySelectionToClipboard succeeds.
|
|
// Note that the above newly allocated p_clipboard has not been put in the list
|
|
// yet so it will not get deleted by accident here.
|
|
while (!p_clipboard->CopySelectionToClipboard(area))
|
|
{
|
|
if (!mp_clipboards)
|
|
{
|
|
// Run out of clipboards to delete! If this happens then CopySelectionToClipboard
|
|
// must be failing because the total number of pieces the user wants to copy
|
|
// exceeds the total number of CClipboardEntry's available in the pool, which
|
|
// is defined by MAX_CLIPBOARD_METAS in clipboard.h
|
|
break;
|
|
}
|
|
DeleteOldestClipboard();
|
|
}
|
|
|
|
if (p_clipboard->IsEmpty())
|
|
{
|
|
// Nothing got copied into the clipboard, which means either the user tried to copy a
|
|
// blank area or the above attempts at copying failed due to lack of memory.
|
|
|
|
delete p_clipboard;
|
|
p_clipboard=NULL;
|
|
|
|
return false;
|
|
}
|
|
|
|
// Add the new clipboard to the list.
|
|
p_clipboard->mpNext=mp_clipboards;
|
|
mp_clipboards=p_clipboard;
|
|
return true;
|
|
}
|
|
|
|
int CCursor::GetNumClipboards()
|
|
{
|
|
int n=0;
|
|
CClipboard *p_clipboard=mp_clipboards;
|
|
while (p_clipboard)
|
|
{
|
|
++n;
|
|
p_clipboard=p_clipboard->mpNext;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
void CCursor::PasteCurrentClipboard()
|
|
{
|
|
if (mp_current_clipboard)
|
|
{
|
|
mp_current_clipboard->Paste(this);
|
|
}
|
|
}
|
|
|
|
CClipboard *CCursor::get_clipboard(int index)
|
|
{
|
|
CClipboard *p_clipboard=mp_clipboards;
|
|
|
|
for (int i=0; i<index; ++i)
|
|
{
|
|
if (p_clipboard)
|
|
{
|
|
p_clipboard=p_clipboard->mpNext;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return p_clipboard;
|
|
}
|
|
|
|
void CCursor::set_current_clipboard(int index)
|
|
{
|
|
DestroyAnyClipboardCursors();
|
|
mp_current_clipboard=get_clipboard(index);
|
|
|
|
/*
|
|
if (mp_current_clipboard)
|
|
{
|
|
m_cell_dims.SetWHL(mp_current_clipboard->GetWidth(),1,mp_current_clipboard->GetLength());
|
|
if (m_hard_rot & 1)
|
|
{
|
|
m_cell_dims.SetWHL(m_cell_dims.GetL(), m_cell_dims.GetH(), m_cell_dims.GetW());
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
void CCursor::remove_clipboard(int index)
|
|
{
|
|
CClipboard *p_remove=get_clipboard(index);
|
|
if (!p_remove)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CClipboard *p_search=mp_clipboards;
|
|
CClipboard *p_last=NULL;
|
|
while (p_search)
|
|
{
|
|
if (p_search==p_remove)
|
|
{
|
|
if (p_last)
|
|
{
|
|
p_last->mpNext=p_remove->mpNext;
|
|
}
|
|
else
|
|
{
|
|
mp_clipboards=p_remove->mpNext;
|
|
}
|
|
delete p_remove;
|
|
break;
|
|
}
|
|
|
|
p_last=p_search;
|
|
p_search=p_search->mpNext;
|
|
}
|
|
}
|
|
|
|
void CCursor::RefreshSelectionArea()
|
|
{
|
|
switch (m_num_corners_selected)
|
|
{
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
if (!m_initialised_highlight)
|
|
{
|
|
GridDims area;
|
|
GetAreaSelectDims(&area);
|
|
|
|
m_manager->HighlightMetasInArea(area,true);
|
|
|
|
m_initialised_highlight=true;
|
|
}
|
|
else
|
|
{
|
|
if (m_cell_dims.GetX() != mp_area_corners[1].GetX() ||
|
|
m_cell_dims.GetZ() != mp_area_corners[1].GetZ())
|
|
{
|
|
GridDims area;
|
|
GetAreaSelectDims(&area);
|
|
|
|
m_manager->HighlightMetasInArea(area,false);
|
|
|
|
mp_area_corners[1]=m_cell_dims;
|
|
|
|
GetAreaSelectDims(&area);
|
|
|
|
m_manager->HighlightMetasInArea(area,true);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Find all the pieces intersecting the cursor
|
|
// and turn the highlight effect on or off
|
|
// (In THPS3, the highlight was a wireframe. Here I think we are going to try coloring it red)
|
|
void CCursor::HighlightIntersectingMetas(bool on)
|
|
{
|
|
if (m_mode==PASTE)
|
|
{
|
|
if (mp_current_clipboard)
|
|
{
|
|
mp_current_clipboard->HighlightIntersectingMetas(this,on);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Get the list of (concrete) meta pieces that intersect the
|
|
// dimension of the cursor's m_cell_dims
|
|
CMapListTemp metas_at_pos = m_manager->GetMetaPiecesAt(m_cell_dims);
|
|
if (metas_at_pos.IsEmpty())
|
|
{
|
|
// Nothing intersecting, so do nothing and return
|
|
return;
|
|
}
|
|
|
|
// Iterate over the list of metapieces we just found, and highlight each one
|
|
// (Whcih will actually highlight the pieces
|
|
CMapListNode *p_entry = metas_at_pos.GetList();
|
|
while(p_entry)
|
|
{
|
|
p_entry->GetConcreteMeta()->Highlight(on);
|
|
p_entry = p_entry->GetNext();
|
|
}
|
|
}
|
|
|
|
void CCursor::SetVisibility(bool visible)
|
|
{
|
|
//Dbg_Assert(mp_meta);
|
|
if (mp_meta)
|
|
{
|
|
mp_meta->SetVisibility(visible);
|
|
}
|
|
|
|
if (!visible)
|
|
{
|
|
if (mp_current_clipboard)
|
|
{
|
|
mp_current_clipboard->DestroyMetas();
|
|
}
|
|
}
|
|
|
|
m_initialised_highlight=false;
|
|
}
|
|
|
|
|
|
|
|
void CCursor::ChangePieceInSet(int dir)
|
|
{
|
|
CParkManager::CPieceSet &piece_set = m_manager->GetPieceSet(m_selected_set, &m_menu_set_number);
|
|
int selected_entry = piece_set.mSelectedEntry;
|
|
selected_entry += dir;
|
|
if (selected_entry < 0)
|
|
selected_entry = piece_set.mTotalEntries - 1;
|
|
else if (selected_entry >= piece_set.mTotalEntries)
|
|
selected_entry = 0;
|
|
piece_set.mSelectedEntry = selected_entry;
|
|
|
|
if (piece_set.mIsClipboardSet)
|
|
{
|
|
set_current_clipboard(piece_set.mSelectedEntry);
|
|
}
|
|
else
|
|
{
|
|
set_source_meta(piece_set.mEntryTab[selected_entry].mNameCrc);
|
|
}
|
|
}
|
|
|
|
void CCursor::ChangeSet(int dir)
|
|
{
|
|
for (int count = m_manager->GetTotalNumPieceSets(); count > 0; count--)
|
|
{
|
|
m_selected_set += dir;
|
|
if (m_selected_set < 0)
|
|
m_selected_set = m_manager->GetTotalNumPieceSets() - 1;
|
|
if (m_selected_set >= m_manager->GetTotalNumPieceSets())
|
|
m_selected_set = 0;
|
|
//printf("set is: %s\n", m_palette_set[m_selected_set].mpName);
|
|
if (m_manager->GetPieceSet(m_selected_set, &m_menu_set_number).mVisible) break;
|
|
}
|
|
CParkManager::CPieceSet &piece_set = m_manager->GetPieceSet(m_selected_set, &m_menu_set_number);
|
|
if (piece_set.mIsClipboardSet)
|
|
{
|
|
set_current_clipboard(piece_set.mSelectedEntry);
|
|
// Destroy the regular cursor meta
|
|
DestroyGeometry();
|
|
|
|
|
|
change_mode(PASTE);
|
|
}
|
|
else
|
|
{
|
|
set_source_meta(piece_set.mEntryTab[piece_set.mSelectedEntry].mNameCrc);
|
|
}
|
|
}
|
|
|
|
void CCursor::SwitchMenuPieceToMostRecentClipboard()
|
|
{
|
|
if (!GetNumClipboards())
|
|
{
|
|
return;
|
|
}
|
|
|
|
int num_sets=m_manager->GetTotalNumPieceSets();
|
|
CParkManager::CPieceSet *p_piece_set=NULL;
|
|
|
|
for (int i=0; i<num_sets; ++i)
|
|
{
|
|
CParkManager::CPieceSet &piece_set = m_manager->GetPieceSet(i, &m_menu_set_number);
|
|
if (piece_set.mIsClipboardSet)
|
|
{
|
|
m_selected_set=i;
|
|
p_piece_set=&piece_set;
|
|
break;
|
|
}
|
|
}
|
|
Dbg_MsgAssert(p_piece_set,("Clipboard piece set not found?"));
|
|
|
|
p_piece_set->mSelectedEntry=0;
|
|
set_current_clipboard(p_piece_set->mSelectedEntry);
|
|
// Destroy the regular cursor meta
|
|
DestroyGeometry();
|
|
change_mode(PASTE);
|
|
|
|
// Fix to TT14349: Crash bug if copying tree pieces at the edge of the largest map by highlighting starting at the
|
|
// lower right corner of the set of trees.
|
|
// Caused by the cursor being out of bounds for a frame, hence causing it to read outside the map array.
|
|
ForceInBounds();
|
|
}
|
|
|
|
bool CCursor::ChangeFloorHeight(GridDims dims, int height, int dir, bool uniformHeight)
|
|
{
|
|
//printf("CCursor::ChangeFloorHeight: ");
|
|
|
|
/*
|
|
Uneven floor:
|
|
If going up, raise to height of topmost
|
|
If going down, only lower ones on same level
|
|
*/
|
|
|
|
//printf("height=%d uniform_height=%d\n",height,uniformHeight);
|
|
/*
|
|
Now,
|
|
*/
|
|
|
|
if (dims.GetW() > CLIPBOARD_MAX_W || dims.GetL() > CLIPBOARD_MAX_L)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//Spt::SingletonPtr<CParkEditor> p_editor;
|
|
//if (p_editor->IsParkFull())
|
|
//{
|
|
// return false;
|
|
//}
|
|
|
|
bool success = true;
|
|
|
|
|
|
if (m_manager->SlideColumn(dims, dims.GetY(), height, (dir > 0), !uniformHeight))
|
|
{
|
|
//Ryan("Slide column, dir = %d, dims=", dir);
|
|
//dims.PrintContents();
|
|
|
|
change_cell_pos(0, 0);
|
|
Spt::SingletonPtr<CParkEditor> p_editor;
|
|
if (m_manager->RebuildFloor(p_editor->IsParkFull()))
|
|
{
|
|
m_manager->HighlightMetasWithGaps(false, NULL);
|
|
}
|
|
else
|
|
{
|
|
// out of memory, so reverse slide
|
|
m_manager->UndoSlideColumn();
|
|
m_manager->RebuildFloor();
|
|
success = false;
|
|
}
|
|
}
|
|
else
|
|
success = false;
|
|
|
|
return success;
|
|
}
|
|
|
|
bool CCursor::ChangeFloorHeight(int dir)
|
|
{
|
|
GridDims dims;
|
|
switch (m_mode)
|
|
{
|
|
case AREA_SELECT:
|
|
if (m_num_corners_selected)
|
|
{
|
|
GetAreaSelectDims(&dims);
|
|
}
|
|
else
|
|
{
|
|
dims=m_cell_dims;
|
|
}
|
|
break;
|
|
case PASTE:
|
|
if (mp_current_clipboard)
|
|
{
|
|
mp_current_clipboard->GetArea(this,&dims);
|
|
}
|
|
break;
|
|
default:
|
|
dims=m_cell_dims;
|
|
break;
|
|
}
|
|
|
|
// If the dims exceeds the area of the park, then do not raise or lower.
|
|
// This can happen if the park is been resized to its smallest possible size and then a big pool
|
|
// piece selected. If the raise was allowed to go ahead, it would result in the fence raising too. (TT11825)
|
|
GridDims park_bounds = CParkManager::sInstance()->GetParkNearBounds();
|
|
if (dims.GetW() > park_bounds.GetW() || dims.GetL() > park_bounds.GetL())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
bool uniform_height;
|
|
int height = m_manager->GetFloorHeight(dims, &uniform_height);
|
|
|
|
// If pasting, destroy the clipboard metas, otherwise the dry run that ChangeFloorHeight
|
|
// does to determine whether it is safe to raise or lower will incorrectly think it
|
|
// is safe when it is not. I think the function generate_floor_pieces_from_height_map
|
|
// gets confused by the presence of the clipboard metas. (TT7495 & TT6152)
|
|
if (m_mode==PASTE)
|
|
{
|
|
if (mp_current_clipboard)
|
|
{
|
|
mp_current_clipboard->DestroyMetas();
|
|
}
|
|
}
|
|
bool ret_val=ChangeFloorHeight(dims,height,dir,uniform_height);
|
|
|
|
if (m_mode==AREA_SELECT)
|
|
{
|
|
ForceSelectionAreaHighlightRefresh();
|
|
}
|
|
return ret_val;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CCursor::IsSittingOnGap()
|
|
{
|
|
int half;
|
|
CGapManager::GapDescriptor *pDesc = m_manager->GetGapDescriptor(m_cell_dims, &half);
|
|
if (pDesc)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
CCursor *CCursor::sInstance(bool assert)
|
|
{
|
|
Dbg_Assert(!assert || sp_instance);
|
|
return sp_instance;
|
|
}
|
|
|
|
|
|
|
|
|
|
void CCursor::ForceInBounds()
|
|
{
|
|
if (m_cell_dims[X] < m_manager->GetParkNearBounds().GetX())
|
|
{
|
|
m_cell_dims[X] = m_manager->GetParkNearBounds().GetX();
|
|
}
|
|
if (m_cell_dims[X] + m_cell_dims[W] > m_manager->GetParkNearBounds().GetX() + m_manager->GetParkNearBounds().GetW())
|
|
{
|
|
m_cell_dims[X] = m_manager->GetParkNearBounds().GetX() + m_manager->GetParkNearBounds().GetW() - m_cell_dims[W];
|
|
}
|
|
if (m_cell_dims[Z] < m_manager->GetParkNearBounds().GetZ())
|
|
{
|
|
m_cell_dims[Z] = m_manager->GetParkNearBounds().GetZ();
|
|
}
|
|
if (m_cell_dims[Z] + m_cell_dims[L] > m_manager->GetParkNearBounds().GetZ() + m_manager->GetParkNearBounds().GetL())
|
|
{
|
|
m_cell_dims[Z] = m_manager->GetParkNearBounds().GetZ() + m_manager->GetParkNearBounds().GetL() - m_cell_dims[L];
|
|
}
|
|
|
|
if (m_mode==PASTE)
|
|
{
|
|
if (mp_current_clipboard)
|
|
{
|
|
GridDims area;
|
|
mp_current_clipboard->GetArea(this,&area);
|
|
|
|
int dx=0;
|
|
int park_x_left=m_manager->GetParkNearBounds().GetX();
|
|
int park_x_right=m_manager->GetParkNearBounds().GetX()+m_manager->GetParkNearBounds().GetW()-1;
|
|
sint8 x_left=area.GetX();
|
|
if (x_left < park_x_left)
|
|
{
|
|
dx=park_x_left-x_left;
|
|
}
|
|
sint8 x_right=area.GetX();
|
|
x_right+=area.GetW()-1;
|
|
if (x_right > park_x_right)
|
|
{
|
|
dx=park_x_right-x_right;
|
|
}
|
|
m_cell_dims[X]+=dx;
|
|
|
|
int dz=0;
|
|
int park_z_top=m_manager->GetParkNearBounds().GetZ();
|
|
int park_z_bottom=m_manager->GetParkNearBounds().GetZ()+m_manager->GetParkNearBounds().GetL()-1;
|
|
|
|
sint8 z_top=area.GetZ();
|
|
if (z_top < park_z_top)
|
|
{
|
|
dz=park_z_top-z_top;
|
|
}
|
|
sint8 z_bottom=area.GetZ();
|
|
z_bottom+=area.GetL()-1;
|
|
if (z_bottom > park_z_bottom)
|
|
{
|
|
dz=park_z_bottom-z_bottom;
|
|
}
|
|
|
|
m_cell_dims[Z]+=dz;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CCursor::change_cell_pos(int incX, int incZ)
|
|
{
|
|
//printf("change_cell_pos:\n");
|
|
//printf("Before:");
|
|
//m_cell_dims.PrintContents();
|
|
|
|
ForceInBounds();
|
|
GridDims old_pos = m_cell_dims;
|
|
|
|
m_cell_dims[X] += incX;
|
|
m_cell_dims[Z] += incZ;
|
|
|
|
ForceInBounds();
|
|
|
|
if (m_mode==PASTE)
|
|
{
|
|
if (mp_current_clipboard)
|
|
{
|
|
m_clipboard_y=mp_current_clipboard->FindMaxFloorHeight(this);
|
|
m_cell_dims[Y]=m_clipboard_y;
|
|
}
|
|
else
|
|
{
|
|
m_cell_dims[Y]=0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int current_floor_height = m_manager->GetFloorHeight(m_cell_dims);
|
|
int floor_height_old_pos = m_manager->GetFloorHeight(old_pos);
|
|
m_cell_dims[Y] = (current_floor_height > floor_height_old_pos) ? current_floor_height : floor_height_old_pos;
|
|
}
|
|
|
|
//Ryan("cursor at %d,%d\n", m_cell_dims[X], m_cell_dims[Z]);
|
|
|
|
//printf("After:");
|
|
//m_cell_dims.PrintContents();
|
|
|
|
#if 0
|
|
printf("park bounds: %d,%d,%d,%d, cell_dims: %d,%d\n",
|
|
m_manager->GetParkNearBounds().GetX(), m_manager->GetParkNearBounds().GetZ(),
|
|
m_manager->GetParkNearBounds().GetW(), m_manager->GetParkNearBounds().GetL(),
|
|
m_cell_dims[W], m_cell_dims[L]);
|
|
#endif
|
|
|
|
if (m_mode == GAP || m_mode == GAP_ADJUST)
|
|
{
|
|
ECursorMode new_mode = GAP;
|
|
|
|
// see if cursor is over a metapiece with attached gap
|
|
CMapListTemp meta_list = m_manager->GetMetaPiecesAt(m_cell_dims);
|
|
if (!meta_list.IsEmpty())
|
|
{
|
|
int half;
|
|
GridDims area = meta_list.GetList()->GetConcreteMeta()->GetArea();
|
|
CGapManager::GapDescriptor *p_desc = m_manager->GetGapDescriptor(area, &half);
|
|
if (p_desc)
|
|
{
|
|
if (m_current_gap.numCompleteHalves != 1)
|
|
{
|
|
m_current_gap = *p_desc;
|
|
}
|
|
new_mode = GAP_ADJUST;
|
|
}
|
|
}
|
|
|
|
change_mode(new_mode);
|
|
|
|
if (m_current_gap.numCompleteHalves > 0)
|
|
m_manager->HighlightMetasWithGaps(true, &m_current_gap);
|
|
else
|
|
m_manager->HighlightMetasWithGaps(true, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void CCursor::set_source_meta(uint32 nameChecksum)
|
|
{
|
|
#ifndef DONT_USE_CURSOR_META
|
|
if (mp_meta)
|
|
{
|
|
mp_meta->MarkUnlocked();
|
|
m_manager->DestroyConcreteMeta(mp_meta, CParkManager::mDONT_DESTROY_PIECES_ABOVE);
|
|
mp_meta = NULL;
|
|
}
|
|
|
|
CAbstractMetaPiece *p_source_meta = m_manager->GetAbstractMeta(nameChecksum);
|
|
Dbg_MsgAssert(p_source_meta, ("couldn't find metapiece named %s", Script::FindChecksumName(nameChecksum)));
|
|
|
|
if (p_source_meta->IsRailPlacement())
|
|
{
|
|
m_cell_dims.SetWHL(1, 1, 1);
|
|
}
|
|
else
|
|
{
|
|
mp_meta = m_manager->CreateConcreteMeta(p_source_meta, true);
|
|
mp_meta->MarkLocked();
|
|
m_cell_dims.SetWHL(mp_meta->GetArea().GetW(), mp_meta->GetArea().GetH(), mp_meta->GetArea().GetL());
|
|
if (m_hard_rot & 1)
|
|
m_cell_dims.SetWHL(m_cell_dims.GetL(), m_cell_dims.GetH(), m_cell_dims.GetW());
|
|
}
|
|
#else
|
|
m_cell_dims.SetWHL(1, 1, 1);
|
|
#endif
|
|
|
|
ClearAreaSelection();
|
|
|
|
if (p_source_meta->IsGapPlacement())
|
|
{
|
|
change_mode(GAP);
|
|
//m_manager->HighlightMetasWithGaps(true, NULL);
|
|
}
|
|
else if (p_source_meta->IsAreaSelection())
|
|
{
|
|
change_mode(AREA_SELECT);
|
|
m_manager->HighlightMetasWithGaps(false, NULL);
|
|
}
|
|
else if (p_source_meta->IsRailPlacement())
|
|
{
|
|
change_mode(RAIL_PLACEMENT);
|
|
m_manager->HighlightMetasWithGaps(false, NULL);
|
|
}
|
|
else
|
|
{
|
|
change_mode(REGULAR);
|
|
m_manager->HighlightMetasWithGaps(false, NULL);
|
|
}
|
|
|
|
//m_manager->AddMetaPieceToPark(GridDims(0, 8, 0), mp_meta);
|
|
|
|
//printf("selected set %d, entry %d/%d\n", m_selected_set, m_palette_set[m_selected_set].mSelectedEntry, m_palette_set[m_selected_set].mTotalEntries);
|
|
}
|
|
|
|
void CCursor::change_mode(ECursorMode newMode)
|
|
{
|
|
if (m_mode != newMode)
|
|
{
|
|
m_mode = newMode;
|
|
RefreshHelperText();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void CCursor::RefreshHelperText()
|
|
{
|
|
Script::CStruct params;
|
|
if (m_mode == GAP_ADJUST)
|
|
params.AddChecksum(CRCD(0x6835b854,"mode"), CRCD(0xe75a3a17,"gap_adjust"));
|
|
else if (m_mode == GAP)
|
|
params.AddChecksum(CRCD(0x6835b854,"mode"), CRCD(0x780a5cf3,"gap_regular"));
|
|
else if (m_mode == RAIL_PLACEMENT)
|
|
params.AddChecksum(CRCD(0x6835b854,"mode"), CRCD(0xffd81c08,"rail_placement"));
|
|
else
|
|
params.AddChecksum(CRCD(0x6835b854,"mode"), CRCD(0xb58efc2b,"regular"));
|
|
Script::RunScript("parked_set_helper_text_mode", ¶ms);
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CCursor::is_gap_descriptor_same_as_current(CGapManager::GapDescriptor *pDesc)
|
|
{
|
|
if (m_current_gap.numCompleteHalves == 1 &&
|
|
(pDesc->loc[0].GetX() != m_current_gap.loc[0].GetX() ||
|
|
pDesc->loc[0].GetY() != m_current_gap.loc[0].GetY() ||
|
|
pDesc->loc[0].GetZ() != m_current_gap.loc[0].GetZ()))
|
|
{
|
|
// we are currently working on a gap and it's not the same as the one at this location, so fail
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
CUpperMenuManager::CUpperMenuManager()
|
|
{
|
|
//Rulon: Commented this out to prevent menu set items from being added twice
|
|
//Enable();
|
|
|
|
mp_current_set = NULL;
|
|
m_current_entry_in_set = 0;
|
|
m_current_set_index = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
CUpperMenuManager::~CUpperMenuManager()
|
|
{
|
|
Disable();
|
|
}
|
|
|
|
|
|
|
|
|
|
void CUpperMenuManager::SetSourceMeta(uint32 nameChecksum)
|
|
{
|
|
//Script::RunScript("parked_make_piece_menu");
|
|
|
|
CAbstractMetaPiece *p_source_meta = m_manager->GetAbstractMeta(nameChecksum);
|
|
Dbg_MsgAssert(p_source_meta, ("couldn't find metapiece named %s", Script::FindChecksumName(nameChecksum)));
|
|
|
|
Script::CStruct params;
|
|
params.AddChecksum("metapiece_id", nameChecksum);
|
|
if (p_source_meta->IsSingular())
|
|
{
|
|
params.AddChecksum("sector", nameChecksum);
|
|
Script::RunScript("parked_make_piece_menu_item", ¶ms);
|
|
}
|
|
else
|
|
{
|
|
Script::CArray sectors_array;
|
|
p_source_meta->BuildElement3dSectorsArray(§ors_array);
|
|
params.AddArray("sectors", §ors_array);
|
|
Script::RunScript("parked_make_piece_menu_item", ¶ms);
|
|
Script::CleanUpArray(§ors_array);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void CUpperMenuManager::SetPieceSet(CParkManager::CPieceSet *pSet, int set_number, int menuSetNumber)
|
|
{
|
|
ParkEd("CUpperMenuManager::SetPieceSet(pSet = %p, set_number = %d)", pSet, set_number);
|
|
|
|
Dbg_Assert(pSet);
|
|
|
|
bool is_clipboard_set=false;
|
|
int num_clipboards=0;
|
|
if (pSet->mIsClipboardSet)
|
|
{
|
|
is_clipboard_set=true;
|
|
num_clipboards=CCursor::sInstance()->GetNumClipboards();
|
|
CCursor::sInstance()->ClearAreaSelection();
|
|
}
|
|
|
|
Obj::CTracker* p_tracker = Obj::CTracker::Instance();
|
|
if (mp_current_set)
|
|
{
|
|
//uint32 name_crc = pSet->mEntryTab[m_current_entry_in_set].mNameCrc;
|
|
uint32 name_crc = mp_current_set->mEntryTab[m_current_entry_in_set].mNameCrc;
|
|
|
|
ParkEd("unfocusing item in piece menu %s", Script::FindChecksumName(name_crc));
|
|
if (p_tracker->GetObject(name_crc))
|
|
p_tracker->LaunchEvent(Obj::CEvent::TYPE_UNFOCUS, name_crc);
|
|
}
|
|
|
|
ParkEd("current set is %p\n", mp_current_set);
|
|
if (pSet != mp_current_set)
|
|
{
|
|
//printf("Script::RunScript(\"parked_make_piece_menu\");");
|
|
Script::RunScript("parked_make_piece_menu");
|
|
|
|
for (int i = 0; i < pSet->mTotalEntries; i++)
|
|
{
|
|
uint32 name_checksum = pSet->mEntryTab[i].mNameCrc;
|
|
|
|
if (is_clipboard_set)
|
|
{
|
|
Script::CStruct params;
|
|
params.AddChecksum("metapiece_id", name_checksum);
|
|
if (i<num_clipboards)
|
|
{
|
|
params.AddInteger("ClipBoardIndex",i+1);
|
|
}
|
|
else
|
|
{
|
|
params.AddChecksum(NONAME,CRCD(0x66da03b3,"EmptyClipBoard"));
|
|
}
|
|
Script::RunScript("parked_make_piece_menu_item", ¶ms);
|
|
}
|
|
else
|
|
{
|
|
CAbstractMetaPiece *p_source_meta = m_manager->GetAbstractMeta(name_checksum);
|
|
Dbg_MsgAssert(p_source_meta, ("couldn't find metapiece named %s", Script::FindChecksumName(name_checksum)));
|
|
|
|
Script::CStruct params;
|
|
params.AddChecksum("metapiece_id", name_checksum);
|
|
if (p_source_meta->IsSingular())
|
|
{
|
|
params.AddChecksum("sector", name_checksum);
|
|
Script::RunScript("parked_make_piece_menu_item", ¶ms);
|
|
}
|
|
else
|
|
{
|
|
Script::CArray sectors_array;
|
|
p_source_meta->BuildElement3dSectorsArray(§ors_array);
|
|
params.AddArray("sectors", §ors_array);
|
|
Script::RunScript("parked_make_piece_menu_item", ¶ms);
|
|
Script::CleanUpArray(§ors_array);
|
|
}
|
|
}
|
|
}
|
|
|
|
Script::RunScript("parked_make_set_menu");
|
|
|
|
Script::CStruct params;
|
|
params.AddInteger("set_number", menuSetNumber);
|
|
params.AddInteger("last_set_number", m_current_set_index);
|
|
Script::RunScript("parked_lock_piece_and_set_menus", ¶ms);
|
|
|
|
mp_current_set = pSet;
|
|
m_current_set_index = menuSetNumber;
|
|
}
|
|
|
|
// m_current_entry_in_set
|
|
|
|
//Dbg_Assert(m_current_entry_in_set >= 0 && m_current_entry_in_set <
|
|
|
|
ParkEd("focusing item in piece menu %s", Script::FindChecksumName(pSet->mEntryTab[pSet->mSelectedEntry].mNameCrc));
|
|
if (p_tracker->GetObject(pSet->mEntryTab[pSet->mSelectedEntry].mNameCrc))
|
|
p_tracker->LaunchEvent(Obj::CEvent::TYPE_FOCUS, pSet->mEntryTab[pSet->mSelectedEntry].mNameCrc);
|
|
m_current_entry_in_set = pSet->mSelectedEntry;
|
|
|
|
/* Make the slider reflect the selection window */
|
|
|
|
int first_in_window = m_current_entry_in_set - 3;
|
|
int last_in_window = m_current_entry_in_set + 3;
|
|
if (pSet->mTotalEntries <= 7)
|
|
{
|
|
first_in_window = 0;
|
|
last_in_window = pSet->mTotalEntries - 1;
|
|
}
|
|
else if (first_in_window < 0)
|
|
{
|
|
last_in_window += -first_in_window;
|
|
first_in_window = 0;
|
|
}
|
|
else if (last_in_window >= pSet->mTotalEntries)
|
|
{
|
|
first_in_window += pSet->mTotalEntries - last_in_window - 1;
|
|
last_in_window = pSet->mTotalEntries - 1;
|
|
}
|
|
|
|
Front::CScreenElementManager* p_element_manager = Front::CScreenElementManager::Instance();
|
|
Front::CScreenElementPtr p_slider = p_element_manager->GetElement(Script::GenerateCRC("piece_slider_orange"), Front::CScreenElementManager::ASSERT);
|
|
float slider_x, slider_y;
|
|
p_slider->GetLocalPos(&slider_x, &slider_y);
|
|
float slider_start = 375.0f * first_in_window / pSet->mTotalEntries;
|
|
float slider_end = 375.0f * (last_in_window + 1) / pSet->mTotalEntries;
|
|
p_slider->SetPos(slider_start, slider_y, Front::CScreenElement::FORCE_INSTANT);
|
|
p_slider->SetScale((slider_end - slider_start) / 4.0f, 1.0f, false, Front::CScreenElement::FORCE_INSTANT);
|
|
|
|
Front::CScreenElementPtr p_name_text = p_element_manager->GetElement(Script::GenerateCRC("piece_menu_name_text"), Front::CScreenElementManager::ASSERT);
|
|
if (pSet->mEntryTab[m_current_entry_in_set].mpName)
|
|
((Front::CTextElement *) p_name_text.Convert())->SetText(pSet->mEntryTab[m_current_entry_in_set].mpName);
|
|
else
|
|
((Front::CTextElement *) p_name_text.Convert())->SetText("---");
|
|
}
|
|
|
|
|
|
|
|
|
|
void CUpperMenuManager::Enable()
|
|
{
|
|
ParkEd("CUpperMenuManager::Enable()");
|
|
//printf("CUpperMenuManager::Enable()");
|
|
|
|
Script::RunScript("parked_make_piece_menu");
|
|
Script::RunScript("parked_make_set_menu");
|
|
|
|
for (int i = 0; i < m_manager->GetTotalNumPieceSets(); i++)
|
|
{
|
|
CParkManager::CPieceSet &set = m_manager->GetPieceSet(i);
|
|
if (set.mVisible)
|
|
{
|
|
Script::CStruct params;
|
|
params.AddString("set_name", set.mpName);
|
|
Script::RunScript("parked_make_set_menu_item", ¶ms);
|
|
}
|
|
}
|
|
|
|
// will force menu to be rebuilt in SetPieceSet()
|
|
mp_current_set = NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
void CUpperMenuManager::Disable()
|
|
{
|
|
ParkEd("CUpperMenuManager::Disable()");
|
|
|
|
Script::RunScript("parked_destroy_piece_menu");
|
|
Script::RunScript("parked_destroy_set_menu");
|
|
mp_current_set= NULL;
|
|
}
|
|
|
|
bool ScriptSetParkEditorTimeOfDay(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
uint32 tod_script=0;
|
|
pParams->GetChecksum(CRCD(0x4c72ed98,"tod_script"),&tod_script);
|
|
Ed::CParkEditor::Instance()->SetTimeOfDayScript(tod_script);
|
|
return true;
|
|
}
|
|
|
|
bool ScriptGetParkEditorTimeOfDayScript(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
uint32 tod_script=Ed::CParkEditor::Instance()->GetTimeOfDayScript();
|
|
if (tod_script)
|
|
{
|
|
pScript->GetParams()->AddChecksum(CRCD(0x4c72ed98,"tod_script"),tod_script);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Added so that when choosing to create a goal, the node array can be initialised, otherwise the
|
|
// cursor will not be able to detect kill polys (unless a test play had been done)
|
|
bool ScriptRebuildParkNodeArray(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
Ed::CParkManager::sInstance()->RebuildNodeArray();
|
|
return true;
|
|
}
|
|
|
|
bool ScriptFreeUpMemoryForPlayingPark(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
// The following will free up everything on the park editor heap, then delete the
|
|
// heap itself.
|
|
|
|
Ed::CParkEditor::Instance()->CreatePlayModeGapManager();
|
|
|
|
Ed::CParkEditor::Instance()->DeleteCursor();
|
|
// Note: Only destroying pieces, not the cloned sectors, otherwise the whole park
|
|
// will disappear from beneath the skater.
|
|
Ed::CParkManager::sInstance()->Destroy(Ed::CParkGenerator::DESTROY_ONLY_PIECES);
|
|
|
|
Ed::CParkEditor::Instance()->SwitchToPlayModeGapManager();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ScriptCalibrateMemoryGauge(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
// Old
|
|
return true;
|
|
}
|
|
|
|
bool ScriptGetParkEditorCursorPos(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
CParkEditor* p_editor = CParkEditor::Instance();
|
|
Mth::Vector pos=p_editor->GetCursorPos();
|
|
pScript->GetParams()->AddVector(CRCD(0x7f261953,"pos"),pos[X],pos[Y],pos[Z]);
|
|
return true;
|
|
}
|
|
|
|
bool ScriptSwitchToParkEditorCamera(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
// Create the park editor camera if it does not exist, then switch to it.
|
|
Obj::CCompositeObject * p_obj = (Obj::CCompositeObject *) Obj::CCompositeObjectManager::Instance()->GetObjectByID(CRCD(0x64716bee,"parked_cam"));
|
|
if (!p_obj)
|
|
{
|
|
Script::CStruct * p_cam_params = new Script::CStruct;
|
|
p_cam_params->AddChecksum("name",CRCD(0x64716bee,"parked_cam"));
|
|
|
|
Obj::CCompositeObjectManager::Instance()->CreateCompositeObjectFromNode(
|
|
Script::GetArray("parkedcam_composite_structure"),p_cam_params);
|
|
|
|
delete p_cam_params;
|
|
}
|
|
|
|
CParkEditor::Instance()->SetAppropriateCamera();
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
Parameters:
|
|
|
|
state
|
|
command
|
|
|
|
States:
|
|
-edit
|
|
Command:
|
|
-initialize
|
|
-clear whole park
|
|
-regenerate from compressed map
|
|
-build floor
|
|
-test_play
|
|
-off
|
|
|
|
Will
|
|
*/
|
|
bool ScriptSetParkEditorState(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
ParkEd("CCursor::ScriptSetParkEditorState()");
|
|
#if DEBUG_THIS_DAMN_THING
|
|
Script::PrintContents(pParams, 4);
|
|
#endif
|
|
|
|
CParkEditor* p_editor = CParkEditor::Instance();
|
|
|
|
CParkEditor::EEditorState new_state = CParkEditor::vKEEP_SAME_STATE;
|
|
pParams->GetChecksum("state", (uint32 *) &new_state);
|
|
Dbg_MsgAssert(new_state == CParkEditor::vEDITING ||
|
|
new_state == CParkEditor::vINACTIVE ||
|
|
new_state == CParkEditor::vREGULAR_PLAY ||
|
|
new_state == CParkEditor::vTEST_PLAY,
|
|
("invalid park editor state"));
|
|
|
|
CParkEditor::EEditorCommand command = CParkEditor::vNO_COMMAND;
|
|
pParams->GetChecksum("command", (uint32 *) &command);
|
|
Dbg_MsgAssert(command == CParkEditor::vINITIALIZE ||
|
|
command == CParkEditor::vCLEAR ||
|
|
command == CParkEditor::vREGENERATE_FROM_MAP ||
|
|
command == CParkEditor::vBUILD_FLOOR ||
|
|
command == CParkEditor::vNO_COMMAND,
|
|
("invalid park editor command"));
|
|
|
|
if (new_state == CParkEditor::vINACTIVE)
|
|
{
|
|
p_editor->SetState(new_state);
|
|
p_editor->Cleanup();
|
|
p_editor->SetPaused(false);
|
|
}
|
|
else
|
|
{
|
|
if (command == CParkEditor::vINITIALIZE)
|
|
{
|
|
p_editor->Initialize((new_state == CParkEditor::vEDITING));
|
|
}
|
|
else
|
|
{
|
|
if (command == CParkEditor::vCLEAR)
|
|
p_editor->Rebuild(false, true, (new_state == CParkEditor::vEDITING));
|
|
else if (command == CParkEditor::vREGENERATE_FROM_MAP)
|
|
p_editor->Rebuild(false, false, (new_state == CParkEditor::vEDITING));
|
|
else if (command == CParkEditor::vBUILD_FLOOR)
|
|
p_editor->Rebuild(true, false, (new_state == CParkEditor::vEDITING));
|
|
}
|
|
p_editor->SetState(new_state);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ScriptSetParkEditorPauseMode(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
ParkEd("CCursor::ScriptSetParkEditorPauseMode()");
|
|
#if DEBUG_THIS_DAMN_THING
|
|
Script::PrintContents(pParams, 4);
|
|
#endif
|
|
|
|
CParkEditor* p_editor = CParkEditor::Instance();
|
|
|
|
if (pParams->ContainsFlag("pause"))
|
|
p_editor->SetPaused(true);
|
|
else if (pParams->ContainsFlag("unpause"))
|
|
p_editor->SetPaused(false);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ScriptCustomParkMode(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
CParkEditor* p_editor = CParkEditor::Instance();
|
|
if (pParams->ContainsFlag("editing"))
|
|
{
|
|
return p_editor->EditingCustomPark();
|
|
}
|
|
else if (pParams->ContainsFlag("testing"))
|
|
{
|
|
return p_editor->TestingCustomPark();
|
|
}
|
|
else if (pParams->ContainsFlag("just_using"))
|
|
{
|
|
return p_editor->UsingCustomPark();
|
|
}
|
|
|
|
Dbg_MsgAssert(0, ("need a parameter -- 'editing' or 'just_using'"));
|
|
return false;
|
|
}
|
|
|
|
bool ScriptSetParkEditorMaxPlayers(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
int max_players=1;
|
|
pParams->GetInteger(NONAME,&max_players);
|
|
Dbg_MsgAssert(max_players>=1 && max_players<=8,("\n%s\nBad value of %d sent to SetParkEditorMaxPlayers",pScript->GetScriptInfo(),max_players));
|
|
|
|
CParkManager::Instance()->GetGenerator()->SetMaxPlayers(max_players);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ScriptGetParkEditorMaxPlayers(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
pScript->GetParams()->AddInteger("MaxPlayers",CParkManager::Instance()->GetGenerator()->GetMaxPlayers());
|
|
return true;
|
|
}
|
|
|
|
bool ScriptGetParkEditorMaxPlayersPossible(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
pScript->GetParams()->AddInteger("MaxPlayersPossible",CParkManager::Instance()->GetGenerator()->GetMaxPlayersPossible());
|
|
return true;
|
|
}
|
|
|
|
|
|
// a helper function used by ScriptCanCleanlyResizePark(), ScriptResizePark()
|
|
GridDims ComputeResizedDims(Script::CStruct *pParams)
|
|
{
|
|
// these are the current bounds, may be replaced with new info
|
|
GridDims new_bounds = CParkManager::sInstance()->GetParkNearBounds();
|
|
|
|
// assume current w,l unless new parms passed in
|
|
int w = new_bounds.GetW();
|
|
int l = new_bounds.GetL();
|
|
pParams->GetInteger("w", &w);
|
|
pParams->GetInteger("l", &l);
|
|
|
|
// these diffs may be replaced below
|
|
int w_diff = w - (int) new_bounds.GetW();
|
|
int l_diff = l - (int) new_bounds.GetL();
|
|
|
|
if (pParams->GetInteger("inc_w", &w_diff))
|
|
w = new_bounds.GetW() + w_diff;
|
|
if (pParams->GetInteger("inc_l", &l_diff))
|
|
l = new_bounds.GetL() + l_diff;
|
|
|
|
new_bounds[X] = new_bounds[X] - w_diff / 2;
|
|
new_bounds[Z] = new_bounds[Z] - l_diff / 2;
|
|
new_bounds[W] = w;
|
|
new_bounds[L] = l;
|
|
|
|
|
|
return new_bounds;
|
|
}
|
|
|
|
// Prevents rail points or goal peds being placed too close to the edge of the park.
|
|
bool IsWithinParkBoundaries(Mth::Vector pos, float margin)
|
|
{
|
|
GridDims park_bounds = CParkManager::sInstance()->GetParkNearBounds();
|
|
Mth::Vector corner_pos;
|
|
Mth::Vector area_dims;
|
|
corner_pos=Ed::CParkManager::Instance()->GridCoordinatesToWorld(park_bounds,&area_dims);
|
|
|
|
if (pos[X] > corner_pos[X]+margin && pos[X] < corner_pos[X]+area_dims[X]-margin &&
|
|
pos[Z] > corner_pos[Z]+margin && pos[Z] < corner_pos[Z]+area_dims[Z]-margin)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool ScriptCanCleanlyResizePark(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
GridDims new_bounds;
|
|
|
|
Script::CStruct *p_new_bounds=NULL;
|
|
if (pParams->GetStructure(CRCD(0xb4f88771,"NewBounds"),&p_new_bounds))
|
|
{
|
|
int x,z,w,l;
|
|
p_new_bounds->GetInteger(CRCD(0x7323e97c,"x"),&x);
|
|
p_new_bounds->GetInteger(CRCD(0x9d2d8850,"z"),&z);
|
|
p_new_bounds->GetInteger(CRCD(0xe39cf4ed,"w"),&w);
|
|
p_new_bounds->GetInteger(CRCD(0x69f93d01,"l"),&l);
|
|
new_bounds.SetXYZ(x,0,z);
|
|
new_bounds.SetWHL(w,1,l);
|
|
|
|
bool can_resize=true;
|
|
if (CParkManager::sInstance()->AreMetasOutsideBounds(new_bounds))
|
|
{
|
|
can_resize=false;
|
|
}
|
|
|
|
Mth::Vector corner_pos;
|
|
Mth::Vector area_dims;
|
|
corner_pos=Ed::CParkManager::Instance()->GridCoordinatesToWorld(new_bounds,&area_dims);
|
|
if (Obj::GetRailEditor()->ThereAreRailPointsOutsideArea(corner_pos[X]+PARK_BOUNDARY_MARGIN,
|
|
corner_pos[Z]+PARK_BOUNDARY_MARGIN,
|
|
corner_pos[X]+area_dims[X]-PARK_BOUNDARY_MARGIN,
|
|
corner_pos[Z]+area_dims[Z]-PARK_BOUNDARY_MARGIN))
|
|
{
|
|
can_resize=false;
|
|
}
|
|
|
|
if (Obj::GetGoalEditor()->ThereAreGoalsOutsideArea(corner_pos[X], corner_pos[Z], corner_pos[X]+area_dims[X], corner_pos[Z]+area_dims[Z]))
|
|
{
|
|
can_resize=false;
|
|
}
|
|
|
|
return can_resize;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
void ResizePark(GridDims newBounds)
|
|
{
|
|
CParkManager::sInstance()->RebuildInnerShell(newBounds);
|
|
CParkManager::sInstance()->RebuildFloor();
|
|
|
|
Mth::Vector corner_pos;
|
|
Mth::Vector area_dims;
|
|
corner_pos=Ed::CParkManager::Instance()->GridCoordinatesToWorld(newBounds,&area_dims);
|
|
Obj::GetRailEditor()->ClipRails(corner_pos[X]+PARK_BOUNDARY_MARGIN, corner_pos[Z]+PARK_BOUNDARY_MARGIN,
|
|
corner_pos[X]+area_dims[X]-PARK_BOUNDARY_MARGIN, corner_pos[Z]+area_dims[Z]-PARK_BOUNDARY_MARGIN,
|
|
Obj::CRailEditorComponent::DELETE_POINTS_OUTSIDE);
|
|
Obj::GetGoalEditor()->DeleteGoalsOutsideArea(corner_pos[X], corner_pos[Z], corner_pos[X]+area_dims[X], corner_pos[Z]+area_dims[Z]);
|
|
|
|
CParkEditor::Instance()->DestroyClipboardsWhichAreTooBigToFit();
|
|
}
|
|
|
|
bool ScriptResizePark(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
static GridDims stored_dims;
|
|
|
|
GridDims new_bounds;
|
|
|
|
Script::CStruct *p_new_bounds=NULL;
|
|
if (pParams->GetStructure(CRCD(0xb4f88771,"NewBounds"),&p_new_bounds))
|
|
{
|
|
int x,z,w,l;
|
|
p_new_bounds->GetInteger(CRCD(0x7323e97c,"x"),&x);
|
|
p_new_bounds->GetInteger(CRCD(0x9d2d8850,"z"),&z);
|
|
p_new_bounds->GetInteger(CRCD(0xe39cf4ed,"w"),&w);
|
|
p_new_bounds->GetInteger(CRCD(0x69f93d01,"l"),&l);
|
|
new_bounds.SetXYZ(x,0,z);
|
|
new_bounds.SetWHL(w,1,l);
|
|
}
|
|
else
|
|
{
|
|
new_bounds = ComputeResizedDims(pParams);
|
|
}
|
|
|
|
|
|
if (pParams->ContainsFlag("delayed"))
|
|
{
|
|
stored_dims = new_bounds;
|
|
}
|
|
else
|
|
{
|
|
if (pParams->ContainsFlag("use_stored"))
|
|
{
|
|
new_bounds = stored_dims;
|
|
}
|
|
if (!CParkManager::sInstance()->EnoughMemoryToResize(new_bounds))
|
|
{
|
|
Script::RunScript("parked_show_out_of_memory_message");
|
|
return false;
|
|
}
|
|
|
|
ResizePark(new_bounds);
|
|
// Refresh the rail geometry so that UpdateSuperSectors gets called on them.
|
|
//Obj::GetRailEditor()->RefreshGeometry();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool ScriptGetCurrentParkBounds(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
GridDims bounds = CParkManager::sInstance()->GetParkNearBounds();
|
|
pScript->GetParams()->AddInteger(CRCD(0x7323e97c,"x"),bounds.GetX());
|
|
pScript->GetParams()->AddInteger(CRCD(0x9d2d8850,"z"),bounds.GetZ());
|
|
pScript->GetParams()->AddInteger(CRCD(0xe39cf4ed,"w"),bounds.GetW());
|
|
pScript->GetParams()->AddInteger(CRCD(0x69f93d01,"l"),bounds.GetL());
|
|
return true;
|
|
}
|
|
|
|
bool ScriptCanChangeParkDimension(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
GridDims current_bounds = CParkManager::sInstance()->GetParkNearBounds();
|
|
GridDims max_bounds = CParkManager::sInstance()->GetParkFarBounds();
|
|
|
|
Script::CArray *p_dim_array = NULL;
|
|
if (pParams->GetArray(NONAME, &p_dim_array))
|
|
{
|
|
int w = p_dim_array->GetInt(0);
|
|
int l = p_dim_array->GetInt(1);
|
|
if (w != current_bounds.GetW() || l != current_bounds.GetL())
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// otherwise, decrease
|
|
bool test_for_increase = pParams->ContainsFlag("up");
|
|
|
|
if (pParams->ContainsFlag("width"))
|
|
{
|
|
if (test_for_increase && current_bounds.GetW() < max_bounds.GetW()) return true;
|
|
else if (!test_for_increase && current_bounds.GetW() > 16) return true;
|
|
}
|
|
else
|
|
{
|
|
if (test_for_increase && current_bounds.GetL() < max_bounds.GetL()) return true;
|
|
else if (!test_for_increase && current_bounds.GetL() > 16) return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ScriptSaveParkToDisk(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
int slot = 0;
|
|
pParams->GetInteger("slot", &slot, Script::ASSERT);
|
|
// XXX
|
|
Ryan("saving park at slot %d\n", slot);
|
|
CParkEditor* p_editor = CParkEditor::Instance();
|
|
p_editor->AccessDisk(true, slot, false);
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ScriptLoadParkFromDisk(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
int slot = 0;
|
|
pParams->GetInteger("slot", &slot, Script::ASSERT);
|
|
|
|
bool block_rebuild = pParams->ContainsFlag("block_rebuild");
|
|
|
|
// XXX
|
|
Ryan("loading park in slot %d\n", slot);
|
|
CParkEditor* p_editor = CParkEditor::Instance();
|
|
p_editor->AccessDisk(false, slot, block_rebuild);
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ScriptIsParkUnsaved(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
return !CParkManager::sInstance()->IsMapSavedLocally();
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ScriptFireCustomParkGap(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
int gap_index;
|
|
pParams->GetInteger("gap_index", &gap_index, true);
|
|
|
|
// XXX
|
|
Ryan("ScriptFireCustomParkGap() %d\n", gap_index);
|
|
|
|
CGapManager::sInstance()->LaunchGap(gap_index, pScript);
|
|
return true;
|
|
}
|
|
|
|
bool ScriptSetEditedParkGapInfo(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
const char *p_name = NULL;
|
|
pParams->GetString("name", &p_name);
|
|
int score = -1;
|
|
pParams->GetInteger("score", &score);
|
|
|
|
CCursor::sInstance()->SetGapNameAndScore(p_name, score);
|
|
|
|
Script::CStruct *p_cancel_flags=NULL;
|
|
pParams->GetStructure(CRCD(0x49ec3f9,"cancel_flags"),&p_cancel_flags);
|
|
CCursor::sInstance()->SetGapCancelFlags(p_cancel_flags);
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ScriptGetEditedParkGapName(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
pScript->GetParams()->AddString("name", CCursor::sInstance()->GetGapName());
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ScriptParkEditorSelectionAreaTooBigToCopy(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
return CCursor::sInstance()->SelectionAreaTooBigToCopy();
|
|
}
|
|
|
|
bool ScriptCopyParkEditorSelectionToClipboard(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
bool success=CCursor::sInstance()->CopySelectionToClipboard();
|
|
CCursor::sInstance()->ClearAreaSelection();
|
|
return success;
|
|
}
|
|
|
|
bool ScriptSwitchParkEditorMenuPieceToMostRecentClipboard(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
CParkEditor::Instance()->SwitchMenuPieceToMostRecentClipboard();
|
|
return true;
|
|
}
|
|
|
|
bool ScriptCutParkEditorAreaSelection(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
bool success=CCursor::sInstance()->CopySelectionToClipboard();
|
|
if (success)
|
|
{
|
|
CCursor::sInstance()->DeleteSelectedPieces();
|
|
CCursor::sInstance()->ResetSelectedHeights();
|
|
}
|
|
CCursor::sInstance()->ClearAreaSelection();
|
|
return success;
|
|
}
|
|
|
|
bool ScriptParkEditorAreaSelectionDeletePieces(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
CCursor::sInstance()->DeleteSelectedPieces();
|
|
return true;
|
|
}
|
|
|
|
bool ScriptContinueParkEditorAreaSelection(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
CCursor::sInstance()->ContinueAreaSelection();
|
|
return true;
|
|
}
|
|
|
|
bool ScriptGetEditorTheme(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
pScript->GetParams()->AddInteger(CRCD(0x688a18f7,"theme"), CParkManager::sInstance()->GetTheme());
|
|
return true;
|
|
}
|
|
|
|
bool ScriptSetEditorTheme(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
int theme=0;
|
|
pParams->GetInteger(CRCD(0x688a18f7,"theme"),&theme);
|
|
CParkManager::sInstance()->SetTheme(theme);
|
|
return true;
|
|
}
|
|
|
|
bool ScriptGetEditorMaxThemes(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
pScript->GetParams()->AddInteger(CRCD(0x7ddc0da8,"max_themes"), MAX_THEMES);
|
|
return true;
|
|
}
|
|
|
|
bool ScriptGetCustomParkName(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
int truncate_char_num = -1;
|
|
pParams->GetInteger(NONAME, &truncate_char_num);
|
|
|
|
const char *p_name = CParkManager::sInstance()->GetParkName();
|
|
|
|
if (truncate_char_num == -1)
|
|
{
|
|
if (p_name)
|
|
pScript->GetParams()->AddString("name", p_name);
|
|
else
|
|
pScript->GetParams()->AddString("name", "unnamed park");
|
|
}
|
|
else
|
|
{
|
|
char out_name[64];
|
|
for (int i = 0; i < truncate_char_num; i++)
|
|
out_name[i] = p_name[i];
|
|
out_name[truncate_char_num] = '\0';
|
|
pScript->GetParams()->AddString("name", out_name);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ScriptSetCustomParkName(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
const char *p_name = NULL;
|
|
pParams->GetString("name", &p_name, Script::ASSERT);
|
|
CParkManager::sInstance()->SetParkName(p_name);
|
|
return true;
|
|
}
|
|
|
|
|
|
// @script | IsCustomPark | returns true if this is a custom park
|
|
bool ScriptIsCustomPark(Script::CScriptStructure *pParams, Script::CScript *pScript)
|
|
{
|
|
return Ed::CParkEditor::Instance()->UsingCustomPark();
|
|
}
|
|
|
|
|
|
|
|
bool ScriptBindParkEditorToController( Script::CStruct* pParams, Script::CScript* pScript )
|
|
{
|
|
int controller;
|
|
pParams->GetInteger( NONAME, &controller, Script::ASSERT );
|
|
CParkEditor* p_editor = CParkEditor::Instance();
|
|
p_editor->BindParkEditorToController( controller );
|
|
return true;
|
|
}
|
|
|
|
#ifdef __PLAT_NGC__
|
|
// Required in order that the park rebuild when defragmenting during resizing does not
|
|
// reset the map heights.
|
|
// (Used in the script parked_defragment_memory_for_resize in sk5ed_scripts)
|
|
bool ScriptWriteCompressedMapBuffer(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
CParkManager::sInstance()->WriteCompressedMapBuffer();
|
|
return true;
|
|
}
|
|
|
|
bool ScriptRequiresDefragment(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
Mem::Heap *p_top_down_heap = Mem::Manager::sHandle().TopDownHeap();
|
|
if (p_top_down_heap->mp_region->MemAvailable() < TOP_DOWN_REQUIRED_MARGIN)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
Mem::Heap *p_main_heap = Mem::Manager::sHandle().BottomUpHeap();
|
|
if (p_main_heap->mFreeMem.m_count > 200000)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ScriptTopDownHeapTooLow(Script::CStruct *pParams, Script::CScript *pScript)
|
|
{
|
|
Mem::Heap *p_top_down_heap = Mem::Manager::sHandle().TopDownHeap();
|
|
if (p_top_down_heap->mp_region->MemAvailable() < TOP_DOWN_REQUIRED_MARGIN)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
}
|