📄 creature.cpp
字号:
Item *Creature::getItemAtLocation(int location) { int i; for(i = 0; i < Character::INVENTORY_COUNT; i++) { if((1 << i) == location) { if(equipped[i] < MAX_INVENTORY_SIZE) { return getInventory(equipped[i]); } else { return NULL; } } } return NULL;}// calculate the aggregate values based on equipped itemsvoid Creature::recalcAggregateValues() { // calculate the armor (0-100, 100-total protection) armor = (monster ? monster->getBaseArmor() : 0); for(int i = 0; i < Character::INVENTORY_COUNT; i++) { if(equipped[i] != MAX_INVENTORY_SIZE) { Item *item = inventory[equipped[i]]; if(item->getRpgItem()->getType() == RpgItem::ARMOR) { armor += item->getRpgItem()->getAction(); } } } armor += bonusArmor;}Item *Creature::getBestWeapon(float dist) { Item *item = getItemAtLocation(Character::INVENTORY_RIGHT_HAND); if(item && item->getRpgItem()->getDistance() >= dist) return item; item = getItemAtLocation(Character::INVENTORY_LEFT_HAND); if(item && item->getRpgItem()->getDistance() >= dist) return item; item = getItemAtLocation(Character::INVENTORY_WEAPON_RANGED); if(item && item->getRpgItem()->getDistance() >= dist) return item; return NULL;}// return the initiative for a battle round (0-10), the lower the faster the attack// the method can return negative numbers if the weapon skill is very high (-10 to 10)int Creature::getInitiative(Item *weapon, Spell *spell) { // use the speed skill float speed = getSkill(Constants::SPEED); // roll for half the luck speed += (getSkill(Constants::LUCK / 2) * rand()/RAND_MAX); if(spell) { speed -= spell->getSpeed(); speed += getSkill(spell->getSchool()->getSkill()); } else if(weapon) { // add weapon speed (bare hand attack is the fastest, unless weapon skill is very good) speed -= weapon->getRpgItem()->getSpeed(); if(weapon->getRpgItem()->getSkill() > -1) speed += getSkill(weapon->getRpgItem()->getSkill()); } // at this point a score of 150 is the fastest and 0 is the slowest // convert to 0-10 and flip (so 10 is the slowest) return(10 - (int)(speed / 15.0f));}// return number of projectiles that can be launched simultaniously// it is a function of speed, level, and weapon skill// this method returns a number from 1-10int Creature::getMaxProjectileCount(Item *item) { int n = (int)((double)(getSkill(Constants::SPEED) + (getLevel() * 10) + getSkill(item->getRpgItem()->getSkill())) / 30.0f); if(n <= 0) n = 1; return n;}// roll the die for the toHit number. returns a value between 0(total miss) - 100(best hit)int Creature::getToHit(Item *weapon) { float tohit = getSkill(Constants::COORDINATION) + getSkill(Constants::LUCK) / 2; if(weapon && weapon->getRpgItem()->getSkill() > -1) { tohit += getSkill(weapon->getRpgItem()->getSkill()); } else { tohit += getSkill(Constants::HAND_TO_HAND_COMBAT); } // so far the max score is 250 // tohit = 75% of tohit + (rand(25% of tohit)) float score = (0.75f * tohit) + ((0.25f * tohit) * rand()/RAND_MAX); // convert to 0-100 value return(int)(score / 2.5f);}// return the damage as:// rand(weapon + power + (skill - 50 % weapon))int Creature::getDamage(Item *weapon) { float damage = 0.0f; float baseDamage = (weapon ? weapon->getRpgItem()->getAction() : (getSkill(Constants::POWER) / 10)); damage = baseDamage; damage += (float)getSkill(Constants::POWER) / 10.0f; float skill = (weapon && weapon->getRpgItem()->getSkill() > -1 ? getSkill(weapon->getRpgItem()->getSkill()) : getSkill(Constants::HAND_TO_HAND_COMBAT)); damage = damage + (damage * ((skill - 50) / 100.0f) ); return(int)(damage * rand()/RAND_MAX);}/** take some damage*/bool Creature::takeDamage(int damage, int effect_type) { hp -= damage; // if creature dies start effect at its location if(hp > 0) startEffect(effect_type); else if(effect_type != Constants::EFFECT_GLOW) { scourge->getMap()->startEffect(getX(), getY(), getZ(), effect_type, (Constants::DAMAGE_DURATION * 4), getShape()->getWidth(), getShape()->getDepth()); } return(hp <= 0);}void Creature::startEffect(int effect_type, int duration) { // show an effect if(isEffectOn() && effect_type == getEffectType()) { return; } effect->deleteParticles(); resetDamageEffect(); setEffectType(effect_type); effectDuration = duration; // need to do this to make sure effect shows up scourge->getMap()->refresh();}/** Get the total value of armor worn and roll for the skill of each piece. Monsters' base armor is not rolled (ie. they're experts in using their natural armor.) */int Creature::getSkillModifiedArmor() { // calculate the armor (0-100, 100-total protection) int armor = (monster ? monster->getBaseArmor() : 0); armor += bonusArmor; for(int i = 0; i < Character::INVENTORY_COUNT; i++) { if(equipped[i] != MAX_INVENTORY_SIZE) { Item *item = inventory[equipped[i]]; if(item->getRpgItem()->getType() == RpgItem::ARMOR) { int skill_index = (item->getRpgItem()->getSkill() > -1 ? item->getRpgItem()->getSkill() : Constants::HAND_DEFEND); float skill = (float)getSkill(skill_index); int value = item->getRpgItem()->getAction(); // add (value + ((skill-50)% of value)) to armor armor += value + (int)( (float)value * ((skill - 50.0f) / 100.0f) ); } } } return armor;}// add exp after killing a creature// only called for charactersint Creature::addExperience(Creature *creature_killed) { int n = creature_killed->level - getLevel(); if( n < 1 ) n = 1; float m = (float)(creature_killed->getMonster()->getHp()) / 2.0f; int delta = n * 10 * (int)((m * rand()/RAND_MAX) + m); return addExperience(delta);}// add n exp points// only called for charactersint Creature::addExperience(int delta) { exp += delta; // level up? (mark as state, with graphic over character) if(exp >= expOfNextLevel && !getStateMod(Constants::leveled)) { setStateMod(Constants::leveled, true); availableSkillPoints = character->getSkillBonus(); } return delta;}// add money after a creature is killedint Creature::addMoney(Creature *creature_killed) { int n = creature_killed->level - getLevel(); if( n < 1 ) n = 1; // fixme: use creature_killed->getMonster()->getMoney() instead of 100.0f long delta = (long)n * (int)(50.0f * rand()/RAND_MAX); money += delta; return money;}void Creature::monsterInit() { // equip starting inventory for(int i = 0; i < getMonster()->getStartingItemCount(); i++) { addInventory(scourge->newItem(getMonster()->getStartingItem(i))); equipInventory(inventory_count - 1); } // add spells for(int i = 0; i < getMonster()->getStartingSpellCount(); i++) { addSpell(getMonster()->getStartingSpell(i)); } // set some skills for(int i = 0; i < Constants::SKILL_COUNT; i++) { setSkill(i, (int)((float)(10 * level) * rand()/RAND_MAX)); } // add some hp //startingHp = hp = 4 + (int)((float)(10.0f * level) * rand()/RAND_MAX); //startingMp = mp = 4 + (int)((float)(4.0f * level) * rand()/RAND_MAX); startingHp = hp = monster->getHp() + (int)((float)(10.0f * level) * rand()/RAND_MAX); startingMp = mp = monster->getMp() + (int)((float)(4.0f * level) * rand()/RAND_MAX);}// only for characters: leveling upbool Creature::incSkillMod(int index) { if(!availableSkillPoints || getSkill(index) + skillMod[index] >= character->getMaxSkillLevel(index)) return false; availableSkillPoints--; skillMod[index]++; return true;}bool Creature::decSkillMod(int index) { if(!skillMod[index]) return false; availableSkillPoints++; skillMod[index]--; return true;}void Creature::applySkillMod() { for(int i = 0; i < Constants::SKILL_COUNT; i++) { setSkill(i, getSkill(i) + skillMod[i]); skillMod[i] = 0; } level++; hp += character->getStartingHp(); mp += character->getStartingMp(); setStateMod(Constants::leveled, false); availableSkillPoints = 0; calculateExpOfNextLevel();}int Creature::getMaxHp() { if(isMonster()) { return monster->getHp(); // FIXME: incorrect, see monsterInit() } else { return(character->getStartingHp() * getLevel()); }}int Creature::getMaxMp() { if(isMonster()) { return monster->getMp(); // FIXME: incorrect, see monsterInit() } else { return(character->getStartingMp() * getLevel()); }}float Creature::getTargetAngle() { if(!targetCreature) return -1.0f; return Util::getAngle(getX(), getY(), getShape()->getWidth(), getShape()->getDepth(), getTargetCreature()->getX(), getTargetCreature()->getY(), getTargetCreature()->getShape()->getWidth(), getTargetCreature()->getShape()->getHeight());}// FIXME: O(n) but there aren't that many spells...bool Creature::isSpellMemorized(Spell *spell) { for(int i = 0; i < (int)spells.size(); i++) { if(spells[i] == spell) return true; } return false;}// FIXME: O(n) but there aren't that many spells...// return true if spell was added, false if creature already had this spellbool Creature::addSpell(Spell *spell) { for(vector<Spell*>::iterator e = spells.begin(); e != spells.end(); ++e) { Spell *thisSpell = *e; if(thisSpell == spell) return false; } spells.push_back(spell); return true;}void Creature::cancelTarget() { setTargetCreature(NULL); setTargetItem(0, 0, 0, NULL); setDistanceRange(0, 0); if(preActionTargetCreature) setTargetCreature(preActionTargetCreature); preActionTargetCreature = NULL; setAction(Constants::ACTION_NO_ACTION); if(isMonster()) setMotion(Constants::MOTION_LOITER); }void Creature::followTarget() { setSelXY(getTargetX(), getTargetY(), true);}// FIXME: make this more intelligent: potions, spells, scrolls, etc.void Creature::decideMonsterAction() { if(!isMonster()) return; // does monster need to be healed? // increase MP, AC or skill (via potion)? Creature *p = scourge->getParty()->getClosestPlayer(getX(), getY(), getShape()->getWidth(), getShape()->getDepth(), 20); if(p) { float dist = Constants::distance(getX(), getY(), getShape()->getWidth(), getShape()->getDepth(), p->getX(), p->getY(), p->getShape()->getWidth(), p->getShape()->getDepth()); // can monster use magic? if(getSpellCount()) { /* FIXME: Other considerations: -heal other monsters (by spell)? -attack by spell? -group attack vs. single target? For now, just assume that monsters only know attack spells where the target can be a single creature. Later when spell casting is smarter (by monsters) we'll need to implement some way to classify spells (attack, help (hp+,ac+,etc.), group vs. single target, etc.) */ for(int i = 0; i < getSpellCount(); i++) { Spell *spell = getSpell(i); if(spell->getMp() < getMp()) { if((spell->getDistance() == 1 && dist <= Constants::MIN_DISTANCE) || (spell->getDistance() > 1 && dist > Constants::MIN_DISTANCE)) { setAction(Constants::ACTION_CAST_SPELL, NULL, spell); setMotion(Constants::MOTION_MOVE_TOWARDS); setTargetCreature(p); return; } } } } // attack with item setMotion(Constants::MOTION_MOVE_TOWARDS); setTargetCreature(p); //setDistanceRange(0, Constants::MIN_DISTANCE); }}float Creature::getDistanceToTarget() { if(!hasTarget()) return 0.0f; if(getTargetCreature()) { return Constants::distance(getX(), getY(), getShape()->getWidth(), getShape()->getDepth(), getTargetCreature()->getX(), getTargetCreature()->getY(), getTargetCreature()->getShape()->getWidth(), getTargetCreature()->getShape()->getDepth()); } else if(getTargetItem()) { return Constants::distance(getX(), getY(), getShape()->getWidth(), getShape()->getDepth(), getTargetX(), getTargetY(), getTargetItem()->getShape()->getWidth(), getTargetItem()->getShape()->getDepth()); } else { return Constants::distance(getX(), getY(), getShape()->getWidth(), getShape()->getDepth(), getTargetX(), getTargetY(), 1, 1); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -