📄 creature.cpp
字号:
/*************************************************************************** creature.cpp - description ------------------- begin : Sat May 3 2003 copyright : (C) 2003 by Gabor Torok email : cctorok@yahoo.com ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/#include "creature.h"/** * Formations are defined by 4 set of coordinates in 2d space. * These starting positions assume dir=Constants::MOVE_UP */static const Sint16 layout[][4][2] = { { {0, 0}, {-1, 1}, {1, 1}, {0, 2}}, // DIAMOND_FORMATION { {0, 0}, {-1, 1}, {0, 1}, {-1, 2}}, // STAGGERED_FORMATION { {0, 0}, {1, 0}, {1, 1}, {0, 1}}, // SQUARE_FORMATION { {0, 0}, {0, 1}, {0, 2}, {0, 3}}, // ROW_FORMATION { {0, 0}, {-2, 2}, {0, 2}, {2, 2}}, // SCOUT_FORMATION { {0, 0}, {-1, 1}, {1, 1}, {0, 3}} // CROSS_FORMATION};Creature::Creature(Scourge *scourge, Character *character, char *name) { this->scourge = scourge; this->character = character; this->monster = NULL; this->name = name; this->model_name = character->getModelName(); this->skin_name = character->getSkinName(); sprintf(description, "%s the %s", name, character->getName()); this->speed = 50; this->motion = Constants::MOTION_MOVE_TOWARDS; this->armor=0; this->bonusArmor=0; this->thirst=10; this->hunger=10; this->shape = scourge->getShapePalette()->getCreatureShape(model_name, skin_name); commonInit(); }Creature::Creature(Scourge *scourge, Monster *monster) { this->scourge = scourge; this->character = NULL; this->monster = monster; this->name = monster->getType(); this->model_name = monster->getModelName(); this->skin_name = monster->getSkinName(); sprintf(description, "You see %s", monster->getType()); this->speed = monster->getSpeed(); this->motion = Constants::MOTION_LOITER; this->armor = monster->getBaseArmor(); this->bonusArmor=0; this->shape = scourge->getShapePalette()->getCreatureShape(model_name, skin_name, monster->getScale(), monster->getWidth(), monster->getDepth(), monster->getHeight()); commonInit(); monsterInit();}void Creature::commonInit() { this->x = this->y = this->z = 0; this->dir = Constants::MOVE_UP; this->next = NULL; this->formation = DIAMOND_FORMATION; this->index = 0; this->tx = this->ty = -1; this->selX = this->selY = -1; this->quadric = gluNewQuadric(); this->inventory_count = 0; for(int i = 0; i < Character::INVENTORY_COUNT; i++) { equipped[i] = MAX_INVENTORY_SIZE; } for(int i = 0; i < Constants::SKILL_COUNT; i++) { skillMod[i] = skillBonus[i] = 0; } this->stateMod = 0; this->level = 1; this->exp = 0; this->hp = 0; this->mp = 0; this->startingHp = 0; this->startingMp = 0; this->ac = 0; this->targetCreature = NULL; this->targetX = this->targetY = this->targetZ = 0; this->targetItem = NULL; this->lastTick = 0; this->moveRetrycount = 0; this->cornerX = this->cornerY = -1; this->lastTurn = 0; this->damageEffectCounter = 0; this->effectDuration = Constants::DAMAGE_DURATION; this->effect = new Effect(scourge, scourge->getShapePalette(), shape); this->effectType = Constants::EFFECT_FLAMES; this->facingDirection = Constants::MOVE_UP; // good init ? this->availableSkillPoints = 0; this->minRange = this->maxRange = 0; this->failedToMoveWithinRangeAttemptCount = 0; this->action = Constants::ACTION_NO_ACTION; this->actionItem = NULL; this->actionSpell = NULL; this->preActionTargetCreature = NULL; // Yes, monsters have inventory weight issues too inventoryWeight = 0.0f; for(int i = 0; i < inventory_count; i++) { inventoryWeight += inventory[i]->getRpgItem()->getWeight(); } this->money = this->level * (int)(10.0f * rand()/RAND_MAX); calculateExpOfNextLevel();}void Creature::calculateExpOfNextLevel() { if(isMonster()) return; expOfNextLevel = 0; for(int i = 0; i < level; i++) { expOfNextLevel += ((i + 1) * character->getLevelProgression()); }}Creature::~Creature(){ delete effect; // do this before deleting the shape scourge->getShapePalette()->decrementSkinRefCount(skin_name); delete shape;}// moving monsters onlybool Creature::move(Uint16 dir, Map *map) { if(character) return false; // a hack for runaway creatures if(!(x > 10 && x < MAP_WIDTH - 10 && y > 10 && y < MAP_DEPTH - 10)) { if(monster) cerr << "hack for " << getName() << endl; return false; } int nx = x; int ny = y; int nz = z; switch(dir) { case Constants::MOVE_UP: ny = y - 1; break; case Constants::MOVE_DOWN: ny = y + 1; break; case Constants::MOVE_LEFT: nx = x - 1; break; case Constants::MOVE_RIGHT: nx = x + 1; break; } setFacingDirection(dir); map->removeCreature(x, y, z); Location *loc = map->getBlockingLocation(getShape(), nx, ny, nz); Item *item = NULL; if(loc) item = loc->item; if(!loc || (item && !item->isBlocking())) { // pick up item if(item) { addInventory(item); char message[100]; sprintf(message, "%s picks up %s.", getName(), item->getItemName()); scourge->getMap()->addDescription(message); } map->setCreature(nx, ny, nz, this); ((MD2Shape*)shape)->setDir(dir); moveTo(nx, ny, nz); setDir(dir); return true; } else { // move back map->setCreature(x, y, z, this); return false; }}bool Creature::follow(Map *map) { // find out where the creature should be relative to the formation Sint16 px, py, pz; getFormationPosition(&px, &py, &pz); setSelXY(px, py); return true; }void Creature::setSelXY(int x, int y, bool force) { selX = x; selY = y; moveRetrycount = 0; setMotion(Constants::MOTION_MOVE_TOWARDS); if(force) { tx = ty = -1; } // if we're trying to move within a range, try a number of times adjustMovementToRange();}/** Return true only if a range is specified and we're within it. */bool Creature::isInRange() { if(maxRange > 0) { float d = getDistanceToTarget(); //cerr << "\tisInRange: dist=" << d << " min=" << minRange << " max=" << maxRange << endl; return(d >= minRange && d < maxRange); } return false;}/** Check that we're within range (if range specified). If not, try n times, then wait n times before trying again.*/void Creature::adjustMovementToRange() { if(maxRange <= 0 || !hasTarget()) return; float d = getDistanceToTarget(); bool inRange = (d >= minRange && d < maxRange); if(inRange) { // we're in range: stop moving failedToMoveWithinRangeAttemptCount = 0; stopMoving(); return; } else if(failedToMoveWithinRangeAttemptCount < MAX_FAILED_MOVE_ATTEMPTS) { // we're not in range: move away if too close failedToMoveWithinRangeAttemptCount++; // if too close, move away if(d < minRange) { Sint16 nz; findCorner(&cornerX, &cornerY, &nz); setMotion(Constants::MOTION_MOVE_AWAY); } return; } else if(failedToMoveWithinRangeAttemptCount < MAX_FAILED_MOVE_ATTEMPTS * 2) { // we're still not in range: return true to continue attacks and not try to position forever failedToMoveWithinRangeAttemptCount++; return; } else { // we're still not in range but continue to try to position creature failedToMoveWithinRangeAttemptCount = 0; return; }}void Creature::setTargetCreature(Creature *c) { targetCreature = c; if(!c) { setDistanceRange(0, 0); }}void Creature::stopMoving() { bestPathPos = (int)bestPath.size(); selX = selY = -1;}bool Creature::moveToLocator(Map *map) { // Don't move when attacking... // this is actually wrong, the method should not be called in this // case, but the code is simpler this way. (Returning false is // is incorrect.) if(((MD2Shape*)getShape())->getAttackEffect()) return false; // don't move when in range if(isInRange()) return false; bool moved = false; if(selX > -1) { // take a step if(getMotion() == Constants::MOTION_MOVE_AWAY){ //if(this == scourge->getParty()->getParty(1)) cerr << "Barlett: moving away! attempt=" << failedToMoveWithinRangeAttemptCount << endl; moved = gotoPosition(map, cornerX, cornerY, 0, "cornerXY"); } else { //if(this == scourge->getParty()->getParty(1)) cerr << "Barlett: moving towards! attempt=" << failedToMoveWithinRangeAttemptCount << " min=" << minRange << " max=" << maxRange << endl; moved = gotoPosition(map, selX, selY, 0, "selXY"); } // if we've no more steps if((int)bestPath.size() <= bestPathPos && selX > -1) { // if we're not there yet, and it's possible to stand there, recalc steps if(!(selX == getX() && selY == getY()) && map->shapeFits(getShape(), selX, selY, -1) && moveRetrycount < MAX_MOVE_RETRY) { // don't keep trying forever moveRetrycount++; tx = ty = -1; } else { // do this so the animation switches to "stand" stopMoving(); } // if this is the player, return to regular movement if(this == scourge->getParty()->getPlayer()) { scourge->getParty()->setPartyMotion(Constants::MOTION_MOVE_TOWARDS); } } } return moved;}bool Creature::anyMovesLeft() { return(selX > -1 && (int)bestPath.size() > bestPathPos); }bool Creature::gotoPosition(Map *map, Sint16 px, Sint16 py, Sint16 pz, char *debug) { // If the target moved, get the best path to the location if(!(tx == px && ty == py)) { // cerr << getName() << " - " << debug << " steps left: " << // ((int)bestPath.size() - bestPathPos) << " out of " << (int)bestPath.size() << endl; tx = px; ty = py; bestPathPos = 1; // skip 0th position; it's the starting location Util::findPath(getX(), getY(), getZ(), px, py, pz, &bestPath, scourge->getMap(), getShape()); } if((int)bestPath.size() > bestPathPos) { // take a step on the bestPath Location location = bestPath[bestPathPos]; // if we can't step there, someone else has moved there ahead of us Uint16 oldDir = dir; //dir = next->getDir(); if(getX() < location.x) dir = Constants::MOVE_RIGHT; else if(getX() > location.x) dir = Constants::MOVE_LEFT; else if(getY() < location.y) dir = Constants::MOVE_DOWN; else if(getY() > location.y) dir = Constants::MOVE_UP; setFacingDirection(dir); Location *position = map->moveCreature(getX(), getY(), getZ(), location.x, location.y, getZ(), this); if(!position) { bestPathPos++; moveTo(location.x, location.y, getZ()); ((MD2Shape*)shape)->setDir(dir); return true; } else { dir = oldDir; /* commented out: this doesn't really work... the player will block forever if 'creature' can't move // if another party member is blocking the player, // make them move out of the way Creature *creature = position->creature; if(this == scourge->getParty()->getPlayer() && creature && creature->character && scourge->getParty()->getPlayer() != creature) { creature->moveRetrycount++; if(creature->moveRetrycount < MAX_MOVE_RETRY) { Sint16 nz; creature->findCorner(&creature->cornerX, &creature->cornerY, &nz); // creature->gotoPosition(map, nx, ny, nz, "corner"); creature->setMotion(Constants::MOTION_MOVE_AWAY); } else { // do this so the animation switches to "stand" creature->stopMoving(); } } else { */ // if we're not at the destination, but it's possible to stand there
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -