a5ec8db5f7
build / build (push) Failing after 5s
dependency (SDL2, SDL2_mixer, fluidsynth-lite, a MIDI soundfont) prebuilt, so compiling the engine needs no network access - just the image and the engine source. Add res/assets/extract_assets.sh to pull the game's data files out of a purchased GOG installer, and a Makefile that assembles a runnable dist/ from the two. Also add `make package`, which builds a redistributable tarball that omits the proprietary game assets (shipping res/GET_ASSETS.txt instead) plus license information for both the MIT tooling and the GPLv3 engine, and a Gitea Actions workflow that builds and publishes it to dl.ladkau.de on every push.
333 lines
11 KiB
C
333 lines
11 KiB
C
/*
|
|
|
|
Copyright (C) 2015-2018 Night Dive Studios, LLC.
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
/*
|
|
* $Source: r:/prj/cit/src/RCS/automap.c $
|
|
* $Revision: 1.43 $
|
|
* $Author: xemu $
|
|
* $Date: 1994/10/16 15:56:00 $
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "amaploop.h"
|
|
#include "player.h"
|
|
#include "newmfd.h"
|
|
#include "mfdint.h"
|
|
#include "mfddims.h"
|
|
#include "automap.h"
|
|
#include "colors.h"
|
|
#include "rcolors.h"
|
|
#include "tools.h"
|
|
#include "mainloop.h"
|
|
#include "wares.h"
|
|
#include "lvldata.h"
|
|
#include "cit2d.h"
|
|
#include "gr2ss.h"
|
|
#include "gamestrn.h"
|
|
#include "sfxlist.h"
|
|
#include "musicai.h"
|
|
|
|
#include "mfdart.h"
|
|
#include "gamescr.h"
|
|
#include "cybstrng.h"
|
|
|
|
#define WORKING_INC_MFDS
|
|
|
|
#define AUTOMAP_ZOOM 0
|
|
#define AUTOMAP_STATION 1
|
|
#define AUTOMAP_STATES 2
|
|
|
|
#define ZOOM_STR get_temp_string(REF_STR_AutomapMFDButtons)
|
|
#define FULL_STR get_temp_string(REF_STR_AutomapMFDButtons + 1)
|
|
#define SIDE_STR get_temp_string(REF_STR_AutomapMFDButtons + 2)
|
|
|
|
#define BTXT_HGT (MFD_VIEW_HGT - 7)
|
|
|
|
// what is all this bullshit, anyway?
|
|
|
|
#define SetAutomapMode(m, mode) \
|
|
player_struct.mfd_func_data[MFD_MAP_FUNC][(m)] = (player_struct.mfd_func_data[MFD_MAP_FUNC][(m)] & 0xfc) + (mode)
|
|
#define GetAutomapMode(m) (player_struct.mfd_func_data[MFD_MAP_FUNC][(m)] & 0x03)
|
|
|
|
#define SetLastAutomapMode(m, mode) \
|
|
player_struct.mfd_func_data[MFD_MAP_FUNC][(m)] = \
|
|
(player_struct.mfd_func_data[MFD_MAP_FUNC][(m)] & 0xf3) + ((mode) << 2)
|
|
#define GetLastAutomapMode(m) ((player_struct.mfd_func_data[MFD_MAP_FUNC][(m)] & 0x0c) >> 2)
|
|
|
|
#define AutomapLastUpdated (player_struct.mfd_func_data[MFD_MAP_FUNC][2])
|
|
|
|
// -----------
|
|
// PROTOTYPES
|
|
// -----------
|
|
int mfd_to_map(int mid);
|
|
void automap_expose_cross_section(MFD *m, ubyte tic);
|
|
void automap_expose_zoom(MFD *m, ubyte tac);
|
|
|
|
// -------
|
|
// Globals
|
|
// -------
|
|
static long last_update = 0;
|
|
extern uchar full_game_3d;
|
|
|
|
// ===========================================================================
|
|
// * THE AUTOMAP CODE *
|
|
// ===========================================================================
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// mfd_map_init()
|
|
//
|
|
// Initializes the automap settings on either side to appropriate values.
|
|
|
|
errtype mfd_map_init(MFD_Func *mfd) {
|
|
// set them up to be different cur and last, and left zoom, right station
|
|
player_struct.mfd_func_data[MFD_MAP_FUNC][MFD_LEFT] = (AUTOMAP_STATION << 2) + AUTOMAP_ZOOM;
|
|
player_struct.mfd_func_data[MFD_MAP_FUNC][MFD_RIGHT] = (AUTOMAP_ZOOM << 2) + AUTOMAP_STATION;
|
|
AutomapLastUpdated = 1;
|
|
#ifdef WORKING_INC_MFDS
|
|
player_struct.mfd_func_status[MFD_MAP_FUNC] |= 1 << 4;
|
|
#endif
|
|
return OK;
|
|
}
|
|
|
|
int mfd_to_map(int mid) {
|
|
int i = 0, m;
|
|
|
|
for (m = 0; m < mid; m++) {
|
|
if (mfd_get_func(m, player_struct.mfd_current_slots[m]) == MFD_MAP_FUNC)
|
|
i++;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// mfd_map_handler()
|
|
//
|
|
// Simply toggles a bit which tells the expose function whether to draw
|
|
// the overhead map view, or the cross-level segment of the station
|
|
|
|
#define MODE_RIGHT 25
|
|
#define OPT_LEFT (MFD_VIEW_WID - 25)
|
|
|
|
uchar mfd_map_handler(MFD *m, uiEvent *e) {
|
|
uchar retval = FALSE;
|
|
ubyte map_state;
|
|
int mapid = mfd_to_map(m->id);
|
|
|
|
// If we don't have an automap, we shouldn't do shit.
|
|
if (player_struct.hardwarez[HARDWARE_AUTOMAP] == 0)
|
|
return FALSE;
|
|
uiMouseData *mouse = &e->mouse_data;
|
|
|
|
if (mouse->action & (MOUSE_WHEELUP | MOUSE_WHEELDN)) {
|
|
if (!digi_fx_playing(SFX_MAP_ZOOM, NULL))
|
|
play_digi_fx(SFX_MAP_ZOOM, 1);
|
|
amap_zoom(oAMap(mapid), FALSE, mouse->action & MOUSE_WHEELUP ? 1 : -1);
|
|
return TRUE;
|
|
}
|
|
|
|
if (!(mouse->action & MOUSE_LDOWN))
|
|
return FALSE; // ignore click releases
|
|
|
|
if (e->pos.y > m->rect.lr.y - 8) // bottom row
|
|
{
|
|
int xp = e->pos.x - m->rect.ul.x;
|
|
|
|
if (xp < MODE_RIGHT) {
|
|
map_state = GetAutomapMode(mapid);
|
|
SetAutomapMode(mapid, (map_state + 1) % AUTOMAP_STATES);
|
|
SetLastAutomapMode(mapid, map_state);
|
|
mfd_notify_func(MFD_MAP_FUNC, MFD_MAP_SLOT, FALSE, MFD_ACTIVE, FALSE);
|
|
last_update = 0;
|
|
play_digi_fx(SFX_MAP_ZOOM, 1);
|
|
return TRUE;
|
|
} else if (xp > OPT_LEFT) {
|
|
_new_mode = AUTOMAP_LOOP;
|
|
chg_set_flg(GL_CHG_LOOP);
|
|
play_digi_fx(SFX_MAP_ZOOM, 1);
|
|
} else if (GetAutomapMode(mapid) == AUTOMAP_ZOOM) {
|
|
int zfac;
|
|
play_digi_fx(SFX_MAP_ZOOM, 1);
|
|
if (xp < (MFD_VIEW_WID / 2))
|
|
zfac = 1;
|
|
else
|
|
zfac = -1;
|
|
amap_zoom(oAMap(mapid), FALSE, zfac);
|
|
}
|
|
} else if (GetAutomapMode(mapid) != AUTOMAP_STATION) {
|
|
char buf[80];
|
|
int tmpx = e->pos.x - m->rect.ul.x, tmpy = e->pos.y - m->rect.ul.y;
|
|
if (amap_deal_with_map_click(oAMap(mapid), &tmpx, &tmpy) != NULL) {
|
|
retval = amap_get_note(oAMap(mapid), buf);
|
|
if (full_game_3d && !retval) {
|
|
retval = mfd_scan_opacity(m->id, e->pos);
|
|
}
|
|
if (retval) {
|
|
strtoupper(buf);
|
|
message_info(buf);
|
|
retval = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// mfd_map_expose()
|
|
//
|
|
#include "fullscrn.h"
|
|
|
|
void mfd_map_expose(MFD *m, ubyte control) {
|
|
ubyte map_state, last_map_state;
|
|
int mapid = mfd_to_map(m->id);
|
|
|
|
if ((control & MFD_EXPOSE) && ((!full_game_3d) || (full_visible & (visible_mask(m->id))))) {
|
|
// If we don't have an automap, we shouldn't do shit.
|
|
if (player_struct.hardwarez[HARDWARE_AUTOMAP] == 0) {
|
|
char buf[128];
|
|
short w, h;
|
|
gr_push_canvas(pmfd_canvas);
|
|
ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
|
|
if (!full_game_3d)
|
|
draw_res_bm(REF_IMG_bmBlankMFD, 0, 0);
|
|
// draw_hires_resource_bm(REF_IMG_bmBlankMFD, 0, 0);
|
|
draw_raw_resource_bm(MKREF(RES_mfdArtOverlays, MFD_ART_TRIOP), 0, 0);
|
|
get_string(REF_STR_NoAutomap, buf, sizeof(buf));
|
|
gr_set_font(ResLock(MFD_FONT));
|
|
gr_string_wrap(buf, MFD_VIEW_WID - 2);
|
|
gr_string_size(buf, &w, &h);
|
|
gr_set_fcolor(RED_BASE + 5);
|
|
draw_shadowed_string(buf, (MFD_VIEW_WID - w) / 2, (MFD_VIEW_HGT - h) / 2, full_game_3d);
|
|
ResUnlock(MFD_FONT);
|
|
gr_pop_canvas();
|
|
mfd_update_display(m, 0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
|
|
return;
|
|
}
|
|
|
|
// what is all this stuff???
|
|
map_state = GetAutomapMode(mapid);
|
|
last_map_state = GetLastAutomapMode(mapid);
|
|
|
|
if (!(control & MFD_EXPOSE_FULL) && map_state == last_map_state) {
|
|
if (map_state == AUTOMAP_STATION) {
|
|
if (!(control & MFD_EXPOSE_FULL))
|
|
return;
|
|
} else {
|
|
#define WORKING_INC_MFDS
|
|
#ifndef WORKING_INC_MFDS
|
|
if (last_update + (CIT_CYCLE >> 3) > (*tmd_ticks)) {
|
|
mfd_notify_func(MFD_MAP_FUNC, MFD_MAP_SLOT, FALSE, MFD_ACTIVE, FALSE);
|
|
return;
|
|
} else
|
|
#endif
|
|
{
|
|
if ((AutomapLastUpdated == mapid) && (GetAutomapMode((mapid == 0) ? 1 : 0) ==
|
|
AUTOMAP_ZOOM)) { // we were last done, and both of us need to
|
|
// be done, so give the other guy a chance...
|
|
AutomapLastUpdated = 0xff; // neither of us, so next time either will work
|
|
#ifndef WORKING_INC_MFDS
|
|
mfd_notify_func(MFD_MAP_FUNC, MFD_MAP_SLOT, FALSE, MFD_ACTIVE, FALSE);
|
|
#endif
|
|
return;
|
|
}
|
|
AutomapLastUpdated = mapid;
|
|
#ifndef WORKING_INC_MFDS
|
|
last_update = *tmd_ticks;
|
|
#endif
|
|
}
|
|
}
|
|
} else {
|
|
if (map_state == AUTOMAP_ZOOM)
|
|
if (!oAMap(mapid)->init) {
|
|
automap_init(player_struct.hardwarez[HARDWARE_AUTOMAP], mapid);
|
|
oAMap(mapid)->zoom++;
|
|
}
|
|
}
|
|
SetLastAutomapMode(mapid, map_state);
|
|
gr_push_canvas(pmfd_canvas);
|
|
ss_safe_set_cliprect(0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
|
|
if (!full_game_3d)
|
|
draw_res_bm(REF_IMG_bmBlankMFD, 0, 0);
|
|
// gr_bitmap(&mfd_background, 0, 0);
|
|
switch (map_state) {
|
|
case AUTOMAP_ZOOM:
|
|
automap_expose_zoom(m, control);
|
|
break;
|
|
case AUTOMAP_STATION:
|
|
automap_expose_cross_section(m, control);
|
|
break;
|
|
}
|
|
gr_pop_canvas();
|
|
mfd_update_display(m, 0, 0, MFD_VIEW_WID, MFD_VIEW_HGT);
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// automap_expose_cross_section()
|
|
//
|
|
// The expose function for drawing the cross-section mode for the automap
|
|
|
|
#define BUF_SIZE 10
|
|
|
|
void automap_expose_cross_section(MFD *mfd, ubyte tic) {
|
|
grs_font *mfdamapfont;
|
|
char buf[BUF_SIZE];
|
|
short w, h;
|
|
|
|
draw_res_bm(MKREF(RES_mfdArtOverlays, MFD_ART_STATN), 0, 0);
|
|
draw_res_bm(MKREF(RES_mfdArtOverlays, MFD_ART_LVL(player_struct.level)), 0, 0);
|
|
mfdamapfont = ResLock(RES_tinyTechFont);
|
|
gr_set_font(mfdamapfont);
|
|
gr_set_fcolor(ORANGE_8_BASE + 2);
|
|
fsmap_get_lev_str(buf, BUF_SIZE);
|
|
gr_string_size(buf, &w, &h);
|
|
// KLC draw_shadowed_string(fsmap_get_lev_str(buf,BUF_SIZE),MFD_VIEW_WID-w-2,1,full_game_3d);
|
|
draw_shadowed_string(buf, MFD_VIEW_WID - w - 2, 1, full_game_3d);
|
|
ResUnlock(RES_tinyTechFont);
|
|
|
|
mfdamapfont = ResLock(RES_mfdFont);
|
|
gr_set_font(mfdamapfont);
|
|
gr_set_fcolor(ORANGE_8_BASE);
|
|
draw_shadowed_string(ZOOM_STR, 1, BTXT_HGT, full_game_3d);
|
|
draw_shadowed_string(FULL_STR, MFD_VIEW_WID - 25, BTXT_HGT, full_game_3d);
|
|
ResUnlock(RES_mfdFont);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// automap_expose_zoom_in()
|
|
//
|
|
// The expose function for drawing the zoomed in mode for the automap
|
|
|
|
void automap_expose_zoom(MFD *m, ubyte tac) {
|
|
grs_font *mfdamapfont;
|
|
int mapid = mfd_to_map(m->id);
|
|
|
|
amap_draw(oAMap(mapid), 0);
|
|
mfdamapfont = ResLock(RES_mfdFont);
|
|
gr_set_font(mfdamapfont);
|
|
gr_set_fcolor(ORANGE_8_BASE);
|
|
draw_shadowed_string(SIDE_STR, 1, BTXT_HGT, full_game_3d);
|
|
draw_shadowed_string("+ -", (MFD_VIEW_WID / 2) - 10, BTXT_HGT, full_game_3d);
|
|
draw_shadowed_string(FULL_STR, MFD_VIEW_WID - 25, BTXT_HGT, full_game_3d);
|
|
ResUnlock(RES_mfdFont);
|
|
#ifndef WORKING_INC_MFDS
|
|
mfd_notify_func(MFD_MAP_FUNC, MFD_MAP_SLOT, FALSE, MFD_ACTIVE, FALSE);
|
|
#endif
|
|
}
|