📄 charcontrol.cpp
字号:
} catch (ItemVisualEffectDB::NotFound) {}
}
} catch (ItemVisualDB::NotFound) {}
}
} else {
cd.equipment[slot] = 0; // no such model? :(
}
} catch (ItemDisplayDB::NotFound) {}
}
}
void CharControl::RefreshCreatureItem(int slot)
{
// delete all attachments in that slot
canvas->root->delSlot(slot);
int itemnum = cd.equipment[slot];
if (itemnum!=0) {
// load new model(s)
int id1=-1;
string path;
//float sc = 1.0f;
if (slot == CS_HAND_LEFT)
id1 = 2;
else if (slot == CS_HAND_RIGHT)
id1 = 1;
else
return;
if (slot==CS_HAND_LEFT || slot==CS_HAND_RIGHT) {
if (items.get(itemnum).type == IT_SHIELD) {
path = "Item\\ObjectComponents\\Shield\\";
id1 = 0;
} else {
path = "Item\\ObjectComponents\\Weapon\\";
}
}
try {
const ItemRecord &item = items.get(itemnum);
ItemDisplayDB::Record r = itemdb.getById(item.model);
GLuint tex;
string mp;
bool succ = false;
Attachment *att = NULL;
Model *m = NULL;
if (id1>=0) {
mp = path + r.getString(ItemDisplayDB::Model);
if (mp.length()) {
att = canvas->root->addChild(mp.c_str(), id1, slot);
if (att) {
m = static_cast<Model*>(att->model);
if (m->ok) {
mp = path + r.getString(ItemDisplayDB::Skin);
mp.append(".blp");
tex = texturemanager.add(mp);
m->replaceTextures[2] = tex;
succ = true;
}
}
}
}
if (succ) {
// okay, see if we have any glowy effects
int visualid = r.getInt(ItemDisplayDB::Visuals);
if (visualid == 0) {
if ((modelViewer->enchants->RHandEnchant > -1) && (slot == CS_HAND_RIGHT)) {
visualid = modelViewer->enchants->RHandEnchant;
} else if ((modelViewer->enchants->LHandEnchant > -1) && (slot == CS_HAND_LEFT)) {
visualid = modelViewer->enchants->LHandEnchant;
}
}
if (m == NULL)
m = static_cast<Model*>(att->model);
if (visualid > 0) {
try {
ItemVisualDB::Record vis = visualdb.getById(visualid);
for (int i=0; i<5; i++) {
// try all five visual slots
int effectid = vis.getInt(ItemVisualDB::Effect1 + i);
if (effectid==0 || m->attLookup[i]<0) continue;
try {
ItemVisualEffectDB::Record eff = effectdb.getById(effectid);
const char *filename = eff.getString(ItemVisualEffectDB::Model);
att->addChild(filename, i, -1);
} catch (ItemVisualEffectDB::NotFound) {}
}
} catch (ItemVisualDB::NotFound) {}
}
} else {
cd.equipment[slot] = 0; // no such model? :(
}
} catch (ItemDisplayDB::NotFound) {}
}
}
std::string CharControl::makeItemTexture(int region, const char *name)
{
// just return an empty filename
if (!name || !strlen(name)) return "";
// try gender-specific version first
std::string fn = regionPaths[region];
fn += name;
fn += "_";
fn += cd.gender ? "F" : "M";
fn += ".blp";
if (MPQFile::exists(fn.c_str())) return fn;
// try unisex version
fn[fn.length()-5] = 'U';
return fn;
}
void CharTexture::compose(TextureID tex)
{
// if we only have one texture then don't bother with compositing
if (components.size()==1) {
Texture temp(components[0].name);
texturemanager.LoadBLP(tex, &temp);
return;
}
std::sort(components.begin(), components.end());
unsigned char destbuf[256*256*4], tempbuf[256*256*4];
memset(destbuf, 0, 256*256*4);
for (std::vector<CharTextureComponent>::iterator it = components.begin(); it != components.end(); ++it) {
CharTextureComponent &comp = *it;
const CharRegionCoords &coords = regions[comp.region];
TextureID temptex = texturemanager.add(comp.name);
Texture &tex = *((Texture*)texturemanager.items[temptex]);
tex.getPixels(tempbuf);
// blit the texture region over the original
//assert(tex.w==coords.xsize && tex.h==coords.ysize);
if (tex.w==coords.xsize && tex.h==coords.ysize) {
for (int y=0, dy=coords.ypos; y<tex.h; y++,dy++) {
for (int x=0, dx=coords.xpos; x<tex.w; x++,dx++) {
unsigned char *src = tempbuf + y*tex.w*4 + x*4;
unsigned char *dest = destbuf + dy*256*4 + dx*4;
// this is slow and ugly but I don't care
float r = src[3] / 255.0f;
float ir = 1.0f - r;
// zomg RGBA?
dest[0] = (unsigned char)(dest[0]*ir + src[0]*r);
dest[1] = (unsigned char)(dest[1]*ir + src[1]*r);
dest[2] = (unsigned char)(dest[2]*ir + src[2]*r);
dest[3] = 255;
}
}
}
texturemanager.del(temptex);
}
// good, upload this to video
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, destbuf);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);}
void CharDetails::reset()
{
skinColor = 0;
faceType = 0;
hairColor = 0;
hairStyle = 0;
facialHair = 0;
showUnderwear = true;
showHair = true;
showFacialHair = true;
showEars = true;
for (int i=0; i<NUM_CHAR_SLOTS; i++) {
equipment[i] = 0;
}
}
bool correctType(int type, int slot)
{
if (type == IT_ALL)
return true;
switch (slot) {
case CS_HEAD: return (type == IT_HEAD);
case CS_NECK: return (type == IT_NECK);
case CS_SHOULDER: return (type == IT_SHOULDER);
case CS_SHIRT: return (type == IT_SHIRT);
case CS_CHEST: return (type == IT_CHEST || type == IT_ROBE);
case CS_BELT: return (type == IT_BELT);
case CS_PANTS: return (type == IT_PANTS);
case CS_BOOTS: return (type == IT_BOOTS);
case CS_BRACERS: return (type == IT_BRACERS);
case CS_GLOVES: return (type == IT_GLOVES);
//case CS_HAND_RIGHT: return (type == IT_1HANDED || type == IT_GUN || type == IT_2HANDED || type == IT_CLAW || type == IT_DAGGER);
//case CS_HAND_LEFT: return (type == IT_1HANDED || type == IT_SHIELD || type == IT_DAGGER || type == IT_BOW);
case CS_HAND_RIGHT: return (type == IT_1HANDED || type == IT_GUN || type == IT_THROWN || type == IT_2HANDED || type == IT_CLAW || type == IT_DAGGER);
case CS_HAND_LEFT: return (type == IT_1HANDED || type == IT_BOW || type == IT_2HANDED || type == IT_SHIELD || type == IT_CLAW || type == IT_DAGGER || type == IT_OFFHAND);
case CS_CAPE: return (type == IT_CAPE);
case CS_TABARD: return (type == IT_TABARD);
}
return false;
}
void CharControl::ClearItemDialog()
{
if (itemDialog) {
itemDialog->Show(FALSE);
delete itemDialog;
itemDialog = 0;
}
}
void CharControl::selectItem(int slot, int current, const wxChar *caption)
{
ClearItemDialog();
numbers.clear();
choices.Clear();
// collect all items for this slot, making note of the occurring subclasses
set<pair<int,int> > subclassesFound;
int sel=0, ord=0;
for (std::vector<ItemRecord>::iterator it = items.items.begin(); it != items.items.end(); ++it) {
if (correctType(it->type, slot)) {
choices.Add(wxString(it->name, *wxConvCurrent));
numbers.push_back(it->id);
if (it->id == (unsigned int)current) sel = ord;
ord++;
if (it->itemclass > 0)
subclassesFound.insert(pair<int,int>(it->itemclass,it->subclass));
}
}
// make category list
cats.clear();
catnames.clear();
map<pair<int,int>, int> subclasslookup;
for (ItemSubClassDB::Iterator it=subclassdb.begin(); it != subclassdb.end(); ++it) {
int cl = it->getInt(ItemSubClassDB::ClassID);
int scl = it->getInt(ItemSubClassDB::SubClassID);
// only add the subclass if it was found in the itemlist
if (cl>0 && subclassesFound.find(pair<int,int>(cl,scl)) != subclassesFound.end()) {
// Used to go through the 'string fields' looking for the one with data.
wxString str;
for (int i = ItemSubClassDB::Name; i<18; i++)
{
str = wxString(it->getString(i), *wxConvCurrent);
if (!str.IsEmpty()) {
//p.name = str.fn_str();
break;
}
}
//string str = it->getString(ItemSubClassDB::Name);
int hands = it->getInt(ItemSubClassDB::Hands);
if (hands > 0) {
char buf[16];
sprintf(buf, " (%d-handed)", hands);
str.append(buf);
}
catnames.Add(str.c_str());
subclasslookup[pair<int,int>(cl,scl)] = (int)catnames.size()-1;
}
}
if (subclassesFound.size() > 1) {
// build category list
for (size_t i=0; i<numbers.size(); i++) {
ItemRecord r = items.get(numbers[i]);
cats.push_back(subclasslookup[pair<int,int>(r.itemclass, r.subclass)]);
}
itemDialog = new CategoryChoiceDialog(this, UPDATE_ITEM, canvas->GetParent(), _T("Choose an item"), caption, choices, cats, catnames);
} else {
itemDialog = new FilteredChoiceDialog(this, UPDATE_ITEM, canvas->GetParent(), _T("Choose an item"), caption, choices);
}
itemDialog->SetSelection(sel);
wxSize s = itemDialog->GetSize();
const int w = 250;
if (s.GetWidth() > w) {
itemDialog->SetSizeHints(w,-1,-1,-1,-1,-1);
itemDialog->SetSize(w, -1);
}
itemDialog->Move(itemDialog->GetParent()->GetPosition() + wxPoint(4,64));
itemDialog->Show();
choosingSlot = slot;
}
/*
struct NumStringPair {
int id;
string name;
const bool operator< (const NumStringPair &p) const {
return name < p.name;
}
};
*/
void CharControl::selectSet()
{
ClearItemDialog();
std::vector<NumStringPair> items;
for (ItemSetDB::Iterator it = sets.begin(); it != sets.end(); ++it) {
int id = it->getUInt(ItemSetDB::SetID);
if (sets.available(id)) {
NumStringPair p;
p.id = id;
// Used to go through the 'string fields' looking for the one with data.
for (int i = ItemSetDB::Name; i<9; i++)
{
//wxString str = wxString(it->getString(i), *wxConvCurrent);
wxString str(wxCSConv("iso-8859-1").cWC2WX(wxConvUTF8.cMB2WC(it->getString(i))));
if (!str.IsEmpty()) {
p.name = str.fn_str();
break;
}
}
//p.name = it->getString(ItemSetDB::Name);
items.push_back(p);
}
}
std::sort(items.begin(), items.end());
numbers.clear();
choices.Clear();
for (std::vector<NumStringPair>::iterator it = items.begin(); it != items.end(); ++it) {
//choices.Add(wxString(it->name.c_str(), *wxConvCurrent));
choices.Add(wxString(it->name.c_str(), *wxConvCurrent));
numbers.push_back(it->id);
}
itemDialog = new FilteredChoiceDialog(this, UPDATE_SET, canvas->GetParent(), _("Choose an item set"), _("Item sets"), choices);
itemDialog->Move(itemDialog->GetParent()->GetPosition() + wxPoint(4,64));
itemDialog->Show();
}
void CharControl::selectStart()
{
ClearItemDialog();
numbers.clear();
choices.Clear();
for (StartOutfitDB::Iterator it = start.begin(); it != start.end(); ++it) {
if ((it->getByte(StartOutfitDB::Race) == cd.race) && (it->getByte(StartOutfitDB::Gender) == cd.gender)) {
try {
CharClassesDB::Record r = classdb.getById(it->getByte(StartOutfitDB::Class));
for (int i = CharClassesDB::Name; i<13; i++)
{
//wxString str = wxString(r.getString(i), *wxConvCurrent);
wxString str(wxCSConv("iso-8859-1").cWC2WX(wxConvUTF8.cMB2WC(r.getString(i))));
if (!str.IsEmpty()) {
choices.Add(str);
numbers.push_back(it->getUInt(StartOutfitDB::StartOutfitID));
break;
}
}
} catch (CharClassesDB::NotFound) {}
}
}
itemDialog = new ChoiceDialog(this, UPDATE_START, canvas->GetParent(), _T("Choose a class"), _T("Classes"), choices);
itemDialog->Move(itemDialog->GetParent()->GetPosition() + wxPoint(4,64));
itemDialog->Show();
}
bool filterCreatures(string fn)
{
wxString tmp(fn);
tmp.LowerCase();
const size_t len = tmp.Length();
if (len < 4) return false;
return (tmp[0]=='c' && tmp[1]=='r' && tmp[len-1]=='2' && tmp[len-2]=='m');
}
vector<wxString> creaturemodels;
vector<bool> ridablelist;
// TODO: Add an equivilant working version of this function for Linux / Mac OS X
void CharControl::selectMount()
{
#ifdef _WIN32
ClearItemDialog();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -