void KGrFigure::walkDown(int WALKDELAY, int FALLDELAY) { if (hangAtPole() || (! canStand())) { // On bar or no firm ground underneath: so must fall. initFall (FALL2, FALLDELAY); } else { actualPixmap = (actualPixmap == CLIMB1) ? CLIMB2 : CLIMB1; if (walkCounter++ < 4) { // Not end of 4-step cycle: move one step down, if possible. if (canWalkDown()) { rely += STEP; absy += STEP; } walkTimer->start ((WALKDELAY * NSPEED) / speed, TRUE); } else { // End of 4-step cycle: move down to next cell, if possible. if (canWalkDown()) { y++; } // Always reset position, in case we are stuck partly into a brick. rely = 0; absy = y*16; // Must be able to halt at a pole when going down. if (! (canStand() || hangAtPole())) initFall(FALL2, FALLDELAY); // kein Halt....urgs else // Wait for caller to set next direction. status = STANDING; } } }
void KGrFigure::walkRight(int WALKDELAY, int FALLDELAY) { if (walkCounter++) { // wenn 0, soll sich Figur nur umdrehen if (++actualPixmap % 4) { // wenn true, dann ist kein vollständiger Schritt gemacht if (canWalkRight()) { relx += STEP; absx += STEP; // nur vorwärts gehen, wenn es auch möglich ist } walkTimer->start ((WALKDELAY * NSPEED) / speed, TRUE); } else { actualPixmap -= 4; // Schritt war vollendet if (canWalkRight()) { x++; } //gehe entgültig nach rechts // Always reset position, in case we are stuck partly into a brick. relx = 0; absx = x*16; if (!(canStand()||hangAtPole())) // kein Halt mehr...arrrgghhh initFall (FALL2, FALLDELAY); else status = STANDING; // Figur hat Halt } } else { status = STANDING; // Figur sollte sich nur Umdrehen. } }
void KGrFigure::walkLeft (int WALKDELAY, int FALLDELAY) { // If counter != 0, the figure is walking, otherwise he is turning around. if (walkCounter++ != 0) { // Change to the next pixmap in the animation. if ((++actualPixmap%4) != 0) { // Not end of 4-pixmap cycle: move one step left, if possible. if (canWalkLeft()) { relx -= STEP; absx -=STEP; } walkTimer->start ((WALKDELAY * NSPEED) / speed, TRUE); } else { // End of 4-pixmap cycle: start again, in next cell if possible. actualPixmap -= 4; if (canWalkLeft()) { x--; } // Always reset position, in case we are stuck partly into a brick. relx = 0; absx = x*16; // If cannot stand or hang, start fall, else await next assignment. if (! (canStand() || hangAtPole())) initFall (FALL1, FALLDELAY); else status = STANDING; // Caller should set next direction. } } else { status = STANDING; // The figure is turning around. } }
Direction KGrEnemy::searchbestway(int ew,int eh,int hw,int hh) { Direction dirn; if ((*playfield)[x][y]->whatIam() == USEDHOLE) // Could not get out of return UP; // hole (eg. brick above // closed): keep trying. if (!canStand() && // Cannot stand, !hangAtPole() && // not on pole, not !standOnEnemy() && // walking on friend and !((*playfield)[x][y+1]->whatIam() == HOLE)) // not just out of hole, return DOWN; // so must fall. switch (searchStrategy) { // Traditional search strategy. case LOW: dirn = STAND; if (eh == hh) { // Hero on same row. dirn = lowGetHero (ew, eh, hw); } if (dirn != STAND) return (dirn); // Can go towards him. if (eh >= hh) { // Hero above enemy. dirn = lowSearchUp (ew, eh, hh); // Find a way up. } else { // Hero below enemy. dirn = lowSearchDown (ew, eh, hh); // Find way down to him. if (dirn == STAND) { dirn = lowSearchUp (ew, eh, hh); // No go: try up. } } if (dirn == STAND) { // When all else fails, dirn = lowSearchDown (ew, eh, eh - 1); // find way below hero. } return dirn; break; // KGoldrunner search strategy. case MEDIUM: case HIGH: if(searchStatus==VERTIKAL){ if (eh > hh) return searchupway(ew,eh); if (eh < hh) return searchdownway(ew,eh); return STAND; } else { if (ew > hw) return searchleftway(ew,eh); if (ew < hw) return searchrightway(ew,eh); return STAND; } break; } return STAND; }
/* Es ist Notwendig der eigentlichen Timerfunktion diese Startwalk vorzuschalten, um bei einem evtl. notwendigem Richtungswechsel der Figur diese Bewegung mit einzufügen */ void KGrHero::startWalk () { switch (nextDir) { case UP: if ((*playfield)[x][y]->whatIam () == LADDER) {walkCounter = 1; direction = UP;} break; case RIGHT: if (hangAtPole()) actualPixmap = RIGHTCLIMB1; else actualPixmap = RIGHTWALK1; if (direction != RIGHT) walkCounter = 0; else walkCounter = 1; direction = RIGHT; break; case DOWN: if (((*playfield)[x][y]->whatIam () == LADDER)|| ((*playfield)[x][y+1]->whatIam () == LADDER)) {walkCounter = 1; direction = DOWN;} else // wenn figur an Stange haengt und nichts unter ihr, if (hangAtPole() && (!canStand())) // dann soll sie fallen { status = STANDING; actualPixmap = (direction==RIGHT)?19:18; walkCounter=1; direction=STAND; walkTimer->stop(); } break; case LEFT: if (hangAtPole()) actualPixmap = LEFTCLIMB1; else actualPixmap = LEFTWALK1; if (direction != LEFT) walkCounter = 0; else walkCounter = 1; direction = LEFT; break; default : direction = STAND; status = FALLING; break; } nextDir = STAND; if (status != FALLING)//immer ausführen, ausser beim fallen { status = WALKING; // da sonst der FALLINGstatus wieder showFigure (); // geaendert wird und der falsche Timer anspringt. } } // END KGrHero::startWalk
void KGrHero::fallTimeDone() { if (! started) return; // Ignore signals from earlier play. if (KGrObject::frozen) {fallFrozen = TRUE; return; } if (!standOnEnemy()) { if (walkCounter++ < 4) { // Held fällt vier Positionen fallTimer->start((FALLDELAY * NSPEED) / speed, TRUE); rely+=STEP; absy+=STEP; } else { //Held ist ein Feld weitergefallen // Verschiebung der Figur zum 0-Punkt des Objekts (Brick etc...) heroy = ++y; rely = 0; absy = y*16; // wird Null und Figur eins runter collectNugget(); // gesetzt. Zeit evtl. Nugget zu nehmen if (! (canStand()||hangAtPole())) { // Held muss wohl weiterfallen. fallTimer->start((FALLDELAY * NSPEED) / speed, TRUE); walkCounter = 1; } else { // Held hat Boden (oder Feind) unter den status = STANDING; // Füssen oder hängt an Stange -> steh! walkTimer->start((WALKDELAY * NSPEED) / speed, TRUE); direction = (actualPixmap == 19) ? RIGHT : LEFT; if ((*playfield)[x][y]->whatIam() == POLE) actualPixmap = (direction == RIGHT)? RIGHTCLIMB1:LEFTCLIMB1; // else // Reduce jerkiness when descending over a falling enemy. // actualPixmap = (direction == RIGHT)? RIGHTWALK1:LEFTWALK1; } } showFigure(); } else { if (rely == 0) { // If at the bottom of a cell, try to walk or just stand still. status = STANDING; direction = (actualPixmap == 19) ? RIGHT : LEFT; if ((*playfield)[x][y]->whatIam() == POLE) actualPixmap = (direction == RIGHT)? RIGHTCLIMB1:LEFTCLIMB1; // else // Reduce jerkiness when descending over a falling enemy. // actualPixmap = (direction == RIGHT)? RIGHTWALK1:LEFTWALK1; walkTimer->start((WALKDELAY * NSPEED) / speed, TRUE); } else { // Else, freeze hero until enemy moves out of the way. fallTimer->start((FALLDELAY * NSPEED) / speed, TRUE); } } if (isInEnemy() && (! standOnEnemy())) emit caughtHero(); }
void KGrHero::start() { started = TRUE; walkFrozen = FALSE; fallFrozen = FALSE; if (!(canStand()||hangAtPole())) { // Held muss wohl fallen... status = FALLING; fallTimeDone(); } else { status = STANDING; walkTimeDone(); } }
void KGrEnemy::startSearching() { // Called from "KGoldrunner::startPlaying" and "KGrEnemy::dieAndReappear". init(x,y); if (canStand()||((*playfield)[x][y+1]->whatIam()==USEDHOLE)) { status = WALKING; walkTimer->start ((WALKDELAY * NSPEED) / speed, TRUE); } else { status = FALLING; fallTimer->start ((FALLDELAY * NSPEED) / speed, TRUE); } walkCounter = 1; direction = searchbestway(x,y,herox,heroy); startWalk(); }
Direction KGrEnemy :: searchupway(int ew,int eh){ int i,j; i=j=ew; if ( (*playfield)[ew][eh]->searchValue & CANWALKUP) return UP; else while((i>=0)||(j<=FIELDWIDTH)){// search for the first way up if (i>=0) if ( (*playfield)[i][eh]->searchValue & CANWALKUP) return LEFT; else if (!(( (*playfield)[i--][eh]->searchValue & CANWALKLEFT) || (runThruHole && ( (*playfield)[i][eh]->whatIam() == HOLE)))) i=-1; if (j<=FIELDWIDTH) if ( (*playfield)[j][eh]->searchValue & CANWALKUP) return RIGHT; else if (!(( (*playfield)[j++][eh]->searchValue & CANWALKRIGHT) || (runThruHole && ( (*playfield)[j][eh]->whatIam() == HOLE)))) j=FIELDWIDTH+1; } // BUG FIX - Ian W., 30/4/01 - Don't leave an enemy standing in mid air. if (!canStand()) return DOWN; else return STAND; }
// Checked: 2010-12-11 (RLVa-1.2.2) bool RlvActions::canAcceptTpOffer(const LLUUID& idSender) { return ((!gRlvHandler.hasBehaviour(RLV_BHVR_TPLURE)) || (gRlvHandler.isException(RLV_BHVR_TPLURE, idSender))) && (canStand()); }
/** * This method calculates the moves for the AI player * * @param movePtr Pointer to move the move list into */ bool AIPlayer::getAIMove(Move *movePtr) { *movePtr = NullMove; // Use the eye as the current position. MatrixF eye; getEyeTransform(&eye); Point3F location = eye.getPosition(); Point3F rotation = getRotation(); #ifdef TORQUE_NAVIGATION_ENABLED if(mDamageState == Enabled) { if(mMoveState != ModeStop) updateNavMesh(); if(!mFollowData.object.isNull()) { if(mPathData.path.isNull()) { if((getPosition() - mFollowData.object->getPosition()).len() > mFollowData.radius) followObject(mFollowData.object, mFollowData.radius); } else { if((mPathData.path->mTo - mFollowData.object->getPosition()).len() > mFollowData.radius) repath(); else if((getPosition() - mFollowData.object->getPosition()).len() < mFollowData.radius) { clearPath(); mMoveState = ModeStop; throwCallback("onTargetInRange"); } else if((getPosition() - mFollowData.object->getPosition()).len() < mAttackRadius) { throwCallback("onTargetInFiringRange"); } } } } #endif // TORQUE_NAVIGATION_ENABLED // Orient towards the aim point, aim object, or towards // our destination. if (mAimObject || mAimLocationSet || mMoveState != ModeStop) { // Update the aim position if we're aiming for an object if (mAimObject) mAimLocation = mAimObject->getPosition() + mAimOffset; else if (!mAimLocationSet) mAimLocation = mMoveDestination; F32 xDiff = mAimLocation.x - location.x; F32 yDiff = mAimLocation.y - location.y; if (!mIsZero(xDiff) || !mIsZero(yDiff)) { // First do Yaw // use the cur yaw between -Pi and Pi F32 curYaw = rotation.z; while (curYaw > M_2PI_F) curYaw -= M_2PI_F; while (curYaw < -M_2PI_F) curYaw += M_2PI_F; // find the yaw offset F32 newYaw = mAtan2( xDiff, yDiff ); F32 yawDiff = newYaw - curYaw; // make it between 0 and 2PI if( yawDiff < 0.0f ) yawDiff += M_2PI_F; else if( yawDiff >= M_2PI_F ) yawDiff -= M_2PI_F; // now make sure we take the short way around the circle if( yawDiff > M_PI_F ) yawDiff -= M_2PI_F; else if( yawDiff < -M_PI_F ) yawDiff += M_2PI_F; movePtr->yaw = yawDiff; // Next do pitch. if (!mAimObject && !mAimLocationSet) { // Level out if were just looking at our next way point. Point3F headRotation = getHeadRotation(); movePtr->pitch = -headRotation.x; } else { // This should be adjusted to run from the // eye point to the object's center position. Though this // works well enough for now. F32 vertDist = mAimLocation.z - location.z; F32 horzDist = mSqrt(xDiff * xDiff + yDiff * yDiff); F32 newPitch = mAtan2( horzDist, vertDist ) - ( M_PI_F / 2.0f ); if (mFabs(newPitch) > 0.01f) { Point3F headRotation = getHeadRotation(); movePtr->pitch = newPitch - headRotation.x; } } } } else { // Level out if we're not doing anything else Point3F headRotation = getHeadRotation(); movePtr->pitch = -headRotation.x; } // Move towards the destination if (mMoveState != ModeStop) { F32 xDiff = mMoveDestination.x - location.x; F32 yDiff = mMoveDestination.y - location.y; // Check if we should mMove, or if we are 'close enough' if (mFabs(xDiff) < mMoveTolerance && mFabs(yDiff) < mMoveTolerance) { mMoveState = ModeStop; onReachDestination(); } else { // Build move direction in world space if (mIsZero(xDiff)) movePtr->y = (location.y > mMoveDestination.y) ? -1.0f : 1.0f; else if (mIsZero(yDiff)) movePtr->x = (location.x > mMoveDestination.x) ? -1.0f : 1.0f; else if (mFabs(xDiff) > mFabs(yDiff)) { F32 value = mFabs(yDiff / xDiff); movePtr->y = (location.y > mMoveDestination.y) ? -value : value; movePtr->x = (location.x > mMoveDestination.x) ? -1.0f : 1.0f; } else { F32 value = mFabs(xDiff / yDiff); movePtr->x = (location.x > mMoveDestination.x) ? -value : value; movePtr->y = (location.y > mMoveDestination.y) ? -1.0f : 1.0f; } // Rotate the move into object space (this really only needs // a 2D matrix) Point3F newMove; MatrixF moveMatrix; moveMatrix.set(EulerF(0.0f, 0.0f, -(rotation.z + movePtr->yaw))); moveMatrix.mulV( Point3F( movePtr->x, movePtr->y, 0.0f ), &newMove ); movePtr->x = newMove.x; movePtr->y = newMove.y; // Set movement speed. We'll slow down once we get close // to try and stop on the spot... if (mMoveSlowdown) { F32 speed = mMoveSpeed; F32 dist = mSqrt(xDiff*xDiff + yDiff*yDiff); F32 maxDist = mMoveTolerance*2; if (dist < maxDist) speed *= dist / maxDist; movePtr->x *= speed; movePtr->y *= speed; mMoveState = ModeSlowing; } else { movePtr->x *= mMoveSpeed; movePtr->y *= mMoveSpeed; mMoveState = ModeMove; } if (mMoveStuckTestCountdown > 0) --mMoveStuckTestCountdown; else { // We should check to see if we are stuck... F32 locationDelta = (location - mLastLocation).len(); if (locationDelta < mMoveStuckTolerance && mDamageState == Enabled) { // If we are slowing down, then it's likely that our location delta will be less than // our move stuck tolerance. Because we can be both slowing and stuck // we should TRY to check if we've moved. This could use better detection. if ( mMoveState != ModeSlowing || locationDelta == 0 ) { mMoveState = ModeStuck; onStuck(); } } } } } // Test for target location in sight if it's an object. The LOS is // run from the eye position to the center of the object's bounding, // which is not very accurate. if (mAimObject) { if (checkInLos(mAimObject.getPointer())) { if (!mTargetInLOS) { throwCallback( "onTargetEnterLOS" ); mTargetInLOS = true; } } else if (mTargetInLOS) { throwCallback( "onTargetExitLOS" ); mTargetInLOS = false; } } Pose desiredPose = mPose; if ( mSwimming ) desiredPose = SwimPose; else if ( mAiPose == 1 && canCrouch() ) desiredPose = CrouchPose; else if ( mAiPose == 2 && canProne() ) desiredPose = PronePose; else if ( mAiPose == 3 && canSprint() ) desiredPose = SprintPose; else if ( canStand() ) desiredPose = StandPose; setPose( desiredPose ); // Replicate the trigger state into the move so that // triggers can be controlled from scripts. for( U32 i = 0; i < MaxTriggerKeys; i++ ) movePtr->trigger[ i ] = getImageTriggerState( i ); #ifdef TORQUE_NAVIGATION_ENABLED if(mJump == Now) { movePtr->trigger[2] = true; mJump = None; } else if(mJump == Ledge) { // If we're not touching the ground, jump! RayInfo info; if(!getContainer()->castRay(getPosition(), getPosition() - Point3F(0, 0, 0.4f), StaticShapeObjectType, &info)) { movePtr->trigger[2] = true; mJump = None; } } #endif // TORQUE_NAVIGATION_ENABLED mLastLocation = location; return true; }
void KGrEnemy::fallTimeDone () { if (KGrObject::frozen) {fallFrozen = TRUE; return; } if ((*playfield)[x][y+1]->whatIam() == HOLE) { // wenn Enemy ins Loch fällt ((KGrBrick*)(*playfield)[x][y+1])->useHole(); // reserviere das Loch, damit // kein anderer es benutzt und if (nuggets) { // er muss Gold vorher fallen lassen nuggets=0; switch ((*playfield)[x][y]->whatIam()) { case FREE: case HLADDER: ((KGrFree *)(*playfield)[x][y])->setNugget(true); break; default: emit lostNugget(); break; // Cannot drop the nugget here. } } emit trapped (75); // Enemy trapped: score 75. } else if (walkCounter <= 1) { // Enemies collect nuggets when falling. if (!nuggets) { collectNugget(); } } if ((*playfield)[x][y]->whatIam()==BRICK) { // sollte er aber in einem Brick dieAndReappear(); // sein, dann stirbt er wohl return; // Must leave "fallTimeDone" when an enemy dies. } if (standOnEnemy()) { // Don't fall into a friend. fallTimer->start((FALLDELAY * NSPEED) / speed, TRUE); return; } if (walkCounter++ < 4){ fallTimer->start((FALLDELAY * NSPEED) / speed, TRUE); { rely+=STEP; absy+=STEP;} } else { rely = 0; y ++; absy=16*y; if ((*playfield)[x][y]->whatIam() == USEDHOLE) { captiveCounter = 0; status = CAPTIVE; captiveTimer->start((CAPTIVEDELAY * NSPEED) / speed, TRUE); } else if (!(canStand()||hangAtPole())) { fallTimer->start((FALLDELAY * NSPEED) / speed, TRUE); walkCounter=1; } else { status = STANDING; if (hangAtPole()) actualPixmap=(direction ==RIGHT)?8:12; } } if (status == STANDING) { status = WALKING; walkCounter = 1; direction = searchbestway(x,y,herox,heroy); walkTimer->start ((WALKDELAY * NSPEED) / speed, TRUE); startWalk (); if (!nuggets) collectNugget(); else dropNugget(); } showFigure(); }
void KGrEnemy::walkTimeDone () { if (KGrObject::frozen) {walkFrozen = TRUE; return; } // Check we are alive BEFORE checking for friends being in the way. // Maybe a friend overhead is blocking our escape from a brick. if ((*playfield)[x][y]->whatIam()==BRICK) { // sollte er aber in einem Brick dieAndReappear(); // sein, dann stirbt er wohl return; // Must leave "walkTimeDone" when an enemy dies. } if (! bumpingFriend()) { switch (direction) { case UP: walkUp (WALKDELAY); if ((rely == 0) && ((*playfield)[x][y+1]->whatIam() == USEDHOLE)) // Enemy kletterte grad aus einem Loch hinaus // -> gib es frei! ((KGrBrick *)(*playfield)[x][y+1])->unUseHole(); break; case DOWN: walkDown (WALKDELAY, FALLDELAY); break; case RIGHT: walkRight (WALKDELAY, FALLDELAY); break; case LEFT: walkLeft (WALKDELAY, FALLDELAY); break; default: // Switch search direction in KGoldrunner search (only). searchStatus = (searchStatus==VERTIKAL) ? HORIZONTAL : VERTIKAL; // In KGoldrunner rules, if a hole opens under an enemy // who is standing and waiting to move, he should fall. if (!(canStand()||hangAtPole())) { initFall (actualPixmap, FALLDELAY); } else { status = STANDING; } break; } // wenn die Figur genau ein Feld gelaufen ist if (status == STANDING) { // dann suche den Helden direction = searchbestway(x,y,herox,heroy); // und if (walkCounter >= 4) { if (! nuggets) collectNugget(); else dropNugget(); } status = WALKING; // initialisiere die Zählervariablen und walkCounter = 1; // den Timer um den Held weiter walkTimer->start ((WALKDELAY * NSPEED) / speed, TRUE); // zu jagen startWalk (); } } else { // A friend is in the way. Try a new direction, but not if leaving a hole. Direction dirn; // In KGoldrunner rules, change the search strategy, // to avoid enemy-enemy deadlock. searchStatus = (searchStatus==VERTIKAL) ? HORIZONTAL : VERTIKAL; dirn = searchbestway (x, y, herox, heroy); if ((dirn != direction) && ((*playfield)[x][y]->whatIam() != USEDHOLE)) { direction = dirn; status = WALKING; walkCounter = 1; relx = 0; absx = 16 * x; rely = 0; absy = 16 * y; startWalk (); } walkTimer->start ((WALKDELAY * NSPEED) / speed, TRUE); } showFigure(); }
void KGrHero::walkTimeDone () { if (! started) return; // Ignore signals from earlier play. if (KGrObject::frozen) {walkFrozen = TRUE; return; } if ((*playfield)[x][y]->whatIam() == BRICK) { emit caughtHero(); // Brick closed over hero. return; } if ((y==1)&&(nuggets<=0)) { // If on top row and all nuggets collected, emit leaveLevel(); // the hero has won and can go to next level. return; } if (status == STANDING) setNextDir(); if ((status == STANDING) && (nextDir != STAND)) { if ((standOnEnemy()) && (nextDir == DOWN)) { emit caughtHero(); // Hero is going to step down into an enemy. return; } startWalk(); } if (status != STANDING) { switch (direction) { case UP: walkUp (WALKDELAY); break; case DOWN: walkDown (WALKDELAY, FALLDELAY); break; case RIGHT: walkRight (WALKDELAY, FALLDELAY); break; case LEFT: walkLeft (WALKDELAY, FALLDELAY); break; default : // The following code is strange. It makes the hero fall off a pole. // It works because of other strange code in "startWalk(), case DOWN:". if (!canStand()||hangAtPole()) // falling initFall(FALL1, FALLDELAY); else status = STANDING; break; } herox=x;heroy=y; // Koordinatenvariablen neu // wenn Held genau ein Feld weitergelaufen ist, if ((relx==0)&&(rely==0)) // dann setzte statische { collectNugget(); // und nehme evtl. Nugget } showFigure(); // Is this REDUNDANT now? See showFigure() below. ////////////////////////////////////////////////// } if (status == STANDING) if (!canStand()&&!hangAtPole()) initFall(FALL1, FALLDELAY); else walkTimer->start ((WALKDELAY * NSPEED) / speed, TRUE); // This additional showFigure() is to update the hero position after it is // altered by the hero-enemy deadlock fix in standOnEnemy(). Messy, but ... //////////////////////////////////////////////////////////////////////////// showFigure(); if(isInEnemy()) { walkTimer->stop(); emit caughtHero(); } }