00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "pent_include.h"
00020
00021 #include "CombatProcess.h"
00022 #include "Actor.h"
00023 #include "CurrentMap.h"
00024 #include "World.h"
00025 #include "UCList.h"
00026 #include "LoopScript.h"
00027 #include "WeaponInfo.h"
00028 #include "AnimationTracker.h"
00029 #include "Kernel.h"
00030 #include "DelayProcess.h"
00031 #include "PathfinderProcess.h"
00032 #include "ShapeInfo.h"
00033 #include "MonsterInfo.h"
00034 #include "getObject.h"
00035 #include "LoiterProcess.h"
00036 #include "AmbushProcess.h"
00037
00038 #include "IDataSource.h"
00039 #include "ODataSource.h"
00040
00041
00042 DEFINE_RUNTIME_CLASSTYPE_CODE(CombatProcess,Process);
00043
00044 CombatProcess::CombatProcess() : Process()
00045 {
00046
00047 }
00048
00049 CombatProcess::CombatProcess(Actor* actor_)
00050 {
00051 assert(actor_);
00052 item_num = actor_->getObjId();
00053
00054 type = 0x00F2;
00055 target = 0;
00056 fixedTarget = 0;
00057 combatmode = CM_WAITING;
00058 }
00059
00060 void CombatProcess::terminate()
00061 {
00062 Actor* a = getActor(item_num);
00063 if (a)
00064 a->clearActorFlag(Actor::ACT_INCOMBAT);
00065
00066 Process::terminate();
00067 }
00068
00069 bool CombatProcess::run(const uint32 )
00070 {
00071 Actor* a = getActor(item_num);
00072 if (!(a->getFlags() & Item::FLG_FASTAREA)) return false;
00073
00074 Actor* t = getActor(target);
00075
00076 if (!t || !isValidTarget(t)) {
00077
00078
00079 target = seekTarget();
00080
00081 if (!target) {
00082 waitForTarget();
00083 return false;
00084 }
00085
00086 pout << "[COMBAT " << item_num << "] target found: "
00087 << target << std::endl;
00088 combatmode = CM_WAITING;
00089 }
00090
00091 int targetdir = getTargetDirection();
00092 if (a->getDir() != targetdir) {
00093 turnToDirection(targetdir);
00094 return false;
00095 }
00096
00097 if (inAttackRange()) {
00098 combatmode = CM_ATTACKING;
00099
00100 pout << "[COMBAT " << item_num << "] target (" << target
00101 << ") in range" << std::endl;
00102
00103 bool hasidle1 = a->hasAnim(Animation::idle1);
00104 bool hasidle2 = a->hasAnim(Animation::idle2);
00105
00106 if ((hasidle1 || hasidle2) && (std::rand()%5) == 0) {
00107
00108
00109 Animation::Sequence idleanim;
00110
00111 if (!hasidle1) {
00112 idleanim = Animation::idle2;
00113 } else if (!hasidle2) {
00114 idleanim = Animation::idle1;
00115 } else {
00116 if (std::rand()%2)
00117 idleanim = Animation::idle1;
00118 else
00119 idleanim = Animation::idle2;
00120 }
00121 uint16 idlepid = a->doAnim(idleanim, 8);
00122 waitFor(idlepid);
00123 } else {
00124
00125
00126 ProcId attackanim = a->doAnim(Animation::attack, 8);
00127
00128
00129 int dex = a->getDex();
00130 if (dex < 25) {
00131 int recoverytime = 3 * (25 - dex);
00132 Process* waitproc = new DelayProcess(recoverytime);
00133 ProcId waitpid = Kernel::get_instance()->addProcess(waitproc);
00134 waitproc->waitFor(attackanim);
00135 waitFor(waitpid);
00136 } else {
00137 waitFor(attackanim);
00138 }
00139 }
00140
00141 return false;
00142 } else if (combatmode != CM_PATHFINDING) {
00143
00144
00145 Process* pfproc = new PathfinderProcess(a, target, true);
00146
00147 waitFor(Kernel::get_instance()->addProcess(pfproc));
00148 combatmode = CM_PATHFINDING;
00149 return false;
00150 }
00151
00152 combatmode = CM_WAITING;
00153 waitForTarget();
00154 return false;
00155 }
00156
00157 ObjId CombatProcess::getTarget()
00158 {
00159 Actor* t = getActor(target);
00160
00161 if (!t || !isValidTarget(t))
00162 target = 0;
00163
00164 return target;
00165 }
00166
00167 void CombatProcess::setTarget(ObjId newtarget)
00168 {
00169 if (fixedTarget == 0) {
00170 fixedTarget = newtarget;
00171 }
00172
00173 target = newtarget;
00174 }
00175
00176 bool CombatProcess::isValidTarget(Actor* target)
00177 {
00178 assert(target);
00179 Actor* a = getActor(item_num);
00180 if (!a) return false;
00181
00182
00183 if (target == a) return false;
00184
00185
00186 if (!(target->getFlags() & Item::FLG_FASTAREA)) return false;
00187
00188
00189 if (target->isDead()) return false;
00190
00191
00192 if (target->getActorFlags() & Actor::ACT_FEIGNDEATH) {
00193
00194 if ((a->getDefenseType() & WeaponInfo::DMG_UNDEAD) ||
00195 (a->getShape() == 96)) return false;
00196 }
00197
00198
00199 return true;
00200 }
00201
00202 bool CombatProcess::isEnemy(Actor* target)
00203 {
00204 assert(target);
00205
00206 Actor* a = getActor(item_num);
00207 if (!a) return false;
00208
00209 return ((a->getEnemyAlignment() & target->getAlignment()) != 0);
00210 }
00211
00212 ObjId CombatProcess::seekTarget()
00213 {
00214 Actor* a = getActor(item_num);
00215 if (!a) return 0;
00216
00217 if (fixedTarget) {
00218 Actor* t = getActor(fixedTarget);
00219 if (t && isValidTarget(t))
00220 return fixedTarget;
00221 }
00222
00223 UCList itemlist(2);
00224 LOOPSCRIPT(script, LS_TOKEN_TRUE);
00225 CurrentMap* cm = World::get_instance()->getCurrentMap();
00226 cm->areaSearch(&itemlist, script, sizeof(script), a, 768, false);
00227
00228 for (unsigned int i = 0; i < itemlist.getSize(); ++i) {
00229 Actor* t = getActor(itemlist.getuint16(i));
00230
00231 if (t && isValidTarget(t) && isEnemy(t)) {
00232
00233 return itemlist.getuint16(i);
00234 }
00235 }
00236
00237
00238 return 0;
00239 }
00240
00241 int CombatProcess::getTargetDirection()
00242 {
00243 Actor* a = getActor(item_num);
00244 Actor* t = getActor(target);
00245
00246 return a->getDirToItemCentre(*t);
00247 }
00248
00249 void CombatProcess::turnToDirection(int direction)
00250 {
00251 Actor* a = getActor(item_num);
00252 int curdir = a->getDir();
00253 int step = 1;
00254 if ((curdir - direction + 8) % 8 < 4) step = -1;
00255 Animation::Sequence turnanim = Animation::combatStand;
00256
00257 ProcId prevpid = 0;
00258 bool done = false;
00259
00260 for (int dir = curdir; !done; ) {
00261 ProcId animpid = a->doAnim(turnanim, dir);
00262
00263 if (dir == direction) done = true;
00264
00265 if (prevpid) {
00266 Process* proc = Kernel::get_instance()->getProcess(animpid);
00267 assert(proc);
00268 proc->waitFor(prevpid);
00269 }
00270
00271 prevpid = animpid;
00272
00273 dir = (dir + step + 8) % 8;
00274 }
00275
00276 if (prevpid) waitFor(prevpid);
00277 }
00278
00279 bool CombatProcess::inAttackRange()
00280 {
00281 Actor* a = getActor(item_num);
00282 ShapeInfo* shapeinfo = a->getShapeInfo();
00283 MonsterInfo* mi = 0;
00284 if (shapeinfo) mi = shapeinfo->monsterinfo;
00285
00286 if (mi && mi->ranged)
00287 return true;
00288
00289 AnimationTracker tracker;
00290 if (!tracker.init(a, Animation::attack, a->getDir(), 0))
00291 return false;
00292
00293 while (tracker.step()) {
00294 if (tracker.hitSomething()) break;
00295 }
00296
00297 ObjId hit = tracker.hitSomething();
00298 if (hit == target) return true;
00299
00300 return false;
00301 }
00302
00303 void CombatProcess::waitForTarget()
00304 {
00305 Actor* a = getActor(item_num);
00306 ShapeInfo* shapeinfo = a->getShapeInfo();
00307 MonsterInfo* mi = 0;
00308 if (shapeinfo) mi = shapeinfo->monsterinfo;
00309
00310 if (mi && mi->shifter && a->getMapNum() != 43 && (std::rand()%2) == 0 ) {
00311
00312
00313
00314
00315 ProcId shift1pid = a->doAnim(static_cast<Animation::Sequence>(20), 8);
00316 Process* ambushproc = new AmbushProcess(a);
00317 ProcId ambushpid = Kernel::get_instance()->addProcess(ambushproc);
00318 ProcId shift2pid = a->doAnim(static_cast<Animation::Sequence>(21), 8);
00319 Process* shift2proc = Kernel::get_instance()->getProcess(shift2pid);
00320
00321 ambushproc->waitFor(shift1pid);
00322 shift2proc->waitFor(ambushpid);
00323 waitFor(shift2proc);
00324
00325 } else {
00326 waitFor(Kernel::get_instance()->addProcess(new LoiterProcess(a, 1)));
00327 }
00328 }
00329
00330 void CombatProcess::dumpInfo()
00331 {
00332 Process::dumpInfo();
00333 pout << "Target: " << target << std::endl;
00334 }
00335
00336 void CombatProcess::saveData(ODataSource* ods)
00337 {
00338 Process::saveData(ods);
00339
00340 ods->write2(target);
00341 ods->write2(fixedTarget);
00342 ods->write1(static_cast<uint8>(combatmode));
00343 }
00344
00345 bool CombatProcess::loadData(IDataSource* ids, uint32 version)
00346 {
00347 if (!Process::loadData(ids, version)) return false;
00348
00349 target = ids->read2();
00350 fixedTarget = ids->read2();
00351 combatmode = static_cast<CombatMode>(ids->read1());
00352
00353 return true;
00354 }