1 #include "libs/savepng/savepng.h"
2 #include "libs/lazyass/lazyass.h"
3 #include "libs/binaryheap/binhl.h"
4 #include "libs/SDL_inprint/SDL2_inprint.h"
16 void init_factions() {
18 memset(factions
, 0, sizeof(faction_t
) * 8);
20 strcpy(factions
[0].title
, "Your Kingdom");
21 factions
[0].color
.r
= 0;
22 factions
[0].color
.g
= 0;
23 factions
[0].color
.b
= 0xff;
24 factions
[0].gold
= 10000;
26 strcpy(factions
[1].title
, "Reavers");
27 factions
[1].color
.r
= 0xff;
28 factions
[1].color
.g
= 0;
29 factions
[1].color
.b
= 0;
30 factions
[1].gold
= 10000;
34 void clear_house(int id
) {
35 house_t
*h
= &houses
[id
];
40 memset(h
->flag_id
, -1, sizeof(Sint8
) * MAX_FACTIONS
);
42 /* Assign visual refs */
43 h
->axis_refs
[HAXIS_TYPE
] = &h
->tile
;
44 h
->axis_refs
[HAXIS_STATE
] = &h
->built
;
45 h
->axis_refs
[HAXIS_FRAME
] = &h
->frame
;
48 void clear_unit(int id
) {
49 unit_t
*u
= &units
[id
];
51 memset(u
, 0, sizeof(unit_t
));
55 memset(u
->flag_id
, -1, sizeof(Sint8
) * MAX_FACTIONS
);
57 u
->axis_refs
[UAXIS_TYPE
] = &u
->tile
;
58 u
->axis_refs
[UAXIS_MODE
] = &u
->mode
;
59 u
->axis_refs
[UAXIS_FRAME
] = &u
->frame
;
60 u
->axis_refs
[UAXIS_FACEFRAME
] = &u
->faceframe
;
65 for (i
= 0; i
< MAX_HOUSES
; i
++) {
73 for (i
= 0; i
< MAX_UNITS
; i
++) {
79 void remove_flag(int id
) {
80 flag_t
*f
= &your
->flags
[id
];
83 f
->house
->flag_id
[ui
.faction
] = -1;
86 f
->unit
->flag_id
[ui
.faction
] = -1;
89 if (id
< your
->num_flags
) {
90 memcpy(&your
->flags
[id
], &your
->flags
[your
->num_flags
- 1], sizeof(flag_t
));
91 if (ui
.flag
== your
->num_flags
- 1) ui
.flag
= id
;
94 if (ui
.flag
== id
) ui
.flag
= -1;
97 int add_flag(Uint8 tx
, Uint8 ty
, Uint8 type
) {
99 int id
= your
->num_flags
;
101 flag_t
*f
= &your
->flags
[id
];
115 if (ui
.hover
== overUnit
) {
116 unit_t
*u
= &units
[ui
.hover_id
];
119 f
->w
= bunits
[u
->tile
].w
;
120 f
->h
= bunits
[u
->tile
].h
;
122 u
->flag_id
[ui
.faction
] = id
;
124 } else if (ui
.hover
== overHouse
) {
126 f
->house
= &houses
[ui
.hover_id
];
128 f
->w
= houses
[ui
.hover_id
].w
;
129 f
->h
= houses
[ui
.hover_id
].h
;
131 houses
[ui
.hover_id
].flag_id
[ui
.faction
] = id
;
147 flag_t
*f
= &your
->flags
[ui
.flag
];
149 if (your
->gold
< 100) {
151 log_add(&gamelog
, "Not enough gold, your majesty!");
160 int add_house(Uint32 tx
, Uint32 ty
) {
163 house_p
*m
= &bhouses
[ui
.builder
];
165 house_t
*h
= &houses
[id
];
168 h
->tile
= ui
.builder
;//m->tile;
178 h
->faction
= 0;/* :( */
180 h
->capacity
= h
->w
* h
->h
;
182 your
->gold
-= m
->gold_cost
;
189 void stress_unit(int id
, int dmg
) {
190 unit_t
*u
= &units
[id
];
194 void kill_unit(int id
) {
195 unit_t
*u
= &units
[id
];
199 /* When devotee dies, his link to lord is removed */
201 ///* Lord is alarmed */
202 //unit_t *l = u->link;
203 //while (l->link) l = l->link;
206 u
->link
->ref_count
[u
->link_stat
]--;
207 u
->link
->ref_counts
--;
210 /* When lord dies, his devotees are freed! */
211 if (u
->ref_count
[u
->link_stat
]) {
213 for (i
= 0; i
< num_units
; i
++) {
214 if (units
[i
].link
== u
) {
216 units
[i
].link
= NULL
;
217 u
->ref_count
[u
->link_stat
]--;
225 int spawn_unit(Uint8 type
, Uint8 faction
, Uint8 x
, Uint8 y
) {
227 int id
= num_units
++; //TODO: proper handling
229 unit_t
*u
= &units
[id
];
230 unit_p
*p
= &bunits
[type
];
237 u
->faction
= faction
;
241 for (i
= 0; i
< MAX_STAT
; i
++) {
242 u
->base_stat
[i
] = p
->base_stat
[i
];
250 int find_flagT(Uint8 tx
, Uint8 ty
) {
253 for (i
= 0; i
< your
->num_flags
; i
++) {
254 flag_t
*f
= &your
->flags
[i
];
255 if (tx
>= f
->x
&& tx
<= f
->x
+(f
->w
-1) &&
256 ty
>= f
->y
&& ty
<= f
->y
+(f
->h
-1))
263 return flag_grid_i
[ty
][tx
];
267 int find_houseT(Uint8 tx
, Uint8 ty
) {
270 for (i
= 0; i
< num_houses
; i
++) {
271 house_t
*h
= &houses
[i
];
272 if (tx
>= h
->x
&& tx
<= h
->x
+(h
->w
-1) &&
273 ty
>= h
->y
&& ty
<= h
->y
+(h
->h
-1))
280 return house_grid_i
[ty
][tx
];
284 int find_house(Uint32 x
, Uint32 y
) {
286 (x
+ ui
.vx
- game_map
.x
) / TILE_W
,
287 (y
+ ui
.vy
- game_map
.y
) / TILE_H
291 int find_unitT(Uint8 tx
, Uint8 ty
) {
294 for (i
= 0; i
< num_units
; i
++) {
295 unit_t
*u
= &units
[i
];
296 unit_p
*p
= &bunits
[u
->tile
];
297 if (u
->visiting
) continue;
298 if (u
->mode
== ANIM_DEATH
) continue;
299 if (tx
>= u
->x
&& tx
<= u
->x
+(p
->w
-1) &&
300 ty
<= u
->y
&& ty
>= u
->y
-(p
->h
-1) )
307 /*unit_t *u = unit_grid[ty][tx];
309 if (u->visiting) return -1;
310 if (u->mode == ANIM_DEATH) return -1;
312 return unit_grid_i
[ty
][tx
];
316 int find_unit(Uint32 x
, Uint32 y
) {
317 x
= x
+ ui
.vx
- game_map
.x
;
318 y
= y
+ ui
.vy
- game_map
.y
;
321 for (i
= 0; i
< num_units
; i
++) {
322 unit_t
*u
= &units
[i
];
323 unit_p
*p
= &bunits
[u
->tile
];
324 if (u
->visiting
) continue;
327 pos
.x
= u
->x
* TILE_W
+ u
->ox
;
328 pos
.y
= (u
->y
-(p
->h
-1)) * TILE_H
+ u
->oy
;
330 pos
.w
= TILE_W
* p
->w
;
331 pos
.h
= TILE_H
* p
->h
;
333 if (SDL_InBounds(x
, y
, &pos
))
341 int xcollide(Uint8 tx
, Uint8 ty
, Uint8 w
, Uint8 h
) {
343 for (j
= 0; j
< h
; j
++) {
344 for (i
= 0; i
< w
; i
++) {
345 //if (fog[ty + j][tx + i]) return 1;
346 if (find_houseT(tx
+ i
, ty
+ j
) != -1) return 1;
347 if (find_unitT (tx
+ i
, ty
+ j
) != -1) return 1;
353 #include "SDL2_particles.h"
355 particle_system psystems
[128];
356 int num_psystems
= 0;
358 void add_fire(Sint16 x
, Sint16 y
, Uint16 limit
) {
359 int id
= num_psystems
++;
360 particle_system
*ps
= &psystems
[id
];
365 ps
->init
= &basic_particle_init
;
366 ps
->move
= &basic_particle_move
;
367 ps
->reset
= &basic_particle_reset
;
371 void update_particles() {
373 for (i
= 0; i
< num_psystems
; i
++) {
374 particle_system
*ps
= &psystems
[i
];
379 void draw_particles(SDL_Renderer
*target
, Uint32 bx
, Uint32 by
) {
382 for (i
= 0; i
< num_psystems
; i
++) {
383 particle_system
*ps
= &psystems
[i
];
384 if (!ps
->limit
) continue;
385 PS_Render(target
, ps
, reds
, 1, bx
, by
);
393 for (ty
= 0; ty
< level_h
; ty
++) {
394 for (tx
= 0; tx
< level_w
; tx
++) {
396 scent_human
[ty
][tx
] = 0;
405 for (ty
= 0; ty
< level_h
; ty
++) {
406 for (tx
= 0; tx
< level_w
; tx
++) {
408 if (scent_human
[ty
][tx
] > 0) scent_human
[ty
][tx
]--;
409 if (scent_human
[ty
][tx
] > 255) scent_human
[ty
][tx
] = 255;
414 for (i
= 0; i
< num_houses
; i
++) {
415 house_t
*h
= &houses
[i
];
416 int j
, k
, bl
= h
->h
/2;
417 for (j
= -h
->h
+bl
; j
< h
->h
+bl
+1; j
++) {
418 if (h
->y
+ j
< 0) continue;
419 if (h
->y
+ j
>= level_h
) break;
420 for (k
= -h
->w
; k
< h
->w
+1; k
++) {
421 if (h
->x
+ k
< 0) continue;
422 if (h
->x
+ k
>= level_w
) break;
423 fog
[h
->y
+ j
][h
->x
+ k
] = 0;
428 for (i
= 0; i
< num_units
; i
++) {
429 unit_t
*u
= &units
[i
];
430 unit_p
*p
= &bunits
[u
->tile
];
432 for (j
= -1; j
< 2; j
++) {
433 if (u
->y
+ j
< 0) continue;
434 if (u
->y
+ j
>= level_h
) break;
435 for (k
= -1; k
< 2; k
++) {
436 if (u
->x
+ k
< 0) continue;
437 if (u
->x
+ k
>= level_w
) break;
438 if (fog
[u
->y
+ j
][u
->x
+ k
] == 1) {
441 fog
[u
->y
+ j
][u
->x
+ k
] = 0;
442 scent_human
[u
->y
+ j
][u
->x
+ k
] += p
->base_scent
[SCENT_HUMAN
];
463 log_add(&gamelog
, "Started");
465 add_fire(100,100,25000);
474 tiles
= ASS_LoadTexture("data/gfx/runelord.bmp", &white
);
476 cfg_load("data/rune.cfg");
478 uibg
= ASS_LoadTexture("data/gfx/woodui.bmp", &white
);
480 small_font
= ASS_LoadTexture("data/fonts/oddball6x8.bmp", &magenta
);
482 mid_font
= ASS_LoadTexture("data/fonts/webby8.bmp", &black
);
484 large_font
= NULL
; /* aka inline */
495 for (i
= 0; i
< 50; i
++) {
501 units
[0].x
= units
[0].y
= units
[0].tx
= units
[0].ty
= 0;
503 units
[1].tx
= units
[1].x
= (units
[1].x
- 3);
504 units
[1].ty
= units
[1].y
= (units
[1].y
+ 2);
505 units
[2].tx
= units
[2].x
= (units
[2].x
- 2);
506 units
[2].ty
= units
[2].y
= (units
[2].y
+ 4);
510 void focus_on_unit() {
511 unit_t
*u
= &units
[ui
.unit
];
512 int nvx
= u
->tx
* TILE_W
- ui
.log_width
/ 2;
513 int nvy
= u
->ty
* TILE_H
- ui
.log_height
/ 2;
515 ui
.flingx
= nvx
- ui
.vx
;
516 ui
.flingy
= nvy
- ui
.vy
;
519 void do_update_grids(void) {
522 for (j
= 0; j
< level_h
; j
++)
523 for (i
= 0; i
< level_w
; i
++) {
525 unit_grid
[j
][i
] = NULL
;
526 house_grid
[j
][i
] = NULL
;
528 flag_grid_i
[j
][i
] = -1;
529 unit_grid_i
[j
][i
] = -1;
530 house_grid_i
[j
][i
] = -1;
534 for (i
= 0; i
< your
->num_flags
; i
++) {
535 flag_t
*flag
= &your
->flags
[i
];
536 for (k
= 0; k
< flag
->h
; k
++) for (j
= 0; j
< flag
->w
; j
++) {
538 flag_grid_i
[flag
->y
+ k
][flag
->x
+ j
] = i
;
543 for (i
= 0; i
< num_houses
; i
++) {
544 house_t
*house
= &houses
[i
];
545 for (k
= 0; k
< house
->h
; k
++) for (j
= 0; j
< house
->w
; j
++) {
547 house_grid
[house
->y
+ k
][house
->x
+ j
] = house
;
548 house_grid_i
[house
->y
+ k
][house
->x
+ j
] = i
;
553 for (i
= 0; i
< num_units
; i
++) {
554 unit_t
*unit
= &units
[i
];
555 unit_p
*proto
= &bunits
[unit
->tile
];
556 if (unit
->visiting
) continue;
557 if (unit
->mode
== ANIM_DEATH
) continue;
558 for (k
= 0; k
< proto
->h
; k
++) for (j
= 0; j
< proto
->w
; j
++) {
560 unit_grid
[unit
->y
- (proto
->h
-1) + k
][unit
->x
+ j
] = unit
;
561 unit_grid_i
[unit
->y
- (proto
->h
-1) + k
][unit
->x
+ j
] = i
;
566 void do_update_links(void) {
574 void do_scroll_out() {
575 if (ui
.unit
== -1) return;
576 unit_t
*su
= &units
[ui
.unit
];
582 for (i
= 0; i
< num_units
; i
++) if (units
[i
].link
== su
) fs
[f
++] = i
;
585 printf("Rand is: %d\n", i
);
591 void do_scroll_in() {
592 if (ui
.unit
== -1) return;
593 unit_t
*u
= &units
[ui
.unit
];
596 ui
.unit
= u
->link_id
;
601 void do_pin_click() {
603 if (ui
.hover
== overListName
) {
605 ui
.unit
= ui
.hover_id
;
608 if (ui
.hover
== overListPin
) {
610 units
[ui
.hover_id
].pin
= 0;
616 void do_minimap_click() {
617 int x
= ui
.x
- minimap
.x
;
618 int y
= ui
.y
- minimap
.y
;
620 int zY
= (level_h
* TILE_W
) / minimap
.h
;
621 int zX
= (level_w
* TILE_H
) / minimap
.w
;
626 ui
.vx
= vx
- game_map
.w
/ 2;
627 ui
.vy
= vy
- game_map
.h
/ 2;
635 unit_t
*u
= &units
[ui
.unit
];
642 if (u
->tile
== U_PEASANT
) {
644 int next
= U_PEASANT
;
646 case 0: next
= U_MILITIA
; cost
= 250; break;
647 case 1: next
= U_ARCHER
; u
->base_stat
[S_DEX
]+=5; cost
= 200; break;
648 case 2: next
= U_KNIGHT
; cost
= 350; break;
649 case 3: next
= U_FLAMER
+rand()%4; cost
= 500; break;
664 void do_event_cancel() {
679 void do_event_click(Uint32 x
, Uint32 y
) {
681 //printf("Clicked on %d, %d\n", x, y);
684 if (ui
.setflag
!= -1) {
686 if (ui
.hover_top
== overMap
) {
688 if (ui
.hover_xcollide
!= ui
.setflag
|| ui
.hover
== overFlag
) {
690 log_add(&gamelog
, "Can't place here");
692 } else if (your
->gold
< 100) {
694 log_add(&gamelog
, "Not enough gold");
699 ui
.flag
= add_flag(ui
.hover_tx
, ui
.hover_ty
, ui
.setflag
);
709 /* Building houses? */
710 if (ui
.builder
!= -1) {
712 if (ui
.hover_top
== overMap
) {
714 if (ui
.hover_xcollide
) {
715 log_add(&gamelog
, "Can't place here");
720 ui
.house
= add_house(ui
.hover_tx
, ui
.hover_ty
);
739 ui
.setflag
= ui
.hover_id
;
742 case overBuildButton
:
744 ui
.builder
= ui
.hover_id
;
756 ui
.housetab
= ui
.hover_id
;
761 ui
.unittab
= ui
.hover_id
;
766 units
[ui
.unit
].pin
= 1 - units
[ui
.unit
].pin
;
771 ui
.flag
= houses
[ui
.unit
].flag_id
[ui
.hover_id
];
772 if (ui
.flag
!= -1) ui
.house
= -1;
777 ui
.flag
= units
[ui
.unit
].flag_id
[ui
.hover_id
];
778 if (ui
.flag
!= -1) ui
.unit
= -1;
783 /* Start rune linking */
784 if (units
[ui
.unit
].link
== NULL
) ui
.stat
= ui
.hover_id
;
790 if (units
[ui
.unit
].link
== NULL
) ui
.btn
= ui
.hover_id
;
808 if (ui
.hover_id
!= ui
.unit
) { // add other verefications, like factions, costs, etc
810 add_link(ui
.unit
, ui
.hover_id
, ui
.stat
);
812 ui
.unit
= ui
.hover_id
; /* Also select */
814 /* Stop rune-linking, if it's not possible */
815 if (units
[ui
.unit
].link
!= NULL
|| units
[ui
.unit
].ref_count
[ui
.stat
] > 1) ui
.stat
= -1;
822 ui
.unit
= ui
.hover_id
;
830 ui
.house
= ui
.hover_id
;
837 ui
.flag
= ui
.hover_id
;
851 void debug_dump_animation(animation_t
*a
) {
853 //SDL_Rect src = { a->plane.x, a->plane.y, a->plane.w, a->plane.h };
855 printf("Plane: %d, %d -- %d, %d\n", a
->plane
.x
, a
->plane
.y
, a
->plane
.w
, a
->plane
.h
);
858 //...offset by each modifier axis
859 for (i
= 0; i
< a
->num_axises
; i
++) {
861 Uint8 ask
= a
->axis_modifier
[i
];
862 //Uint8 ref = *(u->axis_refs[ask]);
863 //src.x += ref * a->axis_offset[i].w + a->axis_offset[i].x;
864 //src.y += ref * a->axis_offset[i].h + a->axis_offset[i].y;
866 printf(" Axis %d -- modifier %d, mult by X %d Y %d, plus X %d Y %d\n",
871 a
->axis_offset
[i
].y
);
875 void debug_dump_unitp(unit_p
*p
) {
878 debug_dump_animation(&p
->body
);
880 debug_dump_animation(&p
->face
);
883 void debug_dump_unit(unit_t
*u
) {
884 debug_dump_unitp(&bunits
[u
->tile
]);
889 int id
= spawn_unit(22, 1, rand() % level_w
, rand() % level_h
);
890 unit_t
*u
= &units
[id
];
892 strcpy(u
->name
, "Path Finder");
897 int id
= spawn_unit(17, 1, rand() % level_w
, rand() % level_h
);
898 unit_t
*u
= &units
[id
];
899 strcpy(u
->name
, "Ratticate");
904 int id
= spawn_unit(1, 0, rand() % level_w
, rand() % level_h
);
905 unit_t
*u
= &units
[id
];
911 void do_event_key(int sym
, int scan
) {
913 if (sym
== SDLK_AC_BACK
) do_event_cancel();
914 if (scan
== SDL_SCANCODE_MENU
) add_reaver();
915 if (sym
== SDLK_AC_SEARCH
) ui
.draw_minimap
= 1- ui
.draw_minimap
;
916 //if (scan == SDL_SCANCODE_MENU) show_menu();
918 if (sym
== SDLK_m
) debug_dump_unitp(&bunits
[units
[ui
.unit
].tile
]);
920 if (sym
== SDLK_1
) ui
.game_speed
= 25;
921 if (sym
== SDLK_5
) ui
.game_speed
= 1;
923 if (sym
== SDLK_s
) ui
.draw_scent
= 1 - ui
.draw_scent
;
924 if (sym
== SDLK_t
) ui
.draw_path
= 1 - ui
.draw_path
;
925 if (sym
== SDLK_f
) ui
.draw_fog
= 1 - ui
.draw_fog
;
926 if (sym
== SDLK_l
) ui
.draw_overlays
= 1 - ui
.draw_overlays
;
927 if (sym
== SDLK_p
) ui
.draw_pools
= 1 - ui
.draw_pools
;
929 if (sym
== SDLK_z
) add_reaver();
930 if (sym
== SDLK_x
) add_rat();
931 if (sym
== SDLK_a
) add_peasant();
932 if (sym
== SDLK_n
) units
[ui
.unit
].tile
++;
933 if (sym
== SDLK_q
) { units
[ui
.unit
].top_desire
++; units
[ui
.unit
].top_method
= 0; }
934 if (sym
== SDLK_k
) stress_unit(ui
.unit
,1);
935 if (sym
== SDLK_r
) rebuild_pools();
936 if (sym
== SDLK_c
) collect_pools();
937 //if (sym == SDLK_x) prop_pools();
938 if (sym
== SDLK_d
) distrib_pools();
939 if (sym
== SDLK_e
&& ui
.unit
) units
[ui
.unit
].carry_gold
+= 100;
940 if (sym
== SDLK_i
) units
[ui
.unit
].energy
+= 5;
943 units
[ui
.unit
].tx
= units
[ui
.unit
].x
= ui
.hover_tx
;
944 units
[ui
.unit
].ty
= units
[ui
.unit
].y
= ui
.hover_ty
;
949 units
[ui
.unit
].tx
= ui
.x
/ 16;
950 units
[ui
.unit
].ty
= ui
.y
/ 16;
952 if (ui
.house
!= -1) {
953 houses
[ui
.house
].hp
+= 20;
954 if (houses
[ui
.house
].hp
>= houses
[ui
.house
].max_hp
) {
955 houses
[ui
.house
].hp
= houses
[ui
.house
].max_hp
;
956 houses
[ui
.house
].built
= 1;
963 void do_event_mouse(SDL_Event
*e
) {
965 int tracking_mouse
= 0;
967 if (e
->type
== SDL_MOUSEMOTION
) {
969 if (e
->motion
.which
== SDL_TOUCH_MOUSEID
) return;
975 ui
.flingx
-= e
->motion
.xrel
;
976 ui
.flingy
-= e
->motion
.yrel
;
981 if (e
->type
== SDL_MOUSEBUTTONDOWN
|| e
->type
== SDL_MOUSEBUTTONUP
) {
983 if (e
->button
.which
== SDL_TOUCH_MOUSEID
) return;
992 if (e
->type
== SDL_MOUSEBUTTONDOWN
) {
993 if (e
->button
.button
== 2) { /* hold middle button */
996 if (e
->button
.button
== 1) { /* left click (handled on mousedown for smoother UI animations) */
997 do_event_click(ui
.x
, ui
.y
);
1002 if (e
->type
== SDL_MOUSEBUTTONUP
) {
1003 if (e
->button
.button
== 2) { /* release middle button */
1006 if (e
->button
.button
== 3) { /* right click */
1009 if (e
->button
.button
== 1) { /* release left button */
1015 if (tracking_mouse
) track_mouse();
1018 void do_event(SDL_Event
*e
) {
1020 if (e
->type
== SDL_FINGERDOWN
) {
1022 ui
.x
= (int) (e
->tfinger
.x
* ui
.log_width
);
1023 ui
.y
= (int) (e
->tfinger
.y
* ui
.log_height
);
1026 do_event_click(ui
.x
, ui
.y
);
1029 if (e
->type
== SDL_FINGERMOTION
) {
1031 if (e
->tfinger
.fingerId
== 0) {
1033 ui
.flingx
-= (int) (e
->tfinger
.dx
* ui
.log_width
);
1034 ui
.flingy
-= (int) (e
->tfinger
.dy
* ui
.log_height
);
1039 if (e
->type
== SDL_MOUSEMOTION
1040 || e
->type
== SDL_MOUSEBUTTONDOWN
1041 || e
->type
== SDL_MOUSEBUTTONUP
) {
1047 if (e
->type
== SDL_KEYDOWN
) {
1049 do_event_key(e
->key
.keysym
.sym
, e
->key
.keysym
.scancode
);
1053 if (e
->type
== SDL_MOUSEWHEEL
) {
1055 if (e
->wheel
.y
> 0) do_scroll_in();
1056 else if (e
->wheel
.y
< 0) do_scroll_out();
1063 void do_unit_in_house(unit_t
*u
, house_t
*h
) {
1065 /* Unloading gold */
1066 if (u
->carry_gold
>= 100 && h
->tile
== 7) {
1068 if (u
->progress
>= 10) {
1070 u
->carry_gold
-= 100;
1076 if (h
->tile
== 2 && u
->carry_gold
< 100) {
1078 u
->stat_bid
[S_STR
] = 1;
1079 if (u
->progress
>= 10) {
1081 int mined
= u
->calc_stat
[S_STR
] * 3;
1082 if (mined
== 0) mined
= 1;
1083 u
->carry_gold
+= mined
;
1087 /* Seeking shelter? */
1089 u
->stat_bid
[S_MET
] = 1;
1091 if (u
->progress
>= 10) {
1093 int healed
= u
->calc_stat
[S_MET
] * 3;
1094 if (healed
> u
->dmg
) healed
= u
->dmg
;
1106 void compute_stats() {
1108 for (i
= 0; i
< num_units
; i
++) {
1109 unit_t
*u
= &units
[i
];
1111 u
->max_hp
= u
->calc_stat
[S_CON
] * 10;
1112 if (u
->max_hp
< 1) u
->max_hp
= 1;
1114 /* TODO: better formulas than this PoS? */
1115 u
->calc_skill
[SKILL_BUILD
] = u
->calc_stat
[S_STR
] + u
->base_skill
[SKILL_BUILD
];
1116 u
->calc_skill
[SKILL_REPAIR
] = u
->calc_stat
[S_STR
] + u
->base_skill
[SKILL_REPAIR
];
1117 u
->calc_skill
[SKILL_MELEE
] = u
->calc_stat
[S_STR
] + u
->base_skill
[SKILL_MELEE
];
1118 u
->calc_skill
[SKILL_RANGED
] = u
->calc_stat
[S_STR
] + u
->base_skill
[SKILL_RANGED
];
1119 u
->calc_skill
[SKILL_RIDE
] = u
->calc_stat
[S_STR
] + u
->base_skill
[SKILL_RIDE
];
1120 u
->calc_skill
[SKILL_MAGERY
] = u
->calc_stat
[S_STR
] + u
->base_skill
[SKILL_MAGERY
];
1125 void unit_claim_flag(unit_t
*u
, int j
) {
1126 flag_t
*flag
= &your
->flags
[j
];
1128 if (flag
->type
== 0) {
1129 u
->gold
+= flag
->reward
;
1136 void do_unit_hit_unit(unit_t
*u
, int j
) {
1137 unit_t
*target
= &units
[j
];
1139 if (target
->faction
== u
->faction
) return;
1146 void do_unit_hit_house(unit_t
*u
, int k
) {
1147 house_t
*h
= &houses
[k
];
1149 if (u
->faction
!= h
->faction
) {
1154 if (h
->built
== 0) {
1156 if (u
->progress
>= 10) {
1160 if (h
->hp
>= h
->max_hp
) {
1169 if (!u
->visiting
&& h
->visitors
< h
->capacity
)
1179 if (u
->progress
>= 10) {
1185 /* Visiting (to unload gold) ? */
1186 if (h
->tile
== 7 && u
->carry_gold
>= 100) {
1187 if (!u
->visiting
&& h
->visitors
< h
->capacity
)
1193 //printf("%s HITTING HOUSE %s\n", u->name, h->title);
1196 void do_unit_walk(unit_t
*u
) {
1197 unit_p
*p
= &bunits
[u
->tile
];
1201 int h_ind
, u2_ind
, f_ind
;
1204 if (u
->x
< u
->tx
) next_x
= + 1;
1205 if (u
->x
> u
->tx
) next_x
= - 1;
1206 if (u
->y
< u
->ty
) next_y
= + 1;
1207 if (u
->y
> u
->ty
) next_y
= - 1;
1208 //printf("Walk: %d, %d\n", next_x, next_y);
1209 #ifndef ALLOW_DIAGONALS
1210 if (next_x
&& next_y
) { if (rand() % 2) next_y
= 0; else next_x
= 0; }
1213 for (j
= 0; j
< p
->h
; j
++) {
1214 for (i
= 0; i
< p
->w
; i
++) {
1216 f_ind
= find_flagT(next_x
+ u
->x
+ i
, next_y
+ u
->y
- (p
->h
-1) + j
);
1218 unit_claim_flag(u
, f_ind
);
1221 h_ind
= find_houseT(next_x
+ u
->x
+ i
, next_y
+ u
->y
- (p
->h
-1) + j
);
1223 do_unit_hit_house(u
, h_ind
);
1224 u
->refresh
.path
= 1;
1228 u2_ind
= find_unitT(next_x
+ u
->x
+ i
, next_y
+ u
->y
- (p
->h
-1) + j
);
1230 if (&units
[u2_ind
] == u
) {
1231 //printf("Found ownself :(\n");
1234 do_unit_hit_unit(u
, u2_ind
);
1235 u
->refresh
.path
= 1;
1241 u
->ox
= - next_x
* TILE_W
;
1242 u
->oy
= - next_y
* TILE_H
;
1250 if (fog
[u
->y
][u
->x
] == 1) {
1252 fog
[u
->y
][u
->x
] = 0;
1255 u
->mode
= ANIM_WALK
;
1256 if (u
->carry_gold
>= 100) {
1257 u
->mode
= ANIM_CARRY
;
1261 void progress_animation(animation_t
*anim
, Uint8 anim_id
, Uint8
*frame
, Sint8
*frame_counter
) {
1263 Sint8 counter
= *(frame_counter
);
1265 if (counter
>= anim
->num_frames
[anim_id
]) {
1268 if (anim
->frame
[anim_id
][counter
] < 0) {
1269 counter
+= anim
->frame
[anim_id
][counter
];
1275 *(frame
) = anim
->frame
[anim_id
][counter
];
1276 *(frame_counter
) = ++counter
;
1279 void do_unit_anim(unit_t
*u
) {
1280 unit_p
*p
= &bunits
[u
->tile
];
1284 if (u
->carry_gold
) {
1285 u
->mode
= ANIM_CARRY
;
1290 progress_animation(&p
->body
, anim_id
, &u
->frame
, &u
->framecnt
);
1292 u
->faceframe
= p
->face
.frame
[ANIM_FACE
][0]; /* faceframe is always first frame for now... */
1295 void do_house_anim(house_t
*h
) {
1297 house_p
*p
= &bhouses
[h
->tile
];
1299 progress_animation(&p
->body
, 0, &h
->frame
, &h
->framecnt
);
1302 void do_map_scroll() {
1306 if (ui
.flingy
> 0) {
1307 if (step
> ui
.flingy
) step
= ui
.flingy
;
1311 if (ui
.flingy
< 0) {
1312 if (-step
< ui
.flingy
) step
= -ui
.flingy
;
1316 if (ui
.flingx
> 0) {
1317 if (step
> ui
.flingx
) step
= ui
.flingx
;
1321 if (ui
.flingx
< 0) {
1322 if (-step
< ui
.flingx
) step
= -ui
.flingx
;
1329 int view_w
= game_map
.w
;
1330 int view_h
= game_map
.h
;
1332 int max_w
= level_w
* TILE_W
;
1333 int max_h
= level_h
* TILE_H
;
1335 if (ui
.y
>= 480-1) ui
.vy
+= step
;
1336 if (ui
.y
<= 0) ui
.vy
-= step
;
1337 if (ui
.x
>= 640-1) ui
.vx
+= step
;
1338 if (ui
.x
<= 0) ui
.vx
-= step
;
1340 if (ui
.vx
> max_w
- view_w
) ui
.vx
= max_w
- view_w
;
1341 if (ui
.vy
> max_h
- view_h
) ui
.vy
= max_h
- view_h
;
1342 if (ui
.vy
< 0) ui
.vy
= 0;
1343 if (ui
.vx
< 0) ui
.vx
= 0;
1348 binh_list unit_list
= { 0 };
1350 int max_energy
= 1000;
1352 for (i
= 0; i
< num_units
; i
++) {
1353 binhl_push(&unit_list
, i
, max_energy
- units
[i
].energy
);
1357 if (ui
.freq
> 1000) ui
.freq
= 0;
1361 //for (i = 0; i < num_units; i++) {
1362 while (unit_list
.len
) {
1364 i
= binhl_pop(&unit_list
);
1365 unit_t
*u
= &units
[i
];
1366 if (u
->energy
== 0) break;
1368 if (u
->energy
>= ECOST_VISIT
) {
1369 do_unit_in_house(u
, u
->visiting
);
1371 u
->energy
-= ECOST_VISIT
;
1375 if (u
->ox
!= 0 || u
->oy
!= 0) {
1376 if (u
->energy
>= ECOST_SLIDE
) {
1377 #ifndef ALLOW_DIAGONALS
1378 if (u
->ox
) u
->ox
+= (u
->ox
> 0 ? -1 : 1);
1379 else u
->oy
+= (u
->oy
> 0 ? -1 : 1);
1381 u
->ox
+= (u
->ox
> 0 ? -1 : 1);
1382 u
->oy
+= (u
->oy
> 0 ? -1 : 1);
1384 u
->energy
-= ECOST_SLIDE
;
1388 if (u
->x
!= u
->tx
|| u
->y
!= u
->ty
) {
1390 if (u
->energy
>= ECOST_WALK
) {
1393 u
->energy
-= ECOST_WALK
;
1399 if (ui
.hover_top
== overMap
) track_mouse_map();
1407 for (i
= 0; i
< num_units
; i
++) {
1408 unit_t
*u
= &units
[i
];
1411 u
->energy
+= u
->calc_stat
[S_DEX
] * 3;
1412 if (u
->energy
> (u
->calc_stat
[S_DEX
]+1) * 10) u
->energy
= (u
->calc_stat
[S_DEX
]+1) * 10;
1415 if (u
->mode
!= ANIM_DEATH
) u
->framecnt
= 0;
1416 u
->mode
= ANIM_DEATH
;
1429 for (i
= 0; i
< num_units
; i
++) {
1430 unit_t
*u
= &units
[i
];
1432 if (u
->mode
== ANIM_DEATH
) continue;
1435 profile(0, "Unit think");
1440 static Uint32 wait
= 0;
1441 static Uint32 ticks
= 0;
1442 static Uint32 phases
= 0;
1444 Uint32 tick
= SDL_GetTicks();
1445 Uint32 pass
= tick
- wait
;
1449 if (pass
> ui
.game_speed
) {
1466 int rune_main(int argc
, char* argv
[]) {
1471 SDL_Renderer
*screen
;
1472 SDL_DisplayMode
*display
= NULL
;
1473 SDL_DisplayMode basic
;
1475 Uint32 fullscreen
= 0;// SDL_WINDOW_FULLSCREEN;
1478 if (SDL_Init(SDL_INIT_VIDEO
) < 0) {
1479 fprintf(stderr
, "SDL initialization failed: %s\n", SDL_GetError());
1483 /* Pick resolution */
1487 if (fullscreen
) display
= getFullscreenSize( &basic
);
1488 else display
= getWindowSize( &basic
);
1490 if (display
== NULL
) {
1491 fprintf(stderr
, "Warning: can't find suitable display mode, reverting to 640x480.\n");
1496 window
= SDL_CreateWindow("RuneMen",
1497 600, SDL_WINDOWPOS_CENTERED
,
1498 display
->w
, display
->h
,
1499 SDL_WINDOW_SHOWN
| fullscreen
);
1501 if (window
== NULL
) {
1502 fprintf(stderr
, "Window creation failed: %s\n", SDL_GetError());
1507 SDL_GetWindowSize(window
, &width
, &height
);
1509 /* Create renderer */
1510 screen
= SDL_CreateRenderer(window
, -1, 0);
1512 if (screen
== NULL
) {
1513 fprintf(stderr
, "Renderer creation failed: %s\n", SDL_GetError());
1514 SDL_DestroyWindow(window
);
1519 /* Scale the window / ui */
1520 init_ui(screen
, width
, height
);
1522 /* Draw lines, points and rects with alpha blending */
1523 SDL_SetRenderDrawBlendMode(screen
, SDL_BLENDMODE_BLEND
);
1527 /* Turn on SDL mixer */
1531 prepare_inline_font();
1534 ASS_Sound
*music
= ASS_LoadSound("data/music/reavers.ogg");
1535 Mix_PlayChannel(-1, music
, 0);
1537 int next
= mainmenu_loop(screen
);
1538 if (next
== -1) goto done
;
1544 log_addf(&gamelog
, "Window size: %d x %d", width
, height
);
1548 SDL_Event event
= { 0 };
1549 while (SDL_PollEvent(&event
)) {
1550 if (event
.type
== SDL_QUIT
) loops
= 0;
1551 if (event
.type
== SDL_KEYDOWN
&& event
.key
.keysym
.sym
== SDLK_ESCAPE
) loops
= 0;
1557 draw_screen(screen
);
1559 ui
.fps
= count_fps();
1561 SDL_RenderPresent(screen
);
1565 fprintf(stdout
, "Normal termination...\n");
1569 SDL_DestroyRenderer(screen
);
1570 SDL_DestroyWindow(window
);