Vagabond
New Member
- Joined
- Oct 5, 2007
- Messages
- 242
- Reaction score
- 0
These codes are a small portion (which I've deemed fit to release to the general public) of a code for a project I've been planning for quite some time.
These were designed to be easy to add and configure, so it may not be the most efficient code (I haven't run any efficiency tests).
Currently, this only includes:
- Individual attack delay for weapons. This way you can have smaller, lighter weapons attacking fast and big, heavy weapons attacking slow. More realistic, and will keep people from just choosing the bigger weapon for more power.
- True dual wielding. Basically, you attack with one weapon and then the other. You can choose which weapons are dual wieldable by configuring them in items.xml.
- ExtraAtk for weapons/shields when used with a shield or dual wielding (don't ask why you'd need this :s)
The code:
in item.h, after:
after:
after:
in items.cpp, after:
after:
in items.h, after:
in player.cpp, after:
replace:
replace:
after:
replace:
replace:
replace:
after:
at the bottom:
in player.h, after:
in weapons.cpp(WeaponMelee::getWeaponDamage), replace:
add -D__REVSTATS__ to C++ compiler and rebuild all.
Notes:
- Never tested extraAtk. Should work, but no guarantees.
- extraAtk doesn't currently show up in item description. Forgot to do this, too lazy to do it now.
- I was moving around my weapons trying to crash it and it didn't bug or crash, so I assume the dual wielding portion of the code has no bugs. If you do find any, tell me.
Configuring items:
- To make any (one-handed) weapon dual-wieldable, edit items.xml and add the tag:
in the item's tag.
- To give any one-handed weapon extra attack, edit items.xml and add the tag:
, replacing 1 for whatever you want the extra attack to be.
- To give any one-handed weapon a custom attack delay, edit items.xml and add the tag:
, replacing 1500 for whatever you want the delay to be. (don't change it to lower than 100 it won't work)
These were designed to be easy to add and configure, so it may not be the most efficient code (I haven't run any efficiency tests).
Currently, this only includes:
- Individual attack delay for weapons. This way you can have smaller, lighter weapons attacking fast and big, heavy weapons attacking slow. More realistic, and will keep people from just choosing the bigger weapon for more power.
- True dual wielding. Basically, you attack with one weapon and then the other. You can choose which weapons are dual wieldable by configuring them in items.xml.
- ExtraAtk for weapons/shields when used with a shield or dual wielding (don't ask why you'd need this :s)
The code:
in item.h, after:
add:virtual bool readAttr(AttrTypes_t attr, PropStream& propStream);
virtual bool unserializeAttr(PropStream& propStream);
virtual bool unserializeItemNode(FileLoader& f, NODE node, PropStream& propStream);
Code:
#ifdef __REVSTATS__
bool isDualWield() const { return items[id].dualWield; }
int getAttackSpeed() const { return items[id].atkSpeed; };
#endif
add:int getExtraDef() const {return items[id].extraDef;}
Code:
#ifdef __REVSTATS__
int getExtraAtk() const {return items[id].extraAtk;}
#endif //__REVSTATS__
in items.cpp, after:
add:replaceable = true;
Code:
#ifdef __REVSTATS__
dualWield = false;
extraAtk = 0;
atkSpeed = 2000;
#endif //__REVSTATS__
add:else if(strcasecmp(strValue.c_str(), "attack") == 0){
if(readXMLInteger(itemAttributesNode, "value", intValue)){
it.attack = intValue;
}
}
Code:
#ifdef __REVSTATS__
else if(strcasecmp(strValue.c_str(), "extraatk") == 0){
if(readXMLInteger(itemAttributesNode, "value", intValue)){
it.extraAtk = intValue;
}
}
else if(strcasecmp(strValue.c_str(), "dualwield") == 0){
if(readXMLInteger(itemAttributesNode, "value", intValue)){
it.dualWield = (intValue != 0);
}
}
else if(strcasecmp(strValue.c_str(), "attackspeed") == 0){
if(readXMLInteger(itemAttributesNode, "value", intValue)){
it.atkSpeed = (intValue > 100) ? intValue : 2000;
}
}
#endif //__REVSTATS__
in items.h, after:
add:bool replaceable;
Code:
#ifdef __REVSTATS__
bool dualWield;
int extraAtk;
int atkSpeed;
#endif //__REVSTATS__
in player.cpp, after:
add:#ifdef __SKULLSYSTEM__
redSkullTicks = 0;
skull = SKULL_NONE;
#endif
Code:
#ifdef __REVSTATS__
nextWeapon = NULL;
#endif //__REVSTATS__
with:Item* Player::getWeapon()
{
Item* item;
for(uint32_t slot = SLOT_RIGHT; slot <= SLOT_LEFT; slot++){
item = getInventoryItem((slots_t)slot);
if(!item){
continue;
}
switch(item->getWeaponType()){
case WEAPON_SWORD:
case WEAPON_AXE:
case WEAPON_CLUB:
case WEAPON_WAND:
{
const Weapon* weapon = g_weapons->getWeapon(item);
if(weapon){
return item;
}
break;
}
case WEAPON_DIST:
{
if(item->getAmuType() != AMMO_NONE){
Item* ammuItem = getInventoryItem(SLOT_AMMO);
if(ammuItem && ammuItem->getAmuType() == item->getAmuType()){
const Weapon* weapon = g_weapons->getWeapon(ammuItem);
if(weapon){
shootRange = item->getShootRange();
return ammuItem;
}
}
}
else{
const Weapon* weapon = g_weapons->getWeapon(item);
if(weapon){
return item;
}
}
}
default:
break;
}
}
return NULL;
}
Code:
Item* Player::getWeapon()
{
#ifndef __REVSTATS__
Item* item;
for(uint32_t slot = SLOT_RIGHT; slot <= SLOT_LEFT; slot++){
item = getInventoryItem((slots_t)slot);
if(!item){
continue;
}
switch(item->getWeaponType()){
case WEAPON_SWORD:
case WEAPON_AXE:
case WEAPON_CLUB:
case WEAPON_WAND:
{
const Weapon* weapon = g_weapons->getWeapon(item);
if(weapon){
return item;
}
break;
}
case WEAPON_DIST:
{
if(item->getAmuType() != AMMO_NONE){
Item* ammuItem = getInventoryItem(SLOT_AMMO);
if(ammuItem && ammuItem->getAmuType() == item->getAmuType()){
const Weapon* weapon = g_weapons->getWeapon(ammuItem);
if(weapon){
shootRange = item->getShootRange();
return ammuItem;
}
}
}
else{
const Weapon* weapon = g_weapons->getWeapon(item);
if(weapon){
return item;
}
}
}
default:
break;
}
}
return NULL;
#else
return nextWeapon;
#endif //__REVSTATS__
}
with:void Player::getShieldAndWeapon(const Item* &shield, const Item* &weapon) const
{
Item* item;
shield = NULL;
weapon = NULL;
for(uint32_t slot = SLOT_RIGHT; slot <= SLOT_LEFT; slot++){
item = getInventoryItem((slots_t)slot);
if(item){
switch(item->getWeaponType()){
case WEAPON_NONE:
break;
case WEAPON_SHIELD:
shield = item;
break;
default: // weapons that are not shields
weapon = item;
break;
}
}
}
return;
}
Code:
void Player::getShieldAndWeapon(const Item* &shield, const Item* &weapon) const
{
#ifndef __REVSTATS__
Item* item;
shield = NULL;
weapon = NULL;
for(uint32_t slot = SLOT_RIGHT; slot <= SLOT_LEFT; slot++){
item = getInventoryItem((slots_t)slot);
if(item){
switch(item->getWeaponType()){
case WEAPON_NONE:
break;
case WEAPON_SHIELD:
shield = item;
break;
default: // weapons that are not shields
weapon = item;
break;
}
}
}
#else
shield = (nextWeapon == getWeaponLeft()) ? getWeaponRight() : getWeaponLeft();
weapon = nextWeapon;
#endif
return;
}
(note: at the end of the function) add:void Player:nRemoveInventoryItem(slots_t slot, Item* item)
{
//setItemAbility(slot, false);
if(tradeState != TRADE_TRANSFER){
checkTradeState(item);
if(tradeItem){
const Container* container = item->getContainer();
if(container && container->isHoldingItem(tradeItem)){
g_game.playerCloseTrade(this);
}
}
}
Code:
#ifdef __REVSTATS__
if(item == nextWeapon)
{
nextWeapon = NULL;
findNextWeapon();
attackTicks = getAttackSpeed();
}
#endif //__REVSTATS__
with:else if(item != inventory[SLOT_LEFT] && inventory[SLOT_LEFT]->isWeapon() &&
(inventory[SLOT_LEFT]->getWeaponType() != WEAPON_SHIELD) &&
(inventory[SLOT_LEFT]->getWeaponType() != WEAPON_AMMO) &&
item->isWeapon() && (item->getWeaponType() != WEAPON_SHIELD) && (item->getWeaponType() != WEAPON_AMMO)){
ret = RET_CANONLYUSEONEWEAPON;
Code:
#ifndef __REVSTATS__
else if(item != inventory[SLOT_LEFT] && inventory[SLOT_LEFT]->isWeapon() &&
(inventory[SLOT_LEFT]->getWeaponType() != WEAPON_SHIELD) &&
(inventory[SLOT_LEFT]->getWeaponType() != WEAPON_AMMO) &&
item->isWeapon() && (item->getWeaponType() != WEAPON_SHIELD) && (item->getWeaponType() != WEAPON_AMMO)){
ret = RET_CANONLYUSEONEWEAPON;
#else
else if(item != inventory[SLOT_LEFT])
{
Item* i = getWeaponLeft();
if(i && !(i->isDualWield() || i->getWeaponType() == WEAPON_SHIELD || i->getWeaponType() == WEAPON_AMMO))
ret = RET_CANONLYUSEONEWEAPON;
else
ret = RET_NOERROR;
}
#endif
with:else if(item != inventory[SLOT_RIGHT] && inventory[SLOT_RIGHT]->isWeapon() &&
(inventory[SLOT_RIGHT]->getWeaponType() != WEAPON_SHIELD) &&
(inventory[SLOT_RIGHT]->getWeaponType() != WEAPON_AMMO) &&
item->isWeapon() && (item->getWeaponType() != WEAPON_SHIELD) && (item->getWeaponType() != WEAPON_AMMO)){
ret = RET_CANONLYUSEONEWEAPON;
}
Code:
#ifndef __REVSTATS__
else if(item != inventory[SLOT_RIGHT] && inventory[SLOT_RIGHT]->isWeapon() &&
(inventory[SLOT_RIGHT]->getWeaponType() != WEAPON_SHIELD) &&
(inventory[SLOT_RIGHT]->getWeaponType() != WEAPON_AMMO) &&
item->isWeapon() && (item->getWeaponType() != WEAPON_SHIELD) && (item->getWeaponType() != WEAPON_AMMO)){
ret = RET_CANONLYUSEONEWEAPON;
}
#else
else if(item != inventory[SLOT_RIGHT])
{
Item* i = getWeaponRight();
if(i && !(i->isDualWield() || i->getWeaponType() == WEAPON_SHIELD || i->getWeaponType() == WEAPON_AMMO))
ret = RET_CANONLYUSEONEWEAPON;
else
ret = RET_NOERROR;
}
#endif
with:uint32_t Player::getAttackSpeed()
{
return 2000;
}
Code:
uint32_t Player::getAttackSpeed()
{
#ifndef __REVSTATS__
return 2000;
#else
return nextWeapon?nextWeapon->getAttackSpeed():2000; //todo: individual weapon speeds
#endif //__REVSTATS__
}
add:if(weapon && weapon->checkLastAction(this, 100)){
attackTicks = 0;
result = weapon->useWeapon(this, tool, attackedCreature);
}
else
{
attackTicks = 0;
result = Weapon::useFist(this, attackedCreature);
}
Code:
#ifdef __REVSTATS__
findNextWeapon();
#endif
Code:
#ifdef __REVSTATS__
Item* Player::getWeaponLeft() const
{
Item* item = inventory[SLOT_LEFT];
if(item){
switch(item->getWeaponType()){
case WEAPON_NONE: case WEAPON_AMMO:
break;
default:
return item;
break;
}
}
return NULL;
}
Item* Player::getWeaponRight() const
{
Item* item = inventory[SLOT_RIGHT];
if(item){
switch(item->getWeaponType()){
case WEAPON_NONE: case WEAPON_AMMO:
break;
default:
return item;
break;
}
}
return NULL;
}
void Player::findNextWeapon()
{
Item* left = getWeaponLeft();
Item* right = getWeaponRight();
if(nextWeapon == left || !left || left->getWeaponType() == WEAPON_SHIELD)
nextWeapon = right;
else if(nextWeapon == right || !right || right->getWeaponType() == WEAPON_SHIELD)
nextWeapon = left;
else
nextWeapon = NULL;
}
int32_t Player::getAttack() const
{
int32_t attack = 0;
int32_t extraAtk = 0;
int32_t defenseSkill = 0;
const Item* weapon;
const Item* shield;
getShieldAndWeapon(shield, weapon);
if(weapon){
attack = weapon->getAttack();
}
if(weapon && shield)
extraAtk = shield->getExtraAtk();
if(shield && shield->getAttack() >= attack){
attack = shield->getAttack() + extraAtk;
}
return attack;
}
#endif //__REVSTATS__
in player.h, after:
add:uint32_t lossPercent[LOSS_LAST + 1];
Code:
#ifdef __REVSTATS__
Item* nextWeapon;
void findNextWeapon();
Item* getWeaponLeft() const;
Item* getWeaponRight() const;
int32_t getAttack() const;
#endif //__REVSTATS__
in weapons.cpp(WeaponMelee::getWeaponDamage), replace:
with:int32_t attackValue = item->getAttack();
Code:
#ifndef __REVSTATS__
int32_t attackValue = item->getAttack();
#else
int32_t attackValue = player->getAttack();
#endif //__REVSTATS__
add -D__REVSTATS__ to C++ compiler and rebuild all.
Notes:
- Never tested extraAtk. Should work, but no guarantees.
- extraAtk doesn't currently show up in item description. Forgot to do this, too lazy to do it now.
- I was moving around my weapons trying to crash it and it didn't bug or crash, so I assume the dual wielding portion of the code has no bugs. If you do find any, tell me.
Configuring items:
- To make any (one-handed) weapon dual-wieldable, edit items.xml and add the tag:
HTML:
<attribute key="dualwield" value="1" />
- To give any one-handed weapon extra attack, edit items.xml and add the tag:
HTML:
<attribute key="extraatk" value="1" />
- To give any one-handed weapon a custom attack delay, edit items.xml and add the tag:
HTML:
<attribute key="attackspeed" value="1500" />
Last edited: