1 /*
2 *
3 * Copyright (c) 2002, 2003 Johannes Prix
4 * Copyright (c) 2004-2010 Arthur Huillet
5 *
6 *
7 * This file is part of Freedroid
8 *
9 * Freedroid is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * Freedroid is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Freedroid; see the file COPYING. If not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22 * MA 02111-1307 USA
23 *
24 */
25
26 #define _leveleditor_display_c
27
28 #include "system.h"
29
30 #include "defs.h"
31 #include "struct.h"
32 #include "global.h"
33 #include "proto.h"
34
35 #include "lvledit/lvledit.h"
36 #include "lvledit/lvledit_actions.h"
37 #include "lvledit/lvledit_widgets.h"
38
39 struct image level_editor_waypoint_cursor[2] = { EMPTY_IMAGE, EMPTY_IMAGE };
40
41 #define DEFAULT_ZOOM_FACTOR 3.0
42 static float lvledit_zoom_factor = DEFAULT_ZOOM_FACTOR;
43 static float lvledit_zoom_factor_inv = 1.0 / DEFAULT_ZOOM_FACTOR;
44
lvledit_zoomfact()45 float lvledit_zoomfact()
46 {
47 return lvledit_zoom_factor;
48 }
49
lvledit_zoomfact_inv()50 float lvledit_zoomfact_inv()
51 {
52 return lvledit_zoom_factor_inv;
53 }
54
lvledit_set_zoomfact(float zf)55 int lvledit_set_zoomfact(float zf)
56 {
57 lvledit_zoom_factor = zf;
58 lvledit_zoom_factor_inv = 1.0 / zf;
59 return 0;
60 }
61
62 /**
63 * Displays the GPS in the editor
64 */
gps_show()65 static void gps_show() {
66 static char gps_text[200];
67 // TRANSLATORS: Used to display a GPS position (X=10.5 Y=34.3 L=12 layer=1)
68 snprintf(gps_text, sizeof(gps_text) - 1, _(" X=%3.1f Y=%3.1f L=%d layer=%d\n"), Me.pos.x, Me.pos.y, Me.pos.z, current_floor_layer);
69 display_text(gps_text, User_Rect.x + 1, GameConfig.screen_height - 1 * get_font_height(get_current_font()), NULL /*&User_Rect */ , 1.0);
70 }
71
72 /**
73 * Displays counted FPS right above GPS
74 */
lvledit_display_fps(void)75 void lvledit_display_fps(void) {
76 static char fps_text[200];
77 sprintf(fps_text, _(" FPS=%d\n"), get_current_fps());
78 display_text(fps_text, User_Rect.x + 1,
79 GameConfig.screen_height - 2 * get_font_height(get_current_font()), NULL, 1.0);
80 }
81
82 /**
83 * Now we print out the map label information about this map location.
84 */
print_label_information(level * EditLevel)85 static void print_label_information(level *EditLevel)
86 {
87 char PanelText[5000] = "";
88 map_label *m;
89
90 m = get_map_label_from_coords(EditLevel, Me.pos.x, Me.pos.y);
91
92 if (m) {
93 // Create the map label information
94 sprintf(PanelText, _("\n Map label information: \n label_name=\"%s\"."), m->label_name);
95
96 // Display the map label information on the screen
97 display_text(PanelText, User_Rect.x, GameConfig.screen_height - 5 * get_font_height(get_current_font()), NULL, 1.0);
98
99 return;
100 }
101 }
102
show_cursor(int must_zoom)103 static void show_cursor(int must_zoom)
104 {
105 static struct image level_editor_cursor = EMPTY_IMAGE;
106
107 #define HIGHLIGHTCOLOR 255
108
109 // Maybe, if the level editor floor cursor has not yet been loaded,
110 // we need to load it.
111 //
112 if (!image_loaded(&level_editor_cursor)) {
113 load_image(&level_editor_cursor, "level_editor_floor_cursor.png", USE_OFFSET);
114 }
115
116 float scale = must_zoom ? lvledit_zoomfact_inv() : 1.0;
117
118 display_image_on_map(&level_editor_cursor, Me.pos.x, Me.pos.y, IMAGE_SCALE_TRANSFO(scale));
119 print_label_information(EditLevel());
120 }
121
122 /**
123 * This function is used to draw a line between given map tiles. It is
124 * mainly used for the map editor to highlight connections and the
125 * current map tile target.
126 */
draw_connection_between_tiles(float x1,float y1,float x2,float y2,int mask,int rspawn)127 void draw_connection_between_tiles(float x1, float y1, float x2, float y2, int mask, int rspawn)
128 {
129 float steps;
130 float dist;
131 int i;
132 static struct image level_editor_dot_cursor = EMPTY_IMAGE;
133
134 float scale = (mask & ZOOM_OUT) ? lvledit_zoomfact_inv() : 1.0;
135
136 // Maybe, if the level editor dot cursor has not yet been loaded,
137 // we need to load it.
138 //
139 if (!image_loaded(&level_editor_dot_cursor)) {
140 load_image(&level_editor_dot_cursor, "level_editor_waypoint_dot.png", USE_OFFSET);
141 }
142
143 // So now that the dot cursor has been loaded, we can start to
144 // actually draw the dots.
145 //
146
147 // We measure the distance that we have to go and then we draw some
148 // dots at some convex combinations of our two vectors. Very fine.
149 //
150 dist = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
151
152 steps = dist * 4; // let's say 4 dots per square to mark the line, ok?
153
154 if (!steps) // Oh, noh, the points are at the same place
155 return;
156 for (i = 0; i < steps + 1; i++) {
157 float x, y;
158 float r, g, b;
159 x = (((float)i) / steps) * x1 + x2 * (steps - i) / steps;
160 y = (((float)i) / steps) * y1 + y2 * (steps - i) / steps;
161
162 r = 1.0;
163 if (rspawn)
164 g = b = 0;
165 else
166 g = b = 1.0;
167
168 display_image_on_map(&level_editor_dot_cursor, x, y, IMAGE_SCALE_RGB_TRANSFO(scale, r, g, b));
169
170 }
171
172 }; // void draw_connection_between_tiles ( .... )
173
174 /**
175 * This function is used by thelevel *Editor integrated into
176 * FreedroidRPG. It marks all waypoints with a cross.
177 */
show_waypoints(int mask)178 static void show_waypoints(int mask)
179 {
180 float zf = (mask & ZOOM_OUT) ? lvledit_zoomfact_inv() : 1.0;
181 waypoint *wpts = EditLevel()->waypoints.arr;
182 float r, g, b;
183 float x, y;
184 int i, j;
185 int x_min, x_max, y_min, y_max;
186
187 get_floor_boundaries(mask, &y_min, &y_max, &x_min, &x_max);
188
189 // Maybe, if the level editor floor cursor has not yet been loaded,
190 // we need to load it.
191 if (!image_loaded(&level_editor_waypoint_cursor[0])) {
192 load_image(&level_editor_waypoint_cursor[0], "level_editor_waypoint_cursor.png", USE_OFFSET);
193 }
194
195 if (!image_loaded(&level_editor_waypoint_cursor[1])) {
196 load_image(&level_editor_waypoint_cursor[1], "level_editor_norand_waypoint_cursor.png", USE_OFFSET);
197 }
198
199 for (i = 0; i < EditLevel()->waypoints.size; i++) {
200 // Skip waypoints that are not visible
201 if (wpts[i].x <= x_min || wpts[i].x >= x_max)
202 continue;
203 if (wpts[i].y <= y_min || wpts[i].y >= y_max)
204 continue;
205
206 // Calculate the position of the waypoint
207 x = wpts[i].x + 0.5;
208 y = wpts[i].y + 0.5;
209
210 // Apply disco mode when current waypoint is selected
211 object_vtx_color(&wpts[i], &r, &g, &b);
212
213 struct image *img = &level_editor_waypoint_cursor[wpts[i].suppress_random_spawn];
214 display_image_on_map(img, x, y, IMAGE_SCALE_RGB_TRANSFO(zf, r, g, b));
215
216 // Get the connections of the waypoint
217 int *connections = wpts[i].connections.arr;
218
219 for (j = 0; j < wpts[i].connections.size; j++) {
220 // Check validity of the connected waypoint
221 int connected_waypoint = connections[j];
222 if (connected_waypoint < 0 || connected_waypoint >= EditLevel()->waypoints.size)
223 continue;
224
225 waypoint *to_wp = &wpts[connected_waypoint];
226
227 if (((EditX() == wpts[i].x) && (EditY() == wpts[i].y)) || GameConfig.show_wp_connections) {
228 draw_connection_between_tiles(x, y, to_wp->x + 0.5, to_wp->y + 0.5, mask, wpts[i].suppress_random_spawn);
229 }
230 }
231 }
232
233 // Now we do something extra: If there is a connection attempt currently
234 // going on, then we also draw a connection from the origin point to the
235 // current cursor (i.e. 'me') position.
236 if (OriginWaypoint != (-1)) {
237 // Draw the connection between the origin waypoint and the cursor (ie. 'me')
238 draw_connection_between_tiles(wpts[OriginWaypoint].x + 0.5, wpts[OriginWaypoint].y + 0.5, Me.pos.x, Me.pos.y,
239 mask, wpts[OriginWaypoint].suppress_random_spawn);
240 }
241 }
242
243 /**
244 * This function is used by thelevel *Editor integrated into
245 * FreedroidRPG. It marks all places that have a label attached to them.
246 */
show_map_labels(int must_zoom)247 static void show_map_labels(int must_zoom)
248 {
249 level *EditLevel = curShip.AllLevels[Me.pos.z];
250 struct map_label *map_label;
251 int i;
252 float r, g, b;
253 float scale = must_zoom ? lvledit_zoomfact_inv() : 1.0;
254 int x_min, x_max, y_min, y_max;
255
256 get_floor_boundaries(must_zoom, &y_min, &y_max, &x_min, &x_max);
257
258 // Now we can draw a fine indicator at all the necessary positions ...
259 for (i = 0; i < EditLevel->map_labels.size; i++) {
260 // Get the map label
261 map_label = &ACCESS_MAP_LABEL(EditLevel->map_labels, i);
262
263 // Apply disco mode when the current map label is selected
264 object_vtx_color(map_label, &r, &g, &b);
265
266 // Skip map labels that are not visible
267 if (map_label->pos.x < x_min || map_label->pos.x > x_max)
268 continue;
269 if (map_label->pos.y < y_min || map_label->pos.y > y_max)
270 continue;
271
272 struct image *img = get_map_label_image();
273 display_image_on_map(img, map_label->pos.x + 0.5, map_label->pos.y + 0.5, IMAGE_SCALE_RGB_TRANSFO(scale, r, g, b));
274
275 if (!GameConfig.omit_map_labels_in_level_editor) {
276 show_backgrounded_label_at_map_position(map_label->label_name,
277 0, map_label->pos.x,
278 map_label->pos.y, must_zoom);
279 }
280 }
281 }
282
283 /**
284 * Display the cursor in the leveleditor according to the currently
285 * selected tool etc.
286 */
display_cursor()287 static void display_cursor()
288 {
289 struct widget *w;
290 w = get_active_widget(GetMousePos_x(), GetMousePos_y());
291
292 if (w) {
293 if (w->type != WIDGET_MAP)
294 blit_mouse_cursor();
295 else
296 widget_lvledit_map_display_cursor();
297 }
298 }
299
leveleditor_display()300 void leveleditor_display()
301 {
302 char linebuf[1000];
303
304 AssembleCombatPicture(ONLY_SHOW_MAP_AND_TEXT | SHOW_ITEMS | OMIT_TUX | GameConfig.omit_obstacles_in_level_editor *
305 OMIT_OBSTACLES | GameConfig.omit_enemies_in_level_editor * OMIT_ENEMIES | ZOOM_OUT *
306 GameConfig.zoom_is_on | OMIT_BLASTS | SKIP_LIGHT_RADIUS | NO_CURSOR | OMIT_ITEMS_LABEL);
307
308 start_image_batch();
309 show_waypoints(ZOOM_OUT * GameConfig.zoom_is_on);
310 show_map_labels(ZOOM_OUT * GameConfig.zoom_is_on);
311 end_image_batch();
312 show_cursor(ZOOM_OUT * GameConfig.zoom_is_on);
313 gps_show();
314
315 if (GameConfig.Draw_Framerate)
316 lvledit_display_fps();
317
318 set_current_font(FPS_Display_Font);
319
320 // Now we print out the current status directly onto the window:
321 //
322 if (OriginWaypoint != -1) {
323 waypoint *wpts = EditLevel()->waypoints.arr;
324
325 sprintf(linebuf, _(" Source waypoint selected : X=%d Y=%d. "), wpts[OriginWaypoint].x, wpts[OriginWaypoint].y);
326 put_string_left(FPS_Display_Font, GameConfig.screen_height - 2 * get_font_height(get_current_font()), linebuf);
327 }
328 // Now we print out the latest connection operation success or failure...
329 //
330 if (VanishingMessageEndDate > SDL_GetTicks()) {
331 display_text(VanishingMessage, 1, GameConfig.screen_height - 8 * get_font_height(get_current_font()), NULL, 1.0);
332 }
333
334 // Construct the linked list of visible levels.
335 get_visible_levels();
336
337 display_widgets();
338
339 if (EditLevel()->random_dungeon) {
340 sprintf(VanishingMessage, _(" This level is automatically generated. \n Editing will have no effect."));
341 VanishingMessageEndDate = SDL_GetTicks() + 100;
342 }
343
344 display_cursor();
345 // Now that everything is blitted and printed, we may update the screen again...
346 //
347 our_SDL_flip_wrapper();
348
349 }
350