void SpellShell::selfStartSpellCast(const uint8_t* data) { const startCastStruct *c = (const startCastStruct *)data; #ifdef DIAG_SPELLSHELL seqDebug("selfStartSpellCast - id=%d (slot=%d, inv=%d) on spawnid=%d", c->spellId, c->slot, c->inventorySlot, c->targetId); #endif // DIAG_SPELLSHELL // get the target const Item* s; QString targetName; int duration = 0; const Spell* spell = m_spells->spell(c->spellId); SpellItem *item; if (spell) duration = spell->calcDuration(m_player->level()) * 6; if (!spell || spell->targetType() != 6) { if (c->targetId && ((s = m_spawnShell->findID(tSpawn, c->targetId)))) targetName = s->name(); item = findSpell(c->spellId, c->targetId, targetName); } else { targetName = m_player->name(); item = findSpell(c->spellId); } if (item) { // exists item->update(c->spellId, spell, duration, m_player->id(), m_player->name(), c->targetId, targetName); emit changeSpell(item); } else { // new spell item = new SpellItem(); item->update(c->spellId, spell, duration, m_player->id(), m_player->name(), c->targetId, targetName); m_spellList.append(item); if ((m_spellList.count() > 0) && (!m_timer->isActive())) m_timer->start(1000 * pSEQPrefs->getPrefInt("SpellTimer", "SpellList", 6)); emit addSpell(item); m_lastPlayerSpell = item; } }
//slot for loading buffs when main char struct is loaded void SpellShell::buffLoad(const spellBuff* c) { #ifdef DIAG_SPELLSHELL seqDebug("Loading buff - id=%d.",c->spellid); #endif // DIAG_SPELLSHELL const Spell* spell = m_spells->spell(c->spellid); int duration = c->duration * 6; SpellItem *item = findSpell(c->spellid, m_player->id(), m_player->name()); if (item) { // exists item->update(c->spellid, spell, duration, 0, "Buff", m_player->id(), m_player->name()); emit changeSpell(item); } else { // new spell item = new SpellItem(); item->update(c->spellid, spell, duration, 0, "Buff", m_player->id(), m_player->name()); m_spellList.append(item); if ((m_spellList.count() > 0) && (!m_timer->isActive())) m_timer->start(1000 * pSEQPrefs->getPrefInt("SpellTimer", "SpellList", 6)); emit addSpell(item); } }
void cNewMagic::execSpell( P_CHAR pMage, UINT8 spell, UINT8 type, cUORxTarget* target ) { stNewSpell *sInfo = findSpell( spell ); P_PLAYER pp = dynamic_cast<P_PLAYER>(pMage); if( ( ( pp || !pp->isGM() ) && !checkReagents( pMage, spell ) ) || !useMana( pMage, spell ) ) { pMage->setCasting( false ); return; } if( !pp || !pp->isGM() ) useReagents( pMage, spell ); if( !checkSkill( pMage, spell, false ) ) { disturb( pMage, true, -1 ); return; } // Call the Spell Effect for this Spell if( sInfo->script ) sInfo->script->onSpellSuccess( pMage, spell, type, target ); // End Casting pMage->setCasting( false ); }
/*! This checks the needed skill to cast the specified spell. If scroll is true, the spell is cast from a scroll and if needed the scrolllow and scrollhigh values are used instead of the book values. This function returns true if the check was successful. */ bool cNewMagic::checkSkill( P_CHAR pMage, UINT8 spell, bool scroll ) { UINT16 lowSkill, highSkill; stNewSpell *sInfo = findSpell( spell ); if( !sInfo ) return false; // Cut the requirements for scrolls if needed if( scroll && SrvParams->cutScrollReq() ) { lowSkill = sInfo->scrolllow; highSkill = sInfo->scrollhigh; } else { lowSkill = sInfo->booklow; highSkill = sInfo->bookhigh; } // Do the skill check if( !pMage->checkSkill( MAGERY, lowSkill, highSkill ) ) { disturb( pMage, true, -1 ); return false; } // Skillcheck completed return true; }
void SpellShell::action(const uint8_t* data, size_t, uint8_t) { const actionStruct* a = (const actionStruct*)data; if (a->type != 0xe7) // only things to do if action is a spell return; const Item* s; QString targetName; if (a->target && ((s = m_spawnShell->findID(tSpawn, a->target)))) targetName = s->name(); SpellItem *item = findSpell(a->spell, a->target, targetName); if (item || (a->target == m_player->id())) { int duration = 0; const Spell* spell = m_spells->spell(a->spell); if (spell) duration = spell->calcDuration(a->level) * 6; QString casterName; if (a->source && ((s = m_spawnShell->findID(tSpawn, a->source)))) casterName = s->name(); if (item) { #ifdef DIAG_SPELLSHELL seqDebug("action - found - source=%d (lvl: %d) cast id=%d on target=%d causing %d damage", a->source, a->level, a->spell, a->target, a->damage); #endif // DIAG_SPELLSHELL item->update(a->spell, spell, duration, a->source, casterName, a->target, targetName); emit changeSpell(item); } else { // otherwise check for spells cast on us #ifdef DIAG_SPELLSHELL seqDebug("action - new - source=%d (lvl: %d) cast id=%d on target=%d causing %d damage", a->source, a->level, a->spell, a->target, a->damage); #endif // DIAG_SPELLSHELL // only way to get here is if there wasn't an existing spell, so... item = new SpellItem(); item->update(a->spell, spell, duration, a->source, casterName, a->target, targetName); m_spellList.append(item); if ((m_spellList.count() > 0) && (!m_timer->isActive())) m_timer->start(1000 * pSEQPrefs->getPrefInt("SpellTimer", "SpellList", 6)); emit addSpell(item); } } }
void SpellShell::buff(const uint8_t* data, size_t, uint8_t dir) { // we only care about the server if (dir == DIR_Client) return; const buffStruct* b = (const buffStruct*)data; // if this is the second server packet then ignore it if (b->spellid == 0xffffffff) return; #ifdef DIAG_SPELLSHELL seqDebug("Changing buff - id=%d from spawn=%d", b->spellid, b->spawnid); #endif // DIAG_SPELLSHELL const Spell* spell = m_spells->spell(b->spellid); // find the spell item SpellItem* item; const Item* s; QString targetName; if (!spell || spell->targetType() != 6) { if (b->spawnid && ((s = m_spawnShell->findID(tSpawn, b->spawnid)))) targetName = s->name(); item = findSpell(b->spellid, b->spawnid, targetName); } else item = findSpell(b->spellid); if (!item) return; if (b->changetype == 0x01) // removing buff deleteSpell(item); else if (b->changetype == 0x02) { // right now we only know how to find the updated duration item->setDuration(b->duration * 6); emit changeSpell(item); } }
/*! This function is used to check for the required mana to cast a specific spell. If the character does not have enough mana, a message is displayed above the characters head and it returns false. */ bool cNewMagic::checkMana( P_CHAR pMage, UINT8 spell ) { stNewSpell *sInfo = findSpell( spell ); bool enoughMana = false; if( sInfo && pMage->mana() >= sInfo->mana ) enoughMana = true; return enoughMana; }
/*! This function is used to consume the mana for a specific spell. If the character does not have enough mana, this function returns false. */ bool cNewMagic::useMana( P_CHAR pMage, UINT8 spell ) { /* // The character does not need any mana if( pMage->priv2() & 0x10 ) return true;*/ stNewSpell *sInfo = findSpell( spell ); if( !sInfo ) return false; if( pMage->mana() < sInfo->mana && pMage->objectType() == enPlayer ) { dynamic_cast<P_PLAYER>(pMage)->message( tr( "You don't have enough mana to cast this spell." ) ); return false; } pMage->setMana( pMage->mana() - sInfo->mana ); return true; }
void cNewMagic::castSpell( P_PLAYER pMage, UINT8 spell ) { P_PLAYER pp = dynamic_cast<P_PLAYER>(pMage); if( !pp || !pp->socket() ) return; stNewSpell *sInfo = findSpell( spell ); if( !sInfo ) { pp->socket()->sysMessage( tr( "This spell is either not implemented or invalid" ) ); return; } // Check if we can cast this spell if( !hasSpell( pMage, spell ) ) { pp->socket()->sysMessage( tr( "You don't know this spell." ) ); return; } // Check for required mana and required reagents, if not present: cancel casting if( !checkMana( pMage, spell ) ) { pp->message( tr( "You don't have enough mana to cast this spell." ) ); return; } if( !pp->isGM() && !checkReagents( pMage, spell ) ) return; if( pMage->isCasting() ) disturb( pMage, true ); // We start casting here pMage->setCasting( true ); // We get frozen here too pMage->setFrozen( true ); // Say the mantra // Type 0x0A : Spell pMage->talk( sInfo->mantra, pMage->saycolor() ); // This is a very interesting move of OSI // They send all action-packets the character has to perform in a row. // But they use the action 0xE9 instead of 0x10, maybe it's a bitmask // of 0xD9 but i am unsure. // This will repeat the animation until // We are done casting or until we are being // disturbed. //pMage->startRepeatedAction( sInfo->action, sInfo->actiondelay ); // Repeat every 1250 ms // I *do* know that this is a drawback but for now a single animation is exactly what we need. pMage->action( sInfo->action ); // Now we have to do the following: // We show the target cursor after a given amount of time (set in the scripts) // So what we are adding here is cEndCasting() supplying the Serial of our Mage // And the ID of our Spell. TempEffects::instance()->insert( new cEndCasting( pMage, spell, CT_BOOK, sInfo->delay ) ); }
/*! Just like useReagents this function is checking for required reagents on a characater to cast a spell. But unlike useReagents it wont really consume the reagents but just return false if the required reagents are not present. */ bool cNewMagic::checkReagents( P_CHAR pMage, UINT8 spell ) { // Check for each reagent. // So we dont need to loop trough all items over and over again we'll use ONE loop (will be a bit less clean) P_ITEM pPack = pMage->getBackpack(); stNewSpell *sInfo = findSpell( spell ); UINT8 ginseng = sInfo->reagents.ginseng; UINT8 bloodmoss = sInfo->reagents.bloodmoss; UINT8 mandrake = sInfo->reagents.mandrake; UINT8 blackpearl = sInfo->reagents.blackpearl; UINT8 spidersilk = sInfo->reagents.spidersilk; UINT8 garlic = sInfo->reagents.garlic; UINT8 nightshade = sInfo->reagents.nightshade; UINT8 sulfurash = sInfo->reagents.sulfurash; QPtrList< cItem > content = pPack->getContainment(); for( P_ITEM pItem = content.first(); pItem; pItem = content.next() ) { checkReagent( blackpearl, 0xF7A ) else checkReagent( bloodmoss, 0xF7B ) else checkReagent( garlic, 0xF84 ) else checkReagent( ginseng, 0xF85 ) else checkReagent( mandrake, 0xF86 ) else checkReagent( nightshade, 0xF88 ) else checkReagent( sulfurash, 0xF8C ) else checkReagent( spidersilk, 0xF8D ) } QStringList missing; if( ginseng > 0 ) missing.append( tr( "Ginseng" ) ); if( bloodmoss > 0 ) missing.append( tr( "Bloodmoss" ) ); if( mandrake > 0 ) missing.append( tr( "Mandrake" ) ); if( blackpearl > 0 ) missing.append( tr( "Black Pearls" ) ); if( spidersilk > 0 ) missing.append( tr( "Spider's Silk" ) ); if( garlic > 0 ) missing.append( tr( "Garlic" ) ); if( nightshade > 0 ) missing.append( tr( "Nightshade" ) ); if( sulfurash > 0 ) missing.append( tr( "Sulfurous Ash" ) ); bool enoughReagents = true; if( missing.count() > 0 ) { if( pMage->objectType() == enPlayer ) { P_PLAYER pp = dynamic_cast<P_PLAYER>(pMage); if( pp->socket() ) { pp->message( tr( "You don't have enough reagents." ) ); pp->socket()->sysMessage( tr( "You lack the following reagents: %1" ).arg( missing.join( ", ") ) ); } } enoughReagents = false; } return enoughReagents; }