📄 charcontrol.cpp
字号:
numbers.clear();
choices.Clear();
cats.clear();
catnames.Clear();
catnames.Add("Known ridable models");
catnames.Add("Other models");
static bool filelistInitialized = false;
if (!filelistInitialized) {
set<string> filelist;
//#ifdef _WIN32
hash_set<string> knownRidable;
//#else
// __gnu_cxx::hash_set<std::string> knownRidable;
//#endif
getFileLists(filelist, filterCreatures);
FILE *f = fopen("ridable.csv","r");
if (f) {
wxString tmp;
while (!feof(f)) {
char buf[1024];
fgets(buf, 1024, f);
size_t l = strlen(buf);
if (buf[l-1]=='\n')
buf[l-1]=0;
tmp = buf;
tmp.LowerCase();
knownRidable.insert(tmp.c_str());
//creaturemodels.push_back(string(buf));
}
}
for (set<string>::iterator it = filelist.begin(); it != filelist.end(); ++it) {
wxString str(*it);
creaturemodels.push_back(str);
str.MakeLower();
ridablelist.push_back(knownRidable.find(str)!=knownRidable.end());
}
filelistInitialized = true;
}
choices.Add("---- None ----");
cats.push_back(0);
for (size_t i=0; i<creaturemodels.size(); i++) {
choices.Add(wxString(creaturemodels[i].c_str() + 9, *wxConvCurrent));
cats.push_back(ridablelist[i]?0:1);
}
// TODO: obtain a list of "known ridable" models, and filter the list into two categories
itemDialog = new FilteredChoiceDialog(this, UPDATE_MOUNT, canvas->GetParent(), _T("Choose a mount"), _T("Creatures"), choices);
CategoryChoiceDialog *itemDialog = new CategoryChoiceDialog(this, UPDATE_MOUNT, canvas->GetParent(), _T("Choose a mount"), _T("Creatures"), choices, cats, catnames);
itemDialog->Move(itemDialog->GetParent()->GetPosition() + wxPoint(4,64));
itemDialog->Check(1, false);
itemDialog->DoFilter();
itemDialog->Show();
// TODO: figure out why the damn dialog is so big and ugly
const int w = 250;
itemDialog->SetSizeHints(w,-1,-1,-1,-1,-1);
itemDialog->SetSize(w, -1);
this->itemDialog = itemDialog;
#endif
}
void CharControl::OnUpdateItem(int type, int id)
{
switch (type) {
case UPDATE_ITEM:
cd.equipment[choosingSlot] = numbers[id];
if (slotHasModel(choosingSlot))
RefreshItem(choosingSlot);
labels[choosingSlot]->SetLabel(wxString(items.get(cd.equipment[choosingSlot]).name.c_str(), *wxConvCurrent));
// Check if its a 'guild tabard'
if (choosingSlot == CS_TABARD)
td.showCustom = (labels[choosingSlot]->GetLabel() == "Guild Tabard");
break;
case UPDATE_SET:
id = numbers[id];
if (id) {
for (int i=0; i<NUM_CHAR_SLOTS; i++) {
if (i!=CS_HAND_LEFT && i!=CS_HAND_RIGHT) cd.equipment[i] = 0;
}
cd.loadSet(sets, items, id);
RefreshEquipment();
}
break;
case UPDATE_START:
id = numbers[id];
if (id) {
for (int i=0; i<NUM_CHAR_SLOTS; i++) cd.equipment[i] = 0;
cd.loadStart(start, items, id);
RefreshEquipment();
}
break;
case UPDATE_MOUNT:
if (canvas->root->model) {
delete canvas->root->model;
canvas->root->model = 0;
canvas->model = 0;
}
if (id == 0) {
// clearing the mount
modelViewer->animControl->UpdateModel(model);
model->isMounted = false;
canvas->model = model;
canvas->ResetView();
charAtt->scale = canvas->root->scale;
charAtt->id = 0;
} else {
//wxString fn(creaturemodels[id-1].c_str());
Model *m = new Model(creaturemodels[id-1], true);
// TODO: check if model is ridable
canvas->root->model = m;
canvas->model = m;
modelViewer->animControl->UpdateModel(m);
for (size_t i=0; i<model->header.nAnimations; i++) {
if (model->anims[i].animID == 91) {
model->animManager->Stop();
model->currentAnim = (int)i;
model->animManager->Set(0,(short)i,0);
break;
}
}
//model->currentAnim = 132;
charAtt->parent = canvas->root;
model->isMounted = true;
//charAtt->id = 42;
// Need to set this - but from what
// Model data doesn't contain sizes for different race/gender
// Character data doesn't contain sizes for different mounts
// possibly some formula that from both models that needs to be calculated.
// For "Taxi" mounts scale should be 1.0f I think, for now I'll ignore them
// I really have no idea!
if(creaturemodels[id-1].substr(9,9) == "Kodobeast")
charAtt->scale = 2.25f;
else
charAtt->scale = 1.0f;
//Model *mChar = static_cast<Model*>(charAtt->model);
//charAtt->scale = m->rad / mChar->rad;
// Human Male = 2.0346599
// NE Male = 2.5721216
// NE Female = 2.2764397
// RidingFrostSaber = 2.4360743
// 1.00000
//canvas->root->scale = 0.5f;
//Attachment *att = charAtt->addChild("World\\ArtTest\\Boxtest\\xyz.m2", 24, -1);
//m-> = att->scale;
//delete att;
canvas->ResetView();
canvas->vRot.x = 0; // mounted characters look better from the side
}
break;
case UPDATE_CREATURE_ITEM:
cd.equipment[choosingSlot] = numbers[id];
RefreshCreatureItem(choosingSlot);
return;
}
if (canvas->modelType == MT_NPC)
RefreshNPCModel();
else
RefreshModel();
}
void CharControl::OnTabardSpin(wxSpinEvent &event)
{
if (canvas->modelType == MT_NPC)
return;
switch (event.GetId())
{
case ID_TABARD_ICON:
td.Icon = event.GetPosition();
break;
case ID_TABARD_ICONCOLOR:
td.IconColor = event.GetPosition();
break;
case ID_TABARD_BORDER:
td.Border = event.GetPosition();
if (td.Border > 5)
{
td.BorderColor = 0;
tabardSpins[SPIN_TABARD_BORDERCOLOR]->SetValue(0);
tabardSpins[SPIN_TABARD_BORDERCOLOR]->SetRange(0, 3);
}
else
tabardSpins[SPIN_TABARD_BORDERCOLOR]->SetRange(0, 16);
break;
case ID_TABARD_BORDERCOLOR:
td.BorderColor = event.GetPosition();
break;
case ID_TABARD_BACKGROUND:
td.Background = event.GetPosition();
break;
}
RefreshModel();
}
string TabardDetails::GetBackgroundTex(int slot)
{
ostringstream tmpStream;
string tmpU = "textures\\GuildEmblems\\Background_";
if (Background < 10)
tmpU += "0";
tmpStream << Background;
tmpU += tmpStream.str();
tmpU += "_TU_U.blp";
string tmpL = tmpU;
tmpL[37] = 'L';
if (slot == CR_TORSO_UPPER)
return tmpU;
else
return tmpL;
}
string TabardDetails::GetBorderTex(int slot)
{
ostringstream tmpStream;
string tmpU = "textures\\GuildEmblems\\Border_";
if (Border < 10)
tmpU += "0";
tmpStream << Border << "_";
tmpU += tmpStream.str();
tmpStream.flush();
tmpStream.str("");
if (BorderColor < 10)
tmpU += "0";
tmpStream << BorderColor;
tmpU += tmpStream.str();
tmpU += "_TU_U.blp";
string tmpL = tmpU;
tmpL[36] = 'L';
if (slot == CR_TORSO_UPPER)
return tmpU;
else
return tmpL;
}
string TabardDetails::GetIconTex(int slot)
{
ostringstream tmpStream;
string tmpU = "textures\\GuildEmblems\\Emblem_";
if(Icon < 10)
tmpU += "0";
tmpStream << Icon << "_";
tmpU += tmpStream.str();
tmpStream.flush();
tmpStream.str("");
if(IconColor < 10)
tmpU += "0";
tmpStream << IconColor;
tmpU += tmpStream.str();
tmpU += "_TU_U.blp";
string tmpL = tmpU;
tmpL[tmpU.length() - 7] = 'L';
if(slot == CR_TORSO_UPPER)
return tmpU;
else
return tmpL;
}
void CharDetails::save(wxString fn, TabardDetails *td)
{
// TODO: save/load as xml?
// wx/xml/xml.h says the api will change, do not use etc etc.
ofstream f(fn.fn_str(), ios_base::out|ios_base::trunc);
f << race << " " << gender << endl;
f << skinColor << " " << faceType << " " << hairColor << " " << hairStyle << " " << facialHair << " " << facialColor << endl;
for (int i=0; i<NUM_CHAR_SLOTS; i++) {
f << equipment[i] << endl;
}
// 5976 is the ID value for "Guild Tabard"
if (equipment[CS_TABARD] == 5976) {
f << td->Background << " " << td->Border << " " << td->BorderColor << " " << td->Icon << " " << td->IconColor << endl;
}
f.close();
}
bool CharDetails::load(wxString fn, TabardDetails *td)
{
int r, g;
ifstream f(fn.fn_str());
f >> r >> g;
bool same = false;
if (r==race && g==gender) {
f >> skinColor >> faceType >> hairColor >> hairStyle >> facialHair >> facialColor;
same = true;
} else {
int dummy;
for (int i=0; i<6; i++) f >> dummy;
}
for (int i=0; i<NUM_CHAR_SLOTS; i++) {
f >> equipment[i];
}
// 5976 is the ID value for "Guild Tabard"
if (equipment[CS_TABARD] == 5976 && !f.eof()) {
f >> td->Background >> td->Border >> td->BorderColor >> td->Icon >> td->IconColor;
td->showCustom = true;
}
f.close();
return same;
}
void CharDetails::loadSet(ItemSetDB &sets, ItemDatabase &items, int setid)
{
try {
ItemSetDB::Record rec = sets.getById(setid);
for (size_t i=0; i<ItemSetDB::NumItems; i++) {
int id = rec.getInt(ItemSetDB::ItemIDBase + i);
if (id==0) continue;
const ItemRecord &r = items.get(id);
if (r.type > 0) {
// find a slot for it
for (int s=0; s<NUM_CHAR_SLOTS; s++) {
if (correctType(r.type, s)) {
equipment[s] = id;
break;
}
}
}
}
} catch (ItemSetDB::NotFound) {}
}
void CharDetails::loadStart(StartOutfitDB &start, ItemDatabase &items, int setid)
{
try {
StartOutfitDB::Record rec = start.getById(setid);
for (size_t i=0; i<StartOutfitDB::NumItems; i++) {
int id = rec.getInt(StartOutfitDB::ItemIDBase + i);
if (id==0) continue;
const ItemRecord &r = items.get(id);
if (r.type > 0) {
// find a slot for it
for (int s=0; s<NUM_CHAR_SLOTS; s++) {
if (correctType(r.type, s)) {
equipment[s] = id;
break;
}
}
}
}
} catch (ItemSetDB::NotFound) {}
}
const std::string CharControl::selectCharModel()
{
wxArrayString arr;
std::vector<int> ids;
for (CharRacesDB::Iterator it = racedb.begin(); it != racedb.end(); ++it) {
char buf[64];
sprintf(buf,"%s Male", it->getString(CharRacesDB::FullName));
arr.Add(buf);
sprintf(buf,"%s Female", it->getString(CharRacesDB::FullName));
arr.Add(buf);
ids.push_back(it->getInt(CharRacesDB::RaceID));
}
wxSingleChoiceDialog dialog(this, _T("Choose a character model"), _T("Races"), arr);
if (dialog.ShowModal() == wxID_OK) {
int sel = dialog.GetSelection();
int raceid = ids[sel >> 1];
int gender = sel & 1;
string genderStr = gender ? "Female" : "Male";
try {
CharRacesDB::Record r = racedb.getById(raceid);
std::string path = "Character\\";
path += r.getString(CharRacesDB::Name);
path += "\\" + genderStr + "\\";
path += r.getString(CharRacesDB::Name);
path += genderStr + ".m2";
return path;
} catch (CharRacesDB::NotFound) {
return ""; // wtf
}
}
return "";
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -