[Tuto]Ineisis - Inv & Item
Hello EWorld.
This post is to add Item and Inventory code for Ineisis. i copy mmo code for work.
Ok let's go.
1/ Create new Code in Shared => Net Inventory.cpp
Paste this code:
Code:
/******************************************************************************/
enum SLOT_TYPE // inventory item slot
{
SLOT_HEAD , // head slot for helmet
SLOT_NECK , // neck slot for amulet/necklace
SLOT_ARM_L , // left arm slot for weapon/shield/ammo
SLOT_ARM_R , // right arm slot for weapon/shield/ammo
SLOT_BODY , // body slot for armor/clothing
SLOT_HANDS , // hands slot for gloves
SLOT_LEGS , // legs slot for pants
SLOT_FEET , // feet slot for shoes
SLOT_FINGER_L, // left finger slot for ring
SLOT_FINGER_R, // right finger slot for ring
SLOT_TEMP , // temporary slot (current item moved with mouse cursor)
SLOT_SHLD , // number of slots
SLOT_NUM , // number of slots
}
/******************************************************************************/
class NetInventory // net inventory
{
Memc<NetItem> items;
int slots[SLOT_NUM]; // each array value represents a slot, and is equal to index of item in 'items' container or -1 if slot doesn't have an item
// Reference<Item> slot[SLOT_NUM];
NetInventory() {REPAO(slots)=-1;}
// manage
void del()
{
items.del();
REPAO(slots)=-1;
}
// get
bool valid(int slot)C {return InRange(slot, T.slots) && InRange(T.slots[slot], items);} // if 'slot' points to a valid item
// network
void compress(File &f, bool equipped_only=false) // compress data so it can be sent using network connection
{
if(equipped_only)
{
// check which items should be compressed
int equipped_items=0;
Memc<bool> equipped; FREPA(items)equipped .New()=false; FREPA(slots)if(i!=SLOT_TEMP)if(InRange(slots[i], equipped))equipped[slots[i]]=true;
Memc<int> new_index; FREPA(items)new_index.New()=(equipped[i] ? equipped_items++ : -1);
// compress
f.putInt(equipped_items); FREPA(items)if(equipped[i])items[i].compress(f);
FREPA(slots)if(i!=SLOT_TEMP)f.cmpIntV(InRange(slots[i], new_index) ? new_index[slots[i]] : -1);
}else
{
// compress
f.putInt(items.elms()); FREPA(items)items[i].compress(f);
FREPA(slots)if(i!=SLOT_TEMP)f.cmpIntV(slots[i]);
}
}
void decompress(File &f) // decompress data from data obtained using network connection
{
del();
REP(f.getInt())items.New().decompress(f);
FREPA(slots)if(i!=SLOT_TEMP)f.decIntV(slots[i]);
}
// io
void save(File &f) // save item to file
{
items.save(f);
f<<slots;
}
bool load(File &f) // load item from file, false on fail
{
del();
if(!items.load(f))return false;
f>>slots;
return true;
}
}
/******************************************************************************/
2/ Create new Code in Shared => Net Item.cpp
Paste this code:
Code:
class NetItem // net item
{
Game.ObjParamsPtr obj;
// manage
void create(C UID &obj_id)
{
T.obj=obj_id;
}
// network
virtual void compress(File &f) // compress data so it can be sent using network connection
{
f<<obj.id();
}
virtual void decompress(File &f) // decompress data from data obtained using network connection
{
obj=f.getUID();
}
// io
void save(File &f) // save item to file
{
f.cmpUIntV(0); // version
f<<obj.id();
}
bool load(File &f) // load item from file, false on fail
{
switch(f.decUIntV()) // version
{
case 0:
{
obj=f.getUID();
}return true;
}
return false;
}
}
/******************************************************************************/
Memx<NetItem> Items;
/******************************************************************************/
3/ Create new Code in Client => GUI Inventory.cpp
Paste this code:
Code:
/******************************************************************************
'InventoryGui' is a set of visual gui objects which represent character's inventory.
/******************************************************************************/
class InventoryGui
{
class InventoryWindow : Window
{
virtual void update(C GuiPC &gpc)
{
super.update(gpc);
if(Gui.ms()==this && Ms.bp(1))
{
Ms.eat(1);
hide();
}
}
}
Inventory *inv=null; // Inventory which InventoryGui is linked with
GuiObjs gobjs; // gui objects
List<NetItem> list; // list of items
GuiImage slot_image [SLOT_NUM]; // slot images [slot index of SLOT_TYPE]
Region *slot_region[SLOT_NUM]; // slot regions [slot index of SLOT_TYPE]
InventoryGui() {REPAO(slot_region)=null;}
// manage
void create()
{
gobjs.replaceWindow<InventoryWindow>(); gobjs=UID(3696073335, 1090330182, 4248471980, 2484485872); gobjs.hide(); Gui+=gobjs;
Window &window=gobjs.getWindow(S);
window.move(Vec2(D.w()-0.05-window.rect().max.x, 0));
window+=slot_image[SLOT_HEAD ].create((slot_region[SLOT_HEAD ]=&gobjs.getRegion("head" )).rect());
window+=slot_image[SLOT_NECK ].create((slot_region[SLOT_NECK ]=&gobjs.getRegion("neck" )).rect());
window+=slot_image[SLOT_ARM_L ].create((slot_region[SLOT_ARM_L ]=&gobjs.getRegion("arm l" )).rect());
window+=slot_image[SLOT_ARM_R ].create((slot_region[SLOT_ARM_R ]=&gobjs.getRegion("arm r" )).rect());
window+=slot_image[SLOT_BODY ].create((slot_region[SLOT_BODY ]=&gobjs.getRegion("body" )).rect());
window+=slot_image[SLOT_HANDS ].create((slot_region[SLOT_HANDS ]=&gobjs.getRegion("hands" )).rect());
window+=slot_image[SLOT_LEGS ].create((slot_region[SLOT_LEGS ]=&gobjs.getRegion("legs" )).rect());
window+=slot_image[SLOT_FEET ].create((slot_region[SLOT_FEET ]=&gobjs.getRegion("feet" )).rect());
window+=slot_image[SLOT_FINGER_L].create((slot_region[SLOT_FINGER_L]=&gobjs.getRegion("finger l")).rect());
window+=slot_image[SLOT_FINGER_R].create((slot_region[SLOT_FINGER_R]=&gobjs.getRegion("finger r")).rect());
window+=slot_image[SLOT_SHLD].create((slot_region[SLOT_SHLD]=&gobjs.getRegion("shld")).rect());
REPAO(slot_image).rect_color.zero();
// list
{
ListColumn lc[]=
{
ListColumn(MEMBER(Item, icon ), 0.21, "+" ), // 0
ListColumn(MEMBER(Item, name ), 0.52, "Nom" ), // 1
ListColumn(MEMBER(Item, power), 0.21, "Dégât"), // 2
};
gobjs.getRegion("Backpack")+=list.create(lc, Elms(lc));
list.column(0).text_align=0;
list.column(2).precision=1; // set showing only 1 decimal precision for power float attribute
list. cur_mode=LCM_MOUSE;
list.drawMode(LDM_RECTS);
list.flag|=LIST_SCALABLE;
list.elmHeight(0.08);
list.zoom_max*=1.44 ;
}
}
// get
bool visible()
{
if(Window *window=gobjs.findWindow(S))return window.visible();
return false;
}
// operations
void link(Inventory *inv) // link with 'inv' Inventory
{
if(T.inv!=inv)
{
T.inv=inv;
setGui();
}
}
void setGui() // set visual gui components
{
if(inv)
{
// set item list
{
// here we have to hide the items which are assigned to slots
// create a 'visible' array which determines visibility of an element
Memt<bool> visible; visible.setNum(inv.items.elms()); // allocate array of item visibility
REPAO(visible)=true; // set all visibility by default to true
REPA(inv.slots) // iterate through all slots
if(inv.valid(i)) // if the slot is valid
visible[inv.slots[i]]=false; // set visibility for item assigned to a slot to false, to be hidden on the list
list.setData(inv.items, visible); // set list data from items container and visibility list
}
// set slot images
REP(SLOT_NUM) // for all slots
if(i!=SLOT_TEMP) // skip temporary slot because it's not drawn using 'Image' class
if(slot_region[i])
{
Rect image_rect=slot_region[i].rect(); // gui rect
GuiImage &image_item=slot_image [i] ; // gui image
if(!inv.valid(i))image_item.set(null);else // if there is no item then clear the item image slot
{
ImagePtr icon=inv.item(inv->slots[i]).icon; // access item's icon
image_item.set(icon); // set slot image as the item's icon
if(icon) // set proper scaling
{
Vec2 size=icon->size(); size*=PixelSize; // set default size
if(size.x>image_rect.w())size*=image_rect.w()/size.x; // clamp item size to background slot width
if(size.y>image_rect.h())size*=image_rect.h()/size.y; // clamp item size to background slot height
Rect rect(image_rect.center()); rect.extend(size/2);
image_item.rect(rect);
}
}
}
}else
{
list.clear();
REPAO(slot_image).set(null);
}
}
void toggle() {if(visible())hide();else show();} // toggle visibility
void show() {gobjs.getWindow(S).show();}
void hide() {gobjs.getWindow(S).hide();}
// update
void update(Player &owner) // handle moving items with mouse
{
if(inv)
{
if(Ms.bp(0)) // if mouse button pressed
{
if(InRange(inv.slots[SLOT_TEMP], inv.items)) // if we have an item attached with mouse
{
if(Gui.ms()==&list) // if mouse cursor is on the list
{
inv.slots[SLOT_TEMP]=-1; // clear the slot reference which will result in "putting back the item into the list"
setGui(); // update visuals
owner.sendInvSlots();
}
}
else // we don't have an item so we want to get one
{
if(Gui.ms()==&list) // from the list
{
if(list())
{
inv.slots[SLOT_TEMP]=list.visToAbs(list.cur);
setGui(); // update visuals
owner.sendInvSlots();
}
}
}
REPA(slot_image)
if(Gui.ms()==&slot_image[i] || Gui.ms()==slot_region[i]) // if we want to swap temp item with i-th slot
if(inv.slotsCanBeSwapped(SLOT_TEMP, SLOT_TYPE(i)))
{
Swap(inv.slots[SLOT_TEMP], inv.slots[i]); // swap temporary with i-th slot
setGui(); // update visuals
owner.sendInvSlots();
}
}
}
}
// draw
void draw() // draw item being moved with mouse
{
if(inv && InRange(inv.slots[SLOT_TEMP], inv.items))
{
Vec2 pos=Ms.pos();
inv.item(inv.slots[SLOT_TEMP]).drawIcon(pos);
}
}
}
InventoryGui InvGui;
/******************************************************************************/
4/ Create new Code in Client => Inventory.cpp
Paste this code:
Code:
/******************************************************************************/
class Inventory : NetInventory
{
~Inventory() {if(InvGui.inv==this)InvGui.link(null);}
Inventory() {items.replaceClass<Item>();}
// get
Item& item(int i) {return (Item&)items[i];} // we can perform direct cast since 'items' had 'replaceClass' called in constructor
bool slotCanBePutTo(SLOT_TYPE src, SLOT_TYPE dest) // test if slot 'src' can be put to 'dest' slot
{
if(!InRange(src, SLOT_NUM) || !InRange(dest, SLOT_NUM))return false;
return valid(src) ? item(slots[src]).canBePutTo(dest) : true;
}
bool slotsCanBeSwapped(SLOT_TYPE a, SLOT_TYPE b) // test if slot 'a' can be swapped with slot 'b'
{
return slotCanBePutTo(a, b) && slotCanBePutTo(b, a);
}
// manage
void create(NetInventory &src)
{
del();
items.setNum(src.items.elms()); FREPA(src.items)item(i).create(src.items[i]);
Copy(slots, src.slots);
setGui();
}
/*void itemRemoved(Game.Obj &item) // called when an item is being removed
{
// perform check if it is a equipped item
// REPA(slot) // for all slots
// if(slots[i]==item) // if i-th slot is set to item which is being removed
// slots[i].clear(); // clear the slot so it can no longer be referenced to the removed item
}*/
void itemRemoved() // called when an item has been removed
{
setGui();
}
void itemAdded() // called when an item has been added
{
setGui();
}
void setGui()
{
if(InvGui.inv==this)InvGui.setGui();
}
// update
void update(AnimatedSkeleton &skel, Player *owner)
{
if(owner && InvGui.inv==this)if(Player *player=CAST(Player, owner))InvGui.update(*player);
// set matrixes for items in hands
if(valid(SLOT_ARM_L))
{
if(C OrientP *point=skel.findPoint(8"HandL"))
{
Item &item =T.item(slots[SLOT_ARM_L]);
Matrix matrix=item.matrix(); // get current matrix
item.matrix(Matrix().setPosDir(point.pos, point.cross(), point.dir)); // set new matrix
item.update();
// immediately overwrite item members after calling 'update'
GetVel(item.vel, item.ang_vel, matrix, item.matrix()); // calculate velocities between old and new matrixes
}
}
if(valid(SLOT_ARM_R))
{
if(C OrientP *point=skel.findPoint(8"HandR"))
{
Item &item =T.item(slots[SLOT_ARM_R]);
Matrix matrix=item.matrix(); // get current matrix
item.matrix(Matrix().setPosDir(point.pos, point.cross(), point.dir)); // set new matrix
item.update();
// immediately overwrite item members after calling 'update'
GetVel(item.vel, item.ang_vel, matrix, item.matrix()); // calculate velocities between old and new matrixes
}
}
if(valid(SLOT_SHLD))
{
if(C OrientP *point=skel.findPoint(8"Shld"))
{
Item &item =T.item(slots[SLOT_SHLD]);
Matrix matrix=item.matrix(); // get current matrix
item.matrix(Matrix().setPosDir(point.pos, point.cross(), point.dir)); // set new matrix
item.update();
// immediately overwrite item members after calling 'update'
GetVel(item.vel, item.ang_vel, matrix, item.matrix()); // calculate velocities between old and new matrixes
}
}
}
// draw
uint drawPrepare()
{
// draw items in hands
uint modes=0;
if(valid(SLOT_ARM_L))modes|=item(slots[SLOT_ARM_L]).drawPrepare();
if(valid(SLOT_ARM_R))modes|=item(slots[SLOT_ARM_R]).drawPrepare();
if(valid(SLOT_SHLD))modes|=item(slots[SLOT_SHLD]).drawPrepare();
return modes;
}
void drawShadow()
{
// draw items in hands
if(valid(SLOT_ARM_L))item(slots[SLOT_ARM_L]).drawShadow();
if(valid(SLOT_ARM_R))item(slots[SLOT_ARM_R]).drawShadow();
if(valid(SLOT_SHLD))item(slots[SLOT_SHLD]).drawShadow();
}
}
/******************************************************************************/
5/ copy the " gui inventory" file located in MMO Source to you project.
6/ In Net Chr.cpp
=> class ClientChr : NetChr add this :
=> void create(CreateChr &cc) add this :
Code:
inv.items.New().create("ITEM UID");
=> virtual void save(File &f) add this :
=> virtual bool load(File &f) add this :
Code:
if(!inv.load(f))return false;
=> void compress(File &f) add this :
=> void decompress(File &f) add this :
7/ In Commands.cpp
=> enum CLIENT_SERVER_COMMANDS just down why CS_CHR_ANIM, add this:
Code:
CS_CHR_INV_SLOTS , // Inv
=> class ChrVisuals Copy this :
Code:
class ChrVisuals
{
SockAddr addr;
MeshPtr mesh;
NetInventory inv;
void save(File &f)
{
addr.save(f);
f<<mesh.id();
inv.compress(f, true);
}
void load(File &f)
{
addr.load(f);
mesh=f.getUID();
inv.decompress(f);
}
}
void ServerWriteChrVisuals(File &f, ChrVisuals &cv)
{
f.writeMem(); cv.save(f);
}
void ServerSendChrVisuals(Connection &conn, ChrVisuals &cv)
{
File f; f.writeMem().putByte(CS_CHR_VISUALS); cv.save(f); f.pos(0); conn.send(f, -1, false);
}
void ClientRecvChrVisuals(File &f, ChrVisuals &cv)
{
cv.load(f);
}
=> just down why
Code:
// CS_CHR_ANIM
/******************************************************************************/
void ClientSendChrAnim(Connection &conn, C UID &anim, C UID &sound=UIDZero)
{
File f; f.writeMem().putByte(CS_CHR_ANIM)<<anim<<sound; f.pos(0); conn.send(f);
}
void ServerRecvChrAnim(File &f, UID &anim, UID &sound)
{
f>>anim>>sound;
}
void ServerWriteChrAnim(File &f, C SockAddr &addr, C UID &anim, C UID &sound)
{
f.writeMem().putByte(CS_CHR_ANIM); addr.save(f); f<<anim<<sound;
}
void ClientRecvChrAnim(File &f, SockAddr &addr, UID &anim, UID &sound)
{
addr.load(f); f>>anim>>sound;
}
add this:
Code:
// CS_CHR_INV_SLOTS
/******************************************************************************/
void ClientSendChrInvSlots(Connection &conn, int (&slots)[SLOT_NUM])
{
File f; f.writeMem().putByte(CS_CHR_INV_SLOTS); f<<slots; f.pos(0); conn.send(f);
}
void ServerRecvChrInvSlots(File &f, int (&slots)[SLOT_NUM])
{
f>>slots;
}
8/ Create new Code in Client => Item.cpp
Paste this code:
Code:
/******************************************************************************/
class Item : NetItem
{
ITEM_TYPE type=ITEM_NONE;
byte type2=0;
flt scale=1, power=0;
Str name;
MeshPtr mesh;
ImagePtr icon;
Vec vel, ang_vel;
Actor actor ;
//Particles particles;
//bool particles_under_water=false;
void create(NetItem &src)
{
SCAST(NetItem, T)=src;
if(obj)
{
// name
if(Param *p=obj->findParam("name"))name=p.asText();
// type
if(Param *p=obj->findParam("type" ))type =p.asEnum(ITEM_NONE);
if(Param *p=obj->findParam("type2"))type2=p.asEnum();
// power
if(Param *p=obj->findParam("power"))power=p.asFlt();
// icon
if(Param *p=obj->findParam("icon"))icon=p.asID();
scale=obj->scale();
mesh =obj->mesh ();
}
}
// get / set
bool canBePutTo(SLOT_TYPE inv_slot) // test if item can be put to 'inv_slot' inventory slot
{
if(inv_slot==SLOT_TEMP)return true;
switch(inv_slot)
{
case SLOT_HEAD : return type==ITEM_ARMOR && type2==ARMOR_HELMET ;
case SLOT_BODY : return type==ITEM_ARMOR && type2==ARMOR_BODY ;
case SLOT_HANDS: return type==ITEM_ARMOR && type2==ARMOR_GAUNTLET;
case SLOT_LEGS : return type==ITEM_ARMOR && type2==ARMOR_PANTS ;
case SLOT_FEET : return type==ITEM_ARMOR && type2==ARMOR_BOOT ;
case SLOT_SHLD:
case SLOT_ARM_L:
case SLOT_ARM_R:
{
if(type==ITEM_WEAPON)return true;
if(type==ITEM_MISC && Contains(name, "Torch"))return true;
}break;
}
return false;
}
void matrix(Matrix &matrix)
{
T._matrix_scaled=T._matrix=matrix;
T._matrix_scaled.scaleOrn(scale);
}
C Matrix& matrix () {return _matrix ;}
C Matrix& matrixScaled() {return _matrix_scaled;}
// update
void update() {}
// draw
void drawIcon(C Vec2 &pos)
{
if(icon)icon->drawFit(Rect_LU(pos, icon->size()*PixelSize));
}
virtual uint drawPrepare()
{
if(mesh && Frustum(mesh->box, matrixScaled()))mesh->draw(matrixScaled(), vel, ang_vel);
SetHighlight((Cur.obj, this && Cur.highlight) ? Color(34, 85, 85, 0) : TRANSPARENT); //uint modes=super.drawPrepare();
SetHighlight( TRANSPARENT);
// if(particles.is() && !particles_under_water)
// {
//modes|=IndexToFlag(particles.renderMode());
//modes|=IndexToFlag(RM_BLEND); // single particle
//Vec center;
//flt opacity=particles.opacity(¢er);
//LightSqr(6*opacity, center).add(true, this);
// }
return 0;
}
virtual void drawShadow()
{
if(mesh && Frustum(mesh->box, matrixScaled()))mesh->drawShadow(matrixScaled());
//if(CurrentLight.src!=this); //super.drawShadow();
}
//virtual void drawPalette () {if(!particles_under_water){particles.draw();}}
//virtual void drawPalette1() {if(!particles_under_water){particles.draw();}}
//virtual void drawBlend () {if(!particles_under_water){particles.draw(); DrawParticle(*Images(UID(4250561076, 1214902943, 3956203709, 646772750)), 0, Color(255, 255, 170, 0), 0.07, 0.9, 0, particles.shape.pos()*particles.matrix, Vec(0));}}
// network
virtual void decompress(File &f) // decompress data from data obtained using network connection
{
super.decompress(f);
create(T);
}
private:
Matrix _matrix, _matrix_scaled;
}
/******************************************************************************/
9/ In Player.cpp
=> class Player : Game.Chr , BlendObject add this:
Code:
Player() {InvGui.link(&inv);}
Inventory inv;
Code:
// *************************Inv**************** //
void sendInvSlots() // send current equipped items (slots) to server
{
ClientSendChrInvSlots(Server, inv.slots);
}
//************************************************ //
=> void Player.create(ClientChr &chr) add this:
Code:
inv.create(chr.inv);
=> bool Player.update() add this:
Code:
inv.update(skel, this);
if(InvGui.inv==&inv && !inv.valid(SLOT_TEMP))
{
if(Kb.bp(KB_I))InvGui.toggle();
}
=> uint Player.drawPrepare() add this:
Code:
SetHighlight(DamageColor(damage_time));
uint draw_mask=~0;
bool hide_head=(ViewMode==VIEW_FPP && !Renderer.mirror());
if( hide_head)FlagDisable(draw_mask, IndexToFlag(DG_CHR_HEAD));
SetDrawMask(draw_mask); mesh->draw(skel);
SetDrawMask();
SetHighlight();
inv.drawPrepare(); // ADD THIS
10/ In Game.cpp => bool InitGame() add this:
=> void ShutGame() add this:
=> void DrawGame() add this:
11/ In Constants.cpp => add this:
Code:
const flt PixelSize=0.002;
If you have any questions, Post here. Thanks
(This post was last modified: 02-17-2015 11:49 PM by Jben.)
|