Page:
ex__gui__isometric_8c
Pages
Examples
Files
Home
Module AABB3D
Module ACCEPT_POOL
Module ALLEGRO4
Module ALLEGRO5
Module ANIM_LIB
Module ASTAR
Module ATLAS_LIB
Module AVRO
Module CLOCK_SYNC
Module COMMONS
Module CONFIGFILE
Module CYPHER_BASE64
Module CYPHER_VIGENERE
Module DEAD_RECKONING
Module ENUMS
Module EXCEPTIONS
Module GAME_ENV
Module GIT
Module GUI
Module HASH_TABLE
Module ISOMETRIC_ENGINE
Module LIST
Module LOG
Module LOGNODUP
Module LZ4
Module NETWORKING
Module NETWORK_MSG
Module N_COOKIES
Module N_DIFF
Module N_DIGEST
Module N_DISK_CACHE
Module N_DNS
Module N_ECC
Module N_ENTROPY
Module N_FILES
Module N_FLUIDS
Module N_GUI_COLOR
Module N_GUI_COLORWHEEL
Module N_GUI_CURVE
Module N_GUI_GRID
Module N_GUI_POPUP
Module N_HEX
Module N_HTTP3
Module N_HTTP_COOKIE
Module N_HTTP_FORM
Module N_HTTP_MIME
Module N_HTTP_REQ
Module N_HTTP_RESP
Module N_HTTP_ROUTER
Module N_HTTP_SERVER
Module N_ICC
Module N_JSON
Module N_KAFKA
Module N_LINALG
Module N_MODULE
Module N_OPENSSL_COMPAT
Module N_PRETTY
Module N_PTH
Module N_QUERY
Module N_RANDOM
Module N_SHA256
Module N_STR
Module N_TIFF
Module N_TIME
Module N_USER
Module N_X509
Module N_ZIP
Module PARTICLES
Module PCRE
Module PHYSICS
Module SIGNALS
Module STACK
Module THREADS
Module TRAJECTORY
Module TREE
Module ZLIB
Modules
Pages
Struct A4_BMP
Struct A4_TIMER
Struct AABB3D
Struct ANIM_DATA
Struct ANIM_FRAME
Struct ANIM_GFX
Struct ANIM_LIB
Struct ASTAR_BOX
Struct ASTAR_CELL
Struct ASTAR_GRID
Struct ASTAR_HEAP
Struct ASTAR_HEAP_NODE
Struct ASTAR_NODE
Struct ASTAR_PATH
Struct AVRO_FIELD
Struct AVRO_READER
Struct AVRO_SCHEMA
Struct BITMAP
Struct CALLBACK_DATA
Struct CA_CTX
Struct CLIENT_JOB
Struct CLIENT_STATE
Struct CONFIG_FILE
Struct CONFIG_FILE_SECTION
Struct CYPHER_PARAM
Struct DATA
Struct DEMO_PANEL
Struct DICTIONARY_DEFINITION
Struct DICTIONARY_ENTRY
Struct DIFF_OUT
Struct DIFF_TEXT
Struct DRAW_STATE
Struct DR_ENTITY
Struct DR_STATE
Struct DR_VEC3
Struct ExceptionContextList
Struct FONT
Struct GAME_ENV
Struct H2BUF
Struct H2_DYN_ENTRY
Struct H2_STREAM
Struct HASH_NODE
Struct HASH_TABLE
Struct ISO_DRAW_ENTRY
Struct ISO_MAP
Struct ISO_PROJECTION
Struct ISO_TILE_SEGMENT
Struct ISO_TILE_SEGMENTS
Struct ISO_VISIBLE_EDGES
Struct JS_STATE
Struct LEX_ITEM
Struct LIST
Struct LIST_NODE
Struct LOG_LEVELS
Struct LexMenu
Struct MEMBER
Struct MIDI
Struct NESTED
Struct NETWORK
Struct NETWORK_HTTP_INFO
Struct NETWORK_POOL
Struct NETWORK_SSL_THREAD_PARAMS
Struct NETW_ACCEPT_POOL
Struct NETW_ACCEPT_POOL_STATS
Struct NETW_MSG
Struct NETW_SNI_ARG
Struct NODE_DATA
Struct N_ATLAS
Struct N_ATLAS_PAGE
Struct N_CLOCK_SYNC
Struct N_COOKIE
Struct N_COOKIE_JAR
Struct N_DIFF_LINE
Struct N_DIFF_RESULT
Struct N_DISK_CACHE
Struct N_ENTROPY_BIT
Struct N_ENTROPY_POS
Struct N_FILE_INFO
Struct N_FLUID
Struct N_FLUID_THREAD_PARAMS
Struct N_FORM_FIELD
Struct N_GIT_COMMIT_INFO
Struct N_GIT_REMOTE_AUTH
Struct N_GIT_REPO
Struct N_GIT_STATUS_ENTRY
Struct N_GUI_BUTTON_DATA
Struct N_GUI_CHECKBOX_DATA
Struct N_GUI_COLOR_PICKER
Struct N_GUI_COMBOBOX_DATA
Struct N_GUI_CTX
Struct N_GUI_CUSTOM_DATA
Struct N_GUI_DATAGRID_COL
Struct N_GUI_DATAGRID_DATA
Struct N_GUI_DROPMENU_DATA
Struct N_GUI_DROPMENU_ENTRY
Struct N_GUI_GRID_CALLBACKS
Struct N_GUI_HEXVIEW_DATA
Struct N_GUI_IMAGE_DATA
Struct N_GUI_KVTABLE
Struct N_GUI_KV_CONTENT
Struct N_GUI_KV_ROW
Struct N_GUI_LABEL_DATA
Struct N_GUI_LISTBOX_DATA
Struct N_GUI_LISTITEM
Struct N_GUI_MARKDOWNVIEW_DATA
Struct N_GUI_MD_FONTS
Struct N_GUI_MD_STYLE
Struct N_GUI_MEAS_ENTRY
Struct N_GUI_MOUSE_EVENT
Struct N_GUI_PENDING_GEOM
Struct N_GUI_PENDING_WIDGET
Struct N_GUI_POPUP
Struct N_GUI_PROGRESSBAR_DATA
Struct N_GUI_RADIOLIST_DATA
Struct N_GUI_SB_TRACK
Struct N_GUI_SCROLLBAR_DATA
Struct N_GUI_SECTION
Struct N_GUI_SECTIONLIST
Struct N_GUI_SLIDER_DATA
Struct N_GUI_SPLITPANE_DATA
Struct N_GUI_STYLE
Struct N_GUI_SUGGEST_SINK
Struct N_GUI_SYNTAXVIEW_DATA
Struct N_GUI_TAB_PANEL
Struct N_GUI_TB_BUTTONS
Struct N_GUI_TEXTAREA_DATA
Struct N_GUI_TEXT_DIMS
Struct N_GUI_THEME
Struct N_GUI_TREE
Struct N_GUI_TREE_NODE
Struct N_GUI_TREE_STATE
Struct N_GUI_WIDGET
Struct N_GUI_WINDOW
Struct N_H2_FRAME
Struct N_H2_HEADER
Struct N_H2_HPACK
Struct N_H2_REQUEST
Struct N_H2_SERVER
Struct N_H2_SETTING
Struct N_HTML_ATTR_
Struct N_HTML_FORM
Struct N_HTML_TAG_
Struct N_HTTP3_RESPONSE
Struct N_HTTP_FIELD
Struct N_HTTP_FORM
Struct N_HTTP_FORM_MULTIPART
Struct N_HTTP_FORM_PART
Struct N_HTTP_MULTIPART_PART
Struct N_HTTP_REQUEST
Struct N_HTTP_RESP
Struct N_HTTP_RESPONSE
Struct N_HTTP_SERVER
Struct N_HTTP_SERVER_CONFIG
Struct N_HTTP_SERVER_REQUEST
Struct N_HTTP_SERVER_STATS
Struct N_HTTP_SET_COOKIE
Struct N_HTTP_STREAM
Struct N_ISO_CAMERA
Struct N_ISO_OBJECT
Struct N_KAFKA
Struct N_KAFKA_EVENT
Struct N_MOCK_SERVER
Struct N_MODULE
Struct N_PARALLEL_SLICE
Struct N_PARALLEL_TEAM
Struct N_PARALLEL_WORKER
Struct N_PCRE
Struct N_PROXY_CFG
Struct N_PTH
Struct N_PTH_TENSOR
Struct N_QUERY
Struct N_ROUTE
Struct N_ROUTER
Struct N_ROUTE_MATCH
Struct N_SHA256
Struct N_SOCKET
Struct N_SPAWN_PIPE
Struct N_SSE_CONN
Struct N_SSE_EVENT
Struct N_STR
Struct N_TIFF
Struct N_TIFF_ENTRY
Struct N_TIME
Struct N_URL
Struct N_URL_PARAM
Struct N_USER
Struct N_USERLIST
Struct N_WS_CONN
Struct N_WS_FRAME
Struct N_WS_MESSAGE
Struct N_ZIP_MEMBER
Struct OCTREE
Struct OCTREE_NODE
Struct PARSER
Struct PARTICLE
Struct PARTICLE_EMITTER
Struct PARTICLE_SYSTEM
Struct PEER
Struct PHYSICS
Struct PK_OBJ
Struct PK_VM
Struct POINT2D
Struct POINT3D
Struct PRETTY_OUT
Struct QNODE
Struct QUADTREE
Struct QUADTREE_NODE
Struct REC
Struct RGB
Struct SAMPLE
Struct SEEN
Struct SHARER
Struct SRV
Struct SRV_ARG
Struct STACK
Struct STACK_ITEM
Struct SYNTAX_RUN
Struct THREAD_POOL
Struct THREAD_POOL_NODE
Struct THREAD_WAITING_PROC
Struct TRAJECTORY
Struct TRAJECTORY_POINT
Struct TREE
Struct TREE_NODE
Struct TS_LOG
Struct WAYPOINT3D
Struct WORKER_ARG
Struct ZIP_SINK
Struct _N_DC_ENTRY
Struct _N_DC_GROUP_ENTRY
Struct _N_GUI_COLORWHEEL
Struct _N_GUI_COLORWHEEL_BLOCK
Struct _N_GUI_COLORWHEEL_MOUSE
Struct _N_GUI_CURVE
Struct _N_GUI_CURVE_BLOCK
Struct _N_GUI_CURVE_MOUSE
Struct _N_GUI_GRID
Struct _N_GUI_POPUP_ENTRY
Struct _N_GUI_POPUP_LEVEL
Struct _N_GUI_SB_SKIN
Struct _N_GUI_TA_STEP
Struct _N_GUI_THUMB
Struct _N_GUI_WRAP_ACC
Struct _compiled
Struct _conn
Struct _ip_slot
Struct _mp_param
Struct _n_civil
Struct _seg
Struct client
Struct collector
Struct date_vector
Struct md_atom
Struct md_cells
Struct md_hit
Struct md_line_ctx
Struct mline
Struct n_http_req_header
Struct n_http_req_limits
Struct n_http_request
Struct n_markdown_block
Struct n_markdown_doc
Struct n_markdown_inline
Struct n_markdown_span
Struct n_reactor_stats
Struct n_url_safe
Struct n_url_safe_head
Struct n_wrap_item
Struct producer_state
Struct rects
Struct reply
Struct runner
Struct sink
Struct tbuf
Struct wrap_hit
Struct wrap_span
Structures
Union COORD_VALUE
Union HASH_DATA
Union NODE_DATA_TYPES
Union STACK_DATA
dir_310dcdd4703e877a6b99d5dc3fc54d27
dir_68267d1309a1af8e8297ef4c3efbcdba
dir_d28a4824dc47e487b107a5db32ef43c4
dir_d44c64559bbebec7f509842c48db8b23
ex__accept__pool__client_8c
ex__accept__pool__server_8c
ex__allegro__4_8c
ex__atlas_8c
ex__avro_8c
ex__base64_8c
ex__bind__exclusive_8c
ex__clipboard_8c
ex__clock__sync_8c
ex__common_8c
ex__configfile_8c
ex__cookies_8c
ex__crypto_8c
ex__diff_8c
ex__digest_8c
ex__disk__cache_8c
ex__dns_8c
ex__ecc_8c
ex__entropy_8c
ex__exceptions_8c
ex__file_8c
ex__file__copy_8c
ex__fluid_8c
ex__fluid__config_8c
ex__fluid__config_8h
ex__git_8c
ex__gui_8c
ex__gui__bench_8c
ex__gui__button__keys_8c
ex__gui__checkbox__label_8c
ex__gui__checkbox__release_8c
ex__gui__color__picker_8c
ex__gui__colorwheel_8c
ex__gui__combobox__items_8c
ex__gui__combobox__wheel_8c
ex__gui__cursor_8c
ex__gui__curve_8c
ex__gui__custom_8c
ex__gui__custom__mouse_8c
ex__gui__datagrid_8c
ex__gui__datagrid__keys_8c
ex__gui__datagrid__sort_8c
ex__gui__detach_8c
ex__gui__dictionary_8c
ex__gui__display__fallback_8c
ex__gui__double__click_8c
ex__gui__dropmenu_8c
ex__gui__frameless__drag_8c
ex__gui__global__scroll_8c
ex__gui__glyph_8c
ex__gui__grid_8c
ex__gui__hexview_8c
ex__gui__hover_8c
ex__gui__isometric_8c
ex__gui__kvtable_8c
ex__gui__label__fits_8c
ex__gui__label__lines_8c
ex__gui__layout__persist_8c
ex__gui__listbox_8c
ex__gui__md_8c
ex__gui__multiwin_8c
ex__gui__network_8c
ex__gui__particles_8c
ex__gui__placeholder_8c
ex__gui__popup_8c
ex__gui__progressbar_8c
ex__gui__reentrant_8c
ex__gui__round_8c
ex__gui__sectionlist_8c
ex__gui__slider__default_8c
ex__gui__slider__handle_8c
ex__gui__slider__step_8c
ex__gui__splitpane_8c
ex__gui__suggest_8c
ex__gui__syntaxview_8c
ex__gui__text__shorten_8c
ex__gui__textarea__selection_8c
ex__gui__tooltip_8c
ex__gui__tree__lazy_8c
ex__gui__tree__order_8c
ex__gui__tree__state_8c
ex__gui__window__rect_8c
ex__gui__zorder_8c
ex__hash_8c
ex__hex_8c
ex__html_8c
ex__http2_8c
ex__http2__server_8c
ex__http3_8c
ex__http__cookie_8c
ex__http__form_8c
ex__http__mime_8c
ex__http__req_8c
ex__http__response_8c
ex__http__router_8c
ex__http__server_8c
ex__icc_8c
ex__iso__astar_8c
ex__json_8c
ex__kafka_8c
ex__linalg_8c
ex__list_8c
ex__log_8c
ex__markdown_8c
ex__module_8c
ex__monolith_8c
ex__network_8c
ex__network_8h
ex__network__accept_8c
ex__network__alpn_8c
ex__network__connect__abort_8c
ex__network__mock_8c
ex__network__proxy_8c
ex__network__reactor_8c
ex__network__sni_8c
ex__network__sse_8c
ex__network__ssl_8c
ex__network__ssl__hardened_8c
ex__network__ssl__hostname_8c
ex__network__ssl__nonblock_8c
ex__network__tls__defaults_8c
ex__network__ws_8c
ex__network__ws__limits_8c
ex__nstr_8c
ex__parallel__for_8c
ex__parallel__team_8c
ex__pcre_8c
ex__pretty_8c
ex__pth_8c
ex__query_8c
ex__random_8c
ex__sha256_8c
ex__signals_8c
ex__spawn_8c
ex__ssrf_8c
ex__stack_8c
ex__thread__pool__discard_8c
ex__thread__pool__wait_8c
ex__threads_8c
ex__tiff_8c
ex__time__formats_8c
ex__trajectory_8c
ex__trees_8c
ex__url_8c
ex__url__safe_8c
ex__wrap_8c
ex__x509_8c
ex__zip_8c
ex__zlib_8c
ex_accept_pool_client_8c example
ex_accept_pool_server_8c example
ex_allegro_4_8c example
ex_atlas_8c example
ex_base64_8c example
ex_clock_sync_8c example
ex_common_8c example
ex_configfile_8c example
ex_cookies_8c example
ex_crypto_8c example
ex_diff_8c example
ex_digest_8c example
ex_disk_cache_8c example
ex_dns_8c example
ex_ecc_8c example
ex_entropy_8c example
ex_exceptions_8c example
ex_file_8c example
ex_file_copy_8c example
ex_fluid_8c example
ex_fluid_config_8c example
ex_fluid_config_8h example
ex_git_8c example
ex_gui_8c example
ex_gui_bench_8c example
ex_gui_button_keys_8c example
ex_gui_checkbox_label_8c example
ex_gui_checkbox_release_8c example
ex_gui_color_picker_8c example
ex_gui_colorwheel_8c example
ex_gui_combobox_items_8c example
ex_gui_combobox_wheel_8c example
ex_gui_cursor_8c example
ex_gui_curve_8c example
ex_gui_custom_8c example
ex_gui_custom_mouse_8c example
ex_gui_datagrid_8c example
ex_gui_datagrid_keys_8c example
ex_gui_datagrid_sort_8c example
ex_gui_detach_8c example
ex_gui_dictionary_8c example
ex_gui_display_fallback_8c example
ex_gui_double_click_8c example
ex_gui_dropmenu_8c example
ex_gui_frameless_drag_8c example
ex_gui_global_scroll_8c example
ex_gui_glyph_8c example
ex_gui_grid_8c example
ex_gui_hexview_8c example
ex_gui_hover_8c example
ex_gui_isometric_8c example
ex_gui_kvtable_8c example
ex_gui_label_fits_8c example
ex_gui_label_lines_8c example
ex_gui_layout_persist_8c example
ex_gui_listbox_8c example
ex_gui_md_8c example
ex_gui_multiwin_8c example
ex_gui_network_8c example
ex_gui_particles_8c example
ex_gui_placeholder_8c example
ex_gui_popup_8c example
ex_gui_progressbar_8c example
ex_gui_reentrant_8c example
ex_gui_round_8c example
ex_gui_sectionlist_8c example
ex_gui_slider_default_8c example
ex_gui_slider_handle_8c example
ex_gui_slider_step_8c example
ex_gui_splitpane_8c example
ex_gui_suggest_8c example
ex_gui_syntaxview_8c example
ex_gui_text_shorten_8c example
ex_gui_textarea_selection_8c example
ex_gui_tooltip_8c example
ex_gui_tree_lazy_8c example
ex_gui_tree_order_8c example
ex_gui_tree_state_8c example
ex_gui_window_rect_8c example
ex_gui_zorder_8c example
ex_hash_8c example
ex_hex_8c example
ex_html_8c example
ex_http2_8c example
ex_http2_server_8c example
ex_http_cookie_8c example
ex_http_form_8c example
ex_http_mime_8c example
ex_http_req_8c example
ex_http_response_8c example
ex_http_router_8c example
ex_http_server_8c example
ex_icc_8c example
ex_iso_astar_8c example
ex_json_8c example
ex_kafka_8c example
ex_linalg_8c example
ex_list_8c example
ex_log_8c example
ex_markdown_8c example
ex_module_8c example
ex_monolith_8c example
ex_network_8c example
ex_network_8h example
ex_network_accept_8c example
ex_network_alpn_8c example
ex_network_connect_abort_8c example
ex_network_mock_8c example
ex_network_proxy_8c example
ex_network_reactor_8c example
ex_network_sni_8c example
ex_network_sse_8c example
ex_network_ssl_8c example
ex_network_ssl_hardened_8c example
ex_network_ssl_hostname_8c example
ex_network_ssl_nonblock_8c example
ex_network_tls_defaults_8c example
ex_network_ws_8c example
ex_network_ws_limits_8c example
ex_nstr_8c example
ex_parallel_for_8c example
ex_parallel_team_8c example
ex_pcre_8c example
ex_pretty_8c example
ex_pth_8c example
ex_query_8c example
ex_random_8c example
ex_sha256_8c example
ex_signals_8c example
ex_spawn_8c example
ex_ssrf_8c example
ex_stack_8c example
ex_threads_8c example
ex_tiff_8c example
ex_time_formats_8c example
ex_trajectory_8c example
ex_trees_8c example
ex_url_8c example
ex_url_safe_8c example
ex_wrap_8c example
ex_x509_8c example
ex_zip_8c example
ex_zlib_8c example
mainpage_8dox
n__3d_8c
n__3d_8h
n__aabb_8c
n__aabb_8h
n__allegro5_8c
n__allegro5_8h
n__allegro__4_8c
n__allegro__4_8h
n__anim_8c
n__anim_8h
n__astar_8c
n__astar_8h
n__atlas_8c
n__atlas_8h
n__avro_8c
n__avro_8h
n__base64_8c
n__base64_8h
n__clipboard_8c
n__clipboard_8h
n__clock__sync_8c
n__clock__sync_8h
n__common_8c
n__common_8h
n__config__file_8c
n__config__file_8h
n__cookies_8c
n__cookies_8h
n__crypto_8c
n__crypto_8h
n__dead__reckoning_8c
n__dead__reckoning_8h
n__diff_8c
n__diff_8h
n__digest_8c
n__digest_8h
n__disk__cache_8c
n__disk__cache_8h
n__dns_8c
n__dns_8h
n__ecc_8c
n__ecc_8h
n__entropy_8c
n__entropy_8h
n__enum_8h
n__exceptions_8c
n__exceptions_8h
n__files_8c
n__files_8h
n__fluids_8c
n__fluids_8h
n__games_8c
n__games_8h
n__git_8c
n__git_8h
n__gui_8c
n__gui_8h
n__gui__color_8c
n__gui__color_8h
n__gui__colorwheel_8c
n__gui__colorwheel_8h
n__gui__curve_8c
n__gui__curve_8h
n__gui__grid_8c
n__gui__grid_8h
n__gui__md_8c
n__gui__md_8h
n__gui__popup_8c
n__gui__popup_8h
n__hash_8c
n__hash_8h
n__hex_8c
n__hex_8h
n__html_8c
n__html_8h
n__http2_8c
n__http2_8h
n__http2__server_8c
n__http2__server_8h
n__http3_8c
n__http3_8h
n__http__cookie_8c
n__http__cookie_8h
n__http__form_8c
n__http__form_8h
n__http__mime_8c
n__http__mime_8h
n__http__req_8c
n__http__req_8h
n__http__response_8c
n__http__response_8h
n__http__router_8c
n__http__router_8h
n__http__server_8c
n__http__server_8h
n__icc_8c
n__icc_8h
n__iso__engine_8c
n__iso__engine_8h
n__json_8c
n__json_8h
n__kafka_8c
n__kafka_8h
n__linalg_8c
n__linalg_8h
n__list_8c
n__list_8h
n__log_8c
n__log_8h
n__lz4_8c
n__lz4_8h
n__markdown_8c
n__markdown_8h
n__module_8c
n__module_8h
n__network_8c
n__network_8h
n__network__accept__pool_8c
n__network__accept__pool_8h
n__network__msg_8c
n__network__msg_8h
n__nodup__log_8c
n__nodup__log_8h
n__openssl__compat_8h
n__particles_8c
n__particles_8h
n__pcre_8c
n__pcre_8h
n__pretty_8c
n__pretty_8h
n__pth_8c
n__pth_8h
n__query_8c
n__query_8h
n__random_8c
n__random_8h
n__reactor_8c
n__reactor_8h
n__sha256_8c
n__sha256_8h
n__signals_8c
n__signals_8h
n__ssrf_8c
n__ssrf_8h
n__stack_8c
n__stack_8h
n__str_8c
n__str_8h
n__thread__pool_8c
n__thread__pool_8h
n__tiff_8c
n__tiff_8h
n__time_8c
n__time_8h
n__trajectory_8c
n__trajectory_8h
n__trees_8c
n__trees_8h
n__url__safe_8c
n__url__safe_8h
n__user_8c
n__user_8h
n__windows_8h
n__wrap_8c
n__wrap_8h
n__x509_8c
n__x509_8h
n__zip_8c
n__zip_8h
n__zlib_8c
n__zlib_8h
nilorea_8h
No results
7
ex__gui__isometric_8c
gullradriel edited this page 2026-10-29 20:54:40 +01:00
Table of Contents
- examples/ex_gui_isometric.c
- Functions
- Attributes
- Defines
- Functions Documentation
- function randomize_map
- function on_smooth_toggle
- function on_reset_click
- function on_proj_select
- function on_player_toggle
- function on_height_toggle
- function on_grid_toggle
- function on_ghost_toggle
- function main
- function interpolate_height_at_clamped
- function interpolate_height_at
- function draw_player_object
- function draw_ghost_object
- Attributes Documentation
- variable transition_tiles
- variable transition_masks
- variable tile_bitmaps
- variable terrain_names
- variable terrain_files
- variable smooth_slope_max
- variable smooth_height
- variable show_grid
- variable screen_w
- variable screen_h
- variable running
- variable redraw_needed
- variable player_z
- variable player_vz
- variable player_screen_y
- variable player_screen_x
- variable player_path_progress
- variable player_path_idx
- variable player_path
- variable player_on_ground
- variable player_my
- variable player_mx
- variable player_mode
- variable player_fy
- variable player_fx
- variable player_click_fy
- variable player_click_fx
- variable paint_terrain
- variable paint_height
- variable last_mouse_y
- variable last_mouse_x
- variable isomap
- variable hover_my
- variable hover_mx
- variable height_mode
- variable gui_win_tiles
- variable gui_win_proj
- variable gui_win_modes
- variable gui_win_info
- variable gui_win_ghost_dr
- variable gui_sld_slope
- variable gui_sld_height
- variable gui_sld_dr_threshold
- variable gui_sld_dr_interval
- variable gui_sld_dr_blend_time
- variable gui_rad_dr_blend
- variable gui_rad_dr_algo
- variable gui_lst_tiles
- variable gui_lbl_status
- variable gui_lbl_slope
- variable gui_lbl_proj
- variable gui_lbl_hover
- variable gui_lbl_height
- variable gui_lbl_dr_threshold
- variable gui_lbl_dr_interval
- variable gui_lbl_dr_blend_time
- variable gui_lbl_dr_blend
- variable gui_lbl_dr_algo
- variable gui_ctx
- variable gui_btn_smooth
- variable gui_btn_reset
- variable gui_btn_proj
- variable gui_btn_player
- variable gui_btn_height
- variable gui_btn_grid
- variable gui_btn_ghost
- variable ghost_true_y
- variable ghost_true_x
- variable ghost_send_interval
- variable ghost_screen_y
- variable ghost_screen_x
- variable ghost_path_speed
- variable ghost_path_radius
- variable ghost_path_cy
- variable ghost_path_cx
- variable ghost_path_angle
- variable ghost_last_send
- variable ghost_enabled
- variable ghost_dr
- variable current_proj
- variable camera
- Macros Documentation
- define TILE_W
- define TILE_LIFT
- define TILE_H
- define TERRAIN_TEMPLE4
- define TERRAIN_TEMPLE3
- define TERRAIN_SABLE
- define TERRAIN_ROCAILLE
- define TERRAIN_PAILLE
- define TERRAIN_LAVE
- define TERRAIN_EAU
- define TERRAIN_CHEMIN
- define SCREEN_W
- define SCREEN_H
- define PLAYER_MOVE_SPEED
- define PLAYER_MAX_HEIGH_DIFF
- define NUM_TERRAINS
- define NUM_PROJECTIONS
- define NUM_MASKS
- define MAX_HEIGHT
- define MAP_W
- define MAP_H
- define MAP_FILE
- define JUMP_VELOCITY
- define JUMP_GRAVITY
- define FPS
- define CAM_SMOOTHING
- Source code
examples/ex_gui_isometric.c
Functions
| Name | |
|---|---|
| void | randomize_map(void ) |
| void | on_smooth_toggle(int id, void * data) |
| void | on_reset_click(int id, void * data) |
| void | on_proj_select(int id, void * data) |
| void | on_player_toggle(int id, void * data) |
| void | on_height_toggle(int id, void * data) |
| void | on_grid_toggle(int id, void * data) |
| void | on_ghost_toggle(int id, void * data) |
| int | main(int argc, char * argv[]) |
| float | interpolate_height_at_clamped(float fx, float fy, int max_climb) |
| float | interpolate_height_at(float fx, float fy) |
| void | draw_player_object(float sx, float sy, float zoom, float alpha, void * user_data) |
| void | draw_ghost_object(float sx, float sy, float zoom, float alpha, void * user_data) |
Attributes
Defines
Functions Documentation
function randomize_map
static void randomize_map(
void
)
function on_smooth_toggle
static void on_smooth_toggle(
int id,
void * data
)
function on_reset_click
static void on_reset_click(
int id,
void * data
)
function on_proj_select
static void on_proj_select(
int id,
void * data
)
function on_player_toggle
static void on_player_toggle(
int id,
void * data
)
function on_height_toggle
static void on_height_toggle(
int id,
void * data
)
function on_grid_toggle
static void on_grid_toggle(
int id,
void * data
)
function on_ghost_toggle
static void on_ghost_toggle(
int id,
void * data
)
function main
int main(
int argc,
char * argv[]
)
function interpolate_height_at_clamped
static float interpolate_height_at_clamped(
float fx,
float fy,
int max_climb
)
function interpolate_height_at
static float interpolate_height_at(
float fx,
float fy
)
function draw_player_object
static void draw_player_object(
float sx,
float sy,
float zoom,
float alpha,
void * user_data
)
function draw_ghost_object
static void draw_ghost_object(
float sx,
float sy,
float zoom,
float alpha,
void * user_data
)
Attributes Documentation
variable transition_tiles
static ALLEGRO_BITMAP *[8][(16+16)] transition_tiles = {{NULL}};
variable transition_masks
static ALLEGRO_BITMAP *[(16+16)] transition_masks = {NULL};
variable tile_bitmaps
static ALLEGRO_BITMAP *[8] tile_bitmaps = {NULL};
variable terrain_names
static const char *[8] terrain_names = {
"Water", "Lava", "Sand", "Road", "Temple Light", "Temple Dark", "Straw", "Rock"};
variable terrain_files
static const char *[8] terrain_files = {
"DATAS/tiles/eau_centre.bmp",
"DATAS/tiles/lave.bmp",
"DATAS/tiles/sable_centre.bmp",
"DATAS/tiles/chemin_centre.bmp",
"DATAS/tiles/temple3.bmp",
"DATAS/tiles/temple4.bmp",
"DATAS/tiles/paille.bmp",
"DATAS/tiles/rocaille.bmp"};
variable smooth_slope_max
static int smooth_slope_max = 1;
variable smooth_height
static bool smooth_height = (1 == 0);
variable show_grid
static bool show_grid = (1 == 0);
variable screen_w
static int screen_w = 1280;
variable screen_h
static int screen_h = 720;
variable running
static bool running = (1 == 1);
variable redraw_needed
static bool redraw_needed = (1 == 1);
variable player_z
static float player_z = 0.0f;
variable player_vz
static float player_vz = 0.0f;
variable player_screen_y
static float player_screen_y = 0.0f;
variable player_screen_x
static float player_screen_x = 0.0f;
variable player_path_progress
static float player_path_progress = 0.0f;
variable player_path_idx
static int player_path_idx = 0;
variable player_path
static ASTAR_PATH * player_path = NULL;
variable player_on_ground
static bool player_on_ground = (1 == 1);
variable player_my
static int player_my = 10;
variable player_mx
static int player_mx = 10;
variable player_mode
static bool player_mode = (1 == 0);
variable player_fy
static float player_fy = 10.5f;
variable player_fx
static float player_fx = 10.5f;
variable player_click_fy
static float player_click_fy = 0.0f;
variable player_click_fx
static float player_click_fx = 0.0f;
variable paint_terrain
static int paint_terrain = 4;
variable paint_height
static int paint_height = 0;
variable last_mouse_y
static int last_mouse_y = 0;
variable last_mouse_x
static int last_mouse_x = 0;
variable isomap
static ISO_MAP * isomap = NULL;
variable hover_my
static int hover_my = -1;
variable hover_mx
static int hover_mx = -1;
variable height_mode
static bool height_mode = (1 == 0);
variable gui_win_tiles
static int gui_win_tiles = -1;
variable gui_win_proj
static int gui_win_proj = -1;
variable gui_win_modes
static int gui_win_modes = -1;
variable gui_win_info
static int gui_win_info = -1;
variable gui_win_ghost_dr
static int gui_win_ghost_dr = -1;
variable gui_sld_slope
static int gui_sld_slope = -1;
variable gui_sld_height
static int gui_sld_height = -1;
variable gui_sld_dr_threshold
static int gui_sld_dr_threshold = -1;
variable gui_sld_dr_interval
static int gui_sld_dr_interval = -1;
variable gui_sld_dr_blend_time
static int gui_sld_dr_blend_time = -1;
variable gui_rad_dr_blend
static int gui_rad_dr_blend = -1;
variable gui_rad_dr_algo
static int gui_rad_dr_algo = -1;
variable gui_lst_tiles
static int gui_lst_tiles = -1;
variable gui_lbl_status
static int gui_lbl_status = -1;
variable gui_lbl_slope
static int gui_lbl_slope = -1;
variable gui_lbl_proj
static int gui_lbl_proj = -1;
variable gui_lbl_hover
static int gui_lbl_hover = -1;
variable gui_lbl_height
static int gui_lbl_height = -1;
variable gui_lbl_dr_threshold
static int gui_lbl_dr_threshold = -1;
variable gui_lbl_dr_interval
static int gui_lbl_dr_interval = -1;
variable gui_lbl_dr_blend_time
static int gui_lbl_dr_blend_time = -1;
variable gui_lbl_dr_blend
static int gui_lbl_dr_blend = -1;
variable gui_lbl_dr_algo
static int gui_lbl_dr_algo = -1;
variable gui_ctx
static N_GUI_CTX * gui_ctx = NULL;
variable gui_btn_smooth
static int gui_btn_smooth = -1;
variable gui_btn_reset
static int gui_btn_reset = -1;
variable gui_btn_proj
static int[4] gui_btn_proj = {-1, -1, -1, -1};
variable gui_btn_player
static int gui_btn_player = -1;
variable gui_btn_height
static int gui_btn_height = -1;
variable gui_btn_grid
static int gui_btn_grid = -1;
variable gui_btn_ghost
static int gui_btn_ghost = -1;
variable ghost_true_y
static float ghost_true_y = 0.0f;
variable ghost_true_x
static float ghost_true_x = 0.0f;
variable ghost_send_interval
static double ghost_send_interval = 0.25;
variable ghost_screen_y
static float ghost_screen_y = 0.0f;
variable ghost_screen_x
static float ghost_screen_x = 0.0f;
variable ghost_path_speed
static float ghost_path_speed = 0.4f;
variable ghost_path_radius
static float ghost_path_radius = 6.0f;
variable ghost_path_cy
static float ghost_path_cy = 10.0f;
variable ghost_path_cx
static float ghost_path_cx = 10.0f;
variable ghost_path_angle
static float ghost_path_angle = 0.0f;
variable ghost_last_send
static double ghost_last_send = 0.0;
variable ghost_enabled
static bool ghost_enabled = (1 == 0);
variable ghost_dr
static DR_ENTITY * ghost_dr = NULL;
variable current_proj
static int current_proj = 0;
variable camera
static N_ISO_CAMERA * camera = NULL;
Macros Documentation
define TILE_W
#define TILE_W 66
define TILE_LIFT
#define TILE_LIFT 16
define TILE_H
#define TILE_H 34
define TERRAIN_TEMPLE4
#define TERRAIN_TEMPLE4 5 /* temple floor dark */
define TERRAIN_TEMPLE3
#define TERRAIN_TEMPLE3 4 /* temple floor light */
define TERRAIN_SABLE
#define TERRAIN_SABLE 2 /* sand */
define TERRAIN_ROCAILLE
#define TERRAIN_ROCAILLE 7 /* rock - highest precedence */
define TERRAIN_PAILLE
#define TERRAIN_PAILLE 6 /* straw */
define TERRAIN_LAVE
#define TERRAIN_LAVE 1 /* lava */
define TERRAIN_EAU
#define TERRAIN_EAU 0 /* water - lowest precedence, base terrain */
define TERRAIN_CHEMIN
#define TERRAIN_CHEMIN 3 /* road */
define SCREEN_W
#define SCREEN_W 1280
define SCREEN_H
#define SCREEN_H 720
define PLAYER_MOVE_SPEED
#define PLAYER_MOVE_SPEED 4.0f
define PLAYER_MAX_HEIGH_DIFF
#define PLAYER_MAX_HEIGH_DIFF 1 /* max height diff player can walk over */
define NUM_TERRAINS
#define NUM_TERRAINS 8
define NUM_PROJECTIONS
#define NUM_PROJECTIONS ISO_NUM_PROJECTIONS
define NUM_MASKS
#define NUM_MASKS ISO_NUM_MASKS
define MAX_HEIGHT
#define MAX_HEIGHT 5
define MAP_W
#define MAP_W 20
define MAP_H
#define MAP_H 20
define MAP_FILE
#define MAP_FILE "iso_gui_map.isom"
define JUMP_VELOCITY
#define JUMP_VELOCITY 9.0f /* initial upward velocity (height units/sec) */
define JUMP_GRAVITY
#define JUMP_GRAVITY 20.0f /* gravity for jump (height units/sec^2) */
define FPS
#define FPS 60.0
define CAM_SMOOTHING
#define CAM_SMOOTHING 8.0f /* camera lerp speed (higher = snappier) */
Source code
/*
* Nilorea Library
* Copyright (C) 2005-2026 Castagnier Mickael
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdint.h>
/* Allegro5 */
#include <allegro5/allegro.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
/* nilorea-library modules */
#include "nilorea/n_common.h"
#include "nilorea/n_log.h"
#include "nilorea/n_list.h"
#include "nilorea/n_str.h"
#include "nilorea/n_astar.h"
#include "nilorea/n_iso_engine.h"
#include "nilorea/n_dead_reckoning.h"
#include "nilorea/n_gui.h"
/* Constants */
#define SCREEN_W 1280
#define SCREEN_H 720
#define FPS 60.0
/* Tile dimensions (isometric diamond) */
#define TILE_W 66
#define TILE_H 34
/* Map size */
#define MAP_W 20
#define MAP_H 20
/* Number of terrain types */
#define NUM_TERRAINS 8
/* Height / elevation settings */
#define MAX_HEIGHT 5
#define TILE_LIFT 16
/* Player movement settings */
#define PLAYER_MOVE_SPEED 4.0f
#define JUMP_VELOCITY 9.0f /* initial upward velocity (height units/sec) */
#define JUMP_GRAVITY 20.0f /* gravity for jump (height units/sec^2) */
#define CAM_SMOOTHING 8.0f /* camera lerp speed (higher = snappier) */
#define PLAYER_MAX_HEIGH_DIFF 1 /* max height diff player can walk over */
/* Terrain type IDs, ordered by visual precedence (higher = drawn on top) */
#define TERRAIN_EAU 0 /* water - lowest precedence, base terrain */
#define TERRAIN_LAVE 1 /* lava */
#define TERRAIN_SABLE 2 /* sand */
#define TERRAIN_CHEMIN 3 /* road */
#define TERRAIN_TEMPLE3 4 /* temple floor light */
#define TERRAIN_TEMPLE4 5 /* temple floor dark */
#define TERRAIN_PAILLE 6 /* straw */
#define TERRAIN_ROCAILLE 7 /* rock - highest precedence */
/* Terrain names for HUD */
static const char* terrain_names[NUM_TERRAINS] = {
"Water", "Lava", "Sand", "Road", "Temple Light", "Temple Dark", "Straw", "Rock"};
/* Terrain file names */
static const char* terrain_files[NUM_TERRAINS] = {
"DATAS/tiles/eau_centre.bmp",
"DATAS/tiles/lave.bmp",
"DATAS/tiles/sable_centre.bmp",
"DATAS/tiles/chemin_centre.bmp",
"DATAS/tiles/temple3.bmp",
"DATAS/tiles/temple4.bmp",
"DATAS/tiles/paille.bmp",
"DATAS/tiles/rocaille.bmp"};
/* Projection presets, use library defines (ISO_PROJ_CLASSIC, etc.) */
#define NUM_PROJECTIONS ISO_NUM_PROJECTIONS
/* Transition mask count alias */
#define NUM_MASKS ISO_NUM_MASKS
/* State */
static int current_proj = ISO_PROJ_CLASSIC;
static ISO_MAP* isomap = NULL;
static N_ISO_CAMERA* camera = NULL;
static ALLEGRO_BITMAP* tile_bitmaps[NUM_TERRAINS] = {NULL};
static ALLEGRO_BITMAP* transition_masks[NUM_MASKS] = {NULL};
static ALLEGRO_BITMAP* transition_tiles[NUM_TERRAINS][NUM_MASKS] = {{NULL}};
/* Dynamic screen dimensions */
static int screen_w = SCREEN_W;
static int screen_h = SCREEN_H;
/* UI state */
static int paint_terrain = TERRAIN_TEMPLE3;
static int paint_height = 0;
static bool height_mode = false;
static bool show_grid = false;
static bool running = true;
static bool redraw_needed = true;
static bool smooth_height = false;
static int smooth_slope_max = 1;
/* Player state: free movement with continuous float position */
static bool player_mode = false; /* true = player control, false = editor */
static float player_fx = 10.5f; /* continuous map X (tile center = int + 0.5) */
static float player_fy = 10.5f; /* continuous map Y */
static int player_mx = 10; /* current tile X (derived) */
static int player_my = 10; /* current tile Y (derived) */
static float player_screen_x = 0.0f; /* derived screen position */
static float player_screen_y = 0.0f;
static float player_z = 0.0f; /* absolute height position (height units) */
static float player_vz = 0.0f; /* vertical velocity (height units/sec) */
static bool player_on_ground = true; /* true when touching the ground */
/* Dead Reckoning ghost: simulated remote player on circular path */
static bool ghost_enabled = false;
static DR_ENTITY* ghost_dr = NULL;
static float ghost_screen_x = 0.0f;
static float ghost_screen_y = 0.0f;
static float ghost_true_x = 0.0f;
static float ghost_true_y = 0.0f;
static float ghost_path_cx = 10.0f;
static float ghost_path_cy = 10.0f;
static float ghost_path_radius = 6.0f;
static float ghost_path_speed = 0.4f;
static float ghost_path_angle = 0.0f;
static double ghost_last_send = 0.0;
static double ghost_send_interval = 0.25;
/* Mouse hover tile */
static int hover_mx = -1;
static int hover_my = -1;
static int last_mouse_x = 0;
static int last_mouse_y = 0;
/* GUI context and widget IDs */
static N_GUI_CTX* gui_ctx = NULL;
static int gui_win_modes = -1;
static int gui_win_tiles = -1;
static int gui_win_proj = -1;
static int gui_win_info = -1;
static int gui_btn_player = -1;
static int gui_btn_height = -1;
static int gui_btn_grid = -1;
static int gui_btn_smooth = -1;
static int gui_btn_ghost = -1;
static int gui_btn_reset = -1;
static int gui_lbl_height = -1;
static int gui_sld_height = -1;
static int gui_lst_tiles = -1;
static int gui_lbl_slope = -1;
static int gui_sld_slope = -1;
static int gui_btn_proj[NUM_PROJECTIONS] = {-1, -1, -1, -1};
static int gui_lbl_status = -1;
static int gui_lbl_proj = -1;
static int gui_lbl_hover = -1;
/* Ghost dead reckoning GUI */
static int gui_win_ghost_dr = -1;
static int gui_lbl_dr_algo = -1;
static int gui_rad_dr_algo = -1;
static int gui_lbl_dr_blend = -1;
static int gui_rad_dr_blend = -1;
static int gui_lbl_dr_interval = -1;
static int gui_sld_dr_interval = -1;
static int gui_lbl_dr_blend_time = -1;
static int gui_sld_dr_blend_time = -1;
static int gui_lbl_dr_threshold = -1;
static int gui_sld_dr_threshold = -1;
/* A* pathfinding for click-to-move */
static ASTAR_PATH* player_path = NULL;
static int player_path_idx = 0;
static float player_path_progress = 0.0f;
/* Exact fractional click destination within the final tile */
static float player_click_fx = 0.0f;
static float player_click_fy = 0.0f;
#define MAP_FILE "iso_gui_map.isom"
/* Diamond helpers, coordinate conversion, projection interpolation,
* transition mask/tile generation, and diamond masking are all provided
* by the nilorea-library n_iso_engine API. */
/* Bilinear height interpolation with cliff-clamping */
static float interpolate_height_at(float fx, float fy) {
if (fx < 0.0f) fx = 0.0f;
if (fy < 0.0f) fy = 0.0f;
if (fx > (float)MAP_W - 1e-4f) fx = (float)MAP_W - 1e-4f;
if (fy > (float)MAP_H - 1e-4f) fy = (float)MAP_H - 1e-4f;
return iso_map_interpolate_height(isomap, fx, fy);
}
/* Collision-aware height interpolation: clamp neighbor tile heights so the
* bilinear blend does not pull the player upward into wall tiles.
* The standard interpolation samples (ix,iy), (ix+1,iy), (ix,iy+1),
* (ix+1,iy+1). When one of those neighbors is a tall wall, the smooth
* blend makes the player "climb" the wall before the tile-boundary
* collision check fires. Clamping each neighbor to at most
* base_height + max_climb prevents that. */
static float interpolate_height_at_clamped(float fx, float fy, int max_climb) {
if (fx < 0.0f) fx = 0.0f;
if (fy < 0.0f) fy = 0.0f;
if (fx > (float)MAP_W - 1e-4f) fx = (float)MAP_W - 1e-4f;
if (fy > (float)MAP_H - 1e-4f) fy = (float)MAP_H - 1e-4f;
int ix = (int)floorf(fx);
int iy = (int)floorf(fy);
float h00 = (float)iso_map_get_height(isomap, ix, iy);
/* In CUT mode, return flat tile height, no interpolation */
if (!smooth_height) {
return h00;
}
float frac_x = fx - (float)ix;
float frac_y = fy - (float)iy;
/* Clamp neighbor indices to valid range for edge tiles */
int ix1 = (ix + 1 < MAP_W) ? ix + 1 : ix;
int iy1 = (iy + 1 < MAP_H) ? iy + 1 : iy;
float h10 = (float)iso_map_get_height(isomap, ix1, iy);
float h01 = (float)iso_map_get_height(isomap, ix, iy1);
float h11 = (float)iso_map_get_height(isomap, ix1, iy1);
float max_h = h00 + (float)max_climb;
if (h10 > max_h) h10 = max_h;
if (h01 > max_h) h01 = max_h;
if (h11 > max_h) h11 = max_h;
float top = h00 + (h10 - h00) * frac_x;
float bot = h01 + (h11 - h01) * frac_x;
return top + (bot - top) * frac_y;
}
/* Object draw callbacks for N_ISO_OBJECT depth-sorted rendering */
/* Player draw callback: green circle with shadow */
static void draw_player_object(float sx, float sy, float zoom, float alpha, void* user_data) {
(void)user_data;
al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
float cy = sy - 8.0f * zoom; /* offset up from feet */
/* Shadow at ground level (only for normal draw, not overlay) */
if (alpha >= 1.0f) {
float ground_h = interpolate_height_at_clamped(player_fx, player_fy, PLAYER_MAX_HEIGH_DIFF);
float gs_sx, gs_sy;
iso_map_to_screen_f(isomap, player_fx, player_fy, ground_h, &gs_sx, &gs_sy);
float shadow_cx, shadow_cy;
n_iso_camera_world_to_screen(camera, gs_sx, gs_sy, &shadow_cx, &shadow_cy);
al_draw_filled_ellipse(sx, shadow_cy, 4.0f * zoom, 2.0f * zoom,
al_map_rgba(0, 0, 0, 60));
}
al_draw_filled_circle(sx, cy, 5.0f * zoom,
al_map_rgba(50, 200, 50, (unsigned char)(220.0f * alpha)));
al_draw_circle(sx, cy, 5.0f * zoom,
al_map_rgba(255, 255, 255, (unsigned char)(200.0f * alpha)), 1.5f);
}
/* Ghost draw callback: blue circle (DR position) + red outline (true position) */
static void draw_ghost_object(float sx, float sy, float zoom, float alpha, void* user_data) {
(void)user_data;
al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
float cy = sy - 8.0f * zoom;
/* DR-computed position (blue) */
al_draw_filled_circle(sx, cy, 5.0f * zoom,
al_map_rgba(80, 120, 255, (unsigned char)(220.0f * alpha)));
al_draw_circle(sx, cy, 5.0f * zoom,
al_map_rgba(200, 200, 255, (unsigned char)(200.0f * alpha)), 1.5f);
if (alpha >= 1.0f) {
al_draw_filled_ellipse(sx, cy + 8.0f * zoom, 4.0f * zoom, 2.0f * zoom,
al_map_rgba(0, 0, 0, 60));
/* True position: red outline (only in normal draw) */
float tcx, tcy;
n_iso_camera_world_to_screen(camera, ghost_true_x, ghost_true_y, &tcx, &tcy);
tcy -= 8.0f * zoom;
al_draw_circle(tcx, tcy, 5.0f * zoom, al_map_rgba(255, 80, 80, 180), 1.5f);
al_draw_filled_ellipse(tcx, tcy + 8.0f * zoom, 4.0f * zoom, 2.0f * zoom,
al_map_rgba(255, 0, 0, 30));
}
}
/* Randomize the map */
static void randomize_map(void) {
srand((unsigned)time(NULL));
for (int y = 0; y < MAP_H; y++)
for (int x = 0; x < MAP_W; x++) {
iso_map_set_terrain(isomap, x, y, TERRAIN_LAVE);
iso_map_set_height(isomap, x, y, 0);
}
for (int patch = 0; patch < 15; patch++) {
int t = rand() % NUM_TERRAINS;
int cx = rand() % MAP_W;
int cy = rand() % MAP_H;
int radius = 2 + rand() % 4;
for (int dy = -radius; dy <= radius; dy++)
for (int dx = -radius; dx <= radius; dx++) {
int x = cx + dx, y = cy + dy;
if (x < 0 || x >= MAP_W || y < 0 || y >= MAP_H) continue;
float dist = sqrtf((float)(dx * dx + dy * dy));
if (dist <= radius && (rand() % 100) < (int)(100.0f * (1.0f - dist / (float)(radius + 1))))
iso_map_set_terrain(isomap, x, y, t);
}
}
for (int hill = 0; hill < 8; hill++) {
int peak_h = 1 + rand() % MAX_HEIGHT;
int cx = rand() % MAP_W;
int cy = rand() % MAP_H;
int radius = 2 + rand() % 3;
for (int dy = -radius; dy <= radius; dy++)
for (int dx = -radius; dx <= radius; dx++) {
int x = cx + dx, y = cy + dy;
if (x < 0 || x >= MAP_W || y < 0 || y >= MAP_H) continue;
float dist = sqrtf((float)(dx * dx + dy * dy));
if (dist > radius) continue;
int h = (int)((float)peak_h * (1.0f - dist / (float)(radius + 1)) + 0.5f);
if (h > iso_map_get_height(isomap, x, y))
iso_map_set_height(isomap, x, y, h);
}
}
}
/* Button callbacks for n_gui_button_set_keycode bindings */
/* Toggle player mode (P key) */
static void on_player_toggle(int id, void* data) {
(void)id;
(void)data;
player_mode = n_gui_button_is_toggled(gui_ctx, gui_btn_player);
if (player_mode) {
if (height_mode) {
height_mode = false;
n_gui_button_set_toggled(gui_ctx, gui_btn_height, 0);
}
int drop_max_h = 0;
for (int y = 0; y < MAP_H; y++)
for (int x = 0; x < MAP_W; x++) {
int h = iso_map_get_height(isomap, x, y);
if (h > drop_max_h) drop_max_h = h;
}
player_z = (float)(drop_max_h + 1);
player_vz = 0.0f;
player_on_ground = false;
iso_map_to_screen_f(isomap, player_fx, player_fy, player_z,
&player_screen_x, &player_screen_y);
n_iso_camera_center_on(camera, player_screen_x, player_screen_y,
screen_w, screen_h);
}
}
/* Toggle height editing mode (H key) */
static void on_height_toggle(int id, void* data) {
(void)id;
(void)data;
height_mode = n_gui_button_is_toggled(gui_ctx, gui_btn_height);
if (height_mode && player_mode) {
player_mode = false;
n_gui_button_set_toggled(gui_ctx, gui_btn_player, 0);
}
}
/* Toggle grid overlay (G key) */
static void on_grid_toggle(int id, void* data) {
(void)id;
(void)data;
show_grid = n_gui_button_is_toggled(gui_ctx, gui_btn_grid);
}
/* Toggle smooth height (V key) */
static void on_smooth_toggle(int id, void* data) {
(void)id;
(void)data;
smooth_height = n_gui_button_is_toggled(gui_ctx, gui_btn_smooth);
}
/* Toggle ghost dead reckoning display (N key) */
static void on_ghost_toggle(int id, void* data) {
(void)id;
(void)data;
ghost_enabled = n_gui_button_is_toggled(gui_ctx, gui_btn_ghost);
if (ghost_enabled) {
n_gui_open_window(gui_ctx, gui_win_ghost_dr);
if (ghost_dr) {
ghost_last_send = al_get_time();
ghost_path_angle = 0.0f;
int ghost_max_h = 0;
for (int y = 0; y < MAP_H; y++)
for (int x = 0; x < MAP_W; x++) {
int h = iso_map_get_height(isomap, x, y);
if (h > ghost_max_h) ghost_max_h = h;
}
DR_VEC3 init_pos = dr_vec3(ghost_path_cx + ghost_path_radius,
ghost_path_cy, (double)(ghost_max_h + 1));
DR_VEC3 init_vel = dr_vec3(0.0, ghost_path_radius * ghost_path_speed, 0.0);
dr_entity_set_position(ghost_dr, &init_pos, &init_vel, NULL,
al_get_time());
}
} else {
n_gui_close_window(gui_ctx, gui_win_ghost_dr);
}
}
/* reset terrain (R key) */
static void on_reset_click(int id, void* data) {
(void)id;
(void)data;
randomize_map();
iso_map_save(isomap, MAP_FILE);
}
/* Select projection (F1-F4 keys) */
static void on_proj_select(int id, void* data) {
(void)data;
for (int p = 0; p < NUM_PROJECTIONS; p++) {
if (gui_btn_proj[p] == id) {
current_proj = p;
iso_map_set_projection_target(isomap, current_proj);
}
n_gui_button_set_toggled(gui_ctx, gui_btn_proj[p], (gui_btn_proj[p] == id) ? 1 : 0);
}
}
/* Main */
int main(int argc, char* argv[]) {
(void)argc;
(void)argv;
set_log_level(LOG_INFO);
if (!al_init()) {
n_abort("Could not init Allegro.\n");
}
/* The data is in DATAS/ beside the executable: found from wherever the
* example is started, not only from examples/. Started elsewhere it used
* to fail on its data with a window already open, and exiting that way
* crashed on some OpenGL drivers. */
{
ALLEGRO_PATH* here = al_get_standard_path(ALLEGRO_RESOURCES_PATH);
if (here) {
al_change_directory(al_path_cstr(here, ALLEGRO_NATIVE_PATH_SEP));
al_destroy_path(here);
}
}
/* Every tile is looked for before any window exists, so a missing one
* ends the example with nothing to release. */
for (int i = 0; i < NUM_TERRAINS; i++) {
if (!al_filename_exists(terrain_files[i])) {
n_log(LOG_ERR, "Missing tile %s beside the executable", terrain_files[i]);
return EXIT_FAILURE;
}
}
if (!al_init_image_addon()) {
n_abort("image addon\n");
}
if (!al_init_primitives_addon()) {
n_abort("primitives addon\n");
}
if (!al_init_font_addon()) {
n_abort("font addon\n");
}
al_init_ttf_addon();
al_install_keyboard();
al_install_mouse();
al_set_new_display_flags(ALLEGRO_OPENGL | ALLEGRO_WINDOWED | ALLEGRO_RESIZABLE);
ALLEGRO_DISPLAY* display = al_create_display(SCREEN_W, SCREEN_H);
if (!display) {
n_abort("Unable to create display\n");
}
al_set_window_title(display, "Nilorea Isometric Engine + GUI Demo");
ALLEGRO_FONT* font = al_create_builtin_font();
if (!font) {
n_abort("Unable to create builtin font\n");
}
/* Create ISO_MAP with projection */
isomap = iso_map_new(MAP_W, MAP_H, NUM_TERRAINS, MAX_HEIGHT);
if (!isomap) {
n_abort("Failed to create ISO_MAP!\n");
return -1;
}
iso_map_set_projection(isomap, ISO_PROJ_CLASSIC, (float)TILE_W);
isomap->proj.tile_lift = (float)TILE_LIFT;
/* Create camera */
camera = n_iso_camera_new(0.5f, 6.0f);
if (!camera) {
n_abort("Failed to create camera!\n");
}
camera->zoom = 2.0f;
/* Initialize GUI */
gui_ctx = n_gui_new_ctx(font);
n_gui_set_display_size(gui_ctx, (float)SCREEN_W, (float)SCREEN_H);
// n_gui_set_virtual_size(gui_ctx, (float)SCREEN_W, (float)SCREEN_H);
/* Modes window */
gui_win_modes = n_gui_add_window(gui_ctx, "Modes", 5, 5, 200, 310);
gui_btn_player = n_gui_add_toggle_button(gui_ctx, gui_win_modes, "Player [P]",
10, 10, 180, 24, N_GUI_SHAPE_ROUNDED, 0, on_player_toggle, NULL);
n_gui_button_set_keycode(gui_ctx, gui_btn_player, ALLEGRO_KEY_P, 0);
gui_btn_height = n_gui_add_toggle_button(gui_ctx, gui_win_modes, "Height [H]",
10, 40, 180, 24, N_GUI_SHAPE_ROUNDED, 0, on_height_toggle, NULL);
n_gui_button_set_keycode(gui_ctx, gui_btn_height, ALLEGRO_KEY_H, 0);
gui_btn_grid = n_gui_add_toggle_button(gui_ctx, gui_win_modes, "Grid [G]",
10, 70, 180, 24, N_GUI_SHAPE_ROUNDED, 0, on_grid_toggle, NULL);
n_gui_button_set_keycode(gui_ctx, gui_btn_grid, ALLEGRO_KEY_G, 0);
gui_btn_smooth = n_gui_add_toggle_button(gui_ctx, gui_win_modes, "Smooth [V]",
10, 100, 180, 24, N_GUI_SHAPE_ROUNDED, 0, on_smooth_toggle, NULL);
n_gui_button_set_keycode(gui_ctx, gui_btn_smooth, ALLEGRO_KEY_V, 0);
gui_btn_ghost = n_gui_add_toggle_button(gui_ctx, gui_win_modes, "Ghost [N]",
10, 130, 180, 24, N_GUI_SHAPE_ROUNDED, 0, on_ghost_toggle, NULL);
n_gui_button_set_keycode(gui_ctx, gui_btn_ghost, ALLEGRO_KEY_N, 0);
gui_lbl_height = n_gui_add_label(gui_ctx, gui_win_modes, "Height: 0",
10, 165, 180, 16, N_GUI_ALIGN_LEFT);
gui_sld_height = n_gui_add_slider(gui_ctx, gui_win_modes,
10, 185, 150, 20, 0.0, (double)MAX_HEIGHT, 0.0,
N_GUI_SLIDER_VALUE, NULL, NULL);
gui_btn_reset = n_gui_add_button(gui_ctx, gui_win_modes, "Reset terrain [R]",
10, 250, 180, 24, N_GUI_SHAPE_ROUNDED, on_reset_click, NULL);
n_gui_button_set_keycode(gui_ctx, gui_btn_reset, ALLEGRO_KEY_R, 0);
n_gui_set_widget_visible(gui_ctx, gui_lbl_height, 0);
n_gui_set_widget_visible(gui_ctx, gui_sld_height, 0);
/* Tiles window */
gui_win_tiles = n_gui_add_window(gui_ctx, "Tiles", 5, 325, 200, 200);
gui_lst_tiles = n_gui_add_listbox(gui_ctx, gui_win_tiles, 10, 10, 180, 100,
N_GUI_SELECT_SINGLE, NULL, NULL);
for (int t = 0; t < NUM_TERRAINS; t++)
n_gui_listbox_add_item(gui_ctx, gui_lst_tiles, terrain_names[t]);
n_gui_listbox_set_selected(gui_ctx, gui_lst_tiles, paint_terrain, 1);
gui_lbl_slope = n_gui_add_label(gui_ctx, gui_win_tiles, "Slope max: 1",
10, 115, 180, 16, N_GUI_ALIGN_LEFT);
gui_sld_slope = n_gui_add_slider(gui_ctx, gui_win_tiles,
10, 135, 150, 20, 1.0, (double)MAX_HEIGHT, (double)smooth_slope_max,
N_GUI_SLIDER_VALUE, NULL, NULL);
/* Projection window */
gui_win_proj = n_gui_add_window(gui_ctx, "Projection", 5, 535, 200, 160);
gui_btn_proj[0] = n_gui_add_toggle_button(gui_ctx, gui_win_proj, "Classic [F1]",
10, 10, 180, 24, N_GUI_SHAPE_ROUNDED, 1, on_proj_select, NULL);
n_gui_button_set_keycode(gui_ctx, gui_btn_proj[0], ALLEGRO_KEY_F1, 0);
gui_btn_proj[1] = n_gui_add_toggle_button(gui_ctx, gui_win_proj, "Isometric [F2]",
10, 40, 180, 24, N_GUI_SHAPE_ROUNDED, 0, on_proj_select, NULL);
n_gui_button_set_keycode(gui_ctx, gui_btn_proj[1], ALLEGRO_KEY_F2, 0);
gui_btn_proj[2] = n_gui_add_toggle_button(gui_ctx, gui_win_proj, "Military [F3]",
10, 70, 180, 24, N_GUI_SHAPE_ROUNDED, 0, on_proj_select, NULL);
n_gui_button_set_keycode(gui_ctx, gui_btn_proj[2], ALLEGRO_KEY_F3, 0);
gui_btn_proj[3] = n_gui_add_toggle_button(gui_ctx, gui_win_proj, "Staggered [F4]",
10, 100, 180, 24, N_GUI_SHAPE_ROUNDED, 0, on_proj_select, NULL);
n_gui_button_set_keycode(gui_ctx, gui_btn_proj[3], ALLEGRO_KEY_F4, 0);
/* Info window */
gui_win_info = n_gui_add_window(gui_ctx, "Info", 210, 5, 420, 90);
gui_lbl_status = n_gui_add_label(gui_ctx, gui_win_info, "Ready", 10, 5, 400, 16, N_GUI_ALIGN_LEFT);
gui_lbl_proj = n_gui_add_label(gui_ctx, gui_win_info, "Projection: Classic 2:1", 10, 22, 400, 16, N_GUI_ALIGN_LEFT);
gui_lbl_hover = n_gui_add_label(gui_ctx, gui_win_info, "", 10, 39, 400, 16, N_GUI_ALIGN_LEFT);
/* Ghost dead reckoning window */
gui_win_ghost_dr = n_gui_add_window(gui_ctx, "Ghost DR", 1070, 5, 200, 340);
gui_lbl_dr_algo = n_gui_add_label(gui_ctx, gui_win_ghost_dr, "Algo [M]",
10, 5, 180, 16, N_GUI_ALIGN_LEFT);
gui_rad_dr_algo = n_gui_add_radiolist(gui_ctx, gui_win_ghost_dr,
10, 23, 180, 66, NULL, NULL);
n_gui_radiolist_add_item(gui_ctx, gui_rad_dr_algo, "Static");
n_gui_radiolist_add_item(gui_ctx, gui_rad_dr_algo, "Velocity");
n_gui_radiolist_add_item(gui_ctx, gui_rad_dr_algo, "Vel+Acc");
n_gui_radiolist_set_selected(gui_ctx, gui_rad_dr_algo, DR_ALGO_VEL_ACC);
gui_lbl_dr_blend = n_gui_add_label(gui_ctx, gui_win_ghost_dr, "Blend [B]",
10, 93, 180, 16, N_GUI_ALIGN_LEFT);
gui_rad_dr_blend = n_gui_add_radiolist(gui_ctx, gui_win_ghost_dr,
10, 111, 180, 66, NULL, NULL);
n_gui_radiolist_add_item(gui_ctx, gui_rad_dr_blend, "Snap");
n_gui_radiolist_add_item(gui_ctx, gui_rad_dr_blend, "PVB");
n_gui_radiolist_add_item(gui_ctx, gui_rad_dr_blend, "Cubic");
n_gui_radiolist_set_selected(gui_ctx, gui_rad_dr_blend, DR_BLEND_PVB);
gui_lbl_dr_interval = n_gui_add_label(gui_ctx, gui_win_ghost_dr, "Interval [,/.]: 0.25s",
10, 181, 180, 16, N_GUI_ALIGN_LEFT);
gui_sld_dr_interval = n_gui_add_slider(gui_ctx, gui_win_ghost_dr,
10, 199, 180, 20, 0.05, 2.0, ghost_send_interval,
N_GUI_SLIDER_VALUE, NULL, NULL);
gui_lbl_dr_blend_time = n_gui_add_label(gui_ctx, gui_win_ghost_dr, "Blend time: 0.20s",
10, 225, 180, 16, N_GUI_ALIGN_LEFT);
gui_sld_dr_blend_time = n_gui_add_slider(gui_ctx, gui_win_ghost_dr,
10, 243, 180, 20, 0.01, 2.0, 0.2,
N_GUI_SLIDER_VALUE, NULL, NULL);
gui_lbl_dr_threshold = n_gui_add_label(gui_ctx, gui_win_ghost_dr, "Threshold: 0.50",
10, 269, 180, 16, N_GUI_ALIGN_LEFT);
gui_sld_dr_threshold = n_gui_add_slider(gui_ctx, gui_win_ghost_dr,
10, 287, 180, 20, 0.01, 5.0, 0.5,
N_GUI_SLIDER_VALUE, NULL, NULL);
/* Start hidden; shown when ghost is enabled */
n_gui_close_window(gui_ctx, gui_win_ghost_dr);
/* Load tile images */
int saved_bmp_flags = al_get_new_bitmap_flags();
al_set_new_bitmap_flags(saved_bmp_flags & ~(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR));
for (int i = 0; i < NUM_TERRAINS; i++) {
tile_bitmaps[i] = al_load_bitmap(terrain_files[i]);
if (!tile_bitmaps[i]) {
n_log(LOG_ERR, "Failed to load tile: %s", terrain_files[i]);
return EXIT_FAILURE;
}
iso_mask_tile_to_diamond(tile_bitmaps[i], TILE_W, TILE_H);
}
/* Generate transition data (nilorea-library) */
iso_generate_transition_masks(transition_masks, TILE_W, TILE_H);
{
ALLEGRO_BITMAP** trans_ptrs[NUM_TERRAINS];
for (int t = 0; t < NUM_TERRAINS; t++)
trans_ptrs[t] = transition_tiles[t];
iso_generate_transition_tiles(trans_ptrs, transition_masks, tile_bitmaps,
NUM_TERRAINS, TILE_W, TILE_H);
}
al_set_new_bitmap_flags(saved_bmp_flags);
/* Initialize map: try to load from file, else randomize */
{
ISO_MAP* loaded = iso_map_load(MAP_FILE);
if (loaded) {
for (int y = 0; y < MAP_H && y < loaded->height; y++)
for (int x = 0; x < MAP_W && x < loaded->width; x++) {
iso_map_set_terrain(isomap, x, y, iso_map_get_terrain(loaded, x, y));
iso_map_set_height(isomap, x, y, iso_map_get_height(loaded, x, y));
}
iso_map_free(&loaded);
} else {
randomize_map();
iso_map_save(isomap, MAP_FILE);
}
}
/* Center camera */
{
float sx_center, sy_center;
iso_map_to_screen(isomap, MAP_W / 2, MAP_H / 2, 0, &sx_center, &sy_center);
n_iso_camera_center_on(camera, sx_center, sy_center, screen_w, screen_h);
}
/* Initialize dead reckoning ghost entity */
ghost_dr = dr_entity_create(DR_ALGO_VEL_ACC, DR_BLEND_PVB, 0.5, 0.2);
if (ghost_dr) {
DR_VEC3 init_pos = dr_vec3(ghost_path_cx + ghost_path_radius, ghost_path_cy, 0.0);
dr_entity_set_position(ghost_dr, &init_pos, NULL, NULL, 0.0);
}
/* Event queue and timer */
ALLEGRO_TIMER* timer = al_create_timer(1.0 / FPS);
ALLEGRO_EVENT_QUEUE* queue = al_create_event_queue();
al_register_event_source(queue, al_get_display_event_source(display));
al_register_event_source(queue, al_get_timer_event_source(timer));
al_register_event_source(queue, al_get_keyboard_event_source());
al_register_event_source(queue, al_get_mouse_event_source());
al_start_timer(timer);
bool key_up = false, key_down = false, key_left = false, key_right = false;
bool key_space = false;
float scroll_speed = 4.0f;
float dt = 1.0f / (float)FPS;
/* Initialize player position */
{
float interp_h = interpolate_height_at_clamped(player_fx, player_fy, PLAYER_MAX_HEIGH_DIFF);
player_z = interp_h;
iso_map_to_screen_f(isomap, player_fx, player_fy, player_z, &player_screen_x, &player_screen_y);
}
/* Main loop */
while (running) {
ALLEGRO_EVENT ev;
al_wait_for_event(queue, &ev);
/* pass events to the GUI.
* n_gui_process_event returns 1 when the event was consumed by GUI.
* n_gui_wants_mouse() is also checked below before game mouse actions. */
int gui_consumed = n_gui_process_event(gui_ctx, ev);
(void)gui_consumed;
switch (ev.type) {
case ALLEGRO_EVENT_TIMER: {
/* Smooth projection transition */
iso_map_lerp_projection(isomap, dt);
/* A* path following */
if (player_mode && player_path && player_path_idx < player_path->length) {
/* For the last node, target the exact click position;
* for intermediate nodes, target tile centers. */
float target_fx, target_fy;
int is_last_node = (player_path_idx == player_path->length - 1);
if (is_last_node) {
target_fx = player_click_fx;
target_fy = player_click_fy;
} else {
target_fx = (float)player_path->nodes[player_path_idx].x + 0.5f;
target_fy = (float)player_path->nodes[player_path_idx].y + 0.5f;
}
float path_dx = target_fx - player_fx;
float path_dy = target_fy - player_fy;
float path_dist = sqrtf(path_dx * path_dx + path_dy * path_dy);
float step = PLAYER_MOVE_SPEED * dt;
if (path_dist <= step) {
player_fx = target_fx;
player_fy = target_fy;
player_mx = player_path->nodes[player_path_idx].x;
player_my = player_path->nodes[player_path_idx].y;
player_path_idx++;
if (player_path_idx >= player_path->length) {
n_astar_path_free(player_path);
player_path = NULL;
}
} else {
player_fx += (path_dx / path_dist) * step;
player_fy += (path_dy / path_dist) * step;
player_mx = (int)floorf(player_fx);
player_my = (int)floorf(player_fy);
}
}
/* Player free movement update */
if (player_mode) {
float move_dx = 0.0f, move_dy = 0.0f;
if (key_up) move_dy -= 1.0f;
if (key_down) move_dy += 1.0f;
if (key_left) move_dx -= 1.0f;
if (key_right) move_dx += 1.0f;
if (move_dx != 0.0f && move_dy != 0.0f) {
move_dx *= 0.70710678f;
move_dy *= 0.70710678f;
}
/* Jump */
if (key_space && player_on_ground) {
player_vz = JUMP_VELOCITY;
player_on_ground = false;
}
float ground_h = interpolate_height_at_clamped(player_fx, player_fy, PLAYER_MAX_HEIGH_DIFF);
/* Vertical physics */
if (!player_on_ground) {
player_vz -= JUMP_GRAVITY * dt;
player_z += player_vz * dt;
if (player_z <= ground_h) {
player_z = ground_h;
player_vz = 0.0f;
player_on_ground = true;
}
} else {
if (player_z - ground_h > 1.0f) {
player_on_ground = false;
player_vz = 0.0f;
} else {
player_z = ground_h;
}
}
/* Horizontal movement with collision */
if (move_dx != 0.0f || move_dy != 0.0f) {
float speed = PLAYER_MOVE_SPEED * dt;
float new_fx = player_fx + move_dx * speed;
float new_fy = player_fy + move_dy * speed;
if (new_fx < 0.1f) new_fx = 0.1f;
if (new_fx > (float)MAP_W - 0.1f) new_fx = (float)MAP_W - 0.1f;
if (new_fy < 0.1f) new_fy = 0.1f;
if (new_fy > (float)MAP_H - 0.1f) new_fy = (float)MAP_H - 0.1f;
int new_tile_x = (int)floorf(new_fx);
int new_tile_y = (int)floorf(new_fy);
bool can_move = true;
if (new_tile_x != player_mx || new_tile_y != player_my) {
if (new_tile_x >= 0 && new_tile_x < MAP_W &&
new_tile_y >= 0 && new_tile_y < MAP_H) {
int target_h = iso_map_get_height(isomap, new_tile_x, new_tile_y);
int current_h = iso_map_get_height(isomap, player_mx, player_my);
if (player_on_ground) {
if (target_h - current_h > PLAYER_MAX_HEIGH_DIFF)
can_move = false;
} else {
if ((float)target_h > player_z + 0.5f)
can_move = false;
}
} else {
can_move = false;
}
}
if (can_move) {
player_fx = new_fx;
player_fy = new_fy;
player_mx = new_tile_x;
player_my = new_tile_y;
} else {
/* Wall sliding: try each axis independently */
float slide_fx = player_fx + move_dx * speed;
if (slide_fx < 0.1f) slide_fx = 0.1f;
if (slide_fx > (float)MAP_W - 0.1f) slide_fx = (float)MAP_W - 0.1f;
int slide_tx = (int)floorf(slide_fx);
bool can_x = true;
if (slide_tx != player_mx) {
if (slide_tx >= 0 && slide_tx < MAP_W) {
int th = iso_map_get_height(isomap, slide_tx, player_my);
int ch = iso_map_get_height(isomap, player_mx, player_my);
if (player_on_ground) {
if (th - ch > PLAYER_MAX_HEIGH_DIFF) can_x = false;
} else {
if ((float)th > player_z + 0.5f) can_x = false;
}
} else {
can_x = false;
}
}
if (can_x) {
player_fx = slide_fx;
player_mx = slide_tx;
}
float slide_fy = player_fy + move_dy * speed;
if (slide_fy < 0.1f) slide_fy = 0.1f;
if (slide_fy > (float)MAP_H - 0.1f) slide_fy = (float)MAP_H - 0.1f;
int slide_ty = (int)floorf(slide_fy);
bool can_y = true;
if (slide_ty != player_my) {
if (slide_ty >= 0 && slide_ty < MAP_H) {
int th = iso_map_get_height(isomap, player_mx, slide_ty);
int ch = iso_map_get_height(isomap, player_mx, player_my);
if (player_on_ground) {
if (th - ch > PLAYER_MAX_HEIGH_DIFF) can_y = false;
} else {
if ((float)th > player_z + 0.5f) can_y = false;
}
} else {
can_y = false;
}
}
if (can_y) {
player_fy = slide_fy;
player_my = slide_ty;
}
}
}
/* Recompute ground height after movement */
ground_h = interpolate_height_at_clamped(player_fx, player_fy, PLAYER_MAX_HEIGH_DIFF);
if (player_on_ground) {
if (player_z - ground_h > 1.0f) {
player_on_ground = false;
player_vz = 0.0f;
} else {
player_z = ground_h;
}
} else if (player_z <= ground_h) {
player_z = ground_h;
player_vz = 0.0f;
player_on_ground = true;
}
/* Update screen position */
iso_map_to_screen_f(isomap, player_fx, player_fy, player_z, &player_screen_x, &player_screen_y);
}
/* Camera: smoothly follow player in player mode */
if (player_mode) {
n_iso_camera_follow(camera, player_screen_x, player_screen_y,
screen_w, screen_h, CAM_SMOOTHING, dt);
}
/* Editor mode: scroll camera */
if (!player_mode) {
float sdx = 0.0f, sdy = 0.0f;
if (key_left) sdx += scroll_speed / camera->zoom;
if (key_right) sdx -= scroll_speed / camera->zoom;
if (key_up) sdy += scroll_speed / camera->zoom;
if (key_down) sdy -= scroll_speed / camera->zoom;
if (sdx != 0.0f || sdy != 0.0f)
n_iso_camera_scroll(camera, sdx, sdy);
}
/* Dead reckoning ghost update */
if (ghost_enabled && ghost_dr) {
double now = al_get_time();
ghost_path_angle += ghost_path_speed * dt;
if (ghost_path_angle > 2.0f * (float)M_PI)
ghost_path_angle -= 2.0f * (float)M_PI;
float true_fx = ghost_path_cx + ghost_path_radius * cosf(ghost_path_angle);
float true_fy = ghost_path_cy + ghost_path_radius * sinf(ghost_path_angle);
float true_vx = -ghost_path_radius * ghost_path_speed * sinf(ghost_path_angle);
float true_vy = ghost_path_radius * ghost_path_speed * cosf(ghost_path_angle);
float w2r = ghost_path_speed * ghost_path_speed * ghost_path_radius;
float true_ax = -w2r * cosf(ghost_path_angle);
float true_ay = -w2r * sinf(ghost_path_angle);
{
DR_VEC3 pos = dr_vec3(true_fx, true_fy, 0.0);
DR_VEC3 vel = dr_vec3(true_vx, true_vy, 0.0);
DR_VEC3 acc = dr_vec3(true_ax, true_ay, 0.0);
if (now - ghost_last_send >= ghost_send_interval ||
dr_entity_check_threshold(ghost_dr, &pos, &vel, &acc, now)) {
dr_entity_receive_state(ghost_dr, &pos, &vel, &acc, now);
ghost_last_send = now;
}
}
DR_VEC3 dr_pos;
dr_entity_compute(ghost_dr, now, &dr_pos);
float dr_h = interpolate_height_at((float)dr_pos.x, (float)dr_pos.y);
iso_map_to_screen_f(isomap, (float)dr_pos.x, (float)dr_pos.y, dr_h,
&ghost_screen_x, &ghost_screen_y);
float true_h = interpolate_height_at(true_fx, true_fy);
iso_map_to_screen_f(isomap, true_fx, true_fy, true_h,
&ghost_true_x, &ghost_true_y);
}
/* Update hover tile (skip when mouse is over a GUI window) */
if (!n_gui_wants_mouse(gui_ctx)) {
float wx, wy;
n_iso_camera_screen_to_world(camera, (float)last_mouse_x,
(float)last_mouse_y, &wx, &wy);
iso_screen_to_map_height(isomap, wx, wy, TILE_W, TILE_H,
&hover_mx, &hover_my);
} else {
hover_mx = -1;
hover_my = -1;
}
/* GUI <-> variable sync */
{
bool gui_player = n_gui_button_is_toggled(gui_ctx, gui_btn_player) != 0;
bool gui_height = n_gui_button_is_toggled(gui_ctx, gui_btn_height) != 0;
bool gui_grid = n_gui_button_is_toggled(gui_ctx, gui_btn_grid) != 0;
bool gui_smooth = n_gui_button_is_toggled(gui_ctx, gui_btn_smooth) != 0;
bool gui_ghost = n_gui_button_is_toggled(gui_ctx, gui_btn_ghost) != 0;
if (gui_player != player_mode) {
player_mode = gui_player;
if (player_mode) {
int drop_max_h = 0;
for (int y = 0; y < MAP_H; y++)
for (int x = 0; x < MAP_W; x++) {
int h = iso_map_get_height(isomap, x, y);
if (h > drop_max_h) drop_max_h = h;
}
player_z = (float)(drop_max_h + 1);
player_vz = 0.0f;
player_on_ground = false;
iso_map_to_screen_f(isomap, player_fx, player_fy, player_z,
&player_screen_x, &player_screen_y);
n_iso_camera_center_on(camera, player_screen_x, player_screen_y,
screen_w, screen_h);
}
}
if (gui_height != height_mode) {
height_mode = gui_height;
if (height_mode && player_mode)
player_mode = false;
}
if (gui_grid != show_grid) show_grid = gui_grid;
if (gui_smooth != smooth_height) smooth_height = gui_smooth;
if (gui_ghost != ghost_enabled) {
ghost_enabled = gui_ghost;
if (ghost_enabled) {
n_gui_open_window(gui_ctx, gui_win_ghost_dr);
if (ghost_dr) {
ghost_last_send = al_get_time();
ghost_path_angle = 0.0f;
int ghost_max_h = 0;
for (int y = 0; y < MAP_H; y++)
for (int x = 0; x < MAP_W; x++) {
int h = iso_map_get_height(isomap, x, y);
if (h > ghost_max_h) ghost_max_h = h;
}
DR_VEC3 init_pos = dr_vec3(ghost_path_cx + ghost_path_radius,
ghost_path_cy, (double)(ghost_max_h + 1));
DR_VEC3 init_vel = dr_vec3(0.0, ghost_path_radius * ghost_path_speed, 0.0);
dr_entity_set_position(ghost_dr, &init_pos, &init_vel, NULL,
al_get_time());
}
} else {
n_gui_close_window(gui_ctx, gui_win_ghost_dr);
}
}
/* Ghost DR window sync */
if (ghost_enabled && ghost_dr) {
/* Algorithm radiolist */
int gui_algo = n_gui_radiolist_get_selected(gui_ctx, gui_rad_dr_algo);
if (gui_algo >= 0 && gui_algo != (int)ghost_dr->algo)
dr_entity_set_algo(ghost_dr, (DR_ALGO)gui_algo);
n_gui_radiolist_set_selected(gui_ctx, gui_rad_dr_algo, (int)ghost_dr->algo);
/* Blend radiolist */
int gui_blend = n_gui_radiolist_get_selected(gui_ctx, gui_rad_dr_blend);
if (gui_blend >= 0 && gui_blend != (int)ghost_dr->blend_mode)
dr_entity_set_blend_mode(ghost_dr, (DR_BLEND)gui_blend);
n_gui_radiolist_set_selected(gui_ctx, gui_rad_dr_blend, (int)ghost_dr->blend_mode);
/* Send interval slider */
{
double gui_interval = n_gui_slider_get_value(gui_ctx, gui_sld_dr_interval);
if (fabs(gui_interval - ghost_send_interval) > 0.001)
ghost_send_interval = gui_interval;
n_gui_slider_set_value(gui_ctx, gui_sld_dr_interval, ghost_send_interval);
char ibuf[48];
snprintf(ibuf, sizeof(ibuf), "Interval [,/.]: %.2fs", ghost_send_interval);
n_gui_label_set_text(gui_ctx, gui_lbl_dr_interval, ibuf);
}
/* Blend time slider */
{
double gui_bt = n_gui_slider_get_value(gui_ctx, gui_sld_dr_blend_time);
if (fabs(gui_bt - ghost_dr->blend_time) > 0.001)
dr_entity_set_blend_time(ghost_dr, gui_bt);
n_gui_slider_set_value(gui_ctx, gui_sld_dr_blend_time, ghost_dr->blend_time);
char btbuf[48];
snprintf(btbuf, sizeof(btbuf), "Blend time: %.2fs", ghost_dr->blend_time);
n_gui_label_set_text(gui_ctx, gui_lbl_dr_blend_time, btbuf);
}
/* Threshold slider */
{
double gui_th = n_gui_slider_get_value(gui_ctx, gui_sld_dr_threshold);
if (fabs(gui_th - ghost_dr->pos_threshold) > 0.001)
dr_entity_set_threshold(ghost_dr, gui_th);
n_gui_slider_set_value(gui_ctx, gui_sld_dr_threshold, ghost_dr->pos_threshold);
char thbuf[48];
snprintf(thbuf, sizeof(thbuf), "Threshold: %.2f", ghost_dr->pos_threshold);
n_gui_label_set_text(gui_ctx, gui_lbl_dr_threshold, thbuf);
}
}
/* Height slider */
{
int gui_h = (int)(n_gui_slider_get_value(gui_ctx, gui_sld_height) + 0.5);
if (gui_h != paint_height) paint_height = gui_h;
n_gui_slider_set_value(gui_ctx, gui_sld_height, (double)paint_height);
char hbuf[32];
snprintf(hbuf, sizeof(hbuf), "Height: %d", paint_height);
n_gui_label_set_text(gui_ctx, gui_lbl_height, hbuf);
n_gui_set_widget_visible(gui_ctx, gui_lbl_height, height_mode ? 1 : 0);
n_gui_set_widget_visible(gui_ctx, gui_sld_height, height_mode ? 1 : 0);
}
/* Tile listbox */
{
int gui_sel = n_gui_listbox_get_selected(gui_ctx, gui_lst_tiles);
if (gui_sel >= 0 && gui_sel < NUM_TERRAINS && gui_sel != paint_terrain)
paint_terrain = gui_sel;
n_gui_listbox_set_selected(gui_ctx, gui_lst_tiles, paint_terrain, 1);
}
/* Slope slider */
{
int gui_slope = (int)(n_gui_slider_get_value(gui_ctx, gui_sld_slope) + 0.5);
if (gui_slope != smooth_slope_max) smooth_slope_max = gui_slope;
n_gui_slider_set_value(gui_ctx, gui_sld_slope, (double)smooth_slope_max);
char sbuf2[32];
snprintf(sbuf2, sizeof(sbuf2), "Slope max: %d", smooth_slope_max);
n_gui_label_set_text(gui_ctx, gui_lbl_slope, sbuf2);
}
/* Sync variables -> GUI */
n_gui_button_set_toggled(gui_ctx, gui_btn_player, player_mode ? 1 : 0);
n_gui_button_set_toggled(gui_ctx, gui_btn_height, height_mode ? 1 : 0);
n_gui_button_set_toggled(gui_ctx, gui_btn_grid, show_grid ? 1 : 0);
n_gui_button_set_toggled(gui_ctx, gui_btn_smooth, smooth_height ? 1 : 0);
n_gui_button_set_toggled(gui_ctx, gui_btn_ghost, ghost_enabled ? 1 : 0);
/* Projection radio group */
for (int p = 0; p < NUM_PROJECTIONS; p++) {
if (n_gui_button_is_toggled(gui_ctx, gui_btn_proj[p]) && p != current_proj) {
current_proj = p;
iso_map_set_projection_target(isomap, current_proj);
break;
}
}
for (int p = 0; p < NUM_PROJECTIONS; p++)
n_gui_button_set_toggled(gui_ctx, gui_btn_proj[p], (p == current_proj) ? 1 : 0);
}
redraw_needed = true;
break;
}
case ALLEGRO_EVENT_KEY_DOWN:
switch (ev.keyboard.keycode) {
/* Movement keys (not GUI buttons) */
case ALLEGRO_KEY_LEFT:
case ALLEGRO_KEY_A:
key_left = true;
break;
case ALLEGRO_KEY_RIGHT:
case ALLEGRO_KEY_D:
key_right = true;
break;
case ALLEGRO_KEY_UP:
case ALLEGRO_KEY_W:
key_up = true;
break;
case ALLEGRO_KEY_DOWN:
case ALLEGRO_KEY_S:
key_down = true;
break;
case ALLEGRO_KEY_SPACE:
key_space = true;
break;
case ALLEGRO_KEY_ESCAPE:
running = false;
break;
case ALLEGRO_KEY_PGDN:
if (smooth_slope_max > 1) smooth_slope_max--;
n_gui_slider_set_value(gui_ctx, gui_sld_slope, (double)smooth_slope_max);
break;
case ALLEGRO_KEY_PGUP:
if (smooth_slope_max < MAX_HEIGHT) smooth_slope_max++;
n_gui_slider_set_value(gui_ctx, gui_sld_slope, (double)smooth_slope_max);
break;
case ALLEGRO_KEY_EQUALS:
case ALLEGRO_KEY_PAD_PLUS:
if (paint_height < MAX_HEIGHT) paint_height++;
break;
case ALLEGRO_KEY_MINUS:
case ALLEGRO_KEY_PAD_MINUS:
if (paint_height > 0) paint_height--;
break;
case ALLEGRO_KEY_M:
if (ghost_dr) {
int a = (int)((ghost_dr->algo + 1) % 3);
dr_entity_set_algo(ghost_dr, (DR_ALGO)a);
n_gui_radiolist_set_selected(gui_ctx, gui_rad_dr_algo, a);
}
break;
case ALLEGRO_KEY_B:
if (ghost_dr) {
int b = (int)((ghost_dr->blend_mode + 1) % 3);
dr_entity_set_blend_mode(ghost_dr, (DR_BLEND)b);
n_gui_radiolist_set_selected(gui_ctx, gui_rad_dr_blend, b);
}
break;
case ALLEGRO_KEY_COMMA:
ghost_send_interval += 0.05;
if (ghost_send_interval > 2.0) ghost_send_interval = 2.0;
n_gui_slider_set_value(gui_ctx, gui_sld_dr_interval, ghost_send_interval);
break;
case ALLEGRO_KEY_FULLSTOP:
ghost_send_interval -= 0.05;
if (ghost_send_interval < 0.05) ghost_send_interval = 0.05;
n_gui_slider_set_value(gui_ctx, gui_sld_dr_interval, ghost_send_interval);
break;
/* Keys P, H, G, V, N, F1-F4 are handled via
n_gui_button_set_keycode bindings */
}
break;
case ALLEGRO_EVENT_KEY_UP:
switch (ev.keyboard.keycode) {
case ALLEGRO_KEY_LEFT:
case ALLEGRO_KEY_A:
key_left = false;
break;
case ALLEGRO_KEY_RIGHT:
case ALLEGRO_KEY_D:
key_right = false;
break;
case ALLEGRO_KEY_UP:
case ALLEGRO_KEY_W:
key_up = false;
break;
case ALLEGRO_KEY_DOWN:
case ALLEGRO_KEY_S:
key_down = false;
break;
case ALLEGRO_KEY_SPACE:
key_space = false;
break;
}
break;
case ALLEGRO_EVENT_MOUSE_AXES:
last_mouse_x = ev.mouse.x;
last_mouse_y = ev.mouse.y;
if (ev.mouse.dz != 0 && !n_gui_wants_mouse(gui_ctx)) {
n_iso_camera_zoom(camera, (float)ev.mouse.dz * 0.25f,
(float)ev.mouse.x, (float)ev.mouse.y);
}
break;
case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
if (ev.mouse.button == 1 && !n_gui_wants_mouse(gui_ctx)) {
float wx, wy;
n_iso_camera_screen_to_world(camera, (float)ev.mouse.x,
(float)ev.mouse.y, &wx, &wy);
int map_x, map_y;
float click_fx = 0.0f, click_fy = 0.0f;
iso_screen_to_map_height_f(isomap, wx, wy, TILE_W, TILE_H,
&map_x, &map_y, &click_fx, &click_fy);
if (map_x >= 0 && map_x < MAP_W && map_y >= 0 && map_y < MAP_H) {
if (player_mode) {
/* Click-to-move via A* pathfinding */
if (player_path) {
n_astar_path_free(player_path);
player_path = NULL;
}
ASTAR_GRID* grid = iso_map_to_astar_grid(isomap, PLAYER_MAX_HEIGH_DIFF, player_mx, player_my);
if (grid) {
int dest_x = map_x, dest_y = map_y;
/* If destination is blocked, find nearest walkable tile */
if (!n_astar_grid_get_walkable(grid, dest_x, dest_y, 0)) {
int found = 0;
for (int ring = 1; ring <= MAX(MAP_W, MAP_H) && !found; ring++) {
for (int ry = -ring; ry <= ring && !found; ry++)
for (int rx = -ring; rx <= ring && !found; rx++) {
if (abs(rx) != ring && abs(ry) != ring) continue;
int nx = map_x + rx, ny = map_y + ry;
if (nx >= 0 && nx < MAP_W && ny >= 0 && ny < MAP_H &&
n_astar_grid_get_walkable(grid, nx, ny, 0)) {
dest_x = nx;
dest_y = ny;
found = 1;
}
}
}
}
player_path = n_astar_find_path(grid,
player_mx, player_my, 0,
dest_x, dest_y, 0,
ASTAR_ALLOW_DIAGONAL, ASTAR_HEURISTIC_CHEBYSHEV);
n_astar_grid_free(grid);
if (player_path && player_path->length > 1) {
player_path_idx = 1;
player_path_progress = 0.0f;
/* If dest tile matches the clicked tile, use exact
* click position; otherwise center of dest tile. */
int final_tx = player_path->nodes[player_path->length - 1].x;
int final_ty = player_path->nodes[player_path->length - 1].y;
if (final_tx == map_x && final_ty == map_y) {
player_click_fx = click_fx;
player_click_fy = click_fy;
} else {
player_click_fx = (float)final_tx + 0.5f;
player_click_fy = (float)final_ty + 0.5f;
}
/* Clamp to valid map range for border tiles.
* Allow the full extent of the last tile so the
* player can walk anywhere within border tiles. */
if (player_click_fx < 0.0f) player_click_fx = 0.0f;
if (player_click_fy < 0.0f) player_click_fy = 0.0f;
if (player_click_fx > (float)MAP_W - 1e-4f) player_click_fx = (float)MAP_W - 1e-4f;
if (player_click_fy > (float)MAP_H - 1e-4f) player_click_fy = (float)MAP_H - 1e-4f;
} else {
if (player_path) {
n_astar_path_free(player_path);
player_path = NULL;
}
}
}
} else if (height_mode) {
iso_map_set_height(isomap, map_x, map_y, paint_height);
iso_map_save(isomap, MAP_FILE);
} else {
iso_map_set_terrain(isomap, map_x, map_y, paint_terrain);
iso_map_save(isomap, MAP_FILE);
}
}
}
break;
case ALLEGRO_EVENT_DISPLAY_CLOSE:
running = false;
break;
case ALLEGRO_EVENT_DISPLAY_RESIZE:
al_acknowledge_resize(display);
screen_w = al_get_display_width(display);
screen_h = al_get_display_height(display);
n_gui_set_display_size(gui_ctx, (float)screen_w, (float)screen_h);
break;
}
/* Render */
if (redraw_needed && al_is_event_queue_empty(queue)) {
redraw_needed = false;
al_set_target_backbuffer(display);
al_clear_to_color(al_map_rgb(20, 25, 30));
/* Sync ISO_MAP rendering flags */
isomap->smooth_height = smooth_height ? 1 : 0;
isomap->smooth_slope_max = smooth_slope_max;
isomap->show_grid = show_grid ? 1 : 0;
isomap->hover_mx = hover_mx;
isomap->hover_my = hover_my;
/* Build object list for depth-sorted rendering */
N_ISO_OBJECT iso_objects[2];
int iso_num_objects = 0;
if (player_mode) {
iso_objects[iso_num_objects].fx = player_fx;
iso_objects[iso_num_objects].fy = player_fy;
iso_objects[iso_num_objects].fz = player_z;
iso_objects[iso_num_objects].occluded_alpha = 0.35f;
iso_objects[iso_num_objects].is_occluded = 0;
iso_objects[iso_num_objects].draw = draw_player_object;
iso_objects[iso_num_objects].user_data = NULL;
iso_num_objects++;
}
if (ghost_enabled && ghost_dr) {
/* ghost uses the DR-computed screen pos; derive map pos */
DR_VEC3 dr_pos;
dr_entity_compute(ghost_dr, al_get_time(), &dr_pos);
float dr_h = interpolate_height_at((float)dr_pos.x, (float)dr_pos.y);
iso_objects[iso_num_objects].fx = (float)dr_pos.x;
iso_objects[iso_num_objects].fy = (float)dr_pos.y;
iso_objects[iso_num_objects].fz = dr_h;
iso_objects[iso_num_objects].occluded_alpha = 0.35f;
iso_objects[iso_num_objects].is_occluded = 0;
iso_objects[iso_num_objects].draw = draw_ghost_object;
iso_objects[iso_num_objects].user_data = NULL;
iso_num_objects++;
}
/* Draw map with depth-sorted objects */
{
ALLEGRO_BITMAP** trans_ptrs[NUM_TERRAINS];
for (int t = 0; t < NUM_TERRAINS; t++)
trans_ptrs[t] = transition_tiles[t];
iso_map_draw(isomap, tile_bitmaps, trans_ptrs, NUM_MASKS,
NULL, 0,
floorf(camera->x * camera->zoom),
floorf(camera->y * camera->zoom),
camera->zoom,
screen_w, screen_h, player_mode ? 1 : 0,
iso_num_objects > 0 ? iso_objects : NULL,
iso_num_objects);
}
/* Update GUI info labels */
{
char sbuf[256];
if (player_mode) {
float ph = interpolate_height_at_clamped(player_fx, player_fy, PLAYER_MAX_HEIGH_DIFF);
snprintf(sbuf, sizeof(sbuf), "Pos:(%.1f,%.1f) Z:%.1f GndH:%.1f %s | Zoom:%.1fx",
player_fx, player_fy, player_z, ph,
player_on_ground ? "GND" : "AIR", camera->zoom);
} else if (height_mode) {
snprintf(sbuf, sizeof(sbuf), "Paint height:%d | Zoom:%.1fx | Slope max:%d",
paint_height, camera->zoom, smooth_slope_max);
} else {
snprintf(sbuf, sizeof(sbuf), "Brush:[%s] | Zoom:%.1fx | Slope max:%d",
terrain_names[paint_terrain], camera->zoom, smooth_slope_max);
}
n_gui_label_set_text(gui_ctx, gui_lbl_status, sbuf);
snprintf(sbuf, sizeof(sbuf), "Proj: %s (%.1f deg)",
iso_projection_name(current_proj), isomap->proj.angle_deg);
n_gui_label_set_text(gui_ctx, gui_lbl_proj, sbuf);
if (hover_mx >= 0 && hover_mx < MAP_W && hover_my >= 0 && hover_my < MAP_H) {
snprintf(sbuf, sizeof(sbuf), "Hover: (%d,%d) H:%d T:%s",
hover_mx, hover_my,
iso_map_get_height(isomap, hover_mx, hover_my),
terrain_names[iso_map_get_terrain(isomap, hover_mx, hover_my)]);
n_gui_label_set_text(gui_ctx, gui_lbl_hover, sbuf);
}
}
/* Draw GUI overlay */
n_gui_draw(gui_ctx);
al_flip_display();
}
}
/* Cleanup */
dr_entity_destroy(&ghost_dr);
if (player_path) {
n_astar_path_free(player_path);
player_path = NULL;
}
if (gui_ctx) n_gui_destroy_ctx(&gui_ctx);
if (camera) n_iso_camera_free(&camera);
if (isomap) iso_map_free(&isomap);
for (int t = 0; t < NUM_TERRAINS; t++) {
for (int m = 0; m < NUM_MASKS; m++)
if (transition_tiles[t][m]) al_destroy_bitmap(transition_tiles[t][m]);
if (tile_bitmaps[t]) al_destroy_bitmap(tile_bitmaps[t]);
}
for (int m = 0; m < NUM_MASKS; m++)
if (transition_masks[m]) al_destroy_bitmap(transition_masks[m]);
al_destroy_font(font);
al_destroy_timer(timer);
al_destroy_event_queue(queue);
al_destroy_display(display);
return EXIT_SUCCESS;
}
Modules
- AABB3D
- ACCEPT_POOL
- ALLEGRO4
- ALLEGRO5
- ANIM_LIB
- ASTAR
- ATLAS_LIB
- AVRO
- CLOCK_SYNC
- COMMONS
- CONFIGFILE
- CYPHER_BASE64
- CYPHER_VIGENERE
- DEAD_RECKONING
- ENUMS
- EXCEPTIONS
- GAME_ENV
- GIT
- GUI
- HASH_TABLE
- ISOMETRIC_ENGINE
- LIST
- LOG
- LOGNODUP
- LZ4
- NETWORKING
- NETWORK_MSG
- N_COOKIES
- N_DIFF
- N_DIGEST
- N_DISK_CACHE
- N_DNS
- N_ECC
- N_ENTROPY
- N_FILES
- N_FLUIDS
- N_GUI_COLOR
- N_GUI_COLORWHEEL
- N_GUI_CURVE
- N_GUI_GRID
- N_GUI_POPUP
- N_HEX
- N_HTTP3
- N_HTTP_COOKIE
- N_HTTP_FORM
- N_HTTP_MIME
- N_HTTP_REQ
- N_HTTP_RESP
- N_HTTP_ROUTER
- N_HTTP_SERVER
- N_ICC
- N_JSON
- N_KAFKA
- N_LINALG
- N_MODULE
- N_OPENSSL_COMPAT
- N_PRETTY
- N_PTH
- N_QUERY
- N_RANDOM
- N_SHA256
- N_STR
- N_TIFF
- N_TIME
- N_USER
- N_X509
- N_ZIP
- PARTICLES
- PCRE
- PHYSICS
- SIGNALS
- STACK
- THREADS
- TRAJECTORY
- TREE
- ZLIB