6 #include "libs/binaryheap/binhl.h"
8 /* Define this to get lots of _printf's */
9 //#define DEBUG_UNIT_AI
12 #define _printf(...) fprintf (stdout, __VA_ARGS__)
14 #define _printf(...) { }
18 int map_cost(unit_t
*u
, int x
, int y
, int dx
, int dy
);
20 #define GRAPHSIZE (LEVEL_W * LEVEL_H)
21 #define DJ_INFINITY (GRAPHSIZE * GRAPHSIZE)
22 #define LEVEL_POS(X,Y) ((Y) * LEVEL_W + (X))
24 typedef int levelpos_t
;
26 int get_closest(const long *cost
, levelpos_t src
, int *xx
, int *xy
) {
29 long min_cost
= DJ_INFINITY
;
35 int sy
= src
/ level_w
;
36 int sx
= src
% level_w
;
38 for (j
= -1; j
< 2; j
++) {
39 if (sy
+ j
< 0 || sy
+ j
>= level_h
- 1) continue;
40 for (i
= -1; i
< 2; i
++) {
41 if (i
== 0 && j
== 0) continue;
42 if (sx
+ i
< 0 || sx
+ i
>= level_w
- 1) continue;
44 test_pos
= LEVEL_POS(sx
+ i
, sy
+ j
);
45 test_cost
= cost
[test_pos
] + rand() % 10;
46 if (test_cost
< min_cost
) {
55 *xy
= min_pos
/ level_w
;
56 *xx
= min_pos
% level_w
;
62 int build_path(const int *prev
, int *next
, int n
, levelpos_t src
, levelpos_t dest
, int *nn
) {
66 if (dest
== -1) return -1;
68 if (prev
[dest
] == src
) {
77 int get_path(const int *prev
, levelpos_t src
, levelpos_t dest
, int *xx
, int *xy
) {
79 if (dest
== -1) return -1;
80 if (prev
[dest
] == src
)
82 int y
= dest
/ level_w
;
83 int x
= dest
- (y
* level_w
);
88 return get_path(prev
, src
, prev
[dest
], xx
, xy
);
91 if (dest
== -1) return -1;
92 if (prev
[dest
] == src
) {
97 *xy
= (dest
/ level_w
);
98 *xx
= (dest
% level_w
);
103 #ifdef ALLOW_DIAGONALS
104 #define dir_turn_max 8
106 #define dir_turn_max 4
108 static char dir_turn_x
[9] = { -1, 0, 1, 0, -1, 1, 1,-1, 0 };
109 static char dir_turn_y
[9] = { 0,-1, 0, 1, -1, 1,-1, 1, 0 };
111 static int offset_turn
[9] = { 0 };
113 void dijkstra_fast(unit_t
*u
, long *d
, int *prev
, levelpos_t s
, int pitch
, int lines
) {
115 binh_list open_list
= { 0 };
124 int visited
[GRAPHSIZE
];
125 int max_nodes
= (pitch
* lines
);
126 long infinity
= max_nodes
* max_nodes
;
131 if (max_nodes
> GRAPHSIZE
) return;
132 //printf("Max nodes:%d\n", max_nodes);
134 /* Pre-calculate offsets */
135 for (i
= 0; i
< dir_turn_max
; i
++) {
136 offset_turn
[i
] = dir_turn_y
[i
] * lines
+ dir_turn_x
[i
];
139 for (i
= 0; i
< max_nodes
; i
++) {
141 prev
[i
] = -1; /* no path has yet been found to i */
142 visited
[i
] = 0; /* the i-th element has not yet been visited */
146 /* Put ALL the nodes into open list */
147 //for (i = 0; i < max_nodes; i++) {
148 //binhl_push(&open_list, i, d[i]);
151 binhl_push(&open_list
, s
, 0);
153 while (open_list
.len
) {
155 mini
= binhl_pop(&open_list
);
157 /* Revisit protection. Revisits happen very rarely
158 * and can be remove completeley with some care.
159 * This check itself is pretty costly */
160 if (visited
[mini
]) { revis
++; continue; }
163 /* We shall devise a better method of node search
164 * to remove this bit of math: */
165 y
= mini
/ pitch
; /* Get coords from id */
166 x
= mini
% pitch
; /* Yuck! */
168 for (n
= 0; n
< dir_turn_max
; n
++) {
170 /* All for the sake of this out of bounds searcher */
171 if ((dy
= y
+ dir_turn_y
[n
]) < 0 ||
172 (dx
= x
+ dir_turn_x
[n
]) < 0 ||
173 dx
> pitch
-1 || dy
> lines
-1) continue;
175 i
= dy
* pitch
+ dx
; /* Get id from coords! :( */
177 i
= mini
+ offset_turn
[n
];
178 if (i
< 0 || i
>= pitch
* lines
- 1) continue;
182 /* This function get called only once per dx, dy,
183 * the only overhead is the call itself */
184 if ((dist
= map_cost(u
, x
, y
, dx
, dy
))) // or map_cost[mini][i]
185 if (d
[mini
] + dist
< d
[i
]) {
186 d
[i
] = d
[mini
] + dist
;
188 //printf("Best path from %d to %d\n", i,mini);
189 if (!visited
[i
]) /* Again, is this check useless ? */
190 binhl_push(&open_list
, i
, d
[i
]);
192 if (open_list
.len
> max_in
) max_in
= open_list
.len
;
196 //printf("IN %d cycles, MAX IN LIS: %d, REVISITS: %d\n", intops, max_in, revis);
200 int find_flag(long *cost
, faction_t
*faction
, int type
, long *min
, int *id
) {
207 long min_cost
= DJ_INFINITY
;
210 for (i
= 0; i
< faction
->num_flags
; i
++) {
211 flag_t
*f
= &faction
->flags
[i
];
213 if (f
->type
== type
) {
214 test_pos
= LEVEL_POS(f
->x
, f
->y
);
215 test_cost
= cost
[test_pos
] / 2;
216 if (test_cost
< min_cost
) {
217 min_cost
= test_cost
;
223 /* Pick closest corner */
224 flag_t
*f
= &faction
->flags
[mini
];
225 pos
= LEVEL_POS(f
->x
, f
->y
);
227 for (j
= 0; j
< f
->h
; j
++) {
228 //if (j >= 0 && j < h->h) continue;
229 for (i
= 0; i
< f
->w
; i
++) {
230 //if (i >= 0 && i < h->w) continue;
231 test_pos
= LEVEL_POS(f
->x
+ i
, f
->y
+ j
);
232 test_cost
= cost
[test_pos
];
233 if (test_cost
< min_cost
) {
234 min_cost
= test_cost
;
245 int find_entity(long *cost
, int type
, long *min
, int s
, int *id
) {
247 int min_cost
= DJ_INFINITY
;
250 for (i
= 0; i
< num_units
; i
++) {
251 unit_t
*u
= &units
[i
];
252 unit_p
*p
= &bunits
[u
->tile
];
253 if (u
->visiting
) continue;
254 if (u
->mode
== ANIM_DEATH
) continue;
255 if (u
->faction
== type
) {
256 int hp
= LEVEL_POS(u
->x
, u
->y
- (p
->h
-1));
265 /* Pick closest corner */
266 unit_t
*u
= &units
[mini
];
267 unit_p
*p
= &bunits
[u
->tile
];
268 pos
= LEVEL_POS(u
->x
, u
->y
- (p
->h
-1));
269 _printf("Hunting for unit %d\n", mini
);
271 for (j
= 0; j
< p
->h
; j
++) {
272 //if (j >= 0 && j < h->h) continue;
273 for (i
= 0; i
< p
->w
; i
++) {
274 //if (i >= 0 && i < h->w) continue;
275 int hp
= LEVEL_POS(u
->x
+ i
, u
->y
- (p
->h
-1) + j
);
280 //if (pos == s) return -1;
287 //printf("Found : %d, min_cost: %d\n", pos, min_cost);
291 int find_place(long *cost
, int type
, long *min
, int s
, int *id
) {
293 int min_cost
= DJ_INFINITY
;
296 for (i
= 0; i
< num_houses
; i
++) {
297 house_t
*h
= &houses
[i
];
298 if (h
->tile
== type
|| h
->built
== 0) {
299 int hp
= LEVEL_POS(h
->x
, h
->y
);
308 /* Pick closest corner */
309 house_t
*h
= &houses
[mini
];
310 pos
= LEVEL_POS(h
->x
, h
->y
);
312 for (j
= 0; j
< h
->h
; j
++) {
313 //if (j >= 0 && j < h->h) continue;
314 for (i
= 0; i
< h
->w
; i
++) {
315 //if (i >= 0 && i < h->w) continue;
316 int hp
= LEVEL_POS(h
->x
+ i
, h
->y
+ j
);
321 //if (pos == s) return -1;
328 //printf("Found : %d, min_cost: %d\n", pos, min_cost);
332 void unit_pick_destination(int i
) {
333 unit_t
*u
= &units
[i
];
335 long d
[GRAPHSIZE
]; /* d[i] is the length of the shortest path between the source (s) and node i */
336 int prev
[GRAPHSIZE
]; /* prev[i] is the node that comes right before i in the shortest path from the source to i*/
339 int unit_pos
= LEVEL_POS(u
->x
, u
->y
);
341 int target_x
, target_y
;
343 #ifdef DEBUG_PATHFIND
345 #define THE_PREV u->prev
348 #define THE_PREV prev
351 /* Now calculate all path costs */
352 dijkstra_fast(u
, THE_D
, THE_PREV
, unit_pos
, level_w
, level_h
);
356 long target_cost
= 0;
358 target_pos
= -1; /* for safety */
360 if (u
->strategy
== STRAT_WORK
) {
363 if (u
->carry_gold
>= 100) htype
= 7;
365 target_pos
= find_place(THE_D
, htype
, &target_cost
, unit_pos
, &id
);
367 if (target_pos
!= -1) {
369 u
->target_type
= TARGET_HOUSE
;
375 if (u
->strategy
== STRAT_HUNT
) {
377 target_pos
= find_flag(THE_D
, your
, 0, &target_cost
, &id
);
379 if (target_pos
!= -1) {
381 u
->target_type
= TARGET_FLAG
;
386 if (target_pos
== -1) {
388 target_pos
= find_entity(THE_D
, 1 - u
->faction
, &target_cost
, unit_pos
, &id
);
390 if (target_pos
!= -1) {
392 u
->target_type
= TARGET_UNIT
;
401 //target_pos = get_closest(THE_D, unit_pos, &target_x, &target_y);
403 //printf("Picked: %d, %d\n", target_x, target_y);
405 if (target_pos
== -1) return;
407 #ifdef DEBUG_PATHFIND
408 u
->tar_y
= target_pos
/ level_w
;
409 u
->tar_x
= target_pos
% level_w
;
414 int start
= build_path(THE_PREV
, next
, GRAPHSIZE
, unit_pos
, target_pos
, &len
);
418 if (len
< maxi
) maxi
= len
;
419 for (i
= 0; i
< maxi
; i
++) {
420 u
->path
[i
] = next
[start
+ i
];
422 for (; i
< 16; i
++) {
429 /* Select a target */
430 if (!get_path(THE_PREV
, unit_pos
, target_pos
, &target_x
, &target_y
))
434 } else _printf("%s: No path to target\n", u
->name
);
437 void unit_pick_destination2(int i
) {
438 unit_t
*u
= &units
[i
];
440 if (u
->refresh
.path
|| u
->path
[0] == -1) {
443 unit_pick_destination(i
);
448 if (u
->path
[0] != -1) {
450 int target_pos
= u
->path
[0];
451 for (i
= 0; i
< 16 - 1; i
++) {
452 u
->path
[i
] = u
->path
[i
+ 1];
456 int target_y
= target_pos
/ level_w
;
457 int target_x
= target_pos
% level_w
;
465 void unit_pick_strategy(int i
) {
466 unit_t
*u
= &units
[i
];
468 if (u
->top_desire
== DESIRE_NONE
) {
469 _printf("%s has no desires.. Picking one at random.\n", u
->name
);
470 u
->top_desire
= rand() % MAX_DESIRES
;
472 if (u
->top_method
== DESIRE_NONE
) {
473 _printf("%s has no method to achive his desire.. Picking one at random.\n", u
->name
);
474 u
->top_method
= rand() % MAX_DESIRES
;
476 if (u
->strategy
== STRAT_NONE
) {
477 _printf("%s has no strategy.\n", u
->name
);
478 /* Let's pick one... */
479 switch (u
->top_method
) {
481 /* Easiest way to get gold is to work for your kingdom */
482 u
->strategy
= STRAT_WORK
;
494 if (u
->tactic
== TACT_NONE
) {
495 //_printf("%s has no tactic.\n", u->name);
497 _printf("%s wants %s, his plan is to use %s\n", u
->name
, desire_names
[u
->top_desire
],desire_names
[u
->top_method
]);
498 _printf(" - Strategy: %s, Tactic: %s\n", start_names
[u
->strategy
], tact_names
[u
->tactic
]);
501 int map_cost(unit_t
*u
, int x
, int y
, int dx
, int dy
) {
503 int h_ind
, u_ind
, f_ind
;
504 int manh
= abs(u
->x
- dx
) + abs(u
->y
- dy
);
505 //if (manh > 0 && manh <= 2 && find_unitT(dx, dy) != -1) return DJ_INFINITY;
510 if (dx
- x
!= 0 && dy
- y
!= 0) tile_cost
= 15; //diagonal movements should be more expensive
512 if ((u_ind
= find_unitT(dx
, dy
)) != -1) {
513 unit_t
*u2
= &units
[u_ind
];
517 /* probably doesn't matter */
520 else if (u2
->faction
== u
->faction
) {
522 if (u
->strategy
== STRAT_HEAL
) {
525 if (u2
->dmg
) return 10;
533 if (u
->strategy
== STRAT_HUNT
) {
541 /* For all other cases, treat it as solid tile (to move around) IF it's close */
542 if (manh
> 0 && manh
<= 2 && u2
!= u
) return DJ_INFINITY
;
545 if ((f_ind
= find_flagT(dx
, dy
)) != -1) {
546 flag_t
*f
= &your
->flags
[f_ind
];
548 if (u
->strategy
== STRAT_WORK
) {
549 /* Go over flag, but don't obsess over it */
550 if (f
->type
== 0) return 20;
552 if (u
->strategy
== STRAT_HUNT
) {
553 /* Both flags are good */
554 if (f
->type
== 0) return 20;
558 if ((h_ind
= find_houseT(dx
, dy
)) != -1) {
559 house_t
*h
= &houses
[h_ind
];
560 if (u
->strategy
== STRAT_WORK
) {
561 /* Build/Repair building */
562 if (h
->hp
< h
->max_hp
) return 10;
564 if (h
->tile
== 2 && u
->carry_gold
< 100) return 10;
566 if (h
->tile
== 7 && u
->carry_gold
>= 100) return 10;
568 return DJ_INFINITY
/2;// && dx != u->tx && dy != u->ty) return 500;
571 return 30 + tile_cost
;
574 void unit_think(int i
) {
575 unit_t
*u
= &units
[i
];
576 unit_p
*p
= &bunits
[u
->tile
];
578 unit_pick_strategy(i
);
580 /* Tmp Hack -- override strategy */
582 case MODUS_NONE
: u
->strategy
= STRAT_NONE
; break;
583 case MODUS_WORKER
: u
->strategy
= STRAT_WORK
; break;
584 case MODUS_SOLDIER
: u
->strategy
= STRAT_HUNT
; break;
585 case MODUS_HUNTER
: u
->strategy
= STRAT_HUNT
; break;
586 case MODUS_HEALER
: u
->strategy
= STRAT_HEAL
; break;
587 case MODUS_CARRIER
: u
->strategy
= STRAT_NONE
; break;
588 case MODUS_FOLLOWER
: u
->strategy
= STRAT_NONE
; break;
589 case MODUS_BUFFER
: u
->strategy
= STRAT_HEAL
; break;
590 case MODUS_DEBUFFER
: u
->strategy
= STRAT_HEAL
; break;
591 case MODUS_EXPLORER
: u
->strategy
= STRAT_HUNT
; break;
594 if ((u
->ox
== 0 && u
->oy
== 0 && u
->x
== u
->tx
&& u
->y
== u
->ty
) || u
->refresh
.path
)
595 unit_pick_destination2(i
);