Freeciv-3.2
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/****************************************************************************
64 This structure describes a node in a technology tree diagram.
65 A node can by dummy or real. Real node describes a technology.
66****************************************************************************/
67struct tree_node {
68 bool is_dummy;
70
71 /* Incoming edges */
72 int nrequire;
73 struct tree_node **require;
74
75 /* Outgoing edges */
76 int nprovide;
77 struct tree_node **provide;
78
79 /* logical position on the diagram */
80 int order, layer;
81
82 /* Coordinates of the rectangle on the diagram in pixels */
84
85 /* for general purpose */
86 int number;
87};
88
89/****************************************************************************
90 Structure which describes abstract technology diagram.
91 Nodes are ordered inside layers[] table.
92****************************************************************************/
93struct reqtree {
94 int num_nodes;
95 struct tree_node **nodes;
96
97 int num_layers;
98 /* size of each layer */
99 int *layer_size;
100 struct tree_node ***layers;
101
102 /* in pixels */
104};
105
106
107/****************************************************************************
108 Edge types for coloring the edges by type in the tree
109****************************************************************************/
111 REQTREE_EDGE = 0, /* Normal, "unvisited" */
113 REQTREE_KNOWN_EDGE, /* Both nodes known, "visited" */
115 REQTREE_GOAL_EDGE /* Dest node is part of goal "future visited" */
117
118/*********************************************************************/
121static void add_requirement(struct tree_node *node, struct tree_node *req)
122{
123 fc_assert_ret(node != NULL);
124 fc_assert_ret(req != NULL);
125
126 node->require =
127 fc_realloc(node->require,
128 sizeof(*node->require) * (node->nrequire + 1));
129 node->require[node->nrequire] = req;
130 node->nrequire++;
131
132 req->provide =
133 fc_realloc(req->provide,
134 sizeof(*req->provide) * (req->nprovide + 1));
135 req->provide[req->nprovide] = node;
136 req->nprovide++;
137}
138
139/*********************************************************************/
142static struct tree_node *new_tree_node(void)
143{
144 struct tree_node *node = fc_malloc(sizeof(*node));
145
146 node->nrequire = 0;
147 node->nprovide = 0;
148 node->require = NULL;
149 node->provide = NULL;
150 node->order = -1;
151 node->layer = -1;
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 if (v < node_y + node_height / 2) {
263 if (node_y <= 0) {
264 continue;
265 }
266 if (i > 0) {
267 struct tree_node *node_above = tree->layers[layer][i - 1];
268
269 if (node_above->node_y
270 + node_above->node_height >= node_y - 11) {
271 continue;
272 }
273 }
274 node_y--;
275 } else if (v > node_y + node_height / 2) {
276 if (node_y + node_height >= tree->diagram_height - 1) {
277 continue;
278 }
279 if (i < tree->layer_size[layer] - 1) {
280 struct tree_node* node_below = tree->layers[layer][i + 1];
281
282 if (node_y + node_height >= node_below->node_y - 11) {
283 continue;
284 }
285 }
286 node_y++;
287 }
288 node->node_y = node_y;
289 }
290 }
291}
292
293/*********************************************************************/
298{
299 int i, layer, layer_offs;
300
301 /* calculate minimum size of rectangle for each node */
302 for (i = 0; i < tree->num_nodes; i++) {
303 struct tree_node *node = tree->nodes[i];
304
306 &node->node_width, &node->node_height);
307 node->number = i;
308 }
309
310 /* calculate height of the diagram. There should be at least 10 pixels
311 * between any two nodes */
312 tree->diagram_height = 0;
313 for (layer = 0; layer < tree->num_layers; layer++) {
314 int h_sum = 0;
315
316 for (i = 0; i < tree->layer_size[layer]; i++) {
317 struct tree_node *node = tree->layers[layer][i];
318
319 h_sum += node->node_height;
320 if (i < tree->layer_size[layer] - 1) {
321 h_sum += 10;
322 }
323 }
324 tree->diagram_height = MAX(tree->diagram_height, h_sum);
325 }
326
327 /* calculate maximum width of node for each layer and enlarge other nodes
328 * to match maximum width
329 * calculate x offsets
330 */
331 layer_offs = 0;
332 for (layer = 0; layer < tree->num_layers; layer++) {
333 int max_width = 0;
334
335 for (i = 0; i < tree->layer_size[layer]; i++) {
336 struct tree_node *node = tree->layers[layer][i];
337
339 }
340
341 for (i = 0; i < tree->layer_size[layer]; i++) {
342 struct tree_node *node = tree->layers[layer][i];
343
344 node->node_width = max_width;
345 node->node_x = layer_offs;
346 }
347
348 /* space between layers should be proportional to their size */
349 if (layer != tree->num_layers - 1) {
350 layer_offs += max_width * 5 / 4 + 80;
351 } else {
352 layer_offs += max_width + 10;
353 }
354 }
355 tree->diagram_width = layer_offs;
356
357 /* Once we have x positions calculated we can
358 * calculate y-position of nodes on the diagram
359 * Distribute nodes steadily.
360 */
361 for (layer = 0; layer < tree->num_layers; layer++) {
362 int y = 0;
363 int h_sum = 0;
364
365 for (i = 0; i < tree->layer_size[layer]; i++) {
366 struct tree_node *node = tree->layers[layer][i];
367
368 h_sum += node->node_height;
369 }
370 for (i = 0; i < tree->layer_size[layer]; i++) {
371 struct tree_node *node = tree->layers[layer][i];
372
373 node->node_y = y;
374 y += node->node_height;
375 if (tree->layer_size[layer] > 1) {
376 y += (tree->diagram_height - h_sum)
377 / (tree->layer_size[layer] - 1) - 1;
378 }
379 }
380 }
381
382 /* The symmetrize() function moves node by one pixel per call */
383 for (i = 0; i < tree->diagram_height; i++) {
385 }
386}
387
388/*********************************************************************/
395static struct reqtree *create_dummy_reqtree(struct player *pplayer,
396 bool show_all)
397{
398 const struct research *presearch = research_get(pplayer);
399 struct reqtree *tree = fc_malloc(sizeof(*tree));
400 int j;
402 struct tree_node *nodes[ac];
403
404 nodes[A_NONE] = NULL;
407 nodes[tech] = NULL;
408 continue;
409 }
410 if (pplayer && !show_all
412 /* Reqtree requested for particular player and this tech is
413 * unreachable to them. */
414 nodes[tech] = NULL;
415 continue;
416 }
417 nodes[tech] = new_tree_node();
418 nodes[tech]->is_dummy = FALSE;
419 nodes[tech]->tech = tech;
421
425
426 if (!padvance) {
427 continue;
428 }
429 if (nodes[tech] == NULL) {
430 continue;
431 }
432
435
436 if (!show_all && A_NONE != tech_one
437 && A_LAST != tech_two && A_NONE != tech_two
438 && (nodes[tech_one] == NULL || nodes[tech_two] == NULL)) {
439 /* Print only reachable techs. */
440 continue;
441 }
442
443 /* Formerly, we used to remove the redundant requirement nodes
444 * (the technologies already included in the requirements of the other
445 * requirement). However, it doesn't look like a good idea, because
446 * a player can steal any technology independently of the technology
447 * tree. */
448 if (A_NONE != tech_one && A_LAST != tech_two) {
449 add_requirement(nodes[tech], nodes[tech_one]);
450 if (A_NONE != tech_two) {
451 add_requirement(nodes[tech], nodes[tech_two]);
452 }
453 }
455
456 /* Copy nodes from local array to dynamically allocated one.
457 * Skip non-existing entries */
458 tree->nodes = fc_calloc(ac, sizeof(*tree->nodes));
459 j = 0;
461 if (nodes[tech]) {
462 fc_assert_action(valid_advance_by_number(nodes[tech]->tech), continue);
463 tree->nodes[j++] = nodes[tech];
464 }
466 tree->num_nodes = j;
467 tree->layers = NULL;
468
469 return tree;
470}
471
472/*********************************************************************/
476{
477 int i;
478
479 for (i = 0; i < tree->num_nodes; i++) {
480 free(tree->nodes[i]->require);
481 free(tree->nodes[i]->provide);
482 free(tree->nodes[i]);
483 }
484 free(tree->nodes);
485 if (tree->layers) {
486 for (i = 0; i < tree->num_layers; i++) {
487 free(tree->layers[i]);
488 }
489 if (tree->layer_size) {
490 free(tree->layer_size);
491 }
492 }
493 free(tree);
494}
495
496/*********************************************************************/
500static int longest_path(struct tree_node *node)
501{
502 int max, i;
503
504 if (node->layer != -1) {
505 return node->layer;
506 }
507 max = -1;
508 for (i = 0; i < node->nrequire; i++) {
509 max = MAX(max, longest_path(node->require[i]));
510 }
511 node->layer = max + 1;
512 return node->layer;
513}
514
515/*********************************************************************/
519{
520 int i;
521
522 for (i = 0; i < tree->num_nodes; i++) {
523 if (tree->nodes[i]) {
524 longest_path(tree->nodes[i]);
525 }
526 }
527}
528
529/*********************************************************************/
532static int max_provide_layer(struct tree_node *node)
533{
534 int i;
535 int max = node->layer;
536
537 for (i = 0; i < node->nprovide; i++) {
538 if (node->provide[i]->layer > max) {
539 max = node->provide[i]->layer;
540 }
541 }
542 return max;
543}
544
545/*********************************************************************/
549static struct reqtree *add_dummy_nodes(struct reqtree *tree)
550{
551 struct reqtree *new_tree;
552 int num_dummy_nodes = 0;
553 int k, i, j;
554
555 /* Count dummy nodes to be added */
556 for (i = 0; i < tree->num_nodes; i++) {
557 int mpl;
558
559 if (tree->nodes[i] == NULL) {
560 continue;
561 }
562 mpl = max_provide_layer(tree->nodes[i]);
563 if (mpl > tree->nodes[i]->layer + 1) {
564 num_dummy_nodes += mpl - tree->nodes[i]->layer - 1;
565 }
566 }
567
568 /* create new tree */
569 new_tree = fc_malloc(sizeof(*new_tree));
570 new_tree->nodes =
571 fc_malloc(sizeof(new_tree->nodes) *
572 (tree->num_nodes + num_dummy_nodes));
573 new_tree->num_nodes = tree->num_nodes + num_dummy_nodes;
574
575 /* copy normal nodes */
576 for (i = 0; i < tree->num_nodes; i++) {
577 new_tree->nodes[i] = new_tree_node();
578 new_tree->nodes[i]->is_dummy = FALSE;
579 new_tree->nodes[i]->tech = tree->nodes[i]->tech;
580 new_tree->nodes[i]->layer = tree->nodes[i]->layer;
581 tree->nodes[i]->number = i;
582 }
583
584 /* allocate dummy nodes */
585 for (i = 0; i < num_dummy_nodes; i++) {
586 new_tree->nodes[i + tree->num_nodes] = new_tree_node();
587 new_tree->nodes[i + tree->num_nodes]->is_dummy = TRUE;
588 }
589 /* k points to the first unused dummy node */
590 k = tree->num_nodes;
591
592 for (i = 0; i < tree->num_nodes; i++) {
593 struct tree_node *node = tree->nodes[i];
594 int mpl;
595
596 fc_assert_action(!node->is_dummy, continue);
597
598 mpl = max_provide_layer(node);
599
600 /* if this node will have dummy as ancestors, connect them in a chain */
601 if (mpl > node->layer + 1) {
602 add_requirement(new_tree->nodes[k], new_tree->nodes[i]);
603 for (j = node->layer + 2; j < mpl; j++) {
604 add_requirement(new_tree->nodes[k + j - node->layer - 1],
605 new_tree->nodes[k + j - node->layer - 2]);
606 }
607 for (j = node->layer + 1; j < mpl; j++) {
608 new_tree->nodes[k + j - node->layer - 1]->layer = j;
609 }
610 }
611
612 /* copy all edges and create edges with dummy nodes */
613 for (j = 0; j < node->nprovide; j++) {
614 int provide_y = node->provide[j]->layer;
615
616 if (provide_y == node->layer + 1) {
617 /* direct connection */
618 add_requirement(new_tree->nodes[node->provide[j]->number],
619 new_tree->nodes[i]);
620 } else {
621 /* connection through dummy node */
622 add_requirement(new_tree->nodes[node->provide[j]->number],
623 new_tree->nodes[k + provide_y - node->layer - 2]);
624 }
625 }
626
627 if (mpl > node->layer + 1) {
628 k += mpl - node->layer - 1;
629 fc_assert(k <= new_tree->num_nodes);
630 }
631 }
632 new_tree->layers = NULL;
633
634 return new_tree;
635}
636
637/*********************************************************************/
642static void set_layers(struct reqtree *tree)
643{
644 int i;
645 int num_layers = 0;
646
647 /* Count total number of layers */
648 for (i = 0; i < tree->num_nodes; i++) {
649 num_layers = MAX(num_layers, tree->nodes[i]->layer);
650 }
651 num_layers++;
652 tree->num_layers = num_layers;
653
654 {
655 /* Counters for order - order number for the next node in the layer */
656 int T[num_layers];
657
658 tree->layers = fc_malloc(sizeof(*tree->layers) * num_layers);
659 tree->layer_size = fc_malloc(sizeof(*tree->layer_size) * num_layers);
660 for (i = 0; i < num_layers; i++) {
661 T[i] = 0;
662 tree->layer_size[i] = 0;
663 }
664 for (i = 0; i < tree->num_nodes; i++) {
665 tree->layer_size[tree->nodes[i]->layer]++;
666 }
667
668 for (i = 0; i < num_layers; i++) {
669 tree->layers[i]
670 = fc_malloc(sizeof(*tree->layers[i]) * tree->layer_size[i]);
671 }
672 for (i = 0; i < tree->num_nodes; i++) {
673 struct tree_node *node = tree->nodes[i];
674
675 tree->layers[node->layer][T[node->layer]] = node;
676 node->order = T[node->layer];
677 T[node->layer]++;
678 }
679 }
680}
681
684 float value;
685};
686
687/*********************************************************************/
690static int cmp_func(const void *_a, const void *_b)
691{
692 const struct node_and_float *a = _a, *b = _b;
693
694 if (a->value > b->value) {
695 return 1;
696 }
697 if (a->value < b->value) {
698 return -1;
699 }
700 return 0;
701}
702
703/*********************************************************************/
707static void barycentric_sort(struct reqtree *tree, int layer)
708{
709 if (tree->layer_size[layer] > 0) {
710 struct node_and_float T[tree->layer_size[layer]];
711 int i, j;
712 float v;
713
714 for (i = 0; i < tree->layer_size[layer]; i++) {
715 struct tree_node *node = tree->layers[layer][i];
716
717 T[i].node = node;
718 v = 0.0;
719 for (j = 0; j < node->nrequire; j++) {
720 v += node->require[j]->order;
721 }
722 if (node->nrequire > 0) {
723 v /= (float) node->nrequire;
724 }
725 T[i].value = v;
726 }
727 qsort(T, tree->layer_size[layer], sizeof(*T),
728 cmp_func);
729
730 for (i = 0; i < tree->layer_size[layer]; i++) {
731 tree->layers[layer][i] = T[i].node;
732 T[i].node->order = i;
733 }
734 }
735}
736
737/*********************************************************************/
740static int count_crossings(struct reqtree *tree, int layer)
741{
742 int layer1_size = tree->layer_size[layer];
743 int layer2_size = tree->layer_size[layer + 1];
744 int X[layer2_size];
745 int i, j, k;
746 int sum = 0;
747
748 for (i = 0; i < layer2_size; i++) {
749 X[i] = 0;
750 }
751
752 for (i = 0; i < layer1_size; i++) {
753 struct tree_node *node = tree->layers[layer][i];
754
755 for (j = 0; j < node->nprovide; j++) {
756 sum += X[node->provide[j]->order];
757 }
758 for (j = 0; j < node->nprovide; j++) {
759 for (k = 0; k < node->provide[j]->order; k++) {
760 X[k]++;
761 }
762 }
763 }
764
765 return sum;
766}
767
768/*********************************************************************/
771static void swap(struct reqtree *tree, int layer, int order1, int order2)
772{
773 struct tree_node *node1 = tree->layers[layer][order1];
774 struct tree_node *node2 = tree->layers[layer][order2];
775
776 tree->layers[layer][order1] = node2;
777 tree->layers[layer][order2] = node1;
778 node1->order = order2;
779 node2->order = order1;
780}
781
782/*********************************************************************/
786static void improve(struct reqtree *tree)
787{
788 int layers = tree->num_layers;
789 int crossings[layers - 1];
790 int i, x1, x2, layer;
791
792 for (i = 0; i < layers - 1; i++) {
794 }
795
796 for (layer = 0; layer < layers; layer++) {
797 int layer_size = tree->layer_size[layer];
798 int layer_sum = 0;
799
800 if (layer > 0) {
801 layer_sum += crossings[layer - 1];
802 }
803 if (layer < layers - 1) {
805 }
806
807 for (x1 = 0; x1 < layer_size; x1++) {
808 for (x2 = x1 + 1; x2 < layer_size; x2++) {
809 int new_crossings = 0;
810 int new_crossings_before = 0;
811
812 swap(tree, layer, x1, x2);
813 if (layer > 0) {
815 }
816 if (layer < layers - 1) {
818 }
820 swap(tree, layer, x1, x2);
821 } else {
823 if (layer > 0) {
825 }
826 if (layer < layers - 1) {
828 }
829 }
830 }
831 }
832 }
833}
834
835/*********************************************************************/
841struct reqtree *create_reqtree(struct player *pplayer, bool show_all)
842{
843 struct reqtree *tree1, *tree2;
844 int i, j;
845
846 tree1 = create_dummy_reqtree(pplayer, show_all);
851
852 /* It's good heuristics for beginning */
853 for (j = 0; j < 20; j++) {
854 for (i = 0; i < tree2->num_layers; i++) {
856 }
857 }
858
859 /* Now burn some CPU */
860 for (j = 0; j < 20; j++) {
861 improve(tree2);
862 }
863
865
866 return tree2;
867}
868
869/*********************************************************************/
873 int *width, int *height)
874{
875 if (width) {
877 }
878 if (height) {
880 }
881}
882
883/*********************************************************************/
886static enum color_std node_color(struct tree_node *node)
887{
888 if (!node->is_dummy) {
890
891 if (!research) {
892 return COLOR_REQTREE_KNOWN;
893 }
894
897 }
898
901 || node->tech == research->tech_goal) {
903 } else {
905 }
906 }
907
908 if (research->researching == node->tech) {
910 }
911
913 return COLOR_REQTREE_KNOWN;
914 }
915
917 || node->tech == research->tech_goal) {
919 node->tech)) {
921 } else {
923 }
924 }
925
927 node->tech)) {
929 }
930
932 } else {
934 }
935
936}
937
938/*********************************************************************/
943 struct tree_node *dest_node)
944{
946
947 if (dest_node == NULL) {
948 /* assume node is a dummy */
949 dest_node = node;
950 }
951
952 /* find the required tech */
953 while (node->is_dummy) {
954 fc_assert(node->nrequire == 1);
955 node = node->require[0];
956 }
957
958 /* find destination advance by recursing in dest_node->provide[]
959 * watch out: recursion */
960 if (dest_node->is_dummy) {
962 int i;
963
964 fc_assert(dest_node->nprovide > 0);
965 for (i = 0; i < dest_node->nprovide; ++i) {
967 switch (type) {
970 return type;
973 sum_type = type;
974 break;
975 default:
976 /* no change */
977 break;
978 };
979 }
980 return sum_type;
981 }
982
983 if (!research) {
984 /* Global observer case */
985 return REQTREE_KNOWN_EDGE;
986 }
987
988 if (research->researching == dest_node->tech) {
989 return REQTREE_ACTIVE_EDGE;
990 }
991
993 || dest_node->tech == research->tech_goal) {
994 return REQTREE_GOAL_EDGE;
995 }
996
999 return REQTREE_KNOWN_EDGE;
1000 } else {
1001 return REQTREE_READY_EDGE;
1002 }
1003 }
1004
1005 return REQTREE_EDGE;
1006}
1007
1008/*********************************************************************/
1012static enum color_std edge_color(struct tree_node *node,
1013 struct tree_node *dest_node)
1014{
1016
1017 switch (type) {
1020 case REQTREE_GOAL_EDGE:
1022 case REQTREE_KNOWN_EDGE:
1023 /* using "text" black instead of "known" white/ground/green */
1024 return COLOR_REQTREE_TEXT;
1025 case REQTREE_READY_EDGE:
1027 default:
1028 return COLOR_REQTREE_EDGE;
1029 };
1030}
1031
1032/*********************************************************************/
1039 int canvas_x, int canvas_y,
1040 int tt_x, int tt_y, int w, int h)
1041{
1042 int i, j, k;
1043 int swidth, sheight;
1044 struct sprite* sprite;
1045 struct color *color;
1046
1047 /* draw the diagram */
1048 for (i = 0; i < tree->num_layers; i++) {
1049 for (j = 0; j < tree->layer_size[i]; j++) {
1050 struct tree_node *node = tree->layers[i][j];
1051 int startx, starty, endx, endy, width, height;
1052
1053 startx = node->node_x;
1054 starty = node->node_y;
1055 width = node->node_width;
1056 height = node->node_height;
1057
1058 if (node->is_dummy) {
1059 /* Use the same layout as lines for dummy nodes */
1062 LINE_GOTO,
1063 startx, starty, width, 0);
1064 } else {
1065 const char *text = research_advance_name_translation
1066 (research_get(client_player()), node->tech);
1067 int text_w, text_h;
1068 int icon_startx;
1069
1073
1074 /* Print color rectangle with text inside. */
1076 startx + 1, starty + 1,
1077 width - 2, height - 2);
1078 /* The following code is similar to the one in
1079 * node_rectangle_minimum_size(). If you change something here,
1080 * change also node_rectangle_minimum_size().
1081 */
1082
1084
1086 startx + (width - text_w) / 2,
1087 starty + 4,
1090 text);
1091 icon_startx = startx + 5;
1092
1094 unit_type_iterate(utype) {
1095
1096 if (!is_tech_req_for_utype(utype, advance_by_number(node->tech))) {
1097 continue;
1098 }
1099
1105 starty + text_h + 4
1106 + (height - text_h - 4 - sheight) / 2,
1107 sprite);
1108 icon_startx += swidth + 2;
1110
1111 improvement_iterate(pimprove) {
1112 if (valid_improvement(pimprove)) {
1113 requirement_vector_iterate(&(pimprove->reqs), preq) {
1114 if (VUT_ADVANCE == preq->source.kind
1115 && preq->present
1116 && advance_number(preq->source.value.advance) == node->tech) {
1117 sprite = get_building_sprite(tileset, pimprove);
1118 /* Improvement icons are not guaranteed to exist */
1119 if (sprite) {
1123 starty + text_h + 4
1124 + (height - text_h - 4 - sheight) / 2,
1125 sprite);
1126 icon_startx += swidth + 2;
1127 }
1128 }
1130 }
1132
1133 governments_iterate(gov) {
1134 requirement_vector_iterate(&(gov->reqs), preq) {
1135 if (VUT_ADVANCE == preq->source.kind
1136 && preq->present
1137 && advance_number(preq->source.value.advance) == node->tech) {
1142 starty + text_h + 4
1143 + (height - text_h - 4 - sheight) / 2,
1144 sprite);
1145 icon_startx += swidth + 2;
1146 }
1149 }
1150 }
1151
1152 /* Draw all outgoing edges */
1153 startx = node->node_x + node->node_width;
1154 starty = node->node_y + node->node_height / 2;
1155 for (k = 0; k < node->nprovide; k++) {
1156 struct tree_node *dest_node = node->provide[k];
1157
1159
1160 endx = dest_node->node_x;
1161 endy = dest_node->node_y + dest_node->node_height / 2;
1162
1166 endy - starty);
1167 } else {
1170 endy - starty);
1171 }
1172 }
1173 }
1174 }
1175}
1176
1177/*********************************************************************/
1181{
1182 int i;
1183
1184 for (i = 0; i < tree->num_nodes; i++) {
1185 struct tree_node *node = tree->nodes[i];
1186
1187 if (node->is_dummy) {
1188 continue;
1189 }
1190 if (node->node_x <= x && node->node_y <= y
1191 && node->node_x + node->node_width > x
1192 && node->node_y + node->node_height > y) {
1193 return node->tech;
1194 }
1195 }
1196 return A_NONE;
1197}
1198
1199/*********************************************************************/
1204 int *x, int *y, int *w, int *h)
1205{
1206 int i;
1207
1208 for (i = 0; i < tree->num_nodes; i++) {
1209 struct tree_node *node = tree->nodes[i];
1210
1211 if (!node->is_dummy && node->tech == tech) {
1212 if (x) {
1213 *x = node->node_x;
1214 }
1215 if (y) {
1216 *y = node->node_y;
1217 }
1218 if (w) {
1219 *w = node->node_width;
1220 }
1221 if (h) {
1222 *h = node->node_height;
1223 }
1224 return TRUE;
1225 }
1226 }
1227 return FALSE;
1228}
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:75
int Tech_type_id
Definition fc_types.h:377
#define governments_iterate(NAME_pgov)
Definition government.h:124
#define governments_iterate_end
Definition government.h:127
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:191
#define fc_assert(condition)
Definition log.h:176
#define fc_assert_action(condition, action)
Definition log.h:187
#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:72
static int max_provide_layer(struct tree_node *node)
Definition reqtree.c:532
static int longest_path(struct tree_node *node)
Definition reqtree.c:500
static void barycentric_sort(struct reqtree *tree, int layer)
Definition reqtree.c:707
static int cmp_func(const void *_a, const void *_b)
Definition reqtree.c:690
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:1038
void get_reqtree_dimensions(struct reqtree *reqtree, int *width, int *height)
Definition reqtree.c:872
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:121
static enum color_std node_color(struct tree_node *node)
Definition reqtree.c:886
static int count_crossings(struct reqtree *tree, int layer)
Definition reqtree.c:740
static void improve(struct reqtree *tree)
Definition reqtree.c:786
static void symmetrize(struct reqtree *tree)
Definition reqtree.c:240
static struct reqtree * add_dummy_nodes(struct reqtree *tree)
Definition reqtree.c:549
static void set_layers(struct reqtree *tree)
Definition reqtree.c:642
static void longest_path_layering(struct reqtree *tree)
Definition reqtree.c:518
static void calculate_diagram_layout(struct reqtree *tree)
Definition reqtree.c:297
Tech_type_id get_tech_on_reqtree(struct reqtree *tree, int x, int y)
Definition reqtree.c:1180
bool find_tech_on_reqtree(struct reqtree *tree, Tech_type_id tech, int *x, int *y, int *w, int *h)
Definition reqtree.c:1203
static void swap(struct reqtree *tree, int layer, int order1, int order2)
Definition reqtree.c:771
static enum reqtree_edge_type get_edge_type(struct tree_node *node, struct tree_node *dest_node)
Definition reqtree.c:942
static enum color_std edge_color(struct tree_node *node, struct tree_node *dest_node)
Definition reqtree.c:1012
static struct tree_node * new_tree_node(void)
Definition reqtree.c:142
void destroy_reqtree(struct reqtree *tree)
Definition reqtree.c:475
struct reqtree * create_reqtree(struct player *pplayer, bool show_all)
Definition reqtree.c:841
static struct reqtree * create_dummy_reqtree(struct player *pplayer, bool show_all)
Definition reqtree.c:395
reqtree_edge_type
Definition reqtree.c:110
@ REQTREE_READY_EDGE
Definition reqtree.c:112
@ REQTREE_ACTIVE_EDGE
Definition reqtree.c:114
@ REQTREE_EDGE
Definition reqtree.c:111
@ REQTREE_KNOWN_EDGE
Definition reqtree.c:113
@ REQTREE_GOAL_EDGE
Definition reqtree.c:115
#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:668
bool research_goal_tech_req(const struct research *presearch, Tech_type_id goal, Tech_type_id tech)
Definition research.c:807
const char * research_advance_name_translation(const struct research *presearch, Tech_type_id tech)
Definition research.c:273
struct research * research_get(const struct player *pplayer)
Definition research.c:128
enum tech_state research_invention_state(const struct research *presearch, Tech_type_id tech)
Definition research.c:619
bool research_invention_gettable(const struct research *presearch, const Tech_type_id tech, bool allow_holes)
Definition research.c:693
#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:221
bool reqtree_curved_lines
Definition options.h:222
Definition colors.h:21
GdkRGBA color
Definition colors.h:22
struct tree_node * node
Definition reqtree.c:683
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:107
struct advance * valid_advance_by_number(const Tech_type_id id)
Definition tech.c:176
Tech_type_id advance_required(const Tech_type_id tech, enum tech_req require)
Definition tech.c:121
Tech_type_id advance_number(const struct advance *padvance)
Definition tech.c:98
#define advance_index_iterate_max(_start, _index, _max)
Definition tech.h:252
@ AR_TWO
Definition tech.h:112
@ AR_ONE
Definition tech.h:111
#define advance_index_iterate_max_end
Definition tech.h:258
static Tech_type_id advance_count(void)
Definition tech.h:170
#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:6804
struct sprite * get_building_sprite(const struct tileset *t, const struct impr_type *pimprove)
Definition tilespec.c:6794
struct sprite * get_unittype_sprite(const struct tileset *t, const struct unit_type *punittype, enum unit_activity activity, enum direction8 facing)
Definition tilespec.c:6816
bool is_tech_req_for_utype(const struct unit_type *ptype, struct advance *padv)
Definition unittype.c:2724
#define unit_type_iterate(_p)
Definition unittype.h:855
#define unit_type_iterate_end
Definition unittype.h:862