void Plant::draw( Vector3D *inPosition, double inScale, double inMaxZ, double inMinZ ) { if( mPoisoned && mPoisonStatus >= 1) { // draw nothing return; } double drawScale = inScale; if( mPoisoned ) { // shrink with poisoning drawScale *= ( 1 - mPoisonStatus ); } double radius = drawScale * ( mGrowth * 0.8 + 0.2 ); // leaves become black with poisoning // (shades of white to allow texture color to dominate) Color leafColor( 1 - mPoisonStatus, 1 - mPoisonStatus, 1 - mPoisonStatus, 1 ); if( ! Features::drawNicePlantLeaves ) { // set color to shades of green green for leaves if we're drawing // simple boxes, since there's no texture color leafColor.setValues( 0, 1 - mPoisonStatus, 0, 1 ); } Angle3D zeroAngle( 0, 0, 0 ); PlantGenetics *genetics = &( mSeeds.mGenetics ); int maxNumJoints = (int)( genetics->getParameter( jointCount ) ); double growthFactor = mGrowth * 0.8 + 0.2; int numFullJoints = (int)( growthFactor * maxNumJoints ); double partialJoint = growthFactor * maxNumJoints - numFullJoints; int numLeavesPerJoint = (int)( genetics->getParameter( leavesPerJoint ) ); Angle3D angleIncrement( 0, 0, 2 * M_PI / numLeavesPerJoint ); Angle3D startAngle( 0, 0, mStartZAngle ); double currentScale = 1; double scaleDecrement = currentScale / ( maxNumJoints + 1 ); Vector3D leafPosition( inPosition ); Vector3D positionIncrement( 0, 0, -0.5 ); Vector3D leafWalkerTerminus; SimpleVector<Vector3D *> thisLayerLeafTerminii; for( int j=0; j<numFullJoints; j++ ) { // lower leaves are darker double colorScaleFactor = (double)(j+1) / (double)maxNumJoints; // min scaling of 0.5 colorScaleFactor = colorScaleFactor * 0.5 + 0.5; Color thisLevelColor; thisLevelColor.setValues( &leafColor ); thisLevelColor.weightColor( colorScaleFactor ); Angle3D currentAngle( &startAngle ); double zValue = leafPosition.mZ; if( zValue <= inMaxZ && zValue >= inMaxZ ) { // draw this joint for( int g=0; g<numLeavesPerJoint; g++ ) { if( Features::drawShadows ) { // draw shadow glColor4f( 0, 0, 0, 0.5 ); mLeaf.draw( &leafPosition, ¤tAngle, currentScale * radius * 1.05 ); } // draw leaf setGLColor( &thisLevelColor ); mLeaf.draw( &leafPosition, ¤tAngle, currentScale * radius, &leafWalkerTerminus ); thisLayerLeafTerminii.push_back( new Vector3D( &leafWalkerTerminus ) ); currentAngle.add( &angleIncrement ); } // finally cap this joint setGLColor( &thisLevelColor ); mJointCapTexture->enable(); glBegin( GL_QUADS ); { double capRadius = currentScale * radius * 0.1; double capZ = leafPosition.mZ; glTexCoord2f( 0, 0 ); glVertex3d( leafPosition.mX - capRadius, leafPosition.mY - capRadius, capZ ); glTexCoord2f( 1, 0 ); glVertex3d( leafPosition.mX + capRadius, leafPosition.mY - capRadius, capZ ); glTexCoord2f( 1, 1 ); glVertex3d( leafPosition.mX + capRadius, leafPosition.mY + capRadius, capZ ); glTexCoord2f( 0, 1 ); glVertex3d( leafPosition.mX - capRadius, leafPosition.mY + capRadius, capZ ); } glEnd(); mJointCapTexture->disable(); } Angle3D angleToNextJoint( &angleIncrement ); angleToNextJoint.scale( 0.5 ); currentAngle.add( &angleToNextJoint ); // start next joint at our current angle startAngle.setComponents( ¤tAngle ); currentScale -= scaleDecrement; leafPosition.add( &positionIncrement ); } if( partialJoint > 0 ) { Angle3D currentAngle( &startAngle ); // darker as growing completes // lower leaves are darker double colorScaleFactor = (double)(numFullJoints+1) / (double)maxNumJoints; // min scaling of 0.5 colorScaleFactor = colorScaleFactor * 0.5 + 0.5; // scale factor comes into effect as partial joint reaches 1 colorScaleFactor = (1 - partialJoint) + colorScaleFactor * partialJoint; Color thisLevelColor; thisLevelColor.setValues( &leafColor ); thisLevelColor.weightColor( colorScaleFactor ); double zValue = leafPosition.mZ; if( zValue <= inMaxZ && zValue >= inMaxZ ) { // draw this joint for( int g=0; g<numLeavesPerJoint; g++ ) { if( Features::drawShadows ) { // draw shadow glColor4f( 0, 0, 0, 0.5 ); mLeaf.draw( &leafPosition, ¤tAngle, partialJoint * currentScale * radius * 1.05 ); } setGLColor( &thisLevelColor ); mLeaf.draw( &leafPosition, ¤tAngle, // scale down further by partial fraction partialJoint * currentScale * radius ); currentAngle.add( &angleIncrement ); } // finally cap this joint setGLColor( &thisLevelColor ); mJointCapTexture->enable(); glBegin( GL_QUADS ); { double capRadius = currentScale * radius * 0.1; double capZ = leafPosition.mZ; glTexCoord2f( 0, 0 ); glVertex3d( leafPosition.mX - capRadius, leafPosition.mY - capRadius, capZ ); glTexCoord2f( 1, 0 ); glVertex3d( leafPosition.mX + capRadius, leafPosition.mY - capRadius, capZ ); glTexCoord2f( 1, 1 ); glVertex3d( leafPosition.mX + capRadius, leafPosition.mY + capRadius, capZ ); glTexCoord2f( 0, 1 ); glVertex3d( leafPosition.mX - capRadius, leafPosition.mY + capRadius, capZ ); } glEnd(); mJointCapTexture->disable(); } } int numTerminii = thisLayerLeafTerminii.size(); int t; if( mGrowth >= 1 ) { // NOTE: // This method of collecting all leaf terminii for the plant ASSUMES // that each terminus is at a unique location // This seems like a safe assumption, given the way leaves are // arranged now, but it is not safe in the general case. // If two terminii are at the same location, the terminus collection // would finish before collecting all terminii if( !mLeafTerminiiSet ) { // not done collecting leaf terminii for full-growth plant int numExisting = mLeafTerminii.size(); char collision = false; for( int t=0; t<numTerminii && !collision; t++ ) { Vector3D *newTerminus = *( thisLayerLeafTerminii.getElement( t ) ); // make sure not the same as existing char same = false; for( int e=0; e<numExisting && !same; e++ ) { Vector3D *existing = *( mLeafTerminii.getElement( e ) ); if( existing->equals( newTerminus ) ) { same = true; collision = true; } } if( !same ) { // add to list of all terminii mLeafTerminii.push_back( new Vector3D( newTerminus ) ); } } if( collision ) { // we are back to drawing a layer that we've already drawn // before // so we're not gathering new leaf terminii anymore mLeafTerminiiSet = true; } } else { // don't try adding flowers if we already have more than // numTerminii // flowers int numTotalTerminii = mLeafTerminii.size(); int numFlowers = mFlowerTerminusIndicies.size(); int numFruit = mFruitTerminusIndices.size(); if( numFlowers < numTotalTerminii && mTimeSinceLastFlower >= genetics->getParameter( timeBetweenFlowers ) ) { // new flower // pick random, unflowered, unfruited terminus int numTries = 0; char found = false; int foundIndex = -1; while( ! found && numTries < 100 ) { foundIndex = globalRandomSource.getRandomBoundedInt( 0, numTotalTerminii - 1 ); found = true; int f; for( f=0; f<numFlowers && found; f++ ) { if( *( mFlowerTerminusIndicies.getElement( f ) ) == foundIndex ) { // collision with existing flower location found = false; } } for( f=0; f<numFruit && found; f++ ) { if( *( mFruitTerminusIndices.getElement( f ) ) == foundIndex ) { // collision with existing fruit location found = false; } } numTries++; } if( found ) { mFlowerTerminusIndicies.push_back( foundIndex ); mFlowerStages.push_back( 0 ); mFlowerAngles.push_back( new Angle3D( 0, 0, globalRandomSource.getRandomBoundedDouble( 0, 2 * M_PI ) ) ); } mTimeSinceLastFlower = 0; } // recount, since we may have added some numFlowers = mFlowerTerminusIndicies.size(); for( int f=0; f<numFlowers; f++ ) { int terminusIndex = *( mFlowerTerminusIndicies.getElement( f ) ); Vector3D *terminus = *( mLeafTerminii.getElement( terminusIndex ) ); double zValue = terminus->mZ; if( zValue <= inMaxZ && zValue >= inMaxZ ) { Angle3D *flowerAngle = *( mFlowerAngles.getElement( f ) ); double flowerStage = *( mFlowerStages.getElement( f ) ); mFlower.draw( terminus, flowerAngle, drawScale, flowerStage ); } } } // draw fruit int numFruit = mFruit.size(); for( int f=0; f<numFruit; f++ ) { int terminusIndex = *( mFruitTerminusIndices.getElement( f ) ); Vector3D *terminus = *( mLeafTerminii.getElement( terminusIndex ) ); double zValue = terminus->mZ; if( zValue <= inMaxZ && zValue >= inMaxZ ) { Angle3D *fruitAngle = *( mFruitAngles.getElement( f ) ); Fruit *thisFruit = *( mFruit.getElement( f ) ); double fruitScale = drawScale * 0.2; thisFruit->draw( terminus, fruitAngle, fruitScale ); if( mHighlightRipeFruit && thisFruit->isRipe() ) { // make sure this is the fruit that we will harvest // next // (the z-range drawing can screw us // up here, since we might draw fruits out-of-order) // thus, the first-drawn ripe fruit is not necessarily // the fruit that will be next harvested Fruit *fruitNextHarvested = peekAtRipeFruit(); if( thisFruit == fruitNextHarvested ) { // this fruit will be harvested next glColor4f( 1, 1, 1, 0.25 ); // highlight brightens only glBlendFunc( GL_SRC_ALPHA, GL_ONE ); drawBlurCircle( terminus, fruitScale ); // back to normal blend function glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); // only highlight one mHighlightRipeFruit = false; } } } } } // delete this layer's terminus points for( t=0; t<numTerminii; t++ ) { delete *( thisLayerLeafTerminii.getElement( t ) ); } }
/** * Zeichnet einen Vektor als Pfeil. * @param pos Startpunkt des Pfeils. * @param dir Richtung und Länge des Pfeils. */ void drawVector(Vector3D* pos, Vector3D* dir) { //spitze des Vektors Vector3D tip = Vector3D(pos); //normalisierte Richtung des Vektors Vector3D ndir = Vector3D(dir); ndir.normalize(); //Referenzvektor, darf dem Vektor nicht entsprechen Vector3D refdir = Vector3D(1, 0, 0); if (refdir.equals(&ndir)) { refdir.getXYZ()[0] = 0; refdir.getXYZ()[1] = 1; } //Radius der Vektorspitze float radius = .012 * dir->getLength(); //Länge der Vektorspitze float length = .024 * dir->getLength(); //Zwei Referenzvektoren, die zum Ausgansvektor und zueinander einen Winkel von 90° einschließen Vector3D* refvec = ndir.crossProduct(&refdir); Vector3D* refvec2 = ndir.crossProduct(refvec); refvec->normalize(); refvec2->normalize(); //zeichnen der Linie von Ausganspunkt bis Spitze des Pfeils tip.add(dir); Vector3D behind = Vector3D(pos); glLineWidth(2.0); glBegin(GL_LINES); glVertex3dv(behind.getXYZ()); glVertex3dv(tip.getXYZ()); glEnd(); //Hilfsvektoren zum zusammentragen der Spitze des Vektors Vector3D v1 = Vector3D(refvec); Vector3D v2 = Vector3D(refvec2); Vector3D v3 = Vector3D(v1); v3.mult(-1); Vector3D v4 = Vector3D(refvec2); v4.mult(-1); //zeichen der Pfeilspitze v1.mult(radius); v2.mult(radius); v3.mult(radius); v4.mult(radius); ndir.mult(dir->getLength() - length); v1.add(&ndir); v2.add(&ndir); v3.add(&ndir); v4.add(&ndir); v1.add(pos); v2.add(pos); v3.add(pos); v4.add(pos); glBegin(GL_TRIANGLES); glVertex3dv(v1.getXYZ()); glVertex3dv(v2.getXYZ()); glVertex3dv(tip.getXYZ()); glVertex3dv(v2.getXYZ()); glVertex3dv(v3.getXYZ()); glVertex3dv(tip.getXYZ()); glVertex3dv(v3.getXYZ()); glVertex3dv(v4.getXYZ()); glVertex3dv(tip.getXYZ()); glVertex3dv(v4.getXYZ()); glVertex3dv(v1.getXYZ()); glVertex3dv(tip.getXYZ()); glEnd(); glLineWidth(1.0); delete refvec; delete refvec2; }
void GardenerAI::passTime( double inTimeDeltaInSeconds ) { // before doing anything else, check if we are still following parent Gardener *parent = mGardener->getParentToFollow(); if( parent != NULL && ! parent->isDead() ) { // follow it if we get too far away Vector3D *destination; if( mWorld->getGardenerDistance( mGardener, parent ) > 10 ) { // move closer destination = mWorld->getGardenerPosition( parent ); } else { // stay where we are destination = mWorld->getGardenerPosition( mGardener ); } mGardener->setDesiredPosition( destination ); delete destination; return; } mSecondsSinceLastGift += inTimeDeltaInSeconds; mSecondsSinceLastRevenge += inTimeDeltaInSeconds; // first check if hungry int lowIndex = -1; for( int i=0; i<3; i++ ) { if( mGardener->getNutrientLevel(i) == 0 ) { lowIndex = i; } } if( lowIndex != -1 ) { // low in at least one nutrient // try to find a fruit high in that nutrient int index = mGardener->getIndexOfFruitHighInNutrient( lowIndex ); if( index != -1 ) { mGardener->setSelectedObjectIndex( index ); // eat selected fruit mGardener->eat(); } } // next deal with creating plot Vector3D *plotCenter = mWorld->getPlotCenter( mGardener ); if( plotCenter == NULL ) { // need to pick a new plot // walk toward water until we hit it, or until we get // too close to other gardeners Vector3D *waterPoint = mWorld->getClosestWater( mGardener ); double minPleasantDistance = 10; char tooCloseToOtherGardeners = false; Gardener *closestGardener = mWorld->getClosestGardener( mGardener ); if( closestGardener != NULL ) { Vector3D *ourPosition = mWorld->getGardenerPosition( mGardener ); Vector3D *closestGardenerPosition = mWorld->getGardenerPosition( closestGardener ); double distance = ourPosition->getDistance( closestGardenerPosition ); if( distance < minPleasantDistance ) { tooCloseToOtherGardeners = true; } delete ourPosition; delete closestGardenerPosition; } if( ! tooCloseToOtherGardeners && ! mWorld->isInWater( mGardener ) ) { mGardener->setDesiredPosition( waterPoint ); } else { // we just hit the water, or we came too close to other // gardeners // create our plot Vector3D *position = mWorld->getGardenerPosition( mGardener ); Vector3D a( position ); // vector pointing away from water center Vector3D rayFromWaterPoint( position ); rayFromWaterPoint.subtract( waterPoint ); rayFromWaterPoint.normalize(); // plot diagonal of 20 world units rayFromWaterPoint.scale( 20 ); // add this ray to our position position->add( &rayFromWaterPoint ); Vector3D b( position ); delete position; // thus, we pick a plot bordering the water that has a diagonal // length roughly equal to the water's radius // this can be a "skinny" rectangle, though, so widen it if // needed double diffX = fabs( a.mX - b.mX ); double diffY = fabs( a.mY - b.mY ); if( diffX < diffY ) { // taller than wide double increase = diffY - diffX; if( a.mX < b.mX ) { b.mX += increase; } else { a.mX += increase; } } if( diffY < diffX ) { // wider than tall double increase = diffX - diffY; if( a.mY < b.mY ) { b.mY += increase; } else { a.mY += increase; } } mWorld->setGardenerPlot( mGardener, &a, &b ); } delete waterPoint; return; } // we have a plot // check that there are enough plants in it int targetPlantCount = (int)( mGardener->mGenetics.getParameter( desiredPlantCount ) ); SimpleVector<Plant*> *plants = mWorld->getPlotPlants( mGardener ); int numPlants = plants->size(); SimpleVector<Seeds*> *seedsVector = mGardener->getAllSeeds(); int numSeeds = seedsVector->size(); delete seedsVector; if( numSeeds > 0 && numPlants < targetPlantCount ) { // plant more if( mNextPlantingLocation == NULL ) { // haven't picked a spot yet char foundPlantable = false; int numTries = 0; int maxNumTries = 10; while( !foundPlantable && numTries < maxNumTries ) { Vector3D *cornerA, *cornerB; mWorld->getGardenerPlot( mGardener, &cornerA, &cornerB ); double x = globalRandomSource.getRandomBoundedDouble( cornerA->mX, cornerB->mX ); double y = globalRandomSource.getRandomBoundedDouble( cornerA->mY, cornerB->mY ); mNextPlantingLocation = new Vector3D( x, y, 0 ); delete cornerA; delete cornerB; if( mWorld->canPlant( mNextPlantingLocation ) ) { foundPlantable = true; } else { // try again delete mNextPlantingLocation; mNextPlantingLocation = NULL; } numTries++; } } if( mNextPlantingLocation != NULL ) { Vector3D *gardenerPosition = mWorld->getGardenerPosition( mGardener ); if( ! gardenerPosition->equals( mNextPlantingLocation ) ) { // move to next plant location mGardener->setDesiredPosition( mNextPlantingLocation ); } else { // at next location: // make sure we can still plant // else pick another location at next time step if( mWorld->canPlant( mNextPlantingLocation ) ) { // plant here double soilCondition = mWorld->getSoilCondition( mNextPlantingLocation ); SimpleVector<Seeds*> *seedsVector = mGardener->getAllSeeds(); // find best for this soil Seeds *best = NULL; double minSoilDistance = 2; for( int i=0; i<seedsVector->size(); i++ ) { Seeds *seeds = *( seedsVector->getElement( i ) ); double distance = fabs( seeds->mIdealSoilType - soilCondition ); if( distance < minSoilDistance ) { minSoilDistance = distance; best = seeds; } } delete seedsVector; if( best != NULL ) { mWorld->addPlant( mGardener, new Plant( soilCondition, best ), mNextPlantingLocation ); mGardener->removeSeeds( best ); } } delete mNextPlantingLocation; mNextPlantingLocation = NULL; } delete gardenerPosition; } else { // tried to pick a plantable location, but failed // expand plot Vector3D *a, *b; mWorld->getGardenerPlot( mGardener, &a, &b ); // compute a vector stretching from b to a Vector3D b_to_a( a ); b_to_a.subtract( b ); // expand plot by 10% in each direction b_to_a.scale( 0.10 ); // push a away from b a->add( &b_to_a ); // also push b away from a // opposite direction b_to_a.scale( -1 ); b->add( &b_to_a ); mWorld->setGardenerPlot( mGardener, a, b ); delete a; delete b; } delete plants; delete plotCenter; return; } // else we have enough plants (or no seeds left) // if any are ripe, harvest them Plant *ripePlant = NULL; int i; for( i=0; i<numPlants && ripePlant == NULL; i++ ) { Plant *thisPlant = *( plants->getElement( i ) ); if( thisPlant->isRipe() ) { ripePlant = thisPlant; } } if( ripePlant != NULL ) { // move toward it Vector3D *plantPosition = mWorld->getPlantPosition( ripePlant ); Vector3D *gardenerPosition = mWorld->getGardenerPosition( mGardener ); if( ! gardenerPosition->equals( plantPosition ) ) { // move to plant mGardener->setDesiredPosition( plantPosition ); } else { // already at plant // harvest it mWorld->harvestPlant( mGardener, ripePlant ); } delete gardenerPosition; delete plantPosition; delete plants; delete plotCenter; return; } // else no ripe plants // water plants Plant *driestPlant = NULL; // ignore plants that have at least 1/4 water double driestWaterStatus = 0.25; for( int i=0; i<numPlants; i++ ) { Plant *thisPlant = *( plants->getElement( i ) ); double waterStatus = thisPlant->getWaterStatus(); if( waterStatus < driestWaterStatus ) { driestPlant = thisPlant; driestWaterStatus = waterStatus; } } if( mGardener->getCarryingWater() ) { // already carrying water // move to the driest plant if( driestPlant != NULL ) { // found driest // walk to it Vector3D *plantPosition = mWorld->getPlantPosition( driestPlant ); Vector3D *gardenerPosition = mWorld->getGardenerPosition( mGardener ); if( ! gardenerPosition->equals( plantPosition ) ) { // move to plant mGardener->setDesiredPosition( plantPosition ); } else { // already at plant // dump water mGardener->setCarryingWater( false ); mWorld->dumpWater( mGardener ); } delete gardenerPosition; delete plantPosition; } else { // else no dry plant found // wait and do nothing // head to plot center and wait mGardener->setDesiredPosition( plotCenter ); } } else if( driestPlant != NULL ) { // there is a dry plant, and we're not carrying water // fetch water if( ! mWorld->isInWater( mGardener ) ) { Vector3D *waterPoint = mWorld->getClosestWater( mGardener ); mGardener->setDesiredPosition( waterPoint ); delete waterPoint; } else { // grab water mGardener->setCarryingWater( true ); } } else { // no dry plant, and not carrying water char tryingToMate = false; // if not pregnant // and not target of another pregancy // hand have enough fruit to feel secure if( ! mGardener->isPregnant() && ! mWorld->isTargetOfPregnancy( mGardener ) && mGardener->getStoredFruitCount() >= mGardener->mGenetics.getParameter( storedFruitsBeforeMating ) ) { // we are not pregnant already // we have enough fruit stored // consider mating double ourThreshold = mGardener->mGenetics.getParameter( matingThreshold ); Gardener *mostLiked = mGardener->getMostLikedGardener(); if( mostLiked != NULL ) { double mostLikedMatingThreshold = mostLiked->mGenetics.getParameter( matingThreshold ); if( mGardener->getLikeMetric( mostLiked ) >= ourThreshold && mostLiked->getLikeMetric( mGardener ) >= mostLikedMatingThreshold && ! mostLiked->isPregnant() && ! mWorld->isTargetOfPregnancy( mostLiked ) ) { // we like them enough to mate // and // they like us enough to mate // and // they are not already pregnant // and // they are not already target of another pregnancy tryingToMate = true; Vector3D *ourPosition = mWorld->getGardenerPosition( mGardener ); Vector3D *otherPosition = mWorld->getGardenerPosition( mostLiked ); double distance = ourPosition->getDistance( otherPosition ); if( distance < getMaxDistanceForTransactions() ) { mWorld->mateGardeners( mGardener, mostLiked ); } else { // move toward friend mGardener->setDesiredPosition( otherPosition ); } delete ourPosition; delete otherPosition; } } } // check if we should give fruit to a neighbor char tryingToGiveFruit = false; // wait five seconds between gifts to give them // time to arrive before we reasses the situation if( !tryingToMate && mSecondsSinceLastGift > 5 ) { Gardener *mostLiked = mGardener->getMostLikedGardener(); if( mostLiked != NULL ) { // only give if we have 2+ more fruits than them // (to avoid back and forth giving when there is an // odd number of fruits between the two of us) if( mGardener->getStoredFruitCount() > mostLiked->getStoredFruitCount() + 1 ) { // we have fruit to spare compared to our best friend tryingToGiveFruit = true; Vector3D *ourPosition = mWorld->getGardenerPosition( mGardener ); Vector3D *otherPosition = mWorld->getGardenerPosition( mostLiked ); double distance = ourPosition->getDistance( otherPosition ); if( distance < getMaxDistanceForTransactions() ) { // close enough to give // find out which nutrient they are low in int lowIndex = -1; double lowValue = 2; for( int i=0; i<3; i++ ) { double value = mostLiked->getNutrientLevel(i); if( value < lowValue ) { lowIndex = i; lowValue = value; } } // try to find a fruit high in that nutrient int index = mGardener->getIndexOfFruitHighInNutrient( lowIndex ); // we will always get a valid index here, because // we have checked that we have stored fruit above mGardener->setSelectedObjectIndex( index ); mWorld->giveFruit( mGardener, mostLiked, // don't save seeds, but get any fruit, even // if fruit not selected mGardener->getSelectedFruit( false, true ) ); // reset timer mSecondsSinceLastGift = 0; // every time we give a gift, // our friendliness toward this gardener is depleted // a bit // Actually, don't do this for now, since for mating // purposes, we want to retain our friendliness // mGardener->getAngry( mostLiked ); } else { // move toward friend mGardener->setDesiredPosition( otherPosition ); } delete ourPosition; delete otherPosition; } } } char gettingRevenge = false; if( !tryingToMate && !tryingToGiveFruit ) { // consider getting revenge if( mSecondsSinceLastRevenge > 5 ) { Gardener *leastLiked = mGardener->getLeastLikedGardener(); if( leastLiked != NULL ) { Plant *plantToTake = getClosestPlantInGardenerPlot( leastLiked ); if( plantToTake != NULL ) { expandOurPlotToContainPlant( plantToTake ); gettingRevenge = true; // reset timer mSecondsSinceLastRevenge = 0; // every time we take revenge, our anger // toward this gardener lessens a bit mGardener->getFriendly( leastLiked ); } else { // none to take (our plots overlap perfectly) // try looking for a plant to poison Plant *plantToPoison = mWorld->getTendedPlant( leastLiked ); if( plantToPoison != NULL ) { // found candidate gettingRevenge = true; // walk to it Vector3D *plantPosition = mWorld->getPlantPosition( plantToPoison ); Vector3D *gardenerPosition = mWorld->getGardenerPosition( mGardener ); if( ! gardenerPosition->equals( plantPosition ) ) { // move to plant mGardener->setDesiredPosition( plantPosition ); } else { // already at plant mWorld->dumpPoison( mGardener ); // reset timer mSecondsSinceLastRevenge = 0; // every time we take revenge, our anger // toward this gardener lessens a bit mGardener->getFriendly( leastLiked ); } delete gardenerPosition; delete plantPosition; } } } } } if( !tryingToMate && !tryingToGiveFruit && !gettingRevenge ) { // head to plot center and wait mGardener->setDesiredPosition( plotCenter ); } } if( plotCenter != NULL ) { delete plotCenter; } delete plants; }