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.
594 lines
18 KiB
C
594 lines
18 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/leanmetr.c $
|
|
* $Revision: 1.31 $
|
|
* $Author: mahk $
|
|
* $Date: 1994/11/09 20:45:40 $
|
|
*
|
|
*/
|
|
|
|
#include "faketime.h"
|
|
#include "citres.h"
|
|
#include "physics.h"
|
|
#include "player.h"
|
|
#include "criterr.h"
|
|
#include "froslew.h"
|
|
#include "objprop.h"
|
|
#include "objsim.h"
|
|
#include "tools.h"
|
|
#include "wares.h"
|
|
#include "canvchek.h"
|
|
|
|
#include "gamescr.h"
|
|
#include "otrip.h"
|
|
|
|
#include "gr2ss.h"
|
|
|
|
// -------
|
|
// DEFINES
|
|
// -------
|
|
|
|
|
|
#define SLOT_EYEMETER_X 141
|
|
#define SLOT_EYEMETER_Y 1
|
|
|
|
#define FULL_EYEMETER_X 10
|
|
#define FULL_EYEMETER_Y 1
|
|
|
|
#define EYEMETER_X() (current_meter_region->abs_x)
|
|
#define EYEMETER_Y() (current_meter_region->abs_y)
|
|
#define LEANOMETER_XOFF 21
|
|
#define LEANOMETER_YOFF 0
|
|
#define LEANOMETER_X() (EYEMETER_X() + LEANOMETER_XOFF)
|
|
#define LEANOMETER_Y() (EYEMETER_Y() + LEANOMETER_YOFF)
|
|
|
|
#define EYEMETER_W 19
|
|
#define EYEMETER_H 22
|
|
#define EYE_LEFT_MARGIN 2
|
|
#define DISCRETE_EYE_POSITIONS 3
|
|
#define DISCRETE_MIDDLE_H 6
|
|
|
|
#define MAX_EYE_ANGLE (8 * FIXANG_PI / 18)
|
|
|
|
#define LEANOMETER_W 23
|
|
#define LEANOMETER_H EYEMETER_H
|
|
|
|
#define NUM_LEAN_BMAPS 9
|
|
#define BMAPS_PER_POSTURE 3
|
|
|
|
extern uchar full_game_3d;
|
|
|
|
static ubyte discrete_eye_height[DISCRETE_EYE_POSITIONS] = {
|
|
3,
|
|
10,
|
|
18,
|
|
};
|
|
ubyte hires_eye_height[DISCRETE_EYE_POSITIONS] = {
|
|
8,
|
|
26,
|
|
45,
|
|
};
|
|
LGPoint shield_offsets[9] = {
|
|
{2, 1}, // stand right
|
|
{2, 1}, // stand
|
|
{2, 1}, // stand left
|
|
{2, 1}, // crouch right
|
|
{2, 1}, // crouch
|
|
{2, 0}, // crouch left
|
|
{2, 1}, // prone right
|
|
{2, 1}, // prone
|
|
{0, 1} // prone left
|
|
};
|
|
|
|
void EDMS_lean_o_meter(physics_handle ph, fix *lean, fix *crouch);
|
|
|
|
// -------
|
|
// GLOBALS
|
|
// -------
|
|
extern uchar gBioInited;
|
|
|
|
LGRegion slot_meter_region;
|
|
LGRegion fullscrn_meter_region;
|
|
LGRegion *current_meter_region = &slot_meter_region;
|
|
|
|
#define PICK_METER_REGION(full) ((full) ? &fullscrn_meter_region : &slot_meter_region)
|
|
|
|
ushort lean_bmap_res = 0;
|
|
ushort shield_bmap_res = 0;
|
|
|
|
#define lean_bmap_id(i) (MKREF(lean_bmap_res, i))
|
|
#define eye_bmap_r(i) (get_bitmap_from_ref(REF_IMG_bmEyeIconR + (i)))
|
|
#define eye_bmap_l(i) (get_bitmap_from_ref(REF_IMG_bmEyeIconL + (i)))
|
|
// KLC - lock instead of get #define lean_bmaps(i) (get_bitmap_from_ref(lean_bmap_id(i)))
|
|
#define lean_bmaps(i) (lock_bitmap_from_ref(lean_bmap_id(i)))
|
|
#define meter_bkgnd() (get_bitmap_from_ref(full_game_3d ? REF_IMG_bmLeanBkgndTransp : REF_IMG_bmLeanBkgnd))
|
|
|
|
uchar eye_fine_mode = FALSE;
|
|
|
|
|
|
// ---------
|
|
// INTERNALS
|
|
// ---------
|
|
#define MAX_LEAN_BASE (RES_leanMeterRad - RES_leanMeterBase)
|
|
|
|
void set_base_lean_bmap(uchar shield) {
|
|
int v;
|
|
ushort baseRes;
|
|
|
|
// Set the lean bitmaps resource.
|
|
|
|
v = player_struct.hardwarez[CPTRIP(ENV_HARD_TRIPLE)]; // v will be 0-2.
|
|
if (v > MAX_LEAN_BASE)
|
|
v = MAX_LEAN_BASE;
|
|
baseRes = RES_leanMeterBase + v;
|
|
|
|
if (baseRes != lean_bmap_res) // If the base lean bitmap has changed:
|
|
{
|
|
if (lean_bmap_res != 0) // free the old bitmap
|
|
{
|
|
ResUnlock(lean_bmap_res);
|
|
ResDrop(lean_bmap_res);
|
|
}
|
|
ResLock(baseRes); // Load hi and lock the new bitmap series.
|
|
lean_bmap_res = baseRes; // this is our base bitmap now
|
|
}
|
|
|
|
// Set the shield bitmaps resource.
|
|
|
|
if (shield) {
|
|
v = SHIELD_SETTING(player_struct.hardwarez_status[CPTRIP(SHIELD_HARD_TRIPLE)]);
|
|
if (player_struct.hardwarez[CPTRIP(SHIELD_HARD_TRIPLE)] == SHIELD_VERSIONS)
|
|
v = SHIELD_VERSIONS - 1;
|
|
baseRes = RES_leanShield1 + v;
|
|
|
|
if (baseRes != shield_bmap_res) {
|
|
// If the base shield bitmap has changed:
|
|
if (shield_bmap_res != 0) {
|
|
// free the old bitmap
|
|
ResUnlock(shield_bmap_res);
|
|
ResDrop(shield_bmap_res);
|
|
}
|
|
ResLock(baseRes); // Load hi and lock the new bitmap series.
|
|
shield_bmap_res = baseRes; // this is our base shield bitmap now
|
|
}
|
|
} else {
|
|
// If shields are now off:
|
|
if (shield_bmap_res != 0) {
|
|
// If shields were previously on, free up the shield bitmaps.
|
|
ResUnlock(shield_bmap_res);
|
|
ResDrop(shield_bmap_res);
|
|
shield_bmap_res = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define LEAN_CONST (fix_2pi / 10)
|
|
#define LEAN_TO_LEANX(ln) lg_min(100, lg_max(-100, (100 * (ln) / LEAN_CONST)))
|
|
|
|
#define PLAYER_HGT (fix_make(0, 0xbd00))
|
|
#define CROUCH_CONST (2 * PLAYER_HGT / 5)
|
|
#define CROUCH_TO_POSTURE(c) lg_min(2, lg_max(0, (2 - lg_max(c, 0) * 2 / CROUCH_CONST)))
|
|
|
|
// The posture meter output is filtered by a capacitor,
|
|
// the constant below is the reciprocal of the
|
|
// filter's RC time constant, in units of 1/sec.
|
|
#define POSTURE_FILTER_RATE 20
|
|
|
|
#ifdef BIASED_CAPACITOR
|
|
fix compute_filter_weight(ulong deltat) {
|
|
int rate = POSTURE_FILTER_RATE;
|
|
fix bias = FIX_UNIT * CONTROL_MAX_VAL / (CONTROL_MAX_VAL + 3 * abs(player_struct.controls[CONTROL_YVEL]));
|
|
fix weight = fix_make(deltat, 0) * rate >> APPROX_CIT_CYCLE_SHFT;
|
|
Spew(DSRC_USER_I_Lean, ("posture filter weight = %q, bias = %q\n", weight, bias));
|
|
weight = fix_mul(weight, bias);
|
|
return weight;
|
|
}
|
|
#else
|
|
fix compute_filter_weight(ulong deltat) {
|
|
int rate = POSTURE_FILTER_RATE;
|
|
fix weight = fix_make(deltat, 0) * rate >> APPROX_CIT_CYCLE_SHFT;
|
|
|
|
return weight;
|
|
}
|
|
#endif
|
|
|
|
fix apply_weighted_filter(fix input, fix state, ulong deltat) {
|
|
fix weight = compute_filter_weight(deltat);
|
|
return fix_div(fix_mul(weight, input) + state, weight + FIX_UNIT);
|
|
}
|
|
|
|
#define INTENDED_HGT (PLAYER_HGT * (NUM_POSTURES - player_struct.posture - 1) / (NUM_POSTURES - 1))
|
|
|
|
#define STORE_STATE(fval) \
|
|
(player_struct.lean_filter_state = (ushort)((fval) > FIX_UNIT ? FIX_UNIT - 1 : fix_frac(fval)))
|
|
#define GET_STATE (fix_make(0, player_struct.lean_filter_state));
|
|
|
|
#define SLAM_DURATION (CIT_CYCLE / 2)
|
|
|
|
void slam_posture_meter_state(void) {
|
|
STORE_STATE(INTENDED_HGT);
|
|
player_struct.posture_slam_state = player_struct.game_time + SLAM_DURATION;
|
|
}
|
|
|
|
fix velocity_crouch_filter(fix crouch) {
|
|
ubyte posture = player_struct.posture + 1;
|
|
fix hgt = INTENDED_HGT;
|
|
fix vel = posture * FIX_UNIT *
|
|
(abs(player_struct.controls[CONTROL_YVEL] + abs(player_struct.controls[CONTROL_ZVEL]))) /
|
|
(2 * CONTROL_MAX_VAL);
|
|
return fix_div(fix_mul(hgt, vel) + crouch, vel + FIX_UNIT);
|
|
}
|
|
|
|
void lean_icon(LGPoint *pos, grs_bitmap **icon, int *inum) {
|
|
int posture, leanx;
|
|
uchar *bp;
|
|
|
|
// Determine the posture and lean amount for the player currently.
|
|
if (!global_fullmap->cyber) {
|
|
fix ln, crouch;
|
|
fix state = GET_STATE;
|
|
|
|
EDMS_lean_o_meter(PLAYER_PHYSICS, &ln, &crouch);
|
|
|
|
crouch = velocity_crouch_filter(crouch);
|
|
if (player_struct.game_time > player_struct.posture_slam_state)
|
|
state = apply_weighted_filter(crouch, state, player_struct.deltat);
|
|
STORE_STATE(state);
|
|
posture = CROUCH_TO_POSTURE(state);
|
|
leanx = LEAN_TO_LEANX(ln);
|
|
} else {
|
|
posture = POSTURE_STAND;
|
|
leanx = 0;
|
|
}
|
|
|
|
// Calculate the bitmap resource index based on posture and lean.
|
|
*inum = posture * BMAPS_PER_POSTURE + ((100 - leanx) * BMAPS_PER_POSTURE / 201);
|
|
|
|
// Get a pointer to the corresponding lean bitmap.
|
|
FrameDesc *f = RefGet(MKREF(lean_bmap_res,*inum));
|
|
if (f != NULL) {
|
|
f->bm.bits = (uchar *)(f + 1);
|
|
*icon = &(f->bm);
|
|
} else
|
|
DEBUG("%s: No lean resource bitmap!", __FUNCTION__);
|
|
|
|
// Determine where to draw the bitmap.
|
|
pos->y = 53 - (*icon)->h;
|
|
pos->x = (46 - (*icon)->w + 1) * abs(leanx) / 600;
|
|
if (leanx < 0)
|
|
pos->x = -pos->x;
|
|
pos->x += LEANOMETER_X() + (25) / 2 - ((*icon)->w + 1) / 2;
|
|
pos->y += LEANOMETER_Y() - 31;
|
|
}
|
|
|
|
static void undraw_meter_area(LGRect *r) {
|
|
short a, b, c, d;
|
|
char saveMode;
|
|
int x, y;
|
|
|
|
STORE_CLIP(a, b, c, d);
|
|
ss_safe_set_cliprect(r->ul.x, r->ul.y, r->lr.x, r->lr.y);
|
|
x = EYEMETER_X();
|
|
y = EYEMETER_Y();
|
|
|
|
if (is_onscreen())
|
|
uiHideMouse(r);
|
|
ss_bitmap(meter_bkgnd(), x, y);
|
|
if (is_onscreen())
|
|
uiShowMouse(r);
|
|
|
|
RESTORE_CLIP(a, b, c, d);
|
|
}
|
|
|
|
void player_reset_eye(void) { player_struct.eye_pos = eye_mods[1] = 0; }
|
|
|
|
void player_set_eye(byte eyecntl) {
|
|
int theta = MAX_EYE_ANGLE * eyecntl / CONTROL_MAX_VAL;
|
|
player_struct.eye_pos = theta;
|
|
|
|
if (theta < 0)
|
|
theta += 2 * FIXANG_PI;
|
|
eye_mods[1] = theta;
|
|
}
|
|
|
|
byte player_get_eye(void) {
|
|
int theta = eye_mods[1];
|
|
if (theta > FIXANG_PI)
|
|
theta -= 2 * FIXANG_PI;
|
|
return (byte)(theta * CONTROL_MAX_VAL / MAX_EYE_ANGLE);
|
|
}
|
|
|
|
void player_set_eye_fixang(int ang) {
|
|
int theta = ang;
|
|
if (abs(ang) > MAX_EYE_ANGLE)
|
|
theta = (ang < 0) ? -MAX_EYE_ANGLE : MAX_EYE_ANGLE;
|
|
player_struct.eye_pos = theta;
|
|
if (theta < 0)
|
|
theta += 2 * FIXANG_PI;
|
|
eye_mods[1] = theta;
|
|
}
|
|
|
|
int player_get_eye_fixang(void) {
|
|
int theta = eye_mods[1];
|
|
if (theta > FIXANG_PI)
|
|
theta -= 2 * FIXANG_PI;
|
|
return theta;
|
|
}
|
|
|
|
uchar eye_mouse_handler(uiEvent *ev, LGRegion *r, intptr_t data) {
|
|
short x = ev->pos.x - r->abs_x;
|
|
short y = ev->pos.y - r->abs_y;
|
|
extern uchar hack_takeover;
|
|
if (hack_takeover || global_fullmap->cyber)
|
|
return FALSE;
|
|
if (x < 0 || x >= EYEMETER_W)
|
|
return FALSE;
|
|
eye_fine_mode = 2 * x > EYEMETER_W;
|
|
if (!eye_fine_mode)
|
|
y = discrete_eye_height[y * DISCRETE_EYE_POSITIONS / EYEMETER_H];
|
|
if (ev->mouse_data.buttons & (1 << MOUSE_LBUTTON)) {
|
|
int theta;
|
|
if ((ev->mouse_data.action & MOUSE_LDOWN) == 0 && uiLastMouseRegion[MOUSE_LBUTTON] != r)
|
|
return FALSE;
|
|
if (eye_fine_mode)
|
|
theta = -2 * MAX_EYE_ANGLE * (y) / (EYEMETER_H - 1) + MAX_EYE_ANGLE;
|
|
else
|
|
theta = -FIXANG_PI / 6 * (y * DISCRETE_EYE_POSITIONS / EYEMETER_H - 1);
|
|
// ui_mouse_constrain_xy(me->pos.x,r->abs_y,me->pos.x,r->abs_y+EYEMETER_H-1);
|
|
player_set_eye_fixang(theta);
|
|
physics_set_relax(CONTROL_YZROT, FALSE);
|
|
}
|
|
if (ev->mouse_data.buttons == 0) {
|
|
// mouse_constrain_xy(0,0,grd_cap->w-1,grd_cap->h-1);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
uchar lean_mouse_handler(uiEvent *ev, LGRegion *r, intptr_t data) {
|
|
short x = ev->pos.x - r->abs_x - LEANOMETER_XOFF;
|
|
short y = ev->pos.y - r->abs_y - LEANOMETER_YOFF;
|
|
if (x < 0 || x >= LEANOMETER_W || global_fullmap->cyber)
|
|
return FALSE;
|
|
if (ev->mouse_data.buttons & (1 << MOUSE_LBUTTON)) {
|
|
short posture = y * 3 / LEANOMETER_H;
|
|
short xlean = x * 220 / (LEANOMETER_W - 1) - 110;
|
|
if ((ev->mouse_data.action & MOUSE_LDOWN) == 0 && uiLastMouseRegion[MOUSE_LBUTTON] != r)
|
|
return FALSE;
|
|
if (xlean > 10)
|
|
xlean -= 10;
|
|
else if (xlean < -10)
|
|
xlean += 10;
|
|
else
|
|
xlean = 0;
|
|
if (posture != player_struct.posture)
|
|
player_set_posture(posture);
|
|
player_set_lean(xlean, player_struct.leany);
|
|
physics_set_relax(CONTROL_XZROT, FALSE);
|
|
// ui_mouse_constrain_xy(LEANOMETER_X(),LEANOMETER_Y()+posture*LEANOMETER_H/3+1,LEANOMETER_X()+LEANOMETER_W-1,LEANOMETER_Y()+(posture+1)*LEANOMETER_H/3-1);
|
|
}
|
|
if (ev->mouse_data.buttons == 0) {
|
|
// mouse_unconstrain();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
// ---------
|
|
// EXTERNALS
|
|
// ---------
|
|
|
|
#define BAD_REGION_CRITERR 3000
|
|
|
|
void init_posture_meters(LGRegion *root, uchar fullscreen) {
|
|
LGRegion *reg = PICK_METER_REGION(fullscreen);
|
|
int id;
|
|
LGRect r = {{0, 0}, {LEANOMETER_W + LEANOMETER_XOFF, EYEMETER_H}};
|
|
errtype err;
|
|
|
|
if (fullscreen) {
|
|
RECT_MOVE(&r, MakePoint(FULL_EYEMETER_X, FULL_EYEMETER_Y));
|
|
} else {
|
|
RECT_MOVE(&r, MakePoint(SLOT_EYEMETER_X, SLOT_EYEMETER_Y));
|
|
}
|
|
err = region_create(root, reg, &r, 0, 0, REG_USER_CONTROLLED | AUTODESTROY_FLAG, NULL, NULL, NULL, NULL);
|
|
if (err != OK)
|
|
critical_error(BAD_REGION_CRITERR);
|
|
uiInstallRegionHandler(reg, UI_EVENT_MOUSE | UI_EVENT_MOUSE_MOVE, eye_mouse_handler, 0, &id);
|
|
uiInstallRegionHandler(reg, UI_EVENT_MOUSE | UI_EVENT_MOUSE_MOVE, lean_mouse_handler, 0, &id);
|
|
}
|
|
|
|
void update_lean_meter(uchar force) {
|
|
static uchar last_shield = FALSE;
|
|
static uchar last_shieldstr = 0;
|
|
static int last_lean_icon = -1;
|
|
static LGPoint last_lean_pos = {-1, -1};
|
|
|
|
LGRect r;
|
|
LGPoint pos;
|
|
short a, b, c, d;
|
|
grs_bitmap *icon;
|
|
int inum;
|
|
bool shield = WareActive(player_struct.hardwarez_status[CPTRIP(SHIELD_HARD_TRIPLE)]) != 0;
|
|
// int shieldstr = SHIELD_SETTING(player_struct.hardwarez_status[CPTRIP(SHIELD_HARD_TRIPLE)]);
|
|
int shieldstr;
|
|
char saveMode;
|
|
bool saveBio;
|
|
|
|
// if(player_struct.hardwarez[CPTRIP(SHIELD_HARD_TRIPLE)]==SHIELD_VERSIONS)
|
|
// shieldstr=SHIELD_VERSIONS-1;
|
|
|
|
current_meter_region = PICK_METER_REGION(full_game_3d);
|
|
set_base_lean_bmap(shield);
|
|
lean_icon(&pos, &icon, &inum);
|
|
|
|
if (shield_bmap_res > 0)
|
|
shieldstr = shield_bmap_res - RES_leanShield1;
|
|
else
|
|
shieldstr = 0;
|
|
|
|
// If this is not a force update, and we're drawing the same lean icon in the same position as last
|
|
// time, then do nothing.
|
|
if (!force && PointsEqual(pos, last_lean_pos) && MKREF(lean_bmap_res, inum) == last_lean_icon
|
|
&& shield == last_shield && shieldstr == last_shieldstr)
|
|
return;
|
|
|
|
STORE_CLIP(a, b, c, d);
|
|
ss_safe_set_cliprect(LEANOMETER_X(), LEANOMETER_Y(), LEANOMETER_X() + LEANOMETER_W, LEANOMETER_Y() + LEANOMETER_H);
|
|
|
|
saveBio = gBioInited; // Turn off biometer while updating the lean meter.
|
|
gBioInited = FALSE;
|
|
|
|
if (force || last_lean_icon != -1) {
|
|
RECT_FILL(&r, LEANOMETER_X(), LEANOMETER_Y(), LEANOMETER_X() + 46, LEANOMETER_Y() + 53);
|
|
undraw_meter_area(&r);
|
|
}
|
|
RECT_FILL(&r, pos.x, pos.y, pos.x + icon->w, pos.y + icon->h);
|
|
|
|
// saveMode = convert_use_mode;
|
|
// convert_use_mode = 0;
|
|
|
|
if (is_onscreen())
|
|
uiHideMouse(&r);
|
|
ss_bitmap(icon, r.ul.x, r.ul.y);
|
|
|
|
if (shield) {
|
|
grs_bitmap *sbm;
|
|
|
|
// Get a pointer to the corresponding lean bitmap.
|
|
FrameDesc *f = RefGet(MKREF(shield_bmap_res, inum));
|
|
if (f != NULL) {
|
|
f->bm.bits = (uint8_t *)(f + 1);
|
|
sbm = &(f->bm);
|
|
} else
|
|
DEBUG("%s: No shield resource bitmap!", __FUNCTION__);
|
|
|
|
// Place shield image with offset
|
|
ss_bitmap(sbm, r.ul.x - shield_offsets[inum].x, r.ul.y - shield_offsets[inum].y);
|
|
}
|
|
|
|
gBioInited = saveBio;
|
|
|
|
if (is_onscreen())
|
|
uiShowMouse(&r);
|
|
// convert_use_mode = saveMode;
|
|
|
|
last_lean_pos = pos;
|
|
last_lean_icon = MKREF(lean_bmap_res, inum);
|
|
last_shield = shield;
|
|
last_shieldstr = shieldstr;
|
|
RESTORE_CLIP(a, b, c, d);
|
|
}
|
|
|
|
void draw_eye_bitmap(grs_bitmap *eye_bmap, LGPoint pos, int lasty) {
|
|
LGRect r;
|
|
char saveMode;
|
|
|
|
current_meter_region = PICK_METER_REGION(full_game_3d);
|
|
pos.x += EYEMETER_X();
|
|
pos.y += EYEMETER_Y();
|
|
r.ul = pos;
|
|
r.lr.x = pos.x + eye_bmap->w;
|
|
r.ul.y = lasty;
|
|
r.lr.y = lasty + eye_bmap->h + 1;
|
|
undraw_meter_area(&r);
|
|
r.ul.y = pos.y;
|
|
r.lr.y = pos.y + eye_bmap->h;
|
|
|
|
// saveMode = convert_use_mode;
|
|
// convert_use_mode = 0;
|
|
if (is_onscreen())
|
|
uiHideMouse(&r);
|
|
ss_bitmap(eye_bmap, r.ul.x, r.ul.y);
|
|
if (is_onscreen())
|
|
uiShowMouse(&r);
|
|
// convert_use_mode = saveMode;
|
|
}
|
|
|
|
#define HIRES_EYEMETER_H 53
|
|
|
|
void update_eye_meter(uchar force) {
|
|
static short last_y = 0;
|
|
static short last_ly = 0;
|
|
static uchar last_mode = FALSE;
|
|
|
|
short a, b, c, d;
|
|
fix pos = eye_mods[1];
|
|
int yang = pos % (2 * FIXANG_PI);
|
|
short y;
|
|
short lefty;
|
|
grs_bitmap *eye_rbmap = eye_bmap_r(!eye_fine_mode);
|
|
grs_bitmap *eye_lbmap = eye_bmap_l(eye_fine_mode);
|
|
bool saveBio;
|
|
|
|
if (yang > FIXANG_PI)
|
|
yang -= 2 * FIXANG_PI;
|
|
y = -(EYEMETER_H * yang / (2 * MAX_EYE_ANGLE));
|
|
|
|
// Hey, let's take gruesome advantange of the fact that
|
|
// booleans are zero or one.
|
|
lefty = discrete_eye_height[1 + (yang < 0) - (yang > 0)];
|
|
lefty -= (eye_lbmap->h) / 2;
|
|
y += EYEMETER_H / 2 - 2 - (eye_rbmap->h / 2) / 2;
|
|
|
|
if (!force && y == last_y && lefty == last_ly && eye_fine_mode == last_mode)
|
|
return;
|
|
STORE_CLIP(a, b, c, d);
|
|
ss_safe_set_cliprect(EYEMETER_X(), EYEMETER_Y(), EYEMETER_X() + EYEMETER_W, EYEMETER_Y() + EYEMETER_H);
|
|
|
|
saveBio = gBioInited; // Turn off biometer while updating the eye meter.
|
|
gBioInited = FALSE;
|
|
|
|
if (force) {
|
|
LGRect r = {{0, 0}, {46, 53}};
|
|
RECT_MOVE(&r, MakePoint(EYEMETER_X(), EYEMETER_Y()));
|
|
undraw_meter_area(&r);
|
|
}
|
|
draw_eye_bitmap(eye_lbmap, MakePoint(2, lefty), last_ly);
|
|
draw_eye_bitmap(eye_rbmap, MakePoint(19 - eye_rbmap->w, y), last_y);
|
|
|
|
gBioInited = saveBio;
|
|
|
|
RESTORE_CLIP(a, b, c, d);
|
|
last_y = y;
|
|
last_ly = lefty;
|
|
last_mode = eye_fine_mode;
|
|
}
|
|
|
|
void update_meters(uchar force) {
|
|
current_meter_region = PICK_METER_REGION(full_game_3d);
|
|
update_eye_meter(force);
|
|
update_lean_meter(force);
|
|
}
|
|
|
|
void zoom_to_lean_meter(void) {
|
|
extern bool DoubleSize;
|
|
|
|
LGPoint pos;
|
|
LGRect start = {{-5, -5}, {+5, +5}};
|
|
LGRect end = {{0, 0}, {LEANOMETER_W, LEANOMETER_H}};
|
|
|
|
current_meter_region = PICK_METER_REGION(full_game_3d);
|
|
RECT_MOVE(&end, MakePoint(LEANOMETER_X(), LEANOMETER_Y()));
|
|
mouse_get_xy(&pos.x, &pos.y);
|
|
if (!DoubleSize)
|
|
ss_point_convert(&(pos.x), &(pos.y), TRUE);
|
|
RECT_MOVE(&start, pos);
|
|
zoom_rect(&start, &end);
|
|
}
|