/* * pawsskillwindow.cpp * * Copyright (C) 2003 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation (version 2 of the License) * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include "globals.h" #include "pscelclient.h" #include "clientvitals.h" #include "net/messages.h" #include "net/msghandler.h" #include "util/skillcache.h" #include "util/strutil.h" #include "util/psxmlparser.h" // PAWS INCLUDES #include "pawsskillwindow.h" #include "pawschardescription.h" #include "paws/pawstextbox.h" #include "paws/pawslistbox.h" #include "paws/pawsmanager.h" #include "paws/pawsobjectview.h" #include "paws/pawsprogressbar.h" #include "gui/pawscontrolwindow.h" #define BTN_BUY 100 #define BTN_FILTER 101 //#define BTN_QUIT 102 #define BTN_EDIT 102 //Edit description #define BTN_STATS 1000 //Stats button for the tab panel #define BTN_COMBAT 1001 //Combat button for the tab panel #define BTN_MAGIC 1002 //Magic button for the tab panel #define BTN_JOBS 1003 //Jobs button for the tab panel #define BTN_VARIOUS 1004 //Various button for the tab panel #define MAX_CAT 4 ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// pawsSkillWindow::pawsSkillWindow() { selectedSkill.Clear(); skillString.Clear(); skillDescriptions.DeleteAll(); filter = false; hitpointsMax = 0; manaMax = 0; physStaminaMax = 0; menStaminaMax = 0; } pawsSkillWindow::~pawsSkillWindow() { // Delete cached skill description strings csHash::GlobalIterator i = skillDescriptions.GetIterator(); while (i.HasNext()) { delete i.Next(); } skillDescriptions.DeleteAll(); } bool pawsSkillWindow::PostSetup() { msgHandler = psengine->GetMsgHandler(); if ( !msgHandler ) return false; // Setup the Doll if ( !SetupDoll() ) return false; msgHandler = psengine->GetMsgHandler(); if ( !msgHandler->Subscribe( this, MSGTYPE_GUISKILL ) ) return false; xml = CS_QUERY_REGISTRY( PawsManager::GetSingleton().GetObjectRegistry(), iDocumentSystem ); statsSkillList = (pawsListBox*)FindWidget("StatsSkillList"); statsSkillDescription = (pawsMultiLineTextBox*)FindWidget("StatsDescription"); combatSkillList = (pawsListBox*)FindWidget("CombatSkillList"); combatSkillDescription = (pawsMultiLineTextBox*)FindWidget("CombatDescription"); magicSkillList = (pawsListBox*)FindWidget("MagicSkillList"); magicSkillDescription = (pawsMultiLineTextBox*)FindWidget("MagicDescription"); jobsSkillList = (pawsListBox*)FindWidget("JobsSkillList"); jobsSkillDescription = (pawsMultiLineTextBox*)FindWidget("JobsDescription"); variousSkillList = (pawsListBox*)FindWidget("VariousSkillList"); variousSkillDescription = (pawsMultiLineTextBox*)FindWidget("VariousDescription"); hpBar = dynamic_cast (FindWidget("HPBar")); manaBar = dynamic_cast (FindWidget("ManaBar")); pysStaminaBar = dynamic_cast (FindWidget("PysStaminaBar")); menStaminaBar = dynamic_cast (FindWidget("MenStaminaBar")); experienceBar = dynamic_cast (FindWidget("ExperienceBar")); // Shaded text displaying the players current Duel Points pawsTextBox* dpLabel = dynamic_cast (FindWidget("DPLabel")); dpTotal = dynamic_cast (FindWidget("DPTotal")); hpFrac = dynamic_cast (FindWidget("HPFrac")); manaFrac = dynamic_cast (FindWidget("ManaFrac")); pysStaminaFrac = dynamic_cast (FindWidget("PysStaminaFrac")); menStaminaFrac = dynamic_cast (FindWidget("MenStaminaFrac")); experiencePerc = dynamic_cast (FindWidget("ExperiencePerc")); if ( !statsSkillList || !statsSkillDescription || !combatSkillList || !combatSkillDescription || !magicSkillList || !magicSkillDescription || !jobsSkillList || !jobsSkillDescription || !variousSkillList || !variousSkillDescription || !hpBar || !manaBar || !pysStaminaBar || !menStaminaBar || !experienceBar || !hpFrac || !manaFrac || !pysStaminaFrac || !menStaminaFrac || !experiencePerc || !dpLabel || !dpTotal ) { return false; } hpBar->SetTotalValue(1); manaBar->SetTotalValue(1); pysStaminaBar->SetTotalValue(1); menStaminaBar->SetTotalValue(1); experienceBar->SetTotalValue(1); currentTab =0; previousTab =0; return true; } bool pawsSkillWindow::SetupDoll() { pawsObjectView* widget = dynamic_cast(FindWidget("Doll")); GEMClientActor* actor = psengine->GetCelClient()->GetMainPlayer(); if (!widget || !actor) return false; csRef mesh = actor->pcmesh; if (!mesh) return false; // Set the doll view widget->View( mesh->GetMesh() ); // Register this doll for updates widget->SetID( actor->GetEntity()->GetID() ); csRef spstate = SCF_QUERY_INTERFACE(widget->GetObject()->GetMeshObject(),iSpriteCal3DState); if (spstate) { // Setup cal3d to select random 0 velocity anims spstate->SetVelocity(0.0,&psengine->GetRandomGen()); } // Build doll appearance and equipment bool a = psengine->BuildAppearance( widget->GetObject(), actor->traits ); csPDelArray dummy; bool e = psengine->BuildEquipment( widget->GetObject(), actor->equipment, dummy ); widget->EnableMouseControl(true); return (a && e); } void pawsSkillWindow::HandleMessage( MsgEntry* me ) { psGUISkillMessage incoming(me); switch (incoming.command) { case psGUISkillMessage::SKILL_LIST: { skillString = "no"; if ( !IsVisible() && incoming.openWindow == true ) Show(); skillString = incoming.commandData; skillCache.apply(&incoming.skillCache); train=incoming.trainingWindow; int selectedRowIdx = -1; HandleSkillList(&skillCache, incoming.focusSkill, &selectedRowIdx); SelectSkill(selectedRowIdx, incoming.skillCat); dpTotal->FormatText( "%1.2f", incoming.dpTotal ); hitpointsMax = incoming.hitpointsMax; manaMax = incoming.manaMax; physStaminaMax = incoming.physStaminaMax; menStaminaMax = incoming.menStaminaMax; break; } case psGUISkillMessage::DESCRIPTION: { HandleSkillDescription(incoming.commandData); break; } } } void pawsSkillWindow::Close() { Hide(); combatSkillList->Clear(); statsSkillList->Clear(); magicSkillList->Clear(); jobsSkillList->Clear(); variousSkillList->Clear(); skillString.Clear(); selectedSkill.Clear(); } bool pawsSkillWindow::OnButtonPressed( int mouseButton, int keyModifier, pawsWidget* widget ) { switch ( widget->GetID() ) { case BTN_FILTER: { filter = !filter; HandleSkillList(&skillCache); return true; } case BTN_BUY: { BuySkill(); return true; } case BTN_EDIT: { pawsCharDescription* descWnd = (pawsCharDescription*)PawsManager::GetSingleton().FindWidget("DescriptionEdit"); descWnd->PostSetup(); descWnd->Show(); return true; } case BTN_STATS: case BTN_COMBAT: case BTN_MAGIC: case BTN_JOBS: case BTN_VARIOUS: { previousTab = currentTab; //Keep the selection if we are hitting the same tab where we are. currentTab = widget->GetID() - 1000; if (previousTab != currentTab) selectedSkill.Clear(); break; } } return false; } void pawsSkillWindow::SelectSkill(int skill, int cat) { if(skill < 0 || skill > (int)unsortedSkills.Length()|| cat< 0 || cat > MAX_CAT) return; //Let's see which category the skill belongs to switch(cat) { case 0: //Stats { statsSkillList->Select(unsortedSkills[skill]); break; } case 1: //Combat skills { combatSkillList->Select(unsortedSkills[skill]); break; } case 2: //Magic Skills { magicSkillList->Select(unsortedSkills[skill]); break; } case 3://Jobs Skills { jobsSkillList->Select(unsortedSkills[skill]); break; } case 4://Various Skills { variousSkillList->Select(unsortedSkills[skill]); break; } } } void pawsSkillWindow::HandleSkillList(psSkillCache *skills, int selectedNameId, int *rowIdx) { combatSkillList->Clear();//Clear everything each time we filter out. statsSkillList->Clear(); magicSkillList->Clear(); jobsSkillList->Clear(); variousSkillList->Clear(); selectedSkill.Clear(); // Clear descriptions statsSkillDescription->SetText(""); combatSkillDescription->SetText(""); magicSkillDescription->SetText(""); jobsSkillDescription->SetText(""); variousSkillDescription->SetText(""); unsortedSkills.DeleteAll(); x = skills->getProgressionPoints(); foundSelected = false; int idx = 0; // Row index counter psSkillCacheIter p = skills->iterBegin(); while (p.HasNext()) { psSkillCacheItem *skill = p.Next(); if (rowIdx && (int)skill->getNameId() == selectedNameId) *rowIdx = idx; // Row index of the selected skill ++idx; switch (skill->getCategory()) { case 0://Stats { HandleSkillCategory(statsSkillList, "StatsIndicator", "Stats Button", skill); break; } case 1://Combat skills { HandleSkillCategory(combatSkillList, "CombatIndicator", "Combat Button", skill); break; } case 2://Magic skills { HandleSkillCategory(magicSkillList, "MagicIndicator", "Magic Button", skill); break; } case 3://Jobs skills { HandleSkillCategory(jobsSkillList, "JobsIndicator", "Jobs Button", skill); break; } case 4://Various skills { HandleSkillCategory(variousSkillList, "VariousIndicator", "Various Button", skill); break; } } /* if(stat) { combatSkillList->MoveRow(combatSkillList->GetRowCount()-1,stati); stati++; }*/ } if (!foundSelected) { selectedSkill.Clear(); } } void pawsSkillWindow::HandleSkillDescription( csString& description ) { /* Example message: */ csRef descDoc = xml->CreateDocument(); const char* error = descDoc->Parse( description ); if ( error ) { Error2( "Error Parsing Skill Description: %s\n", error ); return; } csRef root = descDoc->GetRoot(); if (!root) { Error1("No XML root in Skill Description"); return; } csRef desc = root->GetNode("DESCRIPTION"); if(!desc) { Error1("No tag in Skill Description"); return; } const char *nameStr = ""; nameStr = desc->GetAttributeValue("NAME"); const char* descStr = ""; descStr = desc->GetAttributeValue("DESC"); if((!descStr) || (!strcmp(descStr,""))|| (!strcmp(descStr,"(null)"))) descStr = "No description available"; int skillCategory = desc->GetAttributeValueAsInt("CAT"); // Add to the cache if (nameStr && strcmp(nameStr, "") && strcmp(nameStr, "(null)")) { csStringID skillNameId = (csStringID)psengine->FindCommonStringId(nameStr); if (skillNameId != csInvalidStringID) { if (skillDescriptions.Contains(skillNameId)) { psSkillDescription *p = skillDescriptions.Get(skillNameId, NULL); if (p) p->update(skillCategory, descStr); } else { psSkillDescription *item = new psSkillDescription(skillCategory, descStr); skillDescriptions.Put(skillNameId, item); } } } switch (skillCategory) { case 0://Stats { statsSkillDescription->SetText(descStr); break; } case 1://Combat skills { combatSkillDescription->SetText( descStr ); break; } case 2://Magic skills { magicSkillDescription->SetText(descStr); break; } case 3://Jobs skills { jobsSkillDescription->SetText(descStr); break; } case 4://Various skills { variousSkillDescription->SetText(descStr); break; } } } void pawsSkillWindow::BuySkill() { char commandData[256]; csString escpxml = ""; escpxml = EscpXML(selectedSkill); if (escpxml== "") { csString warning="You have to select a skill before."; PawsManager::GetSingleton().CreateWarningBox(warning); return; } sprintf( commandData, "", escpxml.GetData() ); psGUISkillMessage outgoing( psGUISkillMessage::BUY_SKILL, commandData); msgHandler->SendMessage( outgoing.msg ); } void pawsSkillWindow::Show() { pawsControlledWindow::Show(); // Hack set to no when show called because of an incoming skill table. if (skillString != "no") { skillCache.clear(); // Clear the skill cache before the new request psGUISkillMessage outgoing(psGUISkillMessage::REQUEST, ""); msgHandler->SendMessage(outgoing.msg); } } void pawsSkillWindow::Hide() { if (msgHandler) { psGUISkillMessage outgoing(psGUISkillMessage::QUIT, ""); msgHandler->SendMessage(outgoing.msg); } skillCache.clear(); pawsControlledWindow::Hide(); } void pawsSkillWindow::OnListAction( pawsListBox* widget, int status ) { if (status==LISTBOX_HIGHLIGHTED) { pawsListBoxRow* row = widget->GetSelectedRow(); pawsTextBox* skillName = (pawsTextBox*)(row->GetColumn(0)); selectedSkill.Replace( skillName->GetText() ); // Try to find cached copy of the description string */ csStringID skillNameId = (csStringID)psengine->FindCommonStringId(selectedSkill); psSkillDescription *desc = NULL; if (skillNameId != csInvalidStringID) desc = skillDescriptions.Get(skillNameId, NULL); if (!desc) { // Request from the server char commandData[256]; csString escpxml = EscpXML(selectedSkill); sprintf( commandData, "", escpxml.GetData() ); psGUISkillMessage outgoing( psGUISkillMessage::SKILL_SELECTED, commandData); msgHandler->SendMessage( outgoing.msg ); } else { // Use the cached version switch (desc->getCategory()) { case 0://Stats { statsSkillDescription->SetText(desc->getDescription()); break; } case 1://Combat skills { combatSkillDescription->SetText(desc->getDescription()); break; } case 2://Magic skills { magicSkillDescription->SetText(desc->getDescription()); break; } case 3://Jobs skills { jobsSkillDescription->SetText(desc->getDescription()); break; } case 4://Various skills { variousSkillDescription->SetText(desc->getDescription()); break; } } } } } void pawsSkillWindow::Draw() { static psClientVitals* vitals = NULL; if ( !vitals && psengine->GetCelClient() && psengine->GetCelClient()->GetMainPlayer() ) vitals = psengine->GetCelClient()->GetMainPlayer()->GetVitalMgr(); if (vitals) { static char buff[12]; sprintf(buff,"%1.0f/%i", vitals->GetHP()*hitpointsMax, hitpointsMax ); hpFrac->SetText(buff); sprintf(buff,"%1.0f/%i", vitals->GetMana()*manaMax, manaMax ); manaFrac->SetText(buff); sprintf(buff,"%1.0f/%i", vitals->GetStamina(true)*physStaminaMax, physStaminaMax ); pysStaminaFrac->SetText(buff); sprintf(buff,"%1.0f/%i", vitals->GetStamina(false)*menStaminaMax, menStaminaMax ); menStaminaFrac->SetText(buff); } pawsWidget::Draw(); } void pawsSkillWindow::FlashTabButton(const char* buttonName) { if (buttonName != NULL && FindWidget(buttonName)) ((pawsButton *) FindWidget(buttonName))->Flash(true); } void pawsSkillWindow::HandleSkillCategory(pawsListBox* tabNameSkillList, const char* indWidget, const char* tabName, psSkillCacheItem *skillInfo) { int R = skillInfo->getRank(); int Y = skillInfo->getKnowledge(); int Z = skillInfo->getPractice(); bool stat = skillInfo->isStat(); // filter out untrained skills if (filter && R==0 && Y==0 && Z==0) return; // Get the skill name string from common strings csString skillName = psengine->FindCommonString(skillInfo->getNameId()); if (skillName == "") { Error2("Invalid skill name with Id %d", skillInfo->getNameId()); return; } pawsListBoxRow* row = tabNameSkillList->NewRow(); pawsTextBox* name = dynamic_cast (row->GetColumn(0)); if (name == NULL) return; name->SetText( skillName ); pawsTextBox* rank = dynamic_cast (row->GetColumn(1)); if (rank == NULL) return; if (stat) rank->FormatText("%i(%i)", skillInfo->getRank(), skillInfo->getActualStat()); else rank->FormatText("%i", skillInfo->getRank()); pawsWidget * indCol = row->GetColumn(2); if (indCol == NULL) return; pawsSkillIndicator * indicator = dynamic_cast (indCol->FindWidget(indWidget)); if (indicator == NULL) return; indicator->Set(x, R, Y, skillInfo->getKnowledgeCost(), Z, skillInfo->getPracticeCost()); unsortedSkills.Push(row); if (skillName == selectedSkill) { statsSkillList->Select(row); foundSelected = true; } if (train) //If we are training, flash the tab button FlashTabButton(tabName); } /************************************************************************************ * * graphical skill indicator * **************************************************************************************/ pawsSkillIndicator::pawsSkillIndicator() { x = 0; rank = 0; y = 0; yCost = 0; z = 0; zCost = 0; g2d = PawsManager::GetSingleton().GetGraphics2D(); } int pawsSkillIndicator::GetRelCoord(int pt) { if (yCost + zCost == 0) // divide-by-zero guard return 0; else { int returnv = int(screenFrame.Width() * pt / float(yCost+zCost)); if(returnv > screenFrame.Width()) returnv = screenFrame.Width(); return returnv; } } void pawsSkillIndicator::DrawSkillProgressBar(int x, int y, int width, int height, int start_r, int start_g, int start_b) { pawsProgressBar::DrawProgressBar( csRect(x, y, x+width-1, y+height-1), PawsManager::GetSingleton().GetGraphics3D(), 1, start_r, start_g, start_b, 100, 100, 100 ); } void pawsSkillIndicator::Draw() { csRect sf = screenFrame; if (y < yCost) { int split = GetRelCoord(yCost); DrawSkillProgressBar(sf.xmin, sf.ymin, split, sf.Height(), 180, 180, 30); DrawSkillProgressBar(sf.xmin+split, sf.ymin, sf.Width()-split, sf.Height(), 180, 30, 30); DrawSkillProgressBar(sf.xmin, sf.ymin, GetRelCoord(y), sf.Height(), 0, 180, 0); DrawSkillProgressBar(sf.xmin, sf.ymin, GetRelCoord(x), sf.Height()/2, 30, 30, 180); } else { int split = GetRelCoord(y+z); DrawSkillProgressBar(sf.xmin, sf.ymin, split, sf.Height(), 0, 180, 0); DrawSkillProgressBar(sf.xmin+split, sf.ymin, sf.Width()-split, sf.Height(), 180, 30, 30); } g2d->DrawLine(sf.xmin, sf.ymin, sf.xmax, sf.ymin, 0); g2d->DrawLine(sf.xmax, sf.ymin, sf.xmax, sf.ymax, 0); g2d->DrawLine(sf.xmin, sf.ymax, sf.xmax, sf.ymax, 0); g2d->DrawLine(sf.xmin, sf.ymin, sf.xmin, sf.ymax, 0); } void pawsSkillIndicator::Set(int x, int rank, int y, int yCost, int z, int zCost) { this->x = x; this->rank = rank; this->y = y; this->yCost = yCost; this->z = z; this->zCost = zCost; }