#include "mxcontrolpresenter.h" #include "define.h" #include "legocontrolmanager.h" #include "mxdsmultiaction.h" #include "mxmisc.h" #include "mxstillpresenter.h" #include "mxticklemanager.h" #include "mxtimer.h" #include "mxutilities.h" #include #include #include DECOMP_SIZE_ASSERT(MxControlPresenter, 0x5c) // FUNCTION: LEGO1 0x10043f50 MxControlPresenter::MxControlPresenter() { m_style = e_none; m_enabledChild = -1; m_unk0x50 = FALSE; m_columnsOrRows = 0; m_states = NULL; m_rowsOrColumns = 0; } // FUNCTION: LEGO1 0x10044110 MxControlPresenter::~MxControlPresenter() { if (m_states) { delete[] m_states; } } // FUNCTION: LEGO1 0x10044180 MxResult MxControlPresenter::AddToManager() { m_enabledChild = 0; return SUCCESS; } // FUNCTION: LEGO1 0x10044190 MxResult MxControlPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) { MxResult result = MxCompositePresenter::StartAction(p_controller, p_action); ApplyMask(m_action, MxDSAction::c_world | MxDSAction::c_looping, TRUE); ParseExtra(); MxS16 i = 0; for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { (*it)->Enable((m_style != e_map || m_enabledChild) && IsEnabled() ? m_enabledChild == i : FALSE); i++; } if (m_style == e_map) { MxDSAction* action = (*m_list.begin())->GetAction(); action->SetFlags(action->GetFlags() | MxDSAction::c_bit11); } TickleManager()->RegisterClient(this, 200); return result; } // FUNCTION: LEGO1 0x10044260 void MxControlPresenter::EndAction() { if (m_action) { m_unk0x50 = TRUE; MxCompositePresenter::EndAction(); } } // FUNCTION: LEGO1 0x10044270 // FUNCTION: BETA10 0x100eae68 MxBool MxControlPresenter::CheckButtonDown(MxS32 p_x, MxS32 p_y, MxPresenter* p_presenter) { assert(p_presenter); //MxVideoPresenter* presenter = dynamic_cast(p_presenter); MxVideoPresenter* presenter = (MxVideoPresenter*)(p_presenter); assert(presenter); if (m_style == e_map) { MxStillPresenter* map = (MxStillPresenter*) m_list.front(); assert(map && map->IsA("MxStillPresenter")); if (presenter == map || map->GetDisplayZ() < presenter->GetDisplayZ()) { if (map->HasFrameBitmapOrAlpha()) { MxRect32 rect(0, 0, map->GetWidth() - 1, map->GetHeight() - 1); rect += map->GetLocation(); if (rect.GetLeft() <= p_x && p_x < rect.GetRight() && rect.GetTop() <= p_y && p_y < rect.GetBottom()) { // DECOMP: Beta uses GetBitmapStart() here, but that causes more diffs for retail. MxU8* start = map->GetAlphaMask() ? NULL : map->GetBitmap()->GetStart(p_x - rect.GetLeft(), p_y - rect.GetTop()); m_stateOrCellIndex = 0; if (m_states) { for (MxS16 i = 1; i <= *m_states; i++) { // TODO: Can we match without the cast here? if (m_states[i] == (MxS16) *start) { m_stateOrCellIndex = i; break; } } } else { if (*start != 0) { m_stateOrCellIndex = 1; } } if (m_stateOrCellIndex) { return TRUE; } } } } } else { if (ContainsPresenter(m_list, presenter)) { if (m_style == e_grid) { MxS32 width = presenter->GetWidth(); MxS32 height = presenter->GetHeight(); if (m_columnsOrRows == 2 && m_rowsOrColumns == 2) { if (p_x < presenter->GetX() + width / 2) { m_stateOrCellIndex = (p_y >= presenter->GetY() + height / 2) ? 3 : 1; } else { m_stateOrCellIndex = (p_y >= presenter->GetY() + height / 2) ? 4 : 2; } } } else { m_stateOrCellIndex = -1; } return TRUE; } } return FALSE; } // FUNCTION: LEGO1 0x10044480 MxBool MxControlPresenter::Notify(LegoControlManagerNotificationParam* p_param, MxPresenter* p_presenter) { if (IsEnabled()) { switch (p_param->GetNotification()) { case c_notificationButtonUp: if (m_style == e_none || m_style == e_grid || m_style == e_map) { p_param->SetClickedObjectId(m_action->GetObjectId()); p_param->SetClickedAtom(m_action->GetAtomId().GetInternal()); UpdateEnabledChild(0); p_param->SetNotification(c_notificationControl); p_param->SetEnabledChild(m_enabledChild); return TRUE; } break; case c_notificationButtonDown: if (CheckButtonDown(p_param->GetX(), p_param->GetY(), p_presenter)) { p_param->SetClickedObjectId(m_action->GetObjectId()); p_param->SetClickedAtom(m_action->GetAtomId().GetInternal()); UpdateEnabledChild(m_stateOrCellIndex); p_param->SetNotification(c_notificationControl); p_param->SetEnabledChild(m_enabledChild); return TRUE; } break; } } return FALSE; } // FUNCTION: LEGO1 0x10044540 void MxControlPresenter::UpdateEnabledChild(MxS16 p_enabledChild) { if (p_enabledChild == -1) { if ((MxS16) ((MxDSMultiAction*) m_action)->GetActionList()->GetNumElements() - m_enabledChild == 1) { m_enabledChild = 0; } else { m_enabledChild++; } } else { m_enabledChild = p_enabledChild; } m_action->SetTimeStarted(Timer()->GetTime()); MxS16 i = 0; for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { (*it)->Enable(((m_style == e_map && m_enabledChild == 0) || !IsEnabled()) ? FALSE : m_enabledChild == i); i++; } } // FUNCTION: LEGO1 0x10044610 void MxControlPresenter::ReadyTickle() { MxPresenter::ParseExtra(); TickleManager()->UnregisterClient(this); ProgressTickleState(e_repeating); } // FUNCTION: LEGO1 0x10044640 // FUNCTION: BETA10 0x100eb5e3 void MxControlPresenter::ParseExtra() { MxU16 extraLength; char* extraData; m_action->GetExtra(extraLength, extraData); if (extraLength) { char extraCopy[256]; memcpy(extraCopy, extraData, extraLength); extraCopy[extraLength] = '\0'; char output[256]; if (KeyValueStringParse(output, g_strSTYLE, extraCopy)) { char* token = strtok(output, g_parseExtraTokens); if (!SDL_strcasecmp(token, g_strTOGGLE)) { m_style = e_toggle; } else if (!SDL_strcasecmp(token, g_strGRID)) { m_style = e_grid; token = strtok(NULL, g_parseExtraTokens); assert(token); m_columnsOrRows = atoi(token); token = strtok(NULL, g_parseExtraTokens); assert(token); m_rowsOrColumns = atoi(token); } else if (!SDL_strcasecmp(token, g_strMAP)) { m_style = e_map; token = strtok(NULL, g_parseExtraTokens); if (token) { MxS16 numStates = atoi(token); m_states = new MxS16[numStates + 1]; assert(numStates); *m_states = numStates; for (MxS16 i = 1; i <= numStates; i++) { token = strtok(NULL, g_parseExtraTokens); assert(token); m_states[i] = atoi(token); } } } else { m_style = e_none; } } if (KeyValueStringParse(output, g_strVISIBILITY, extraCopy)) { if (!SDL_strcasecmp(output, "FALSE")) { Enable(FALSE); } } } } // FUNCTION: LEGO1 0x10044820 void MxControlPresenter::Enable(MxBool p_enable) { if (MxPresenter::IsEnabled() != p_enable) { MxPresenter::Enable(p_enable); MxS16 i = 0; for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { if (i == m_enabledChild) { (*it)->Enable((m_style != e_map || i != 0) ? p_enable : 0); break; } i++; } if (!p_enable) { m_enabledChild = 0; } } } // FUNCTION: LEGO1 0x100448a0 MxBool MxControlPresenter::HasTickleStatePassed(TickleState p_tickleState) { MxCompositePresenterList::const_iterator it = m_list.begin(); #ifdef COMPAT_MODE advance(it, m_enabledChild); #else // Uses forward iterator logic instead of bidrectional for some reason. _Advance(it, m_enabledChild, forward_iterator_tag()); #endif return (*it)->HasTickleStatePassed(p_tickleState); }