Freeciv-3.4
Loading...
Searching...
No Matches
reqtree.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 2005-2007 - The Freeciv Project
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include <stdarg.h>
19#include <string.h>
20
21/* utility */
22#include "log.h"
23
24/* common */
25#include "government.h"
26#include "improvement.h"
27#include "research.h"
28#include "tech.h"
29
30/* client */
31#include "client_main.h"
32#include "options.h"
33#include "tilespec.h"
34#include "reqtree.h"
35
36#include "colors_g.h"
37#include "sprite_g.h"
38
39/*
40 * Hierarchical directed draph drawing for Freeciv's technology tree
41 *
42 *
43 * \ Layer 0 / \ Layer 1 / \ Layer 2 /
44 * vvvvvvvvvvvvvvvv vvvvvvvvvvvvvvv vvvvvvvvvvv
45 *
46 * +-----------------+ +-------------+ +----------+
47 * | Alphabeth |----------| Code of Laws|----| Monarchy |
48 * +-----------------+ +-------------+ /+----------+
49 * /
50 * +-----------------+ Dummy node /
51 * |Ceremonial Burial|-----------=============/
52 * +-----------------+
53 *
54 * ^ node_y
55 * |
56 * |
57 * | node_x
58 * +-------->
59 */
60
61
62/****************************************************************************
63 This structure describes a node in a technology tree diagram.
64 A node can by dummy or real. Real node describes a technology.
65****************************************************************************/
66struct tree_node {
67 bool is_dummy;
69
70 /* Incoming edges */
71 int nrequire;
72 struct tree_node **require;
73
74 /* Outgoing edges */
75 int nprovide;
76 struct tree_node **provide;
77
78 /* Logical position on the diagram */
79 int order, layer;
80
81 /* Coordinates of the rectangle on the diagram in pixels */
83
84 /* For general purpose */
85 int number;
86};
87
88/****************************************************************************
89 Structure which describes abstract technology diagram.
90 Nodes are ordered inside layers[] table.
91****************************************************************************/
92struct reqtree {
93 int num_nodes;
94 struct tree_node **nodes;
95
96 int num_layers;
97 /* Size of each layer */
98 int *layer_size;
99 struct tree_node ***layers;
100
101 /* In pixels */
103};
104
105
106/****************************************************************************
107 Edge types for coloring the edges by type in the tree
108****************************************************************************/
110 REQTREE_EDGE = 0, /* Normal, "unvisited" */
112 REQTREE_KNOWN_EDGE, /* Both nodes known, "visited" */
114 REQTREE_GOAL_EDGE /* Dest node is part of goal "future visited" */
116
117/*********************************************************************/
120static void add_requirement(struct tree_node *node, struct tree_node *req)
121{
122 fc_assert_ret(node != NULL);
123 fc_assert_ret(req != NULL);
124
125 node->require =
126 fc_realloc(node->require,
127 sizeof(*node->require) * (node->nrequire + 1));
128 node->require[node->nrequire] = req;
129 node->nrequire++;
130
131 req->provide =
132 fc_realloc(req->provide,
133 sizeof(*req->provide) * (req->nprovide + 1));
134 req->provide[req->nprovide] = node;
135 req->nprovide++;
136}
137
138/*********************************************************************/
141static struct tree_node *new_tree_node(void)
142{
143 struct tree_node *node = fc_malloc(sizeof(*node));
144
145 node->nrequire = 0;
146 node->nprovide = 0;
147 node->require = NULL;
148 node->provide = NULL;
149 node->order = -1;
150 node->layer = -1;
151
152 return node;
153}
154
155/*********************************************************************/
159static void node_rectangle_minimum_size(struct tree_node *node,
160 int *width, int *height)
161{
162 int max_icon_height; /* Maximal height of icons below the text */
163 int icons_width_sum; /* Sum of icons width plus space between them */
164 struct sprite* sprite;
165 int swidth, sheight;
166
167 if (node->is_dummy) {
168 /* Dummy node is a straight line */
169 *width = *height = 1;
170 } else {
173 (research_get(client_player()), node->tech));
174 *width += 2;
175 *height += 8;
176
177 max_icon_height = 0;
178 icons_width_sum = 5;
179
181 /* Units */
182 unit_type_iterate(utype) {
183
184 if (!is_tech_req_for_utype(utype, advance_by_number(node->tech))) {
185 continue;
186 }
187
192 icons_width_sum += swidth + 2;
194
195 /* Buildings */
196 improvement_iterate(pimprove) {
197 if (valid_improvement(pimprove)) {
198 requirement_vector_iterate(&(pimprove->reqs), preq) {
199 if (VUT_ADVANCE == preq->source.kind
200 && preq->present
201 && advance_number(preq->source.value.advance) == node->tech) {
203 /* Improvement icons are not guaranteed to exist */
204 if (sprite) {
207 icons_width_sum += swidth + 2;
208 }
209 }
211 }
213
214 /* Governments */
216 requirement_vector_iterate(&(gov->reqs), preq) {
217 if (VUT_ADVANCE == preq->source.kind
218 && preq->present
219 && advance_number(preq->source.value.advance) == node->tech) {
223 icons_width_sum += swidth + 2;
224 }
227 }
228
230 if (*width < icons_width_sum) {
232 }
233 }
234}
235
236/*********************************************************************/
240static void symmetrize(struct reqtree* tree)
241{
242 int layer;
243 int i, j;
244
245 for (layer = 0; layer < tree->num_layers; layer++) {
246 for (i = 0; i < tree->layer_size[layer]; i++) {
247 struct tree_node *node = tree->layers[layer][i];
248 int v, node_y, node_height;
249
250 if (node->nrequire == 0) {
251 continue;
252 }
253 v = 0;
254 for (j = 0; j < node->nrequire; j++) {
255 struct tree_node *node_require = node->require[j];
256
257 v += node_require->node_y + node_require->node_height / 2;
258 }
259 v /= node->nrequire;
260 node_y = node->node_y;
261 node_height = node->node_height;
262
263 if (v < node_y + node_height / 2) {
264 if (node_y <= 0) {
265 continue;
266 }
267
268 if (i > 0) {
269 struct tree_node *node_above = tree->layers[layer][i - 1];
270
271 if (node_above->node_y
272 + node_above->node_height >= node_y - 11) {
273 continue;
274 }
275 }
276 node_y--;
277 } else if (v > node_y + node_height / 2) {
278 if (node_y + node_height >= tree->diagram_height - 1) {
279 continue;
280 }
281 if (i < tree->layer_size[layer] - 1) {
282 struct tree_node* node_below = tree->layers[layer][i + 1];
283
284 if (node_y + node_height >= node_below->node_y - 11) {
285 continue;
286 }
287 }
288 node_y++;
289 }
290 node->node_y = node_y;
291 }
292 }
293}
294
295/*********************************************************************/
300{
301 int i, layer, layer_offs;
302
303 /* Calculate minimum size of rectangle for each node */
304 for (i = 0; i < tree->num_nodes; i++) {
305 struct tree_node *node = tree->nodes[i];
306
308 &node->node_width, &node->node_height);
309 node->number = i;
310 }
311
312 /* Calculate height of the diagram. There should be at least 10 pixels
313 * between any two nodes */
314 tree->diagram_height = 0;
315 for (layer = 0; layer < tree->num_layers; layer++) {
316 int h_sum = 0;
317
318 for (i = 0; i < tree->layer_size[layer]; i++) {
319 struct tree_node *node = tree->layers[layer][i];
320
321 h_sum += node->node_height;
322
323 if (i < tree->layer_size[layer] - 1) {
324 h_sum += 10;
325 }
326 }
327 tree->diagram_height = MAX(tree->diagram_height, h_sum);
328 }
329
330 /* Calculate maximum width of node for each layer and enlarge other nodes
331 * to match maximum width.
332 * Calculate x offsets
333 */
334 layer_offs = 0;
335 for (layer = 0; layer < tree->num_layers; layer++) {
336 int max_width = 0;
337
338 for (i = 0; i < tree->layer_size[layer]; i++) {
339 struct tree_node *node = tree->layers[layer][i];
340
342 }
343
344 for (i = 0; i < tree->layer_size[layer]; i++) {
345 struct tree_node *node = tree->layers[layer][i];
346
347 node->node_width = max_width;
348 node->node_x = layer_offs;
349 }
350
351 /* Space between layers should be proportional to their size */
352 if (layer != tree->num_layers - 1) {
353 layer_offs += max_width * 5 / 4 + 80;
354 } else {
355 layer_offs += max_width + 10;
356 }
357 }
358 tree->diagram_width = layer_offs;
359
360 /* Once we have x positions calculated we can
361 * calculate y-position of nodes on the diagram
362 * Distribute nodes steadily.
363 */
364 for (layer = 0; layer < tree->num_layers; layer++) {
365 int y = 0;
366 int h_sum = 0;
367
368 for (i = 0; i < tree->layer_size[layer]; i++) {
369 struct tree_node *node = tree->layers[layer][i];
370
371 h_sum += node->node_height;
372 }
373
374 for (i = 0; i < tree->layer_size[layer]; i++) {
375 struct tree_node *node = tree->layers[layer][i];
376
377 node->node_y = y;
378 y += node->node_height;
379 if (tree->layer_size[layer] > 1) {
380 y += (tree->diagram_height - h_sum)
381 / (tree->layer_size[layer] - 1) - 1;
382 }
383 }
384 }
385
386 /* The symmetrize() function moves node by one pixel per call */
387 for (i = 0; i < tree->diagram_height; i++) {
389 }
390}
391
392/*********************************************************************/
399static struct reqtree *create_dummy_reqtree(struct player *pplayer,
400 bool show_all)
401{
402 const struct research *presearch = research_get(pplayer);
403 struct reqtree *tree = fc_malloc(sizeof(*tree));
404 int j;
406 struct tree_node *nodes[ac];
407
408 nodes[A_NONE] = NULL;
411 nodes[tech] = NULL;
412 continue;
413 }
414
415 if (pplayer && !show_all
417 /* Reqtree requested for particular player and this tech is
418 * unreachable to them. */
419 nodes[tech] = NULL;
420 continue;
421 }
422 nodes[tech] = new_tree_node();
423 nodes[tech]->is_dummy = FALSE;
424 nodes[tech]->tech = tech;
426
430
431 if (!padvance) {
432 continue;
433 }
434 if (nodes[tech] == NULL) {
435 continue;
436 }
437
440
441 if (!show_all && A_NONE != tech_one
442 && A_LAST != tech_two && A_NONE != tech_two
443 && (nodes[tech_one] == NULL || nodes[tech_two] == NULL)) {
444 /* Print only reachable techs. */
445 continue;
446 }
447
448 /* Formerly, we used to remove the redundant requirement nodes
449 * (the technologies already included in the requirements of the other
450 * requirement). However, it doesn't look like a good idea, because
451 * a player can steal any technology independently of the technology
452 * tree. */
453 if (A_NONE != tech_one && A_LAST != tech_two) {
454 add_requirement(nodes[tech], nodes[tech_one]);
455 if (A_NONE != tech_two) {
456 add_requirement(nodes[tech], nodes[tech_two]);
457 }
458 }
460
461 /* Copy nodes from local array to dynamically allocated one.
462 * Skip non-existing entries */
463 tree->nodes = fc_calloc(ac, sizeof(*tree->nodes));
464 j = 0;
466 if (nodes[tech]) {
467 fc_assert_action(valid_advance_by_number(nodes[tech]->tech), continue);
468 tree->nodes[j++] = nodes[tech];
469 }
471 tree->num_nodes = j;
472 tree->layers = NULL;
473
474 return tree;
475}
476
477/*********************************************************************/
481{
482 int i;
483
484 for (i = 0; i < tree->num_nodes; i++) {
485 free(tree->nodes[i]->require);
486 free(tree->nodes[i]->provide);
487 free(tree->nodes[i]);
488 }
489 free(tree->nodes);
490 if (tree->layers) {
491 for (i = 0; i < tree->num_layers; i++) {
492 free(tree->layers[i]);
493 }
494 if (tree->layer_size) {
495 free(tree->layer_size);
496 }
497 }
498 free(tree);
499}
500
501/*********************************************************************/
505static int longest_path(struct tree_node *node)
506{
507 int max, i;
508
509 if (node->layer != -1) {
510 return node->layer;
511 }
512 max = -1;
513 for (i = 0; i < node->nrequire; i++) {
514 max = MAX(max, longest_path(node->require[i]));
515 }
516 node->layer = max + 1;
517 return node->layer;
518}
519
520/*********************************************************************/
524{
525 int i;
526
527 for (i = 0; i < tree->num_nodes; i++) {
528 if (tree->nodes[i]) {
529 longest_path(tree->nodes[i]);
530 }
531 }
532}
533
534/*********************************************************************/
537static int max_provide_layer(struct tree_node *node)
538{
539 int i;
540 int max = node->layer;
541
542 for (i = 0; i < node->nprovide; i++) {
543 if (node->provide[i]->layer > max) {
544 max = node->provide[i]->layer;
545 }
546 }
547
548 return max;
549}
550
551/*********************************************************************/
555static struct reqtree *add_dummy_nodes(struct reqtree *tree)
556{
557 struct reqtree *new_tree;
558 int num_dummy_nodes = 0;
559 int k, i, j;
560
561 /* Count dummy nodes to be added */
562 for (i = 0; i < tree->num_nodes; i++) {
563 int mpl;
564
565 if (tree->nodes[i] == NULL) {
566 continue;
567 }
568 mpl = max_provide_layer(tree->nodes[i]);
569 if (mpl > tree->nodes[i]->layer + 1) {
570 num_dummy_nodes += mpl - tree->nodes[i]->layer - 1;
571 }
572 }
573
574 /* Create new tree */
575 new_tree = fc_malloc(sizeof(*new_tree));
576 new_tree->nodes =
577 fc_malloc(sizeof(new_tree->nodes) *
578 (tree->num_nodes + num_dummy_nodes));
579 new_tree->num_nodes = tree->num_nodes + num_dummy_nodes;
580
581 /* Copy normal nodes */
582 for (i = 0; i < tree->num_nodes; i++) {
583 new_tree->nodes[i] = new_tree_node();
584 new_tree->nodes[i]->is_dummy = FALSE;
585 new_tree->nodes[i]->tech = tree->nodes[i]->tech;
586 new_tree->nodes[i]->layer = tree->nodes[i]->layer;
587 tree->nodes[i]->number = i;
588 }
589
590 /* Allocate dummy nodes */
591 for (i = 0; i < num_dummy_nodes; i++) {
592 new_tree->nodes[i + tree->num_nodes] = new_tree_node();
593 new_tree->nodes[i + tree->num_nodes]->is_dummy = TRUE;
594 }
595 /* k points to the first unused dummy node */
596 k = tree->num_nodes;
597
598 for (i = 0; i < tree->num_nodes; i++) {
599 struct tree_node *node = tree->nodes[i];
600 int mpl;
601
602 fc_assert_action(!node->is_dummy, continue);
603
604 mpl = max_provide_layer(node);
605
606 /* If this node will have dummy as ancestors, connect them in a chain */
607 if (mpl > node->layer + 1) {
608 add_requirement(new_tree->nodes[k], new_tree->nodes[i]);
609 for (j = node->layer + 2; j < mpl; j++) {
610 add_requirement(new_tree->nodes[k + j - node->layer - 1],
611 new_tree->nodes[k + j - node->layer - 2]);
612 }
613 for (j = node->layer + 1; j < mpl; j++) {
614 new_tree->nodes[k + j - node->layer - 1]->layer = j;
615 }
616 }
617
618 /* Copy all edges and create edges with dummy nodes */
619 for (j = 0; j < node->nprovide; j++) {
620 int provide_y = node->provide[j]->layer;
621
622 if (provide_y == node->layer + 1) {
623 /* Direct connection */
624 add_requirement(new_tree->nodes[node->provide[j]->number],
625 new_tree->nodes[i]);
626 } else {
627 /* Connection through dummy node */
628 add_requirement(new_tree->nodes[node->provide[j]->number],
629 new_tree->nodes[k + provide_y - node->layer - 2]);
630 }
631 }
632
633 if (mpl > node->layer + 1) {
634 k += mpl - node->layer - 1;
635 fc_assert(k <= new_tree->num_nodes);
636 }
637 }
638 new_tree->layers = NULL;
639
640 return new_tree;
641}
642
643/*********************************************************************/
648static void set_layers(struct reqtree *tree)
649{
650 int i;
651 int num_layers = 0;
652
653 /* Count total number of layers */
654 for (i = 0; i < tree->num_nodes; i++) {
655 num_layers = MAX(num_layers, tree->nodes[i]->layer);
656 }
657 num_layers++;
658 tree->num_layers = num_layers;
659
660 {
661 /* Counters for order - order number for the next node in the layer */
662 int T[num_layers];
663
664 tree->layers = fc_malloc(sizeof(*tree->layers) * num_layers);
665 tree->layer_size = fc_malloc(sizeof(*tree->layer_size) * num_layers);
666 for (i = 0; i < num_layers; i++) {
667 T[i] = 0;
668 tree->layer_size[i] = 0;
669 }
670 for (i = 0; i < tree->num_nodes; i++) {
671 tree->layer_size[tree->nodes[i]->layer]++;
672 }
673
674 for (i = 0; i < num_layers; i++) {
675 tree->layers[i] =
676 fc_malloc(sizeof(*tree->layers[i]) * tree->layer_size[i]);
677 }
678 for (i = 0; i < tree->num_nodes; i++) {
679 struct tree_node *node = tree->nodes[i];
680
681 tree->layers[node->layer][T[node->layer]] = node;
682 node->order = T[node->layer];
683 T[node->layer]++;
684 }
685 }
686}
687
690 float value;
691};
692
693/*********************************************************************/
696static int cmp_func(const void *_a, const void *_b)
697{
698 const struct node_and_float *a = _a, *b = _b;
699
700 if (a->value > b->value) {
701 return 1;
702 }
703 if (a->value < b->value) {
704 return -1;
705 }
706
707 return 0;
708}
709
710/*********************************************************************/
714static void barycentric_sort(struct reqtree *tree, int layer)
715{
716 if (tree->layer_size[layer] > 0) {
717 struct node_and_float T[tree->layer_size[layer]];
718 int i, j;
719 float v;
720
721 for (i = 0; i < tree->layer_size[layer]; i++) {
722 struct tree_node *node = tree->layers[layer][i];
723
724 T[i].node = node;
725 v = 0.0;
726 for (j = 0; j < node->nrequire; j++) {
727 v += node->require[j]->order;
728 }
729 if (node->nrequire > 0) {
730 v /= (float) node->nrequire;
731 }
732 T[i].value = v;
733 }
734 qsort(T, tree->layer_size[layer], sizeof(*T),
735 cmp_func);
736
737 for (i = 0; i < tree->layer_size[layer]; i++) {
738 tree->layers[layer][i] = T[i].node;
739 T[i].node->order = i;
740 }
741 }
742}
743
744/*********************************************************************/
747static int count_crossings(struct reqtree *tree, int layer)
748{
749 int layer1_size = tree->layer_size[layer];
750 int layer2_size = tree->layer_size[layer + 1];
751 int X[layer2_size];
752 int i, j, k;
753 int sum = 0;
754
755 for (i = 0; i < layer2_size; i++) {
756 X[i] = 0;
757 }
758
759 for (i = 0; i < layer1_size; i++) {
760 struct tree_node *node = tree->layers[layer][i];
761
762 for (j = 0; j < node->nprovide; j++) {
763 sum += X[node->provide[j]->order];
764 }
765 for (j = 0; j < node->nprovide; j++) {
766 for (k = 0; k < node->provide[j]->order; k++) {
767 X[k]++;
768 }
769 }
770 }
771
772 return sum;
773}
774
775/*********************************************************************/
778static void swap(struct reqtree *tree, int layer, int order1, int order2)
779{
780 struct tree_node *node1 = tree->layers[layer][order1];
781 struct tree_node *node2 = tree->layers[layer][order2];
782
783 tree->layers[layer][order1] = node2;
784 tree->layers[layer][order2] = node1;
785 node1->order = order2;
786 node2->order = order1;
787}
788
789/*********************************************************************/
793static void improve(struct reqtree *tree)
794{
795 int layers = tree->num_layers;
796 int crossings[layers - 1];
797 int i, x1, x2, layer;
798
799 for (i = 0; i < layers - 1; i++) {
801 }
802
803 for (layer = 0; layer < layers; layer++) {
804 int layer_size = tree->layer_size[layer];
805 int layer_sum = 0;
806
807 if (layer > 0) {
808 layer_sum += crossings[layer - 1];
809 }
810 if (layer < layers - 1) {
812 }
813
814 for (x1 = 0; x1 < layer_size; x1++) {
815 for (x2 = x1 + 1; x2 < layer_size; x2++) {
816 int new_crossings = 0;
817 int new_crossings_before = 0;
818
819 swap(tree, layer, x1, x2);
820
821 if (layer > 0) {
823 }
824 if (layer < layers - 1) {
826 }
828 swap(tree, layer, x1, x2);
829 } else {
831 if (layer > 0) {
833 }
834 if (layer < layers - 1) {
836 }
837 }
838 }
839 }
840 }
841}
842
843/*********************************************************************/
849struct reqtree *create_reqtree(struct player *pplayer, bool show_all)
850{
851 struct reqtree *tree1, *tree2;
852 int i, j;
853
854 tree1 = create_dummy_reqtree(pplayer, show_all);
859
860 /* It's good heuristics for beginning */
861 for (j = 0; j < 20; j++) {
862 for (i = 0; i < tree2->num_layers; i++) {
864 }
865 }
866
867 /* Now burn some CPU */
868 for (j = 0; j < 20; j++) {
869 improve(tree2);
870 }
871
873
874 return tree2;
875}
876
877/*********************************************************************/
881 int *width, int *height)
882{
883 if (width) {
885 }
886 if (height) {
888 }
889}
890
891/*********************************************************************/
894static enum color_std node_color(struct tree_node *node)
895{
896 if (!node->is_dummy) {
898
899 if (!research) {
900 return COLOR_REQTREE_KNOWN;
901 }
902
905 }
906
909 || node->tech == research->tech_goal) {
911 } else {
913 }
914 }
915
916 if (research->researching == node->tech) {
918 }
919
921 return COLOR_REQTREE_KNOWN;
922 }
923
925 || node->tech == research->tech_goal) {
927 node->tech)) {
929 } else {
931 }
932 }
933
935 node->tech)) {
937 }
938
940 } else {
942 }
943}
944
945/*********************************************************************/
950 struct tree_node *dest_node)
951{
953
954 if (dest_node == NULL) {
955 /* Assume node is a dummy */
956 dest_node = node;
957 }
958
959 /* Find the required tech */
960 while (node->is_dummy) {
961 fc_assert(node->nrequire == 1);
962 node = node->require[0];
963 }
964
965 /* Find destination advance by recursing in dest_node->provide[]
966 * watch out: recursion */
967 if (dest_node->is_dummy) {
969 int i;
970
971 fc_assert(dest_node->nprovide > 0);
972 for (i = 0; i < dest_node->nprovide; ++i) {
974
975 switch (type) {
978 return type;
981 sum_type = type;
982 break;
983 default:
984 /* No change */
985 break;
986 }
987 }
988
989 return sum_type;
990 }
991
992 if (!research) {
993 /* Global observer case */
994 return REQTREE_KNOWN_EDGE;
995 }
996
997 if (research->researching == dest_node->tech) {
998 return REQTREE_ACTIVE_EDGE;
999 }
1000
1002 || dest_node->tech == research->tech_goal) {
1003 return REQTREE_GOAL_EDGE;
1004 }
1005
1008 return REQTREE_KNOWN_EDGE;
1009 } else {
1010 return REQTREE_READY_EDGE;
1011 }
1012 }
1013
1014 return REQTREE_EDGE;
1015}
1016
1017/*********************************************************************/
1021static enum color_std edge_color(struct tree_node *node,
1022 struct tree_node *dest_node)
1023{
1025
1026 switch (type) {
1029 case REQTREE_GOAL_EDGE:
1031 case REQTREE_KNOWN_EDGE:
1032 /* Using "text" black instead of "known" white/ground/green */
1033 return COLOR_REQTREE_TEXT;
1034 case REQTREE_READY_EDGE:
1036 default:
1037 return COLOR_REQTREE_EDGE;
1038 }
1039}
1040
1041/*********************************************************************/
1048 int canvas_x, int canvas_y,
1049 int tt_x, int tt_y, int w, int h)
1050{
1051 int i, j, k;
1052 int swidth, sheight;
1053 struct sprite* sprite;
1054 struct color *color;
1055
1056 /* Draw the diagram */
1057 for (i = 0; i < tree->num_layers; i++) {
1058 for (j = 0; j < tree->layer_size[i]; j++) {
1059 struct tree_node *node = tree->layers[i][j];
1060 int startx, starty, endx, endy, width, height;
1061
1062 startx = node->node_x;
1063 starty = node->node_y;
1064 width = node->node_width;
1065 height = node->node_height;
1066
1067 if (node->is_dummy) {
1068 /* Use the same layout as lines for dummy nodes */
1071 LINE_GOTO,
1072 startx, starty, width, 0);
1073 } else {
1074 const char *text = research_advance_name_translation
1075 (research_get(client_player()), node->tech);
1076 int text_w, text_h;
1077 int icon_startx;
1078
1082
1083 /* Print color rectangle with text inside. */
1085 startx + 1, starty + 1,
1086 width - 2, height - 2);
1087 /* The following code is similar to the one in
1088 * node_rectangle_minimum_size(). If you change something here,
1089 * change also node_rectangle_minimum_size().
1090 */
1091
1093
1095 startx + (width - text_w) / 2,
1096 starty + 4,
1099 text);
1100 icon_startx = startx + 5;
1101
1103 unit_type_iterate(utype) {
1104
1105 if (!is_tech_req_for_utype(utype, advance_by_number(node->tech))) {
1106 continue;
1107 }
1108
1114 starty + text_h + 4
1115 + (height - text_h - 4 - sheight) / 2,
1116 sprite);
1117 icon_startx += swidth + 2;
1119
1120 improvement_iterate(pimprove) {
1121 if (valid_improvement(pimprove)) {
1122 requirement_vector_iterate(&(pimprove->reqs), preq) {
1123 if (VUT_ADVANCE == preq->source.kind
1124 && preq->present
1125 && advance_number(preq->source.value.advance) == node->tech) {
1126 sprite = get_building_sprite(tileset, pimprove);
1127 /* Improvement icons are not guaranteed to exist */
1128 if (sprite) {
1132 starty + text_h + 4
1133 + (height - text_h - 4 - sheight) / 2,
1134 sprite);
1135 icon_startx += swidth + 2;
1136 }
1137 }
1139 }
1141
1142 governments_iterate(gov) {
1143 requirement_vector_iterate(&(gov->reqs), preq) {
1144 if (VUT_ADVANCE == preq->source.kind
1145 && preq->present
1146 && advance_number(preq->source.value.advance) == node->tech) {
1151 starty + text_h + 4
1152 + (height - text_h - 4 - sheight) / 2,
1153 sprite);
1154 icon_startx += swidth + 2;
1155 }
1158 }
1159 }
1160
1161 /* Draw all outgoing edges */
1162 startx = node->node_x + node->node_width;
1163 starty = node->node_y + node->node_height / 2;
1164 for (k = 0; k < node->nprovide; k++) {
1165 struct tree_node *dest_node = node->provide[k];
1166
1168
1169 endx = dest_node->node_x;
1170 endy = dest_node->node_y + dest_node->node_height / 2;
1171
1175 endy - starty);
1176 } else {
1179 endy - starty);
1180 }
1181 }
1182 }
1183 }
1184}
1185
1186/*********************************************************************/
1190{
1191 int i;
1192
1193 for (i = 0; i < tree->num_nodes; i++) {
1194 struct tree_node *node = tree->nodes[i];
1195
1196 if (node->is_dummy) {
1197 continue;
1198 }
1199 if (node->node_x <= x && node->node_y <= y
1200 && node->node_x + node->node_width > x
1201 && node->node_y + node->node_height > y) {
1202 return node->tech;
1203 }
1204 }
1205
1206 return A_NONE;
1207}
1208
1209/*********************************************************************/
1214 int *x, int *y, int *w, int *h)
1215{
1216 int i;
1217
1218 for (i = 0; i < tree->num_nodes; i++) {
1219 struct tree_node *node = tree->nodes[i];
1220
1221 if (!node->is_dummy && node->tech == tech) {
1222 if (x) {
1223 *x = node->node_x;
1224 }
1225 if (y) {
1226 *y = node->node_y;
1227 }
1228 if (w) {
1229 *w = node->node_width;
1230 }
1231 if (h) {
1232 *h = node->node_height;
1233 }
1234 return TRUE;
1235 }
1236 }
1237
1238 return FALSE;
1239}
struct canvas int int struct sprite int int int int height
Definition canvas_g.h:44
struct canvas int int int int struct sprite *sprite canvas_put_rectangle
Definition canvas_g.h:55
struct canvas int int canvas_y
Definition canvas_g.h:43
struct canvas int canvas_x
Definition canvas_g.h:43
struct canvas int int int int struct sprite *sprite struct canvas struct color int int int int height canvas_put_line
Definition canvas_g.h:62
struct canvas * pcanvas
Definition canvas_g.h:42
canvas_put_text
Definition canvas_g.h:80
struct canvas int int struct sprite int int int width
Definition canvas_g.h:44
@ LINE_GOTO
Definition canvas_g.h:26
#define client_player()
#define T(x)
struct color * get_color(const struct tileset *t, enum color_std stdcolor)
char * incite_cost
Definition comments.c:77
int Tech_type_id
Definition fc_types.h:238
#define governments_iterate(NAME_pgov)
Definition government.h:136
#define governments_iterate_end
Definition government.h:139
void canvas_put_sprite_full(struct canvas *pcanvas, int canvas_x, int canvas_y, struct sprite *sprite)
Definition canvas.c:144
void get_text_size(int *width, int *height, enum client_font font, const char *text)
Definition canvas.c:341
void canvas_put_curved_line(struct canvas *pcanvas, struct color *pcolor, enum line_type ltype, int start_x, int start_y, int dx, int dy)
Definition canvas.c:276
GType type
Definition repodlgs.c:1313
const struct impr_type * valid_improvement(const struct impr_type *pimprove)
#define improvement_iterate_end
#define improvement_iterate(_p)
#define fc_assert_ret(condition)
Definition log.h:192
#define fc_assert(condition)
Definition log.h:177
#define fc_assert_action(condition, action)
Definition log.h:188
#define fc_calloc(n, esz)
Definition mem.h:38
#define fc_realloc(ptr, sz)
Definition mem.h:36
#define fc_malloc(sz)
Definition mem.h:34
struct client_options gui_options
Definition options.c:71
static int max_provide_layer(struct tree_node *node)
Definition reqtree.c:537
static int longest_path(struct tree_node *node)
Definition reqtree.c:505
static void barycentric_sort(struct reqtree *tree, int layer)
Definition reqtree.c:714
static int cmp_func(const void *_a, const void *_b)
Definition reqtree.c:696
void draw_reqtree(struct reqtree *tree, struct canvas *pcanvas, int canvas_x, int canvas_y, int tt_x, int tt_y, int w, int h)
Definition reqtree.c:1047
void get_reqtree_dimensions(struct reqtree *reqtree, int *width, int *height)
Definition reqtree.c:880
static void node_rectangle_minimum_size(struct tree_node *node, int *width, int *height)
Definition reqtree.c:159
static void add_requirement(struct tree_node *node, struct tree_node *req)
Definition reqtree.c:120
static enum color_std node_color(struct tree_node *node)
Definition reqtree.c:894
static int count_crossings(struct reqtree *tree, int layer)
Definition reqtree.c:747
static void improve(struct reqtree *tree)
Definition reqtree.c:793
static void symmetrize(struct reqtree *tree)
Definition reqtree.c:240
static struct reqtree * add_dummy_nodes(struct reqtree *tree)
Definition reqtree.c:555
static void set_layers(struct reqtree *tree)
Definition reqtree.c:648
static void longest_path_layering(struct reqtree *tree)
Definition reqtree.c:523
static void calculate_diagram_layout(struct reqtree *tree)
Definition reqtree.c:299
Tech_type_id get_tech_on_reqtree(struct reqtree *tree, int x, int y)
Definition reqtree.c:1189
bool find_tech_on_reqtree(struct reqtree *tree, Tech_type_id tech, int *x, int *y, int *w, int *h)
Definition reqtree.c:1213
static void swap(struct reqtree *tree, int layer, int order1, int order2)
Definition reqtree.c:778
static enum reqtree_edge_type get_edge_type(struct tree_node *node, struct tree_node *dest_node)
Definition reqtree.c:949
static enum color_std edge_color(struct tree_node *node, struct tree_node *dest_node)
Definition reqtree.c:1021
static struct tree_node * new_tree_node(void)
Definition reqtree.c:141
void destroy_reqtree(struct reqtree *tree)
Definition reqtree.c:480
struct reqtree * create_reqtree(struct player *pplayer, bool show_all)
Definition reqtree.c:849
static struct reqtree * create_dummy_reqtree(struct player *pplayer, bool show_all)
Definition reqtree.c:399
reqtree_edge_type
Definition reqtree.c:109
@ REQTREE_READY_EDGE
Definition reqtree.c:111
@ REQTREE_ACTIVE_EDGE
Definition reqtree.c:113
@ REQTREE_EDGE
Definition reqtree.c:110
@ REQTREE_KNOWN_EDGE
Definition reqtree.c:112
@ REQTREE_GOAL_EDGE
Definition reqtree.c:114
#define requirement_vector_iterate_end
#define requirement_vector_iterate(req_vec, preq)
bool research_invention_reachable(const struct research *presearch, const Tech_type_id tech)
Definition research.c:671
bool research_goal_tech_req(const struct research *presearch, Tech_type_id goal, Tech_type_id tech)
Definition research.c:810
const char * research_advance_name_translation(const struct research *presearch, Tech_type_id tech)
Definition research.c:276
struct research * research_get(const struct player *pplayer)
Definition research.c:130
enum tech_state research_invention_state(const struct research *presearch, Tech_type_id tech)
Definition research.c:622
bool research_invention_gettable(const struct research *presearch, const Tech_type_id tech, bool allow_holes)
Definition research.c:696
#define MAX(x, y)
Definition shared.h:54
struct sprite int int y
Definition sprite_g.h:31
struct sprite int x
Definition sprite_g.h:31
struct sprite int int int int struct sprite int int float bool smooth get_sprite_dimensions
Definition sprite_g.h:36
bool reqtree_show_icons
Definition options.h:222
bool reqtree_curved_lines
Definition options.h:223
Definition colors.h:21
GdkRGBA color
Definition colors.h:22
struct tree_node * node
Definition reqtree.c:689
int num_nodes
Definition repodlgs.cpp:86
struct tree_node ** nodes
Definition repodlgs.cpp:87
int * layer_size
Definition repodlgs.cpp:89
int diagram_height
Definition repodlgs.cpp:91
int diagram_width
Definition repodlgs.cpp:91
struct tree_node *** layers
Definition repodlgs.cpp:90
int num_layers
Definition repodlgs.cpp:88
Tech_type_id researching
Definition research.h:52
Tech_type_id tech_goal
Definition research.h:83
Tech_type_id tech
Definition repodlgs.cpp:72
int nprovide
Definition repodlgs.cpp:75
struct tree_node ** provide
Definition repodlgs.cpp:76
int node_width
Definition repodlgs.cpp:78
bool is_dummy
Definition repodlgs.cpp:71
int node_height
Definition repodlgs.cpp:78
int nrequire
Definition repodlgs.cpp:73
struct tree_node ** require
Definition repodlgs.cpp:74
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
struct advance * advance_by_number(const Tech_type_id atype)
Definition tech.c:110
struct advance * valid_advance_by_number(const Tech_type_id id)
Definition tech.c:181
Tech_type_id advance_required(const Tech_type_id tech, enum tech_req require)
Definition tech.c:124
Tech_type_id advance_number(const struct advance *padvance)
Definition tech.c:100
#define advance_index_iterate_max(_start, _index, _max)
Definition tech.h:250
@ AR_TWO
Definition tech.h:109
@ AR_ONE
Definition tech.h:108
#define advance_index_iterate_max_end
Definition tech.h:256
static Tech_type_id advance_count(void)
Definition tech.h:167
#define A_FIRST
Definition tech.h:44
#define A_NONE
Definition tech.h:43
#define A_LAST
Definition tech.h:45
struct sprite * get_government_sprite(const struct tileset *t, const struct government *gov)
Definition tilespec.c:7043
struct sprite * get_building_sprite(const struct tileset *t, const struct impr_type *pimprove)
Definition tilespec.c:7033
struct sprite * get_unittype_sprite(const struct tileset *t, const struct unit_type *punittype, enum unit_activity activity, enum direction8 facing)
Definition tilespec.c:7055
bool is_tech_req_for_utype(const struct unit_type *ptype, struct advance *padv)
Definition unittype.c:2761
#define unit_type_iterate(_p)
Definition unittype.h:865
#define unit_type_iterate_end
Definition unittype.h:872