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 "GravityProcess.h"
00022
00023 #include "Actor.h"
00024 #include "AudioProcess.h"
00025 #include "CurrentMap.h"
00026 #include "Kernel.h"
00027 #include "World.h"
00028 #include "getObject.h"
00029
00030 #include "IDataSource.h"
00031 #include "ODataSource.h"
00032
00033 #include <cmath>
00034
00035
00036
00037 DEFINE_RUNTIME_CLASSTYPE_CODE(GravityProcess,Process);
00038
00039 GravityProcess::GravityProcess()
00040 : Process()
00041 {
00042
00043 }
00044
00045 GravityProcess::GravityProcess(Item* item, int gravity_)
00046 : xspeed(0), yspeed(0), zspeed(0)
00047 {
00048 assert(item);
00049
00050 gravity = gravity_;
00051 item_num = item->getObjId();
00052
00053 type = 0x203;
00054 }
00055
00056 void GravityProcess::init()
00057 {
00058 Item* item = getItem(item_num);
00059 assert(item);
00060
00061 item->setGravityPID(getPid());
00062
00063 Actor* actor = p_dynamic_cast<Actor*>(item);
00064 if (actor) {
00065 actor->setFallStart(actor->getZ());
00066 }
00067 }
00068
00069 void GravityProcess::move(int xs, int ys, int zs)
00070 {
00071 xspeed += xs;
00072 yspeed += ys;
00073 zspeed += zs;
00074 }
00075
00076 void GravityProcess::setGravity(int gravity_)
00077 {
00078
00080 if (gravity_ > gravity)
00081 gravity = gravity_;
00082 }
00083
00084 bool GravityProcess::run(uint32 framenum)
00085 {
00086
00087 Item* item = getItem(item_num);
00088 if (!item) {
00089 terminate();
00090 return false;
00091 }
00092
00093 Actor* actor = p_dynamic_cast<Actor*>(item);
00094 if (actor && actor->getFallStart() < actor->getZ()) {
00095 actor->setFallStart(actor->getZ());
00096 }
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107 sint32 ix,iy,iz;
00108 item->getLocation(ix, iy, iz);
00109 sint32 ixd,iyd,izd;
00110 item->getFootpadWorld(ixd, iyd, izd);
00111
00112 sint32 tx,ty,tz;
00113 tx = ix + xspeed;
00114 ty = iy + yspeed;
00115 tz = iz + zspeed;
00116
00117 bool clipped = false;
00118
00119
00120 #if 0
00121 if (tx < 0 && ix >= 0)
00122 {
00123 sint32 scale = (ix - tx)>>0x8;
00124 tx = 0;
00125 ty = iy + ((yspeed*scale)>>0x2000);
00126 tz = iz + ((zspeed*scale)>>0x2000);
00127 clipped = true;
00128 }
00129 if (ty < 0 && iy >= 0)
00130 {
00131 sint32 scale = (iy - ty)>>0x8;
00132 tx = ix + ((xspeed*scale)>>0x2000);
00133 ty = 0;
00134 tz = iz + ((zspeed*scale)>>0x2000);
00135 clipped = true;
00136 }
00137 if (tz < 0 && iz >= 0)
00138 {
00139 sint32 scale = (iz - tz)>>0x8;
00140 tx = ix + ((xspeed*scale)>>0x2000);
00141 ty = iy + ((yspeed*scale)>>0x2000);
00142 tz = 0;
00143 clipped = true;
00144 }
00145 #endif
00146
00147
00148
00149 ObjId hititemid;
00150 sint32 dist = item->collideMove(tx,ty,tz, false, false, &hititemid);
00151
00152 if (dist == 0 || clipped)
00153 {
00154
00155
00156 bool terminate = true;
00157 Item* hititem = getItem(hititemid);
00158 if(zspeed < -2 && !p_dynamic_cast<Actor*>(item))
00159 {
00160 #ifdef BOUNCE_DIAG
00161 pout << "item " << item_num << " bounce [" << framenum
00162 << "]: hit " << hititem->getObjId() << std::endl;
00163 #endif
00164
00165 sint32 hitx,hity,hitz;
00166 hititem->getLocation(hitx,hity,hitz);
00167 sint32 hitdx,hitdy,hitdz;
00168 hititem->getFootpadWorld(hitdx,hitdy,hitdz);
00169 sint32 endx,endy,endz;
00170 item->getLocation(endx,endy,endz);
00171
00172
00173
00174
00175 bool allow_land_bounce = ((0-zspeed) > 2*gravity);
00176 if(endz == hitz + hitdz &&
00177 (allow_land_bounce || !hititem->getShapeInfo()->is_land()))
00178 {
00179
00180 terminate = false;
00181 #ifdef BOUNCE_DIAG
00182 int xspeedold = xspeed;
00183 int yspeedold = yspeed;
00184 int zspeedold = zspeed;
00185 #endif
00186 zspeed = 0-zspeed/3;
00187 int approx_v = abs(xspeed) + abs(yspeed) + zspeed;
00188
00189
00190
00191 double heading_r = atan2((double)yspeed, (double)xspeed);
00192 double deltah_r = static_cast<double>(rand())
00193 * M_PI / RAND_MAX - M_PI/2;
00194 #ifdef BOUNCE_DIAG
00195 double headingold_r = heading_r;
00196 #endif
00197 heading_r += deltah_r;
00198 if(heading_r > M_PI) heading_r -= 2*M_PI;
00199 if(heading_r < -M_PI) heading_r += 2*M_PI;
00200 yspeed += static_cast<int>(sin(heading_r) *
00201 static_cast<double>(approx_v));
00202 xspeed += static_cast<int>(cos(heading_r) *
00203 static_cast<double>(approx_v));
00204
00205 if(hititem->getShapeInfo()->is_land()) {
00206
00207
00208
00209 xspeed /= 4;
00210 yspeed /= 4;
00211 zspeed /= 2;
00212 if(zspeed == 0) terminate = true;
00213 } else {
00214
00215
00216
00217 if(abs(yspeed) > 2) yspeed /= 2;
00218 if(abs(xspeed) > 2) xspeed /= 2;
00219 }
00220 #ifdef BOUNCE_DIAG
00221 pout << "item " << item_num << " bounce [" << framenum
00222 << "]: speed was (" << xspeedold << ","
00223 << yspeedold << "," << zspeedold << ") new zspeed "
00224 << zspeed << " heading " << headingold_r
00225 << " impulse " << heading_r << " ("
00226 << (xspeed-xspeedold) << "," << (yspeed-yspeedold)
00227 << "), terminate: " << terminate << std::endl;
00228 #endif
00229 } else {
00230 #ifdef BOUNCE_DIAG
00231 pout << "item " << item_num << " bounce [" << framenum
00232 << "]: no bounce" << std::endl;
00233 #endif
00234 }
00235 } else {
00236 #ifdef BOUNCE_DIAG
00237 pout << "item " << item_num << " bounce [" << framenum
00238 << "]: slow hit" << std::endl;
00239 #endif
00240 }
00241 if(terminate) {
00242 item->clearFlag(Item::FLG_BOUNCING);
00243 terminateDeferred();
00244 }
00245 else {
00246 item->setFlag(Item::FLG_BOUNCING);
00247 }
00248 }
00249 else
00250 zspeed -= gravity;
00251
00252 #if 0
00253
00254 CurrentMap* cm = World::get_instance()->getCurrentMap();
00255
00256
00257
00258 if (izd == 0) izd = 8;
00259
00260
00261 uint32 shapeflags = item->getShapeInfo()->flags;
00262
00263 bool valid = true;
00264 int curz = iz;
00265 int zstepsize = izd / 2;
00266 if (tz < iz) zstepsize = -zstepsize;
00267 if (tz == iz) {
00268 valid = cm->isValidPosition(tx,ty,tz,ixd,iyd,izd,shapeflags,
00269 item_num,0,0);
00270 } else {
00271 do {
00272 curz += zstepsize;
00273 int curx = ix + ((tx - ix) * (curz-iz))/(tz-iz);
00274 int cury = iy + ((ty - iy) * (curz-iz))/(tz-iz);
00275
00276 if ((zstepsize > 0 && curz > tz) || (zstepsize < 0 && curz < tz))
00277 curz = tz;
00278
00279 valid &= cm->isValidPosition(curx, cury, curz, ixd, iyd, izd,
00280 shapeflags,item_num, 0, 0);
00281 } while (valid && curz != tz);
00282 }
00283
00284 if (valid) {
00285 item->move(tx, ty, tz);
00286
00287
00288 zspeed -= gravity;
00289 } else {
00291 if (tz != iz) {
00292 curz -= zstepsize;
00293 if ((zstepsize > 0 && curz < iz) || (zstepsize < 0 && curz > iz))
00294 curz = iz;
00295
00296 int curx = ix + ((tx - ix) * (curz-iz))/(tz-iz);
00297 int cury = iy + ((ty - iy) * (curz-iz))/(tz-iz);
00298
00299 if (cm->isValidPosition(curx, cury, curz, ixd, iyd, izd,
00300 shapeflags, item_num, 0, 0))
00301 {
00302 item->move(curx, cury, curz);
00303 }
00304 }
00305
00307
00308 terminate();
00309 }
00310 #endif
00311 return true;
00312 }
00313
00314
00315 void GravityProcess::terminate()
00316 {
00317
00318 Item* item = getItem(item_num);
00319 if (item) {
00320 item->setGravityPID(0);
00321
00322
00323 item->clearFlag(Item::FLG_BOUNCING);
00324 }
00325
00326 Process::terminate();
00327
00328
00329
00330
00331
00332 Actor* actor = p_dynamic_cast<Actor*>(item);
00333 if (actor && !actor->isDead()) {
00334
00335
00336
00337 int height = actor->getFallStart() - actor->getZ();
00338
00339 if (height >= 80) {
00340 int damage = 0;
00341
00342 if (height < 104) {
00343
00344 damage = (height - 72)/4;
00345 } else {
00346
00347 damage = actor->getHP();
00348 }
00349
00350 actor->receiveHit(0, actor->getDir(), damage,
00351 WeaponInfo::DMG_FALLING|WeaponInfo::DMG_PIERCE);
00352
00353
00354 AudioProcess* audioproc = AudioProcess::get_instance();
00355 if (audioproc) audioproc->playSFX(51, 250, item_num, 0);
00356 }
00357
00358 if (!actor->isDead() && actor->getLastAnim() != Animation::die) {
00359
00360
00361 Kernel::get_instance()->killProcesses(item_num, 0xF0, false);
00362 ProcId lpid = actor->doAnim(Animation::land, 8);
00363
00364 if (actor->isInCombat()) {
00365
00366
00367 ProcId spid = actor->doAnim(Animation::combatStand, 8);
00368 Process* sp = Kernel::get_instance()->getProcess(spid);
00369 sp->waitFor(lpid);
00370 }
00371 }
00372 }
00373 }
00374
00375 void GravityProcess::dumpInfo()
00376 {
00377 Process::dumpInfo();
00378
00379 pout << "gravity: " << gravity << ", speed: (" << xspeed << ","
00380 << yspeed << "," << zspeed << ")" << std::endl;
00381 }
00382
00383
00384 void GravityProcess::saveData(ODataSource* ods)
00385 {
00386 Process::saveData(ods);
00387
00388 ods->write4(static_cast<uint32>(gravity));
00389 ods->write4(static_cast<uint32>(xspeed));
00390 ods->write4(static_cast<uint32>(yspeed));
00391 ods->write4(static_cast<uint32>(zspeed));
00392 }
00393
00394 bool GravityProcess::loadData(IDataSource* ids, uint32 version)
00395 {
00396 if (!Process::loadData(ids, version)) return false;
00397
00398 gravity = static_cast<int>(ids->read4());
00399 xspeed = static_cast<int>(ids->read4());
00400 yspeed = static_cast<int>(ids->read4());
00401 zspeed = static_cast<int>(ids->read4());
00402
00403 return true;
00404 }