/** ** Move unit to oil platform. ** ** @param unit Pointer to unit. ** @return TRUE if reached, otherwise FALSE. */ local int MoveToOilWell(Unit* unit) { Unit* well; int i; if( !(i=HandleActionMove(unit)) ) { // reached end-point return 0; } DebugLevel3("Result: %d\n",i); if( i==-1 ) { DebugLevel2("OIL-WELL NOT REACHED\n"); return -1; } well=unit->Command.Data.Move.Goal; if( !well ) { DebugLevel2("Invalid Oil Well\n"); return -1; } // FIXME: the incomplete oil well didn't completed if( well->Command.Action==UnitActionBuilded ) { DebugLevel2("Invalid Oil Well\n"); return -1; } unit->Command.Action=UnitActionHaulOil; DebugCheck( !well || MapDistanceToUnit(unit->X,unit->Y,well)!=1 ); // // Activate oil-well // if( !well->Type->GivesOil ) { // OilWell destoryed. DebugLevel3("WAIT after oil-well destroyed %d\n",unit->Wait); unit->Command.Action=UnitActionStill; unit->SubAction=0; return 0; } well->Command.Data.OilWell.Active++; DebugLevel0(__FUNCTION__": +%d\n",well->Command.Data.OilWell.Active); well->Frame=2; // FIXME: this should be hard coded! RemoveUnit(unit); unit->X=well->X; unit->Y=well->Y; if( HAUL_FOR_OIL<UNIT_MAX_WAIT ) { unit->Wait=HAUL_FOR_OIL; } else { unit->Wait=UNIT_MAX_WAIT; } unit->Value=HAUL_FOR_OIL-unit->Wait; return 1; }
/** ** Wait for transporter. ** ** @param unit Pointer to unit. ** @return True if ship arrived/present, False otherwise. */ local int WaitForTransporter(Unit* unit) { Unit* trans; unit->Wait=6; unit->Reset=1; trans=unit->Orders[0].Goal; if( !trans || !trans->Type->Transporter ) { // FIXME: destination destroyed?? DebugLevel2Fn("TRANSPORTER NOT REACHED %d,%d\n" _C_ unit->X _C_ unit->Y); return 0; } if( trans->Destroyed ) { DebugLevel0Fn("Destroyed transporter\n"); RefsDebugCheck( !trans->Refs ); if( !--trans->Refs ) { ReleaseUnit(trans); } unit->Orders[0].Goal=NoUnitP; return 0; } else if( trans->Removed || !trans->HP || trans->Orders[0].Action==UnitActionDie ) { DebugLevel0Fn("Unusable transporter\n"); RefsDebugCheck( !trans->Refs ); --trans->Refs; RefsDebugCheck( !trans->Refs ); unit->Orders[0].Goal=NoUnitP; return 0; } if( MapDistanceToUnit(unit->X,unit->Y,trans)==1 ) { DebugLevel3Fn("Enter transporter\n"); return 1; } // // FIXME: any enemies in range attack them, while waiting. // DebugLevel2Fn("TRANSPORTER NOT REACHED %d,%d\n" _C_ unit->X _C_ unit->Y); return 0; }
/* ** Return with the wood. ** Return TRUE if reached, otherwise FALSE. */ local int ReturnWithWood(Unit* unit) { int x; int y; //int dx; //int dy; Unit* destu; if( !HandleActionMove(unit) ) { // reached end-point return 0; } DebugCheck( unit->Wait!=1 ); #if 0 // reached nearly? and is there an wood deposit? x=unit->Command.Data.Move.DX; y=unit->Command.Data.Move.DY; dx=unit->X-x; dy=unit->Y-y; destu=WoodDepositOnMap(x,y); DebugLevel3("Near unit %d,%d =%Zd\n",x,y,destu-UnitsPool); if( !destu || dx<-1 || dx>destu->Type->TileWidth || dy<-1 || dy>destu->Type->TileHeight ) { DebugLevel2("WOOD-DEPOSIT NOT REACHED %d=%d,%Zd\n" ,destu-UnitsPool,dx,dy); unit->Command.Action=UnitActionStill; unit->SubAction=0; return 0; } #endif x=unit->Command.Data.Move.DX; y=unit->Command.Data.Move.DY; destu=WoodDepositOnMap(x,y); if( !destu || MapDistanceToUnit(unit->X,unit->Y,destu)!=1 ) { DebugLevel2("WOOD-DEPOSIT NOT REACHED %Zd=%d,%d ? %d\n" ,destu-UnitsPool,x,y ,MapDistanceToUnit(unit->X,unit->Y,destu)); unit->Command.Action=UnitActionStill; unit->SubAction=0; return 0; } unit->Command.Action=UnitActionHarvest; RemoveUnit(unit); unit->X=destu->X; unit->Y=destu->Y; // // Update wood. // unit->Player->Wood+=unit->Player->WoodPerChop; if( unit->Player==ThisPlayer ) { MustRedraw|=RedrawResources; } if( unit->Type->Type==UnitPeonWithWood ) { unit->Type=&UnitTypes[UnitPeon]; } else if( unit->Type->Type==UnitPeasantWithWood ) { unit->Type=&UnitTypes[UnitPeasant]; } else { DebugLevel0("Wrong unit for returning wood %d\n" ,unit->Type->Type); } if( WAIT_FOR_WOOD<UNIT_MAX_WAIT ) { unit->Wait=WAIT_FOR_WOOD; } else { unit->Wait=UNIT_MAX_WAIT; } unit->Value=WAIT_FOR_WOOD-unit->Wait; return 1; }
/** ** Unit Demolishs ** ** @param unit Unit, for that the demolish is handled. */ global void HandleActionDemolish(Unit* unit) { Unit* table[MAX_UNITS]; int i; int n; int x, y, ix, iy; Unit* goal; int err; DebugLevel3("Demolish %d\n",unit-Units); switch( unit->SubAction ) { // // Move near to target. // case 0: // FIXME: RESET FIRST!! err=HandleActionMove(unit); if( unit->Reset ) { goal=unit->Command.Data.Move.Goal; // // Target is dead, stop demolish // if( goal && (!goal->Type || !goal->HP || goal->Command.Action==UnitActionDie) ) { // FIXME: this can't happen, HandleActionMove resets goal! unit->Command.Data.Move.Goal=NoUnitP; unit->Command.Action=UnitActionStill; return; } // // Have reached target? // if( goal ) { if( MapDistanceToUnit(unit->X,unit->Y,goal)<=1 ) { unit->State=0; unit->SubAction=1; } } else if( MapDistance(unit->X,unit->Y ,unit->Command.Data.Move.DX ,unit->Command.Data.Move.DY)<=1 ) { unit->State=0; unit->SubAction=1; } else if( err ) { return; } unit->Command.Action=UnitActionDemolish; } break; // // Demolish the target. // case 1: x=unit->X; y=unit->Y; DestroyUnit(unit); // FIXME: Must play explosion sound n=SelectUnits(x-2,y-2, x+2, y+2,table); // FIXME: Don't hit flying units! for( i=0; i<n; ++i ) { HitUnit(table[i],DEMOLISH_DAMAGE); } for( ix=x-2; ix<=x+2; ix++ ) { for( iy=y-2; iy<=y+2; iy++ ) { n=TheMap.Fields[ix+iy*TheMap.Width].Flags; if( n&MapFieldWall ) { MapRemoveWall(ix,iy); } else if( n&MapFieldRocks ) { MapRemoveRock(ix,iy); } else if( n&MapFieldForest ) { MapRemoveWood(ix,iy); } } } break; } }
/** ** Unit Demolishs ** ** @param unit Unit, for that the demolish is handled. */ global void HandleActionDemolish(Unit* unit) { Unit* table[UnitMax]; int i; int n; int xmin, ymin, xmax, ymax; int ix, iy; Unit* goal; int err; DebugLevel3Fn("Demolish %d\n" _C_ UnitNumber(unit)); switch( unit->SubAction ) { // // Move near to target. // case 0: // first entry. NewResetPath(unit); unit->SubAction=1; // FALL THROUGH case 1: // FIXME: reset first!! why? (johns) err=DoActionMove(unit); if( unit->Reset ) { goal=unit->Orders[0].Goal; // // Target is dead, stop demolish. // FIXME: what should I do, go back or explode on place? // if( goal ) { if( goal->Destroyed ) { DebugLevel0Fn("Destroyed unit\n"); RefsDebugCheck( !goal->Refs ); if( !--goal->Refs ) { ReleaseUnit(goal); } // FIXME: perhaps I should choose an alternative unit->Orders[0].Goal=NoUnitP; unit->Orders[0].Action=UnitActionStill; unit->SubAction=0; return; } else if( goal->Removed || !goal->HP || goal->Orders[0].Action==UnitActionDie ) { RefsDebugCheck( !goal->Refs ); --goal->Refs; RefsDebugCheck( !goal->Refs ); unit->Orders[0].Goal=NoUnitP; // FIXME: perhaps I should choose an alternative unit->Orders[0].Action=UnitActionStill; unit->SubAction=0; return; } } // // Have reached target? FIXME: could use pathfinder result? // if( goal ) { if( MapDistanceToUnit(unit->X,unit->Y,goal)<=1 ) { unit->State=0; unit->SubAction=2; } } else if( MapDistance(unit->X,unit->Y ,unit->Orders[0].X,unit->Orders[0].Y)<=1 ) { unit->State=0; unit->SubAction=2; } else if( err==PF_UNREACHABLE ) { unit->Orders[0].Action=UnitActionStill; return; } DebugCheck( unit->Orders[0].Action!=UnitActionDemolish ); } break; // // Demolish the target. // case 2: goal=unit->Orders[0].Goal; if( goal ) { RefsDebugCheck( !goal->Refs ); --goal->Refs; RefsDebugCheck( !goal->Refs ); unit->Orders[0].Goal=NoUnitP; } xmin = unit->X - 2; ymin = unit->Y - 2; xmax = unit->X + 2; ymax = unit->Y + 2; if (xmin<0) xmin=0; if (xmax > TheMap.Width-1) xmax = TheMap.Width-1; if (ymin<0) ymin=0; if (ymax > TheMap.Height-1) ymax = TheMap.Height-1; // FIXME: Must play explosion sound // FIXME: Currently we take the X fields, the original only the O // XXXXX ..O.. // XXXXX .OOO. // XX.XX OO.OO // XXXXX .OOO. // XXXXX ..O.. // // // Effect of the explosion on units. // n=SelectUnits(xmin,ymin, xmax, ymax,table); for( i=0; i<n; ++i ) { if( table[i]->Type->UnitType!=UnitTypeFly && table[i]->HP && table[i] != unit ) { // Don't hit flying units! HitUnit(unit,table[i],DEMOLISH_DAMAGE); } } // // Terrain effect of the explosion // for( ix=xmin; ix<=xmax; ix++ ) { for( iy=ymin; iy<=ymax; iy++ ) { n=TheMap.Fields[ix+iy*TheMap.Width].Flags; if( n&MapFieldWall ) { MapRemoveWall(ix,iy); } else if( n&MapFieldRocks ) { MapRemoveRock(ix,iy); } else if( n&MapFieldForest ) { MapRemoveWood(ix,iy); } } } LetUnitDie(unit); #ifdef HIERARCHIC_PATHFINDER PfHierMapChangedCallback (xmin, ymin, xmax, ymax); #endif break; } }
/** ** Work for missile hit. ** ** @param missile Missile reaching end-point. */ void MissileHit(Missile *missile) { CUnit *goal; int x; int y; CUnit *table[UnitMax]; int n; int i; int splash; if (missile->Type->ImpactSound.Sound) { PlayMissileSound(missile, missile->Type->ImpactSound.Sound); } x = missile->X + missile->Type->Width / 2; y = missile->Y + missile->Type->Height / 2; // // The impact generates a new missile. // if (missile->Type->ImpactMissile) { MakeMissile(missile->Type->ImpactMissile, x, y, x, y); } if (missile->Type->ImpactParticle) { missile->Type->ImpactParticle->pushPreamble(); missile->Type->ImpactParticle->pushInteger(x); missile->Type->ImpactParticle->pushInteger(y); missile->Type->ImpactParticle->run(); } if (!missile->SourceUnit) { // no owner - green-cross ... return; } x /= TileSizeX; y /= TileSizeY; if (x < 0 || y < 0 || x >= Map.Info.MapWidth || y >= Map.Info.MapHeight) { // FIXME: this should handled by caller? DebugPrint("Missile gone outside of map!\n"); return; // outside the map. } // // Choose correct goal. // if (!missile->Type->Range) { if (missile->TargetUnit) { // // Missiles without range only hits the goal always. // goal = missile->TargetUnit; if (goal->Destroyed) { // Destroyed goal->RefsDecrease(); missile->TargetUnit = NoUnitP; return; } MissileHitsGoal(missile, goal, 1); return; } return; } // // Hits all units in range. // i = missile->Type->Range; n = UnitCache.Select(x - i + 1, y - i + 1, x + i, y + i, table, UnitMax); Assert(missile->SourceUnit != NULL); for (i = 0; i < n; ++i) { goal = table[i]; // // Can the unit attack the this unit-type? // NOTE: perhaps this should be come a property of the missile. // if (CanTarget(missile->SourceUnit->Type, goal->Type)) { splash = MapDistanceToUnit(x, y, goal); if (splash) { splash *= missile->Type->SplashFactor; } else { splash = 1; } MissileHitsGoal(missile, goal, splash); } } }