00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00030
00031
00032
00033
00034
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037
00038 #include "stratagus.h"
00039 #include "missile.h"
00040 #include "unittype.h"
00041 #include "animation.h"
00042 #include "actions.h"
00043 #include "unit.h"
00044 #include "unit_cache.h"
00045 #include "map.h"
00046 #include "pathfinder.h"
00047 #include "spells.h"
00048 #include "player.h"
00049
00050
00051
00052
00053
00059 static bool AutoCast(CUnit *unit)
00060 {
00061 if (unit->AutoCastSpell) {
00062 for (int i = 0; i < (int)SpellTypeTable.size(); ++i) {
00063 if (unit->AutoCastSpell[i] && AutoCastSpell(unit, SpellTypeTable[i])) {
00064 return true;
00065 }
00066 }
00067 }
00068 return false;
00069 }
00070
00081 static CUnit *UnitToRepairInRange(CUnit *unit, int range)
00082 {
00083 CUnit *table[UnitMax];
00084 int n;
00085
00086 n = UnitCache.Select(unit->X - range, unit->Y - range,
00087 unit->X + unit->Type->TileWidth + range,
00088 unit->Y + unit->Type->TileHeight + range,
00089 table, UnitMax);
00090 for (int i = 0; i < n; ++i) {
00091 if (table[i]->IsTeamed(unit) &&
00092 table[i]->Type->RepairHP &&
00093 table[i]->Variable[HP_INDEX].Value < table[i]->Variable[HP_INDEX].Max &&
00094 table[i]->IsVisibleAsGoal(unit->Player)) {
00095 return table[i];
00096 }
00097 }
00098 return NoUnitP;
00099 }
00100
00106 bool AutoRepair(CUnit *unit)
00107 {
00108 if (unit->AutoRepair && unit->Type->Variable[AUTOREPAIRRANGE_INDEX].Value) {
00109 CUnit *repairedUnit = UnitToRepairInRange(unit,
00110 unit->Type->Variable[AUTOREPAIRRANGE_INDEX].Value);
00111 if (repairedUnit != NoUnitP) {
00112 COrder order = *unit->Orders[0];
00113 CommandRepair(unit, -1, -1, repairedUnit, FlushCommands);
00114 unit->SavedOrder = order;
00115 return true;
00116 }
00117 }
00118 return false;
00119 }
00120
00124 static void AutoAttack(CUnit *unit, bool stand_ground)
00125 {
00126 CUnit *temp;
00127 CUnit *goal;
00128
00129 if (unit->Wait) {
00130 unit->Wait--;
00131 return;
00132 }
00133
00134
00135 if (unit->Type->CanAttack && !unit->Type->Coward) {
00136
00137 if (CanMove(unit) && !unit->Removed && !stand_ground) {
00138 if ((goal = AttackUnitsInReactRange(unit))) {
00139
00140 CommandAttack(unit, goal->X, goal->Y, NULL, FlushCommands);
00141 Assert(unit->SavedOrder.Action == UnitActionStill);
00142 Assert(!unit->SavedOrder.Goal);
00143 unit->SavedOrder.Action = UnitActionAttack;
00144 unit->SavedOrder.Range = 0;
00145 unit->SavedOrder.X = unit->X;
00146 unit->SavedOrder.Y = unit->Y;
00147 unit->SavedOrder.Goal = NoUnitP;
00148 } else {
00149 unit->Wait = 15;
00150 }
00151
00152 } else if ((goal = AttackUnitsInRange(unit))) {
00153 temp = unit->Orders[0]->Goal;
00154 if (temp && temp->Orders[0]->Action == UnitActionDie) {
00155 temp->RefsDecrease();
00156 unit->Orders[0]->Goal = temp = NoUnitP;
00157 }
00158 if (!unit->SubAction || temp != goal) {
00159
00160 if (temp) {
00161 temp->RefsDecrease();
00162 }
00163 unit->Orders[0]->Goal = goal;
00164 goal->RefsIncrease();
00165 unit->State = 0;
00166 unit->SubAction = 1;
00167 UnitHeadingFromDeltaXY(unit,
00168 goal->X + (goal->Type->TileWidth - 1) / 2 - unit->X,
00169 goal->Y + (goal->Type->TileHeight - 1) / 2 - unit->Y);
00170 }
00171 return;
00172 }
00173 } else {
00174 unit->Wait = 15;
00175 }
00176
00177 if (unit->SubAction) {
00178 if ((temp = unit->Orders[0]->Goal)) {
00179 temp->RefsDecrease();
00180 unit->Orders[0]->Goal = NoUnitP;
00181 }
00182 unit->SubAction = unit->State = 0;
00183 }
00184 Assert(!unit->Orders[0]->Goal);
00185 }
00186
00193 void ActionStillGeneric(CUnit *unit, bool stand_ground)
00194 {
00195
00196 if (unit->Removed && (!unit->Container ||
00197 !unit->Container->Type->CanTransport ||
00198 !unit->Container->Type->AttackFromTransporter ||
00199 unit->Type->Missile.Missile->Class == MissileClassNone)) {
00200
00201 return;
00202 }
00203
00204
00205 if (unit->SubAction) {
00206 AnimateActionAttack(unit);
00207 } else {
00208 UnitShowAnimation(unit, unit->Type->Animations->Still);
00209 }
00210
00211 if (unit->Anim.Unbreakable) {
00212 return;
00213 }
00214
00215 if (AutoCast(unit) || AutoRepair(unit)) {
00216 return;
00217 }
00218
00219 AutoAttack(unit, stand_ground);
00220
00221
00222
00223 if (unit->Type->SeaUnit || unit->Type->AirUnit) {
00224 unit->IY = (MyRand() >> 15) & 1;
00225 }
00226 }
00227
00233 void HandleActionStill(CUnit *unit)
00234 {
00235 ActionStillGeneric(unit, false);
00236 }
00237