2019-08-10 11:43:24 +00:00
// Hyperbolic Rogue -- map editor and vector graphics editor
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
/** \file mapedit.cpp
* \ brief HyperRogue editors ( map and vector graphics )
*/
2016-08-26 09:58:03 +00:00
2019-09-05 07:15:40 +00:00
# include "hyper.h"
2018-06-10 23:58:31 +00:00
namespace hr {
2019-08-09 23:15:41 +00:00
EX namespace mapeditor {
2020-04-17 18:04:33 +00:00
EX bool drawing_tool ;
2019-08-09 23:15:41 +00:00
# if HDR
enum eShapegroup { sgPlayer , sgMonster , sgItem , sgFloor , sgWall } ;
static const int USERSHAPEGROUPS = 5 ;
# endif
2020-04-17 18:04:33 +00:00
2020-04-18 14:10:56 +00:00
EX color_t dtfill = 0 ;
EX color_t dtcolor = 0x000000FF ;
EX ld dtwidth = .02 ;
2017-04-15 02:48:59 +00:00
2020-04-17 18:04:33 +00:00
/* drawing_tool shapes */
struct dtshape {
cell * where ;
color_t col , fill ;
ld lw ;
virtual void rotate ( const transmatrix & T ) = 0 ;
virtual void save ( hstream & hs ) = 0 ;
virtual dtshape * load ( hstream & hs ) = 0 ;
2020-07-27 16:49:04 +00:00
virtual void draw ( const shiftmatrix & V ) = 0 ;
2020-04-17 18:04:33 +00:00
virtual ld distance ( hyperpoint h ) = 0 ;
2020-04-18 12:32:54 +00:00
virtual ~ dtshape ( ) { }
2020-04-17 18:04:33 +00:00
} ;
struct dtline : dtshape {
hyperpoint s , e ;
void rotate ( const transmatrix & T ) override {
s = T * s ;
e = T * e ;
}
void save ( hstream & hs ) override {
hs . write < char > ( 1 ) ;
hs . write ( s ) ;
hs . write ( e ) ;
}
dtshape * load ( hstream & hs ) override {
hs . read ( s ) ;
hs . read ( e ) ;
return this ;
}
2020-07-27 16:49:04 +00:00
void draw ( const shiftmatrix & V ) override {
2020-04-17 18:04:33 +00:00
queueline ( V * s , V * e , col , 2 + vid . linequality ) ;
}
ld distance ( hyperpoint h ) override {
return hdist ( s , h ) + hdist ( e , h ) - hdist ( s , e ) ;
}
} ;
struct dtcircle : dtshape {
hyperpoint s ; ld radius ;
void rotate ( const transmatrix & T ) override {
s = T * s ;
}
void save ( hstream & hs ) override {
hs . write < char > ( 2 ) ;
hs . write ( s ) ;
hs . write ( radius ) ;
}
dtshape * load ( hstream & hs ) override {
hs . read ( s ) ;
hs . read ( radius ) ;
return this ;
}
2020-07-27 16:49:04 +00:00
void draw ( const shiftmatrix & V ) override {
2020-04-17 18:04:33 +00:00
ld len = sin_auto ( radius ) ;
int ll = ceil ( 360 * len ) ;
2020-07-27 16:49:04 +00:00
shiftmatrix W = V * rgpushxto0 ( s ) ;
2020-04-17 18:04:33 +00:00
for ( int i = 0 ; i < = ll ; i + + )
2020-07-27 16:49:04 +00:00
curvepoint ( xspinpush0 ( 360 * degree * i / ll , radius ) ) ;
queuecurve ( W , col , fill , PPR : : LINE ) ;
2020-04-17 18:04:33 +00:00
}
ld distance ( hyperpoint h ) override {
return abs ( hdist ( s , h ) - radius ) ;
}
} ;
2020-04-26 09:01:45 +00:00
struct dttext : dtshape {
hyperpoint where ;
ld size ;
string caption ;
void rotate ( const transmatrix & T ) override {
where = T * where ;
}
void save ( hstream & hs ) override {
hs . write < char > ( 4 ) ;
hs . write ( where ) ;
hs . write ( size ) ;
hs . write ( caption ) ;
}
dtshape * load ( hstream & hs ) override {
hs . read ( where ) ;
hs . read ( size ) ;
hs . read ( caption ) ;
return this ;
}
2020-07-27 16:49:04 +00:00
void draw ( const shiftmatrix & V ) override {
2020-04-26 09:01:45 +00:00
queuestr ( V * rgpushxto0 ( where ) , size , caption , col ) ;
}
ld distance ( hyperpoint h ) override {
return hdist ( h , where ) ;
}
} ;
2020-04-17 18:04:33 +00:00
struct dtfree : dtshape {
vector < hyperpoint > lh ;
void rotate ( const transmatrix & T ) override {
for ( auto & h : lh ) h = T * h ;
}
void save ( hstream & hs ) override {
hs . write < char > ( 3 ) ;
hs . write ( lh ) ;
}
dtshape * load ( hstream & hs ) override {
hs . read ( lh ) ;
return this ;
}
2020-07-27 16:49:04 +00:00
void draw ( const shiftmatrix & V ) override {
for ( auto & p : lh ) curvepoint ( p ) ;
queuecurve ( V , col , fill , PPR : : LINE ) ;
2020-04-17 18:04:33 +00:00
}
ld distance ( hyperpoint h ) override {
ld mind = 99 ;
for ( auto h1 : lh ) mind = min ( mind , hdist ( h , h1 ) ) ;
return mind ;
}
} ;
vector < unique_ptr < dtshape > > dtshapes ;
2020-05-01 10:27:49 +00:00
EX void clear_dtshapes ( ) { dtshapes . clear ( ) ; }
2020-04-17 18:04:33 +00:00
EX void draw_dtshapes ( ) {
for ( auto & shp : dtshapes ) {
if ( shp = = nullptr ) continue ;
auto & sh = * shp ;
cell * & c = sh . where ;
2020-07-27 16:49:04 +00:00
for ( const shiftmatrix & V : current_display - > all_drawn_copies [ c ] ) {
2020-04-17 18:04:33 +00:00
dynamicval < ld > lw ( vid . linewidth , vid . linewidth * sh . lw ) ;
sh . draw ( V ) ;
}
}
2020-04-17 18:34:49 +00:00
if ( drawing_tool & & ( cmode & sm : : DRAW ) ) {
2020-04-18 14:10:56 +00:00
dynamicval < ld > lw ( vid . linewidth , vid . linewidth * dtwidth * 100 ) ;
2020-04-17 18:34:49 +00:00
if ( holdmouse & & mousekey = = ' c ' )
queue_hcircle ( rgpushxto0 ( lstart ) , hdist ( lstart , mouseh ) ) ;
else if ( holdmouse & & mousekey = = ' l ' )
2020-04-18 14:10:56 +00:00
queueline ( lstart , mouseh , dtcolor , 4 + vid . linequality , PPR : : LINE ) ;
2020-04-17 18:34:49 +00:00
else if ( ! holdmouse ) {
2020-07-27 16:49:04 +00:00
shiftmatrix T = rgpushxto0 ( mouseh ) ;
2020-04-18 14:10:56 +00:00
queueline ( T * xpush0 ( - .1 ) , T * xpush0 ( .1 ) , dtcolor ) ;
queueline ( T * ypush0 ( - .1 ) , T * ypush0 ( .1 ) , dtcolor ) ;
2020-04-17 18:34:49 +00:00
}
}
2020-04-17 18:04:33 +00:00
}
/** dtshapes takes ownership of sh */
void dt_add ( cell * where , dtshape * sh ) {
sh - > where = where ;
2020-04-18 14:10:56 +00:00
sh - > col = dtcolor ;
2020-04-17 18:04:33 +00:00
sh - > fill = dtfill ;
2020-04-18 14:10:56 +00:00
sh - > lw = dtwidth * 100 ;
2020-04-17 18:04:33 +00:00
dtshapes . push_back ( unique_ptr < dtshape > ( sh ) ) ;
}
2020-07-27 16:49:04 +00:00
EX void dt_add_line ( shiftpoint h1 , shiftpoint h2 , int maxl ) {
2020-04-17 18:04:33 +00:00
if ( hdist ( h1 , h2 ) > 1 & & maxl > 0 ) {
2020-07-27 16:49:04 +00:00
shiftpoint h3 = mid ( h1 , h2 ) ;
2020-04-17 18:04:33 +00:00
dt_add_line ( h1 , h3 , maxl - 1 ) ;
dt_add_line ( h3 , h2 , maxl - 1 ) ;
return ;
}
cell * b = centerover ;
2020-07-27 16:49:04 +00:00
auto xh1 = inverse_shift ( ggmatrix ( b ) , h1 ) ;
virtualRebase ( b , xh1 ) ;
2020-04-17 18:04:33 +00:00
auto l = new dtline ;
2020-07-27 16:49:04 +00:00
l - > s = xh1 ;
l - > e = inverse_shift ( ggmatrix ( b ) , h2 ) ;
2020-04-17 18:04:33 +00:00
dt_add ( b , l ) ;
}
2020-07-27 16:49:04 +00:00
EX void dt_add_circle ( shiftpoint h1 , shiftpoint h2 ) {
2020-04-17 18:04:33 +00:00
cell * b = centerover ;
auto d = hdist ( h1 , h2 ) ;
2020-07-27 16:49:04 +00:00
auto xh1 = inverse_shift ( ggmatrix ( b ) , h1 ) ;
virtualRebase ( b , xh1 ) ;
2020-04-17 18:04:33 +00:00
auto l = new dtcircle ;
2020-07-27 16:49:04 +00:00
l - > s = xh1 ;
2020-04-17 18:04:33 +00:00
l - > radius = d ;
dt_add ( b , l ) ;
}
2020-07-27 16:49:04 +00:00
EX void dt_add_text ( shiftpoint h , ld size , string cap ) {
2020-04-26 09:01:45 +00:00
cell * b = centerover ;
2020-07-27 16:49:04 +00:00
auto xh = inverse_shift ( ggmatrix ( b ) , h ) ;
virtualRebase ( b , xh ) ;
2020-04-26 09:01:45 +00:00
auto l = new dttext ;
2020-07-27 16:49:04 +00:00
l - > where = xh ;
2020-04-26 09:01:45 +00:00
l - > size = size ;
l - > caption = cap ;
dt_add ( b , l ) ;
2020-07-12 19:26:15 +00:00
l - > col > > = 8 ;
2020-04-26 09:01:45 +00:00
}
2020-04-17 18:04:33 +00:00
dtshape * load_shape ( hstream & hs ) {
char type = hs . get < char > ( ) ;
switch ( type ) {
case 1 :
return ( new dtline ) - > load ( hs ) ;
case 2 :
return ( new dtcircle ) - > load ( hs ) ;
case 3 :
return ( new dtfree ) - > load ( hs ) ;
2020-07-12 19:39:02 +00:00
case 4 :
return ( new dttext ) - > load ( hs ) ;
2020-04-17 18:04:33 +00:00
default :
return nullptr ;
}
}
dtfree * cfree ;
cell * cfree_at ;
transmatrix cfree_T ;
2020-07-27 16:49:04 +00:00
EX void dt_add_free ( shiftpoint h ) {
2017-04-15 02:48:59 +00:00
2020-04-17 18:04:33 +00:00
cell * b = centerover ;
2020-07-27 16:49:04 +00:00
shiftmatrix T = rgpushxto0 ( h ) ;
auto T1 = inverse_shift ( ggmatrix ( b ) , T ) ;
2020-04-17 18:04:33 +00:00
virtualRebase ( b , T1 ) ;
if ( cfree )
2020-07-27 16:49:04 +00:00
cfree - > lh . push_back ( cfree_T * h . h ) ;
2020-04-17 18:04:33 +00:00
if ( b ! = cfree_at & & ! ( dtfill & & cfree_at ) ) {
cfree = new dtfree ;
dt_add ( b , cfree ) ;
2020-07-27 16:49:04 +00:00
cfree_T = T1 * gpushxto0 ( h . h ) ;
cfree - > lh . push_back ( cfree_T * h . h ) ;
2020-04-17 18:04:33 +00:00
cfree_at = b ;
}
}
2020-07-27 16:49:04 +00:00
EX void dt_erase ( shiftpoint h ) {
2020-04-17 18:04:33 +00:00
ld nearest = 1 ;
int nearest_id = - 1 ;
int id = - 1 ;
for ( auto & shp : dtshapes ) {
id + + ;
if ( shp = = nullptr ) continue ;
auto & sh = * shp ;
cell * & c = sh . where ;
2020-07-27 16:49:04 +00:00
for ( const shiftmatrix & V : current_display - > all_drawn_copies [ c ] ) {
ld dist = sh . distance ( inverse_shift ( V , h ) ) ;
2020-04-17 18:04:33 +00:00
if ( dist < nearest ) nearest = dist , nearest_id = id ;
}
}
if ( nearest_id > = 0 )
dtshapes . erase ( dtshapes . begin ( ) + nearest_id ) ;
}
2020-07-27 16:49:04 +00:00
EX shiftpoint lstart ;
2019-02-08 16:08:00 +00:00
cell * lstartcell ;
2019-02-28 16:49:57 +00:00
ld front_edit = 0.5 ;
2019-08-10 20:33:20 +00:00
enum class eFront { sphere_camera , sphere_center , equidistants , const_x , const_y } ;
2019-05-15 15:38:49 +00:00
eFront front_config ;
ld front_step = 0.1 ;
2019-02-08 16:08:00 +00:00
2019-09-06 06:17:02 +00:00
# if HDR
2017-06-18 16:52:15 +00:00
struct editwhat {
double dist ;
int rotid , symid , pointid ;
bool side ;
cell * c ;
2019-09-06 06:17:02 +00:00
} ;
# endif
EX editwhat ew , ewsearch ;
EX bool autochoose = ISMOBILE ;
2017-06-18 16:52:15 +00:00
2020-04-19 20:43:16 +00:00
EX void scaleall ( ld z , bool keep_mouse ) {
2018-02-03 13:31:17 +00:00
2020-04-19 20:43:16 +00:00
if ( keep_mouse ) {
ld mrx = ( .0 + mousex - current_display - > xcenter ) / vpconf . scale ;
ld mry = ( .0 + mousey - current_display - > ycenter ) / vpconf . scale ;
if ( vid . xres > vid . yres ) {
vpconf . xposition + = ( vpconf . scale - vpconf . scale * z ) * mrx / current_display - > scrsize ;
vpconf . yposition + = ( vpconf . scale - vpconf . scale * z ) * mry / current_display - > scrsize ;
}
2018-02-03 13:31:17 +00:00
}
2020-04-16 22:53:58 +00:00
vpconf . scale * = z ;
// printf("scale = " LDF "\n", vpconf.scale);
2018-02-03 13:31:17 +00:00
# if CAP_TEXTURE
2018-02-13 22:25:44 +00:00
// display(texture::itt);
2018-03-17 20:12:46 +00:00
texture : : config . itt = xyscale ( texture : : config . itt , 1 / z ) ;
if ( false & & texture : : config . tstate ) {
2018-02-03 13:31:17 +00:00
calcparam ( ) ;
2018-03-17 20:12:46 +00:00
texture : : config . perform_mapping ( ) ;
if ( texture : : config . tstate = = texture : : tsAdjusting )
texture : : config . finish_mapping ( ) ;
2018-02-03 13:31:17 +00:00
}
# endif
}
2017-07-22 23:33:27 +00:00
# if CAP_EDIT
2019-08-09 23:15:41 +00:00
EX map < int , cell * > modelcell ;
2017-07-10 18:47:38 +00:00
void handleKeyMap ( int sym , int uni ) ;
2019-08-09 23:15:41 +00:00
EX void applyModelcell ( cell * c ) {
2017-12-09 02:48:30 +00:00
if ( patterns : : whichPattern = = ' H ' ) return ;
2017-12-09 07:06:41 +00:00
auto si = patterns : : getpatterninfo0 ( c ) ;
cell * c2 = modelcell [ si . id ] ;
2016-08-26 09:58:03 +00:00
if ( c2 ) {
c - > wall = c2 - > wall ;
c - > land = c2 - > land ;
c - > monst = c2 - > monst ;
c - > item = c2 - > item ;
c - > landparam = c2 - > landparam ;
c - > wparam = c2 - > wparam ;
c - > mondir = c2 - > mondir ;
2017-11-12 23:37:18 +00:00
c - > stuntime = c2 - > stuntime ;
c - > hitpoints = c2 - > hitpoints ;
2017-12-09 07:06:41 +00:00
if ( c2 - > mondir ! = NODIR ) {
auto si2 = patterns : : getpatterninfo0 ( c2 ) ;
2020-01-18 15:03:32 +00:00
c - > mondir = gmod ( c2 - > mondir - si2 . dir + si . dir , c - > type ) ;
2017-12-09 07:06:41 +00:00
// todo reflect
}
2016-08-26 09:58:03 +00:00
}
}
# endif
}
2018-09-07 13:15:00 +00:00
namespace mapstream {
# if CAP_EDIT
2018-11-24 16:01:49 +00:00
2016-08-26 09:58:03 +00:00
std : : map < cell * , int > cellids ;
vector < cell * > cellbyid ;
vector < char > relspin ;
2020-04-17 18:04:33 +00:00
void load_drawing_tool ( fhstream & hs ) {
using namespace mapeditor ;
if ( hs . vernum < 0xA82A ) return ;
int i = hs . get < int > ( ) ;
while ( i - - ) {
auto sh = load_shape ( hs ) ;
if ( ! sh ) continue ;
hs . read ( sh - > col ) ;
hs . read ( sh - > fill ) ;
hs . read ( sh - > lw ) ;
int id = hs . get < int > ( ) ;
sh - > where = cellbyid [ id ] ;
sh - > rotate ( spin ( currentmap - > spin_angle ( sh - > where , relspin [ id ] ) - currentmap - > spin_angle ( sh - > where , 0 ) ) ) ;
dtshapes . push_back ( unique_ptr < dtshape > ( sh ) ) ;
}
}
void save_drawing_tool ( hstream & hs ) {
using namespace mapeditor ;
hs . write < int > ( isize ( dtshapes ) ) ;
for ( auto & shp : dtshapes ) {
if ( shp = = nullptr ) { hs . write < char > ( 0 ) ; }
else {
auto & sh = * shp ;
sh . save ( hs ) ;
hs . write ( sh . col ) ;
hs . write ( sh . fill ) ;
hs . write ( sh . lw ) ;
hs . write ( cellids [ sh . where ] ) ;
}
}
}
2016-08-26 09:58:03 +00:00
void addToQueue ( cell * c ) {
if ( cellids . count ( c ) ) return ;
2018-06-22 12:47:24 +00:00
int numcells = isize ( cellbyid ) ;
2016-08-26 09:58:03 +00:00
cellbyid . push_back ( c ) ;
cellids [ c ] = numcells ;
}
2019-05-29 13:53:13 +00:00
int fixspin ( int rspin , int dir , int t , int vernum ) {
if ( vernum < 11018 & & dir = = 14 )
return NODIR ;
else if ( vernum < 11018 & & dir = = 15 )
return NOBARRIERS ;
else if ( dir > = 0 & & dir < t )
return ( dir + rspin ) % t ;
else
return dir ;
}
2019-11-23 20:08:47 +00:00
void save_geometry ( fhstream & f ) {
2018-11-24 16:01:49 +00:00
f . write ( geometry ) ;
2018-08-28 15:17:34 +00:00
char nbtype = char ( variation ) ;
2018-11-24 16:01:49 +00:00
f . write ( nbtype ) ;
2019-02-26 13:56:26 +00:00
# if CAP_GP
2020-07-28 11:18:06 +00:00
if ( GOLDBERG | | INVERSE ) {
2018-11-24 16:01:49 +00:00
f . write ( gp : : param . first ) ;
f . write ( gp : : param . second ) ;
2018-04-10 22:30:50 +00:00
}
2019-02-26 13:56:26 +00:00
# endif
# if CAP_FIELD
2018-06-21 23:48:46 +00:00
if ( geometry = = gFieldQuotient ) {
2017-11-07 13:08:50 +00:00
using namespace fieldpattern ;
2018-11-24 16:01:49 +00:00
f . write ( quotient_field_changed ) ;
2017-11-07 13:08:50 +00:00
if ( quotient_field_changed ) {
2018-11-24 16:01:49 +00:00
f . write ( current_extra ) ;
f . write ( fgeomextras [ current_extra ] . current_prime_id ) ;
2017-11-07 13:08:50 +00:00
}
}
2019-02-26 13:56:26 +00:00
# endif
# if CAP_CRYSTAL
2019-08-22 10:14:39 +00:00
if ( cryst ) {
2018-12-14 18:26:03 +00:00
f . write ( ginf [ gCrystal ] . sides ) ;
if ( ginf [ gCrystal ] . sides = = 8 )
2018-12-15 13:16:57 +00:00
f . write ( ginf [ gCrystal ] . vertex ) ;
2018-12-14 18:26:03 +00:00
}
2019-02-26 13:56:26 +00:00
# endif
# if CAP_ARCM
2018-11-24 16:01:49 +00:00
if ( geometry = = gArchimedean ) f . write ( arcm : : current . symbol ) ;
2019-02-26 13:56:26 +00:00
# endif
2020-03-22 08:48:24 +00:00
if ( geometry = = gNil ) {
2019-11-23 20:08:47 +00:00
f . write ( S7 ) ;
f . write ( nilv : : nilperiod ) ;
}
2020-03-22 08:48:24 +00:00
if ( geometry = = gArnoldCat ) {
2019-11-23 20:08:47 +00:00
f . write ( asonov : : period_xy ) ;
f . write ( asonov : : period_z ) ;
}
2020-07-24 00:30:50 +00:00
if ( prod ) {
f . write ( hybrid : : csteps ) ;
2019-11-30 10:22:33 +00:00
f . write ( product : : cspin ) ;
2020-07-24 00:30:50 +00:00
f . write ( product : : cmirror ) ;
}
if ( rotspace ) {
f . write ( hybrid : : csteps ) ;
2019-11-23 20:08:47 +00:00
}
2020-03-22 08:48:24 +00:00
if ( hybri ) {
2019-11-23 20:08:47 +00:00
hybrid : : in_underlying_geometry ( [ & ] { save_geometry ( f ) ; } ) ;
}
2020-03-22 08:48:24 +00:00
if ( bt : : in ( ) )
2019-11-23 20:08:47 +00:00
f . write ( vid . binary_width ) ;
2019-12-14 10:26:03 +00:00
if ( euc : : in ( ) ) {
2019-12-08 09:59:09 +00:00
f . write ( euc : : eu_input . user_axes ) ;
f . write ( euc : : eu_input . twisted ) ;
2019-11-27 21:04:41 +00:00
}
2019-12-27 10:57:23 +00:00
f . write ( mine_adjacency_rule ) ;
2019-11-23 20:08:47 +00:00
}
void load_geometry ( fhstream & f ) {
f . read ( geometry ) ;
char nbtype ;
f . read ( nbtype ) ;
variation = eVariation ( nbtype ) ;
# if CAP_GP
2020-07-28 11:18:06 +00:00
if ( GOLDBERG | | INVERSE ) {
2019-11-23 20:08:47 +00:00
f . read ( gp : : param . first ) ;
f . read ( gp : : param . second ) ;
}
# endif
# if CAP_CRYSTAL
if ( cryst & & f . vernum > = 10504 ) {
int sides ;
f . read ( sides ) ;
# if CAP_CRYSTAL
crystal : : set_crystal ( sides ) ;
# endif
if ( sides = = 8 ) {
int vertices ;
eVariation v = variation ;
f . read ( vertices ) ;
if ( vertices = = 3 ) {
set_variation ( eVariation : : bitruncated ) ;
set_variation ( v ) ;
}
}
}
# endif
# if CAP_FIELD
if ( geometry = = gFieldQuotient ) {
using namespace fieldpattern ;
f . read ( quotient_field_changed ) ;
if ( quotient_field_changed ) {
f . read ( current_extra ) ;
auto & ge = fgeomextras [ current_extra ] ;
auto & id = ge . current_prime_id ;
f . read ( id ) ;
2020-03-22 08:48:24 +00:00
if ( f . vernum < 0xA80C ) switch ( ge . base ) {
2019-11-23 20:08:47 +00:00
case gNormal : id + + ; break ;
case g45 : id + + ; break ;
case g46 : id + = 2 ; break ;
case g47 : id + + ; break ;
default : ;
}
enableFieldChange ( ) ;
}
}
# endif
# if CAP_ARCM
if ( geometry = = gArchimedean ) {
string & symbol = arcm : : current . symbol ;
symbol = f . get < string > ( ) ;
arcm : : current . parse ( ) ;
if ( arcm : : current . errors > 0 ) {
printf ( " Errors! %s \n " , arcm : : current . errormsg . c_str ( ) ) ;
}
}
# endif
2020-03-22 08:48:24 +00:00
if ( geometry = = gNil & & f . vernum > = 0xA80C ) {
2019-11-23 20:08:47 +00:00
f . read ( S7 ) ;
f . read ( nilv : : nilperiod ) ;
nilv : : set_flags ( ) ;
}
2020-03-22 08:48:24 +00:00
if ( geometry = = gArnoldCat & & f . vernum > = 0xA80C ) {
2019-11-23 20:08:47 +00:00
f . read ( asonov : : period_xy ) ;
f . read ( asonov : : period_z ) ;
asonov : : set_flags ( ) ;
}
2020-03-22 08:48:24 +00:00
if ( geometry = = gProduct & & f . vernum > = 0xA80C ) {
2020-07-24 00:30:50 +00:00
f . read ( hybrid : : csteps ) ;
2020-03-22 08:48:24 +00:00
if ( f . vernum > = 0xA80D ) f . read ( product : : cspin ) ;
2020-07-24 00:30:50 +00:00
if ( f . vernum > = 0xA833 ) f . read ( product : : cmirror ) ;
}
if ( geometry = = gRotSpace & & f . vernum > = 0xA833 ) {
f . read ( hybrid : : csteps ) ;
2019-11-23 20:08:47 +00:00
}
2020-03-22 08:48:24 +00:00
if ( hybri & & f . vernum > = 0xA80C ) {
2019-11-23 20:08:47 +00:00
auto g = geometry ;
load_geometry ( f ) ;
2019-11-23 22:09:06 +00:00
set_geometry ( g ) ;
2019-11-23 20:08:47 +00:00
}
2020-03-22 08:48:24 +00:00
if ( bt : : in ( ) & & f . vernum > = 0xA80C )
2019-11-23 20:08:47 +00:00
f . read ( vid . binary_width ) ;
2020-03-22 08:48:24 +00:00
if ( euc : : in ( ) & & f . vernum > = 0xA80D ) {
2019-12-08 09:59:09 +00:00
f . read ( euc : : eu_input . user_axes ) ;
f . read ( euc : : eu_input . twisted ) ;
2019-11-27 21:04:41 +00:00
}
2020-03-22 08:48:24 +00:00
if ( f . vernum > = 0xA810 )
2019-12-27 10:57:23 +00:00
f . read ( mine_adjacency_rule ) ;
2019-11-23 20:08:47 +00:00
}
void save_only_map ( fhstream & f ) {
f . write ( patterns : : whichPattern ) ;
save_geometry ( f ) ;
2018-12-24 14:10:52 +00:00
// game settings
f . write ( safety ) ;
f . write ( autocheat ) ;
f . write ( gen_wandering ) ;
f . write ( reptilecheat ) ;
f . write ( timerghost ) ;
f . write ( patterns : : canvasback ) ;
f . write ( patterns : : whichShape ) ;
f . write ( patterns : : subpattern_flags ) ;
f . write ( patterns : : whichCanvas ) ;
f . write ( patterns : : displaycodes ) ;
2020-01-28 15:42:07 +00:00
f . write ( canvas_default_wall ) ;
2018-12-24 14:10:52 +00:00
f . write ( mapeditor : : drawplayer ) ;
2019-02-06 16:24:03 +00:00
if ( patterns : : whichCanvas = = ' f ' ) f . write ( patterns : : color_formula ) ;
2018-12-24 14:10:52 +00:00
{
int i = ittypes ; f . write ( i ) ;
for ( int k = 0 ; k < i ; k + + ) f . write ( items [ k ] ) ;
i = motypes ; f . write ( i ) ;
for ( int k = 0 ; k < i ; k + + ) f . write ( kills [ k ] ) ;
}
2019-12-14 10:42:16 +00:00
addToQueue ( ( bounded | | euclid | | prod | | arcm : : in ( ) ) ? currentmap - > gamestart ( ) : cwt . at - > master - > c7 ) ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( cellbyid ) ; i + + ) {
2016-08-26 09:58:03 +00:00
cell * c = cellbyid [ i ] ;
if ( i ) {
2018-08-17 22:46:45 +00:00
for ( int j = 0 ; j < c - > type ; j + + ) if ( c - > move ( j ) & & cellids . count ( c - > move ( j ) ) & &
cellids [ c - > move ( j ) ] < i ) {
int32_t i = cellids [ c - > move ( j ) ] ;
2018-11-24 16:01:49 +00:00
f . write ( i ) ;
f . write_char ( c - > c . spin ( j ) ) ;
f . write_char ( j ) ;
2016-08-26 09:58:03 +00:00
break ;
}
}
2018-11-24 16:01:49 +00:00
f . write_char ( c - > land ) ;
f . write_char ( c - > mondir ) ;
f . write_char ( c - > monst ) ;
2019-01-16 23:48:55 +00:00
if ( c - > monst = = moTortoise )
f . write ( tortoise : : emap [ c ] = tortoise : : getb ( c ) ) ;
2018-11-24 16:01:49 +00:00
f . write_char ( c - > wall ) ;
// f.write_char(c->barleft);
// f.write_char(c->barright);
f . write_char ( c - > item ) ;
2019-01-16 23:48:55 +00:00
if ( c - > item = = itBabyTortoise )
f . write ( tortoise : : babymap [ c ] ) ;
2018-11-24 16:01:49 +00:00
f . write_char ( c - > mpdist ) ;
// f.write_char(c->bardir);
f . write ( c - > wparam ) ; f . write ( c - > landparam ) ;
f . write_char ( c - > stuntime ) ; f . write_char ( c - > hitpoints ) ;
2016-08-26 09:58:03 +00:00
for ( int j = 0 ; j < c - > type ; j + + ) {
2018-08-17 22:46:45 +00:00
cell * c2 = c - > move ( j ) ;
2016-08-26 09:58:03 +00:00
if ( c2 & & c2 - > land ! = laNone ) addToQueue ( c2 ) ;
}
}
2018-06-22 12:47:24 +00:00
printf ( " cells saved = %d \n " , isize ( cellbyid ) ) ;
2018-11-24 16:01:49 +00:00
int32_t n = - 1 ; f . write ( n ) ;
2018-08-17 22:46:45 +00:00
int32_t id = cellids . count ( cwt . at ) ? cellids [ cwt . at ] : - 1 ;
2018-11-24 16:01:49 +00:00
f . write ( id ) ;
2020-04-17 18:04:33 +00:00
save_drawing_tool ( f ) ;
2016-08-26 09:58:03 +00:00
2019-05-29 14:27:24 +00:00
f . write ( vid . always3 ) ;
2019-01-28 21:28:17 +00:00
f . write ( mutantphase ) ;
f . write ( rosewave ) ;
f . write ( rosephase ) ;
f . write ( turncount ) ;
int rms = isize ( rosemap ) ; f . write ( rms ) ;
for ( auto p : rosemap ) f . write ( cellids [ p . first ] ) , f . write ( p . second ) ;
f . write ( multi : : players ) ;
if ( multi : : players > 1 )
for ( int i = 0 ; i < multi : : players ; i + + )
f . write ( cellids [ multi : : player [ i ] . at ] ) ;
2016-08-26 09:58:03 +00:00
cellids . clear ( ) ;
cellbyid . clear ( ) ;
}
2019-05-29 13:53:13 +00:00
void load_usershapes ( fhstream & f ) {
if ( f . vernum > = 7400 ) while ( true ) {
int i = f . get < int > ( ) ;
if ( i = = - 1 ) break ;
# if CAP_POLY
int j = f . get < int > ( ) , l = f . get < int > ( ) ;
if ( i > = 4 ) i = 3 ;
if ( i < 0 | | i > = mapeditor : : USERSHAPEGROUPS ) break ;
if ( l < 0 | | l > = USERLAYERS ) break ;
initShape ( i , j ) ;
usershapelayer & ds ( usershapes [ i ] [ j ] - > d [ l ] ) ;
if ( f . vernum > = 11008 ) f . read ( ds . zlevel ) ;
f . read ( ds . sym ) ; f . read ( ds . rots ) ; f . read ( ds . color ) ;
ds . list . clear ( ) ;
int siz = f . get < int > ( ) ;
ds . shift = f . get < hyperpoint > ( ) ;
ds . spin = f . get < hyperpoint > ( ) ;
for ( int i = 0 ; i < siz ; i + + )
ds . list . push_back ( f . get < hyperpoint > ( ) ) ;
# else
printf ( " cannot read shapes \n " ) ; exit ( 1 ) ;
# endif
}
2016-08-26 09:58:03 +00:00
}
2019-05-29 13:53:13 +00:00
void load_only_map ( fhstream & f ) {
stop_game ( ) ;
2019-05-21 22:19:03 +00:00
if ( f . vernum > = 10420 & & f . vernum < 10503 ) {
2018-12-14 18:26:03 +00:00
int i ;
f . read ( i ) ;
patterns : : whichPattern = patterns : : ePattern ( i ) ;
}
2019-05-21 22:19:03 +00:00
else if ( f . vernum > = 7400 ) f . read ( patterns : : whichPattern ) ;
2017-11-07 13:08:50 +00:00
2019-11-23 20:08:47 +00:00
if ( f . vernum > = 10203 )
load_geometry ( f ) ;
2018-12-24 14:10:52 +00:00
2019-05-29 14:50:17 +00:00
check_cgi ( ) ;
cgi . require_basics ( ) ;
2019-05-26 16:04:02 +00:00
usershape_changes + + ;
2016-08-26 09:58:03 +00:00
initcells ( ) ;
if ( shmup : : on ) shmup : : init ( ) ;
2018-12-24 14:10:52 +00:00
2019-05-21 22:19:03 +00:00
if ( f . vernum > = 10505 ) {
2018-12-24 14:10:52 +00:00
// game settings
f . read ( safety ) ;
bool b ;
f . read ( b ) ; if ( b ) autocheat = true ;
f . read ( gen_wandering ) ;
f . read ( reptilecheat ) ;
f . read ( timerghost ) ;
f . read ( patterns : : canvasback ) ;
f . read ( patterns : : whichShape ) ;
f . read ( patterns : : subpattern_flags ) ;
f . read ( patterns : : whichCanvas ) ;
f . read ( patterns : : displaycodes ) ;
2020-03-22 08:48:24 +00:00
if ( f . vernum > = 0xA816 )
2020-01-28 15:42:07 +00:00
f . read ( canvas_default_wall ) ;
2018-12-24 14:10:52 +00:00
f . read ( mapeditor : : drawplayer ) ;
2019-02-06 16:24:03 +00:00
if ( patterns : : whichCanvas = = ' f ' ) f . read ( patterns : : color_formula ) ;
2018-12-24 14:10:52 +00:00
int i ;
f . read ( i ) ; if ( i > ittypes | | i < 0 ) throw hstream_exception ( ) ;
for ( int k = 0 ; k < i ; k + + ) f . read ( items [ k ] ) ;
f . read ( i ) ; if ( i > motypes | | i < 0 ) throw hstream_exception ( ) ;
for ( int k = 0 ; k < i ; k + + ) f . read ( kills [ k ] ) ;
}
2016-08-26 09:58:03 +00:00
2019-11-23 22:09:06 +00:00
int sub = hybri ? 2 : 0 ;
2016-08-26 09:58:03 +00:00
while ( true ) {
cell * c ;
int rspin ;
2018-06-22 12:47:24 +00:00
if ( isize ( cellbyid ) = = 0 ) {
2017-04-04 09:13:15 +00:00
c = currentmap - > gamestart ( ) ;
2016-08-26 09:58:03 +00:00
rspin = 0 ;
}
else {
2018-11-24 16:01:49 +00:00
int32_t parent = f . get < int > ( ) ;
2016-08-26 09:58:03 +00:00
2018-06-22 12:47:24 +00:00
if ( parent < 0 | | parent > = isize ( cellbyid ) ) break ;
2018-11-24 16:01:49 +00:00
int dir = f . read_char ( ) ;
2016-08-26 09:58:03 +00:00
cell * c2 = cellbyid [ parent ] ;
2019-11-23 22:09:06 +00:00
dir = fixspin ( relspin [ parent ] , dir , c2 - > type - sub , f . vernum ) ;
2016-08-26 09:58:03 +00:00
c = createMov ( c2 , dir ) ;
2017-11-07 13:08:50 +00:00
// printf("%p:%d,%d -> %p\n", c2, relspin[parent], dir, c);
2016-08-26 09:58:03 +00:00
// spinval becomes xspinval
2020-01-18 15:03:32 +00:00
rspin = gmod ( c2 - > c . spin ( dir ) - f . read_char ( ) , c - > type - sub ) ;
2019-11-23 22:09:06 +00:00
if ( GDIM = = 3 & & rspin & & ! hybri ) {
2019-04-13 11:08:08 +00:00
println ( hlog , " rspin in 3D " ) ;
throw hstream_exception ( ) ;
}
2016-08-26 09:58:03 +00:00
}
cellbyid . push_back ( c ) ;
relspin . push_back ( rspin ) ;
2018-11-24 16:01:49 +00:00
c - > land = ( eLand ) f . read_char ( ) ;
2019-11-23 22:09:06 +00:00
c - > mondir = fixspin ( rspin , f . read_char ( ) , c - > type - sub , f . vernum ) ;
2018-11-24 16:01:49 +00:00
c - > monst = ( eMonster ) f . read_char ( ) ;
2019-05-21 22:19:03 +00:00
if ( c - > monst = = moTortoise & & f . vernum > = 11001 )
2019-01-16 23:48:55 +00:00
f . read ( tortoise : : emap [ c ] ) ;
2018-11-24 16:01:49 +00:00
c - > wall = ( eWall ) f . read_char ( ) ;
// c->barleft = (eLand) f.read_char();
// c->barright = (eLand) f.read_char();
c - > item = ( eItem ) f . read_char ( ) ;
2019-05-21 22:19:03 +00:00
if ( c - > item = = itBabyTortoise & & f . vernum > = 11001 )
2019-01-16 23:48:55 +00:00
f . read ( tortoise : : babymap [ c ] ) ;
2018-11-24 16:01:49 +00:00
c - > mpdist = f . read_char ( ) ;
2016-08-26 09:58:03 +00:00
c - > bardir = NOBARRIERS ;
2018-11-24 16:01:49 +00:00
// fixspin(rspin, f.read_char(), c->type);
2019-05-21 22:19:03 +00:00
if ( f . vernum < 7400 ) {
2018-06-28 10:59:35 +00:00
short z ;
2018-11-24 16:01:49 +00:00
f . read ( z ) ;
2018-06-28 10:59:35 +00:00
c - > wparam = z ;
2016-08-26 09:58:03 +00:00
}
2018-11-24 16:01:49 +00:00
else f . read ( c - > wparam ) ;
f . read ( c - > landparam ) ;
2016-08-26 09:58:03 +00:00
// backward compatibility
2019-05-21 22:19:03 +00:00
if ( f . vernum < 7400 & & ! isIcyLand ( c - > land ) ) c - > landparam = HEAT ( c ) ;
2018-11-24 16:01:49 +00:00
c - > stuntime = f . read_char ( ) ;
c - > hitpoints = f . read_char ( ) ;
2016-08-26 09:58:03 +00:00
2017-12-09 02:48:30 +00:00
if ( patterns : : whichPattern )
2017-12-09 07:06:41 +00:00
mapeditor : : modelcell [ patterns : : getpatterninfo0 ( c ) . id ] = c ;
2016-08-26 09:58:03 +00:00
}
2018-11-24 16:01:49 +00:00
int32_t whereami = f . get < int > ( ) ;
2018-06-22 12:47:24 +00:00
if ( whereami > = 0 & & whereami < isize ( cellbyid ) )
2018-08-17 22:46:45 +00:00
cwt . at = cellbyid [ whereami ] ;
else cwt . at = currentmap - > gamestart ( ) ;
2016-08-26 09:58:03 +00:00
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( cellbyid ) ; i + + ) {
2016-08-26 09:58:03 +00:00
cell * c = cellbyid [ i ] ;
if ( c - > bardir ! = NODIR & & c - > bardir ! = NOBARRIERS )
extendBarrier ( c ) ;
}
for ( int d = BARLEV - 1 ; d > = 0 ; d - - )
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( cellbyid ) ; i + + ) {
2016-08-26 09:58:03 +00:00
cell * c = cellbyid [ i ] ;
if ( c - > mpdist < = d )
for ( int j = 0 ; j < c - > type ; j + + ) {
cell * c2 = createMov ( c , j ) ;
setdist ( c2 , d + 1 , c ) ;
}
}
relspin . clear ( ) ;
if ( shmup : : on ) shmup : : init ( ) ;
timerstart = time ( NULL ) ; turncount = 0 ;
sagephase = 0 ; hardcoreAt = 0 ;
timerstopped = false ;
savecount = 0 ; savetime = 0 ;
cheater = 1 ;
2020-04-17 18:04:33 +00:00
load_drawing_tool ( f ) ;
2019-05-29 14:27:24 +00:00
dynamicval < bool > a3 ( vid . always3 , vid . always3 ) ;
2019-08-22 09:24:25 +00:00
if ( f . vernum > = 0xA616 ) { f . read ( vid . always3 ) ; geom3 : : apply_always3 ( ) ; }
2019-01-28 21:28:17 +00:00
2019-05-29 13:53:13 +00:00
if ( f . vernum < 0xA61A ) load_usershapes ( f ) ;
2019-05-21 22:19:03 +00:00
if ( f . vernum > = 11005 ) {
2019-01-28 21:28:17 +00:00
f . read ( mutantphase ) ;
f . read ( rosewave ) ;
f . read ( rosephase ) ;
f . read ( turncount ) ;
int i ; f . read ( i ) ;
if ( i ) havewhat | = HF_ROSE ;
while ( i - - ) {
int cid ; int val ; f . read ( cid ) ; f . read ( val ) ;
if ( cid > = 0 & & cid < isize ( cellbyid ) ) rosemap [ cellbyid [ cid ] ] = val ;
}
f . read ( multi : : players ) ;
if ( multi : : players > 1 )
for ( int i = 0 ; i < multi : : players ; i + + ) {
auto & mp = multi : : player [ i ] ;
int whereami = f . get < int > ( ) ;
if ( whereami > = 0 & & whereami < isize ( cellbyid ) )
mp . at = cellbyid [ whereami ] ;
else
mp . at = currentmap - > gamestart ( ) ;
mp . spin = 0 ,
mp . mirrored = false ;
}
}
2016-08-26 09:58:03 +00:00
2019-01-28 21:28:17 +00:00
cellbyid . clear ( ) ;
2019-05-29 13:53:13 +00:00
restartGraph ( ) ;
2016-08-26 09:58:03 +00:00
bfs ( ) ;
2019-05-29 13:53:13 +00:00
game_active = true ;
}
void save_usershapes ( fhstream & f ) {
int32_t n ;
# if CAP_POLY
for ( int i = 0 ; i < mapeditor : : USERSHAPEGROUPS ; i + + ) for ( auto usp : usershapes [ i ] ) {
usershape * us = usp . second ;
if ( ! us ) continue ;
for ( int l = 0 ; l < USERLAYERS ; l + + ) if ( isize ( us - > d [ l ] . list ) ) {
usershapelayer & ds ( us - > d [ l ] ) ;
f . write ( i ) ; f . write ( usp . first ) ; f . write ( l ) ;
f . write ( ds . zlevel ) ;
f . write ( ds . sym ) ; f . write ( ds . rots ) ; f . write ( ds . color ) ;
n = isize ( ds . list ) ; f . write ( n ) ;
f . write ( ds . shift ) ;
f . write ( ds . spin ) ;
for ( int i = 0 ; i < isize ( ds . list ) ; i + + ) f . write ( ds . list [ i ] ) ;
}
}
# endif
n = - 1 ; f . write ( n ) ;
}
bool saveMap ( const char * fname ) {
fhstream f ( fname , " wb " ) ;
if ( ! f . f ) return false ;
f . write ( f . vernum ) ;
f . write ( dual : : state ) ;
// make sure we save in correct order
if ( dual : : state ) dual : : switch_to ( 1 ) ;
dual : : split_or_do ( [ & ] { save_only_map ( f ) ; } ) ;
save_usershapes ( f ) ;
return true ;
}
bool loadMap ( const string & fname ) {
fhstream f ( fname , " rb " ) ;
if ( ! f . f ) return false ;
f . read ( f . vernum ) ;
if ( f . vernum > 10505 & & f . vernum < 11000 )
f . vernum = 11005 ;
auto ds = dual : : state ;
if ( f . vernum > = 0xA61A )
f . read ( ds ) ;
else
ds = 0 ;
if ( ds = = 1 & & dual : : state = = 0 ) dual : : enable ( ) ;
if ( ds = = 0 & & dual : : state = = 1 ) dual : : disable ( ) ;
dual : : split_or_do ( [ & ] { load_only_map ( f ) ; } ) ;
2019-08-02 15:58:00 +00:00
if ( dual : : state ) dual : : assign_landsides ( ) ;
2019-05-29 13:53:13 +00:00
if ( f . vernum > = 0xA61A )
load_usershapes ( f ) ;
2016-08-26 09:58:03 +00:00
return true ;
}
# endif
2018-09-07 13:15:00 +00:00
}
2016-08-26 09:58:03 +00:00
namespace mapeditor {
2019-08-09 23:15:41 +00:00
EX bool drawplayer = true ;
2016-08-26 09:58:03 +00:00
2019-08-09 23:15:41 +00:00
EX cell * drawcell ;
2017-07-04 13:38:33 +00:00
2017-07-22 23:33:27 +00:00
# if CAP_EDIT
2016-08-26 09:58:03 +00:00
int paintwhat = 0 ;
int painttype = 0 ;
2019-02-28 16:06:53 +00:00
int paintstatueid = 0 ;
2016-08-26 09:58:03 +00:00
int radius = 0 ;
string paintwhat_str = " clear monster " ;
2017-11-12 23:37:18 +00:00
cellwalker copysource ;
2016-08-26 09:58:03 +00:00
int whichpart ;
2017-07-04 13:38:33 +00:00
2016-08-26 09:58:03 +00:00
const char * mapeditorhelp =
" This mode allows you to edit the map. \n \n "
" NOTE: Use at your own risk. Combinations which never "
" appear in the real game may work in an undefined way "
" (do not work, look strangely, give strange messages, or crash the game). \n \n "
" To get the most of this editor, "
" some knowledge of inner workings of HyperRogue is required. "
" Each cell has four main fields: land type, wall type, monster type, item type. "
" The same wall type (especially \" none \" , \" sea \" , or \" bonfire \" ) may look or "
" work a bit differently, based on the land it is in. Sometimes an object may "
" appear twice on the list due to subtle differences (for example, Demons could "
" move next turn or not). \n \n "
" Press w, i, l, or m to choose which aspect of cells to change, "
" then just click on the cells and they will change. Press 'c' while "
" hovering over a cell to copy that cell, this copies all information about it. "
" When copying large areas or placing multi-tile monsters, it might be important where "
" on the cell you are clicking. \n \n "
" You can also press 0-9 to apply your changes to a greater radius. "
" This also affects the copy/paste feature, allowing to copy a larger area. \n \n "
" Press F2 to save the current map (and F3 to load it). If you try this after "
" a long game of HyperRogue (without using Orbs of Safety), the filesize will "
" be very large! "
" Note however that large structures, such as "
" Great Walls, large circles and horocycles, are destroyed by this. \n \n "
" Press 'b' to mark cells as boundaries. Such cells, and cells beyond "
" them, are not copied by the copy/paste feature, nor saved by the "
" save feature. \n \n " ;
const char * patthelp =
" Press 'r' to choose a regular pattern. When a pattern is on, "
" editing a cell automatically edits all cells which are "
" equivalent according to this pattern. You can choose from "
" several patterns, and choose which symmetries matter "
" for equivalence. Also, you can press Space to switch between "
" the map and graphics editor quickly -- note that editing floors "
" with the graphics editor also adheres to the pattern. " ;
string mehelptext ( ) {
return XLAT ( mapeditorhelp ) + XLAT ( patthelp ) ;
}
struct undo_info {
cell * c ;
eWall w ;
eItem i ;
eMonster m ;
eLand l ;
char wparam ;
int32_t lparam ;
char dir ;
} ;
vector < undo_info > undo ;
bool checkEq ( undo_info & u ) {
return u . w = = u . c - > wall & & u . i = = u . c - > item & & u . m = = u . c - > monst & & u . l = = u . c - > land & &
u . dir = = u . c - > mondir & & u . lparam = = u . c - > landparam & & u . wparam = = u . c - > wparam ;
}
void saveUndo ( cell * c ) {
undo_info u ;
u . c = c ; u . w = c - > wall ; u . i = c - > item ; u . m = c - > monst ; u . l = c - > land ; u . dir = c - > mondir ;
u . wparam = c - > wparam ; u . lparam = c - > landparam ;
undo . push_back ( u ) ;
}
2018-06-22 12:47:24 +00:00
undo_info & lastUndo ( ) { return undo [ isize ( undo ) - 1 ] ; }
2016-08-26 09:58:03 +00:00
void undoLock ( ) {
2018-06-22 12:47:24 +00:00
if ( ! isize ( undo ) | | lastUndo ( ) . c ) {
2016-08-26 09:58:03 +00:00
undo_info i ; i . c = NULL ; undo . push_back ( i ) ;
}
}
void applyUndo ( ) {
2018-06-22 12:47:24 +00:00
while ( isize ( undo ) & & ! lastUndo ( ) . c ) undo . pop_back ( ) ;
while ( isize ( undo ) ) {
2016-08-26 09:58:03 +00:00
undo_info & i ( lastUndo ( ) ) ;
if ( ! i . c ) break ;
i . c - > wall = i . w ;
i . c - > item = i . i ;
i . c - > monst = i . m ;
i . c - > land = i . l ;
i . c - > mondir = i . dir ;
i . c - > wparam = i . wparam ;
i . c - > landparam = i . lparam ;
undo . pop_back ( ) ;
}
}
void checkUndo ( ) {
2018-06-22 12:47:24 +00:00
if ( checkEq ( undo [ isize ( undo ) - 1 ] ) ) undo . pop_back ( ) ;
2016-08-26 09:58:03 +00:00
}
int itc ( int k ) {
if ( k = = 0 ) return 0 ;
if ( k = = 1 ) return 0x40 ;
if ( k = = 2 ) return 0x80 ;
if ( k = = 3 ) return 0xFF ;
return 0x20 ;
}
bool choosefile = false ;
2019-08-10 20:30:02 +00:00
int editor_fsize ( ) {
return min ( vid . fsize + 5 , ( vid . yres - 16 ) / 32 ) ;
}
2016-08-26 09:58:03 +00:00
void displayFunctionKeys ( ) {
2019-08-10 20:30:02 +00:00
int fs = editor_fsize ( ) ;
2017-03-23 10:53:57 +00:00
displayButton ( 8 , vid . yres - 8 - fs * 11 , XLAT ( " F1 = help " ) , SDLK_F1 , 0 ) ;
displayButton ( 8 , vid . yres - 8 - fs * 10 , XLAT ( " F2 = save " ) , SDLK_F2 , 0 ) ;
displayButton ( 8 , vid . yres - 8 - fs * 9 , XLAT ( " F3 = load " ) , SDLK_F3 , 0 ) ;
2020-04-17 18:18:50 +00:00
displayButton ( 8 , vid . yres - 8 - fs * 7 , drawing_tool ? XLAT ( " F5 = clear " ) : XLAT ( " F5 = restart " ) , SDLK_F5 , 0 ) ;
2018-12-13 12:33:08 +00:00
# if CAP_SHOT
2017-03-23 10:53:57 +00:00
displayButton ( 8 , vid . yres - 8 - fs * 6 , XLAT ( " F6 = HQ shot " ) , SDLK_F6 , 0 ) ;
2018-12-13 12:33:08 +00:00
# endif
2017-03-23 10:53:57 +00:00
displayButton ( 8 , vid . yres - 8 - fs * 5 , XLAT ( " F7 = player on/off " ) , SDLK_F7 , 0 ) ;
2016-08-26 09:58:03 +00:00
displayButton ( 8 , vid . yres - 8 - fs * 3 , XLAT ( " SPACE = map/graphics " ) , ' ' , 0 ) ;
displayButton ( 8 , vid . yres - 8 - fs * 2 , XLAT ( " ESC = return to the game " ) , SDLK_ESCAPE , 0 ) ;
}
2019-12-06 13:03:54 +00:00
EX unordered_set < cell * > affected ;
EX unordered_set < int > affected_id ;
2016-08-26 09:58:03 +00:00
2019-08-09 23:15:41 +00:00
EX void showMapEditor ( ) {
2017-07-12 17:50:39 +00:00
cmode = sm : : MAP ;
2017-07-10 18:47:38 +00:00
gamescreen ( 0 ) ;
2019-08-10 20:30:02 +00:00
int fs = editor_fsize ( ) ;
2017-07-10 18:47:38 +00:00
2019-12-06 13:03:54 +00:00
affected . clear ( ) ;
affected_id . clear ( ) ;
if ( lmouseover ) {
celllister cl ( lmouseover , radius , 10000 , nullptr ) ;
for ( cell * c : cl . lst ) affected . insert ( c ) , affected_id . insert ( patterns : : getpatterninfo0 ( c ) . id ) ;
}
2017-07-10 18:47:38 +00:00
getcstat = ' - ' ;
displayfr ( 8 , 8 + fs , 2 , vid . fsize , paintwhat_str , forecolor , 0 ) ;
displayfr ( 8 , 8 + fs * 2 , 2 , vid . fsize , XLAT ( " use at your own risk! " ) , 0x800000 , 0 ) ;
displayButton ( 8 , 8 + fs * 4 , XLAT ( " 0-9 = radius (%1) " , its ( radius ) ) , ( ' 0 ' + ( radius + 1 ) % 10 ) , 0 ) ;
displayButton ( 8 , 8 + fs * 5 , XLAT ( " b = boundary " ) , ' b ' , 0 ) ;
displayButton ( 8 , 8 + fs * 6 , XLAT ( " m = monsters " ) , ' m ' , 0 ) ;
displayButton ( 8 , 8 + fs * 7 , XLAT ( " w = walls " ) , ' w ' , 0 ) ;
displayButton ( 8 , 8 + fs * 8 , XLAT ( " i = items " ) , ' i ' , 0 ) ;
displayButton ( 8 , 8 + fs * 9 , XLAT ( " l = lands " ) , ' l ' , 0 ) ;
displayfr ( 8 , 8 + fs * 10 , 2 , vid . fsize , XLAT ( " c = copy " ) , 0xC0C0C0 , 0 ) ;
displayButton ( 8 , 8 + fs * 11 , XLAT ( " u = undo " ) , ' u ' , 0 ) ;
if ( painttype = = 4 )
2017-11-12 23:37:18 +00:00
displayButton ( 8 , 8 + fs * 12 , XLAT ( " f = flip %1 " , ONOFF ( copysource . mirrored ) ) , ' u ' , 0 ) ;
2017-07-10 18:47:38 +00:00
displayButton ( 8 , 8 + fs * 13 , XLAT ( " r = regular " ) , ' r ' , 0 ) ;
displayButton ( 8 , 8 + fs * 14 , XLAT ( " p = paint " ) , ' p ' , 0 ) ;
2017-12-03 17:24:34 +00:00
2017-07-10 18:47:38 +00:00
displayFunctionKeys ( ) ;
2018-12-24 14:10:52 +00:00
displayButton ( 8 , vid . yres - 8 - fs * 4 , XLAT ( " F8 = settings " ) , SDLK_F8 , 0 ) ;
2017-07-10 18:47:38 +00:00
keyhandler = handleKeyMap ;
2016-08-26 09:58:03 +00:00
}
int spillinc ( ) {
if ( radius > = 2 ) return 0 ;
if ( anyshiftclick ) return - 1 ;
return 1 ;
}
2019-08-09 23:15:41 +00:00
EX eShapegroup drawcellShapeGroup ( ) {
2018-08-27 17:27:35 +00:00
if ( drawcell = = cwt . at & & drawplayer ) return sgPlayer ;
2019-02-28 16:06:53 +00:00
if ( drawcell - > wall = = waEditStatue ) return sgWall ;
2018-08-27 17:27:35 +00:00
if ( drawcell - > monst ) return sgMonster ;
if ( drawcell - > item ) return sgItem ;
return sgFloor ;
2016-08-26 09:58:03 +00:00
}
2019-08-09 23:15:41 +00:00
EX int drawcellShapeID ( ) {
2018-08-17 22:46:45 +00:00
if ( drawcell = = cwt . at & & drawplayer ) return vid . cs . charid ;
2019-02-28 16:06:53 +00:00
if ( drawcell - > wall = = waEditStatue ) return drawcell - > wparam ;
2016-08-26 09:58:03 +00:00
if ( drawcell - > monst ) return drawcell - > monst ;
if ( drawcell - > item ) return drawcell - > item ;
2018-08-27 17:27:35 +00:00
auto si = patterns : : getpatterninfo0 ( drawcell ) ;
2018-08-30 17:14:04 +00:00
return si . id ;
2016-08-26 09:58:03 +00:00
}
2018-08-28 11:45:11 +00:00
bool editingShape ( eShapegroup group , int id ) {
2016-08-26 09:58:03 +00:00
if ( group ! = mapeditor : : drawcellShapeGroup ( ) ) return false ;
2017-12-09 07:06:41 +00:00
return id = = drawcellShapeID ( ) ;
2016-08-26 09:58:03 +00:00
}
2017-11-12 23:37:18 +00:00
void editCell ( const pair < cellwalker , cellwalker > & where ) {
2018-08-17 22:46:45 +00:00
cell * c = where . first . at ;
2017-11-12 23:37:18 +00:00
int cdir = where . first . spin ;
2016-08-26 09:58:03 +00:00
saveUndo ( c ) ;
switch ( painttype ) {
2018-09-12 22:35:21 +00:00
case 0 : {
eMonster last = c - > monst ;
2016-08-26 09:58:03 +00:00
c - > monst = eMonster ( paintwhat ) ;
c - > hitpoints = 3 ;
c - > stuntime = 0 ;
c - > mondir = cdir ;
2018-08-17 22:46:45 +00:00
if ( ( isWorm ( c ) | | isIvy ( c ) | | isMutantIvy ( c ) ) & & c - > move ( cdir ) & &
! isWorm ( c - > move ( cdir ) ) & & ! isIvy ( c - > move ( cdir ) ) )
2016-08-26 09:58:03 +00:00
c - > mondir = NODIR ;
2018-06-17 10:03:39 +00:00
if ( c - > monst = = moMimic ) {
c - > monst = moNone ;
mirror : : createMirror ( cellwalker ( c , cdir , true ) , 0 ) ;
c - > monst = moMimic ;
}
2018-09-12 22:35:21 +00:00
if ( c - > monst = = moTortoise & & last = = moTortoise ) {
cell * c1 = c ;
for ( int i = 0 ; i < 100 ; i + + ) c1 = c1 - > cmove ( hrand ( c1 - > type ) ) ;
2019-01-16 23:48:55 +00:00
tortoise : : emap [ c ] = tortoise : : getRandomBits ( ) ;
2018-09-12 22:35:21 +00:00
}
2016-08-26 09:58:03 +00:00
break ;
2018-09-12 22:35:21 +00:00
}
case 1 : {
eItem last = c - > item ;
2016-08-26 09:58:03 +00:00
c - > item = eItem ( paintwhat ) ;
2017-03-23 10:53:57 +00:00
if ( c - > item = = itBabyTortoise )
2018-09-12 22:35:21 +00:00
tortoise : : babymap [ c ] = getBits ( c ) ^ ( last = = itBabyTortoise ? tortoise : : getRandomBits ( ) : 0 ) ;
2016-08-26 09:58:03 +00:00
break ;
2018-09-12 22:35:21 +00:00
}
2016-08-26 09:58:03 +00:00
case 2 : {
eLand last = c - > land ;
c - > land = eLand ( paintwhat ) ;
if ( isIcyLand ( c ) & & isIcyLand ( last ) )
HEAT ( c ) + = spillinc ( ) / 100. ;
else if ( last = = laDryForest & & c - > land = = laDryForest )
c - > landparam + = spillinc ( ) ;
else if ( last = = laOcean & & c - > land = = laOcean )
c - > landparam + = spillinc ( ) ;
else if ( last = = laHive & & c - > land = = laHive )
c - > landparam + = spillinc ( ) ;
else
c - > landparam = 0 ;
break ;
}
case 3 : {
eWall last = c - > wall ;
c - > wall = eWall ( paintwhat ) ;
if ( last ! = c - > wall ) {
if ( hasTimeout ( c ) )
c - > wparam = 10 ;
else if ( c - > wall = = waWaxWall )
c - > landparam = hrand ( 0xFFFFFF + 1 ) ;
}
else if ( hasTimeout ( c ) )
c - > wparam + = spillinc ( ) ;
2019-02-28 16:06:53 +00:00
if ( c - > wall = = waEditStatue ) {
c - > wparam = paintstatueid ;
c - > mondir = cdir ;
}
2016-08-26 09:58:03 +00:00
break ;
}
case 5 :
c - > land = laNone ;
c - > wall = waNone ;
c - > item = itNone ;
c - > monst = moNone ;
c - > landparam = 0 ;
// c->tmp = -1;
break ;
case 6 :
c - > land = laCanvas ;
2019-08-15 13:05:43 +00:00
c - > wall = GDIM = = 3 ? waWaxWall : waNone ;
2017-03-23 10:53:57 +00:00
c - > landparam = paintwhat > > 8 ;
2016-08-26 09:58:03 +00:00
break ;
case 4 :
2018-08-17 22:46:45 +00:00
cell * copywhat = where . second . at ;
2016-08-26 09:58:03 +00:00
c - > wall = copywhat - > wall ;
c - > item = copywhat - > item ;
c - > land = copywhat - > land ;
c - > monst = copywhat - > monst ;
c - > landparam = copywhat - > landparam ;
c - > wparam = copywhat - > wparam ;
2017-11-12 23:37:18 +00:00
c - > hitpoints = copywhat - > hitpoints ;
c - > stuntime = copywhat - > stuntime ;
2016-08-26 09:58:03 +00:00
if ( copywhat - > mondir = = NODIR ) c - > mondir = NODIR ;
2020-01-18 15:03:32 +00:00
else c - > mondir = gmod ( ( where . first . mirrored = = where . second . mirrored ? 1 : - 1 ) * ( copywhat - > mondir - where . second . spin ) + cdir , c - > type ) ;
2016-08-26 09:58:03 +00:00
break ;
}
checkUndo ( ) ;
}
2017-11-12 23:37:18 +00:00
vector < pair < cellwalker , cellwalker > > spill_list ;
2018-06-28 11:35:03 +00:00
void list_spill ( cellwalker tgt , cellwalker src , manual_celllister & cl ) {
2018-06-29 10:16:35 +00:00
spill_list . clear ( ) ;
2017-11-12 23:37:18 +00:00
spill_list . emplace_back ( tgt , src ) ;
int crad = 0 , nextstepat = 0 ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( spill_list ) ; i + + ) {
2017-11-12 23:37:18 +00:00
if ( i = = nextstepat ) {
2018-06-22 12:47:24 +00:00
crad + + ; nextstepat = isize ( spill_list ) ;
2017-11-12 23:37:18 +00:00
if ( crad > radius ) break ;
}
auto sd = spill_list [ i ] ;
2018-08-17 22:46:45 +00:00
for ( int i = 0 ; i < sd . first . at - > type ; i + + ) {
2017-11-12 23:37:18 +00:00
auto sd2 = sd ;
2018-03-24 11:59:01 +00:00
sd2 . first = sd2 . first + i + wstep ;
2018-08-17 22:46:45 +00:00
if ( ! cl . add ( sd2 . first . at ) ) continue ;
if ( sd2 . second . at ) {
2018-03-24 11:59:01 +00:00
sd2 . second = sd2 . second + i + wstep ;
2018-08-17 22:46:45 +00:00
if ( sd2 . second . at - > land = = laNone ) continue ;
2017-11-12 23:37:18 +00:00
}
spill_list . push_back ( sd2 ) ;
}
}
}
2018-01-05 13:19:22 +00:00
2018-06-28 11:35:03 +00:00
void editAt ( cellwalker where , manual_celllister & cl ) {
2017-11-12 23:37:18 +00:00
if ( painttype = = 4 & & radius ) {
2018-08-17 22:46:45 +00:00
if ( where . at - > type ! = copysource . at - > type ) return ;
2017-11-12 23:37:18 +00:00
if ( where . spin < 0 ) where . spin = 0 ;
2018-08-28 15:17:34 +00:00
if ( BITRUNCATED & & ! ctof ( mouseover ) & & ( ( where . spin & 1 ) ! = ( copysource . spin & 1 ) ) )
2018-03-24 11:59:01 +00:00
where + = 1 ;
2017-11-12 23:37:18 +00:00
}
2018-08-17 22:46:45 +00:00
if ( painttype ! = 4 ) copysource . at = NULL ;
2018-06-28 10:59:35 +00:00
list_spill ( where , copysource , cl ) ;
2017-11-12 23:37:18 +00:00
for ( auto & st : spill_list )
editCell ( st ) ;
}
void allInPattern ( cellwalker where ) {
2016-08-26 09:58:03 +00:00
2018-06-28 11:35:03 +00:00
manual_celllister cl ;
2017-12-09 02:48:30 +00:00
if ( ! patterns : : whichPattern ) {
2018-06-28 10:59:35 +00:00
editAt ( where , cl ) ;
2016-08-26 09:58:03 +00:00
return ;
}
2018-08-17 22:46:45 +00:00
cl . add ( where . at ) ;
2016-08-26 09:58:03 +00:00
int at = 0 ;
2018-06-28 10:59:35 +00:00
while ( at < isize ( cl . lst ) ) {
cell * c2 = cl . lst [ at ] ;
2016-08-26 09:58:03 +00:00
at + + ;
2018-06-28 10:59:35 +00:00
forCellEx ( c3 , c2 ) cl . add ( c3 ) ;
2017-11-12 23:37:18 +00:00
}
2018-08-17 22:46:45 +00:00
auto si = patterns : : getpatterninfo0 ( where . at ) ;
2017-11-12 23:37:18 +00:00
int cdir = where . spin ;
2017-12-09 07:06:41 +00:00
if ( cdir > = 0 ) cdir = cdir - si . dir ;
2017-11-12 23:37:18 +00:00
2018-06-28 10:59:35 +00:00
for ( cell * c2 : cl . lst ) {
2017-12-09 07:06:41 +00:00
auto si2 = patterns : : getpatterninfo0 ( c2 ) ;
if ( si2 . id = = si . id ) {
2019-08-09 12:39:21 +00:00
editAt ( cellwalker ( c2 , cdir > = 0 ? cdir + si2 . dir : - 1 ) , cl ) ;
2017-12-09 07:06:41 +00:00
modelcell [ si2 . id ] = c2 ;
2016-08-26 09:58:03 +00:00
}
2017-12-09 07:06:41 +00:00
}
2016-08-26 09:58:03 +00:00
}
2017-11-12 23:37:18 +00:00
cellwalker mouseover_cw ( bool fix ) {
int d = neighborId ( mouseover , mouseover2 ) ;
if ( d = = - 1 & & fix ) d = hrand ( mouseover - > type ) ;
return cellwalker ( mouseover , d ) ;
}
2020-04-17 18:04:33 +00:00
void save_level ( ) {
dialog : : openFileDialog ( levelfile , XLAT ( " level to save: " ) , " .lev " , [ ] ( ) {
if ( mapstream : : saveMap ( levelfile . c_str ( ) ) ) {
addMessage ( XLAT ( " Map saved to %1 " , levelfile ) ) ;
return true ;
}
else {
addMessage ( XLAT ( " Failed to save map to %1 " , levelfile ) ) ;
return false ;
}
} ) ;
}
void load_level ( ) {
dialog : : openFileDialog ( levelfile , XLAT ( " level to load: " ) , " .lev " , [ ] ( ) {
if ( mapstream : : loadMap ( levelfile . c_str ( ) ) ) {
addMessage ( XLAT ( " Map loaded from %1 " , levelfile ) ) ;
return true ;
}
else {
addMessage ( XLAT ( " Failed to load map from %1 " , levelfile ) ) ;
return false ;
}
} ) ;
}
2017-11-12 23:37:18 +00:00
2017-12-09 02:48:30 +00:00
void showList ( ) {
2017-12-09 03:01:56 +00:00
dialog : : v . clear ( ) ;
2017-12-09 02:48:30 +00:00
if ( painttype = = 4 ) painttype = 0 ;
switch ( painttype ) {
case 0 :
for ( int i = 0 ; i < motypes ; i + + ) {
eMonster m = eMonster ( i ) ;
if (
m = = moTongue | | m = = moPlayer | | m = = moFireball | | m = = moBullet | |
m = = moFlailBullet | | m = = moShadow | | m = = moAirball | |
m = = moWolfMoved | | m = = moGolemMoved | |
m = = moTameBomberbirdMoved | | m = = moKnightMoved | |
m = = moDeadBug | | m = = moLightningBolt | | m = = moDeadBird | |
m = = moMouseMoved | | m = = moPrincessMoved | | m = = moPrincessArmedMoved ) ;
2017-12-09 03:01:56 +00:00
else if ( m = = moDragonHead ) dialog : : vpush ( i , " Dragon Head " ) ;
else dialog : : vpush ( i , minf [ i ] . name ) ;
2017-12-09 02:48:30 +00:00
}
break ;
case 1 :
2017-12-09 03:01:56 +00:00
for ( int i = 0 ; i < ittypes ; i + + ) dialog : : vpush ( i , iinf [ i ] . name ) ;
2017-12-09 02:48:30 +00:00
break ;
case 2 :
2017-12-09 03:01:56 +00:00
for ( int i = 0 ; i < landtypes ; i + + ) dialog : : vpush ( i , linf [ i ] . name ) ;
2017-12-09 02:48:30 +00:00
break ;
case 3 :
2017-12-09 03:01:56 +00:00
for ( int i = 0 ; i < walltypes ; i + + ) if ( i ! = waChasmD ) dialog : : vpush ( i , winf [ i ] . name ) ;
2017-12-09 02:48:30 +00:00
break ;
}
// sort(v.begin(), v.end());
2017-12-09 03:01:56 +00:00
if ( dialog : : infix ! = " " ) mouseovers = dialog : : infix ;
2017-12-09 02:48:30 +00:00
2017-12-09 03:01:56 +00:00
int q = dialog : : v . size ( ) ;
2017-12-09 02:48:30 +00:00
int percolumn = vid . yres / ( vid . fsize + 5 ) - 4 ;
int columns = 1 + ( q - 1 ) / percolumn ;
for ( int i = 0 ; i < q ; i + + ) {
int x = 16 + ( vid . xres * ( i / percolumn ) ) / columns ;
int y = ( vid . fsize + 5 ) * ( i % percolumn ) + vid . fsize * 2 ;
int actkey = 1000 + i ;
2017-12-09 03:01:56 +00:00
string vv = dialog : : v [ i ] . first ;
2017-12-09 02:48:30 +00:00
if ( i < 9 ) { vv + = " : " ; vv + = ( ' 1 ' + i ) ; }
displayButton ( x , y , vv , actkey , 0 ) ;
}
keyhandler = [ ] ( int sym , int uni ) {
if ( uni > = ' 1 ' & & uni < = ' 9 ' ) uni = 1000 + uni - ' 1 ' ;
if ( sym = = SDLK_RETURN | | sym = = SDLK_KP_ENTER | | sym = = ' - ' | | sym = = SDLK_KP_MINUS ) uni = 1000 ;
2018-06-22 12:47:24 +00:00
for ( int z = 0 ; z < isize ( dialog : : v ) ; z + + ) if ( 1000 + z = = uni ) {
2017-12-09 03:01:56 +00:00
paintwhat = dialog : : v [ z ] . second ;
paintwhat_str = dialog : : v [ z ] . first ;
2019-02-28 16:06:53 +00:00
2017-12-09 02:48:30 +00:00
mousepressed = false ;
popScreen ( ) ;
2019-02-28 16:06:53 +00:00
if ( painttype = = 3 & & paintwhat = = waEditStatue )
dialog : : editNumber ( paintstatueid , 0 , 127 , 1 , 1 , XLAT1 ( " editable statue " ) ,
XLAT ( " These statues are designed to have their graphics edited in the Vector Graphics Editor. Each number has its own, separate graphics. " )
) ;
2017-12-09 02:48:30 +00:00
return ;
}
2017-12-09 03:01:56 +00:00
if ( dialog : : editInfix ( uni ) ) ;
2017-12-09 02:48:30 +00:00
else if ( doexiton ( sym , uni ) ) popScreen ( ) ;
} ;
}
2018-07-22 10:50:03 +00:00
2017-07-10 18:47:38 +00:00
void handleKeyMap ( int sym , int uni ) {
handlePanning ( sym , uni ) ;
// left-clicks are coded with '-', and right-clicks are coded with sym F1
2017-11-06 22:22:13 +00:00
if ( uni = = ' - ' & & ! holdmouse ) undoLock ( ) ;
if ( uni = = ' - ' & & mouseover ) {
2017-11-12 23:37:18 +00:00
allInPattern ( mouseover_cw ( false ) ) ;
2017-11-06 22:22:13 +00:00
holdmouse = true ;
}
2017-07-10 18:47:38 +00:00
if ( mouseover ) for ( int i = 0 ; i < mouseover - > type ; i + + ) createMov ( mouseover , i ) ;
if ( uni = = ' u ' ) applyUndo ( ) ;
else if ( uni = = ' v ' | | sym = = SDLK_F10 | | sym = = SDLK_ESCAPE ) popScreen ( ) ;
else if ( uni > = ' 0 ' & & uni < = ' 9 ' ) radius = uni - ' 0 ' ;
2017-12-09 03:01:56 +00:00
else if ( uni = = ' m ' ) pushScreen ( showList ) , painttype = 0 , dialog : : infix = " " ;
else if ( uni = = ' i ' ) pushScreen ( showList ) , painttype = 1 , dialog : : infix = " " ;
else if ( uni = = ' l ' ) pushScreen ( showList ) , painttype = 2 , dialog : : infix = " " ;
else if ( uni = = ' w ' ) pushScreen ( showList ) , painttype = 3 , dialog : : infix = " " ;
2017-12-09 02:48:30 +00:00
else if ( uni = = ' r ' ) pushScreen ( patterns : : showPattern ) ;
2017-07-10 18:47:38 +00:00
else if ( uni = = ' t ' & & mouseover ) {
2017-11-12 23:37:18 +00:00
playermoved = true ;
cwt = mouseover_cw ( true ) ;
2017-07-10 18:47:38 +00:00
}
else if ( uni = = ' b ' ) painttype = 5 , paintwhat_str = XLAT ( " boundary " ) ;
else if ( uni = = ' p ' ) {
painttype = 6 ;
2016-08-26 09:58:03 +00:00
paintwhat_str = " paint " ;
2017-07-16 21:00:55 +00:00
dialog : : openColorDialog ( ( unsigned & ) ( paintwhat = ( painttype = = 6 ? paintwhat : 0x808080 ) ) ) ;
2016-08-26 09:58:03 +00:00
}
2019-01-02 21:03:23 +00:00
else if ( uni = = ' G ' )
push_debug_screen ( ) ;
2017-07-10 18:47:38 +00:00
else if ( sym = = SDLK_F5 ) {
2020-04-17 18:34:49 +00:00
dialog : : push_confirm_dialog ( [ ] { restart_game ( ) ; } , XLAT ( " Are you sure you want to clear the map? " ) ) ;
2016-08-26 09:58:03 +00:00
}
2020-04-17 18:04:33 +00:00
else if ( sym = = SDLK_F2 ) save_level ( ) ;
else if ( sym = = SDLK_F3 ) load_level ( ) ;
2018-12-13 12:33:08 +00:00
# if CAP_SHOT
2017-07-10 18:47:38 +00:00
else if ( sym = = SDLK_F6 ) {
2018-12-13 12:33:08 +00:00
pushScreen ( shot : : menu ) ;
2017-07-10 18:47:38 +00:00
}
2017-07-22 23:33:27 +00:00
# endif
2017-07-10 18:47:38 +00:00
else if ( sym = = SDLK_F7 ) {
drawplayer = ! drawplayer ;
}
2018-12-24 14:10:52 +00:00
else if ( sym = = SDLK_F8 ) {
pushScreen ( map_settings ) ;
}
2019-01-16 23:57:21 +00:00
else if ( uni = = ' c ' & & mouseover ) {
2017-11-12 23:37:18 +00:00
copysource = mouseover_cw ( true ) ;
painttype = 4 ;
2017-07-10 18:47:38 +00:00
paintwhat_str = XLAT ( " copying " ) ;
}
else if ( uni = = ' f ' ) {
2017-11-12 23:37:18 +00:00
copysource . mirrored = ! copysource . mirrored ;
2017-07-10 18:47:38 +00:00
}
else if ( uni = = ' h ' | | sym = = SDLK_F1 )
gotoHelp ( mehelptext ( ) ) ;
else if ( uni = = ' ' ) {
popScreen ( ) ;
pushScreen ( showDrawEditor ) ;
2018-08-17 22:46:45 +00:00
initdraw ( mouseover ? mouseover : cwt . at ) ;
2016-08-26 09:58:03 +00:00
}
}
// VECTOR GRAPHICS EDITOR
const char * drawhelp =
" In this mode you can draw your own player characters, "
" floors, monsters, and items. Press 'e' while hovering over "
" an object to edit it. Start drawing shapes with 'n', and "
" add extra vertices with 'a'. Press 0-9 to draw symmetric "
" pictures easily. More complex pictures can "
" be created by using several layers ('l'). See the edges of "
" the screen for more keys. " ;
string drawhelptext ( ) {
2017-07-10 18:47:38 +00:00
return XLAT ( drawhelp ) ;
2016-08-26 09:58:03 +00:00
}
int dslayer ;
bool coloring ;
2018-09-04 17:53:42 +00:00
color_t colortouse = 0xC0C0C0FFu ;
2017-10-04 19:25:40 +00:00
// fake key sent to change the color
static const int COLORKEY = ( - 10000 ) ;
2016-08-26 09:58:03 +00:00
2020-07-27 16:49:04 +00:00
EX shiftmatrix drawtrans , drawtransnew ;
2016-08-26 09:58:03 +00:00
2019-02-17 17:41:40 +00:00
# if CAP_POLY
2016-08-26 09:58:03 +00:00
void loadShape ( int sg , int id , hpcshape & sh , int d , int layer ) {
usershapelayer * dsCur = & usershapes [ sg ] [ id ] - > d [ layer ] ;
dsCur - > list . clear ( ) ;
dsCur - > sym = d = = 2 ;
for ( int i = sh . s ; i < sh . s + ( sh . e - sh . s ) / d ; i + + )
2019-05-26 16:04:02 +00:00
dsCur - > list . push_back ( cgi . hpc [ i ] ) ;
2016-08-26 09:58:03 +00:00
}
2019-02-17 17:41:40 +00:00
# endif
2016-08-26 09:58:03 +00:00
2020-07-27 16:49:04 +00:00
EX void drawGhosts ( cell * c , const shiftmatrix & V , int ct ) {
2019-12-06 13:03:54 +00:00
if ( ! ( cmode & sm : : MAP ) ) return ;
if ( darken ! = 0 ) return ;
if ( GDIM = = 2 & & mouseout ( ) ) return ;
if ( patterns : : whichPattern ) {
if ( ! affected_id . count ( patterns : : getpatterninfo0 ( c ) . id ) ) return ;
}
else {
if ( ! affected . count ( c ) ) return ;
2019-10-25 10:44:41 +00:00
}
2019-12-06 13:03:54 +00:00
queuecircleat1 ( c , V , .78 , 0x00FFFFFF ) ;
2016-08-26 09:58:03 +00:00
}
hyperpoint ccenter = C0 ;
hyperpoint coldcenter = C0 ;
2017-12-22 20:23:17 +00:00
unsigned gridcolor = 0xC0C0C040 ;
2020-07-27 16:49:04 +00:00
shiftpoint in_front_dist ( ld d ) {
return shiftless ( direct_exp ( lp_iapply ( ztangent ( d ) ) ) ) ; /* todo direct_shift */
2019-08-10 20:33:20 +00:00
}
2020-07-27 16:49:04 +00:00
shiftpoint find_mouseh3 ( ) {
2019-05-15 15:38:49 +00:00
if ( front_config = = eFront : : sphere_camera )
2019-08-10 20:33:20 +00:00
return in_front_dist ( front_edit ) ;
2019-05-15 15:38:49 +00:00
ld step = 0.01 ;
ld cdist = 0 ;
2020-07-27 16:49:04 +00:00
auto idt = inverse ( unshift ( drawtrans ) ) ;
2019-05-15 15:38:49 +00:00
2020-07-27 16:49:04 +00:00
auto qu = [ & ] ( ld d ) {
2019-08-10 20:33:20 +00:00
ld d1 = front_edit ;
2020-07-27 16:49:04 +00:00
shiftpoint h1 = in_front_dist ( d ) ;
2019-05-15 15:38:49 +00:00
if ( front_config = = eFront : : sphere_center )
2020-04-11 13:08:24 +00:00
d1 = geo_dist ( drawtrans * C0 , h1 ) ;
2019-05-15 15:38:49 +00:00
if ( front_config = = eFront : : equidistants ) {
2020-07-27 16:49:04 +00:00
hyperpoint h = idt * unshift ( in_front_dist ( d ) ) ;
2019-08-10 20:33:20 +00:00
d1 = asin_auto ( h [ 2 ] ) ;
}
if ( front_config = = eFront : : const_x ) {
2020-07-27 16:49:04 +00:00
hyperpoint h = idt * unshift ( in_front_dist ( d ) ) ;
2019-08-10 20:33:20 +00:00
d1 = asin_auto ( h [ 0 ] ) ;
}
if ( front_config = = eFront : : const_y ) {
2020-07-27 16:49:04 +00:00
hyperpoint h = idt * unshift ( in_front_dist ( d ) ) ;
2019-08-10 20:33:20 +00:00
d1 = asin_auto ( h [ 1 ] ) ;
2019-05-15 15:38:49 +00:00
}
2019-08-10 20:33:20 +00:00
return pow ( d1 - front_edit , 2 ) ;
2019-05-15 15:38:49 +00:00
} ;
ld bq = qu ( cdist ) ;
2019-08-10 20:33:20 +00:00
while ( abs ( step ) > 1e-10 ) {
2019-05-15 15:38:49 +00:00
ld cq = qu ( cdist + step ) ;
if ( cq < bq ) cdist + = step , bq = cq ;
2019-08-10 20:33:20 +00:00
else step * = - .5 ;
2019-05-15 15:38:49 +00:00
}
2019-08-10 20:33:20 +00:00
return in_front_dist ( cdist ) ;
2019-05-15 15:38:49 +00:00
}
2019-08-10 20:33:20 +00:00
int parallels = 12 , meridians = 6 ;
ld equi_range = 1 ;
2019-05-15 15:38:49 +00:00
2019-09-06 06:17:02 +00:00
EX void drawGrid ( ) {
2020-04-17 18:34:49 +00:00
if ( ! drawcell ) drawcell = cwt . at ;
2019-05-15 15:38:49 +00:00
color_t lightgrid = gridcolor ;
lightgrid - = ( lightgrid & 0xFF ) / 2 ;
2020-07-27 16:49:04 +00:00
shiftmatrix d2 = drawtrans * rgpushxto0 ( ccenter ) * rspintox ( gpushxto0 ( ccenter ) * coldcenter ) ;
2019-05-15 15:38:49 +00:00
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 ) {
2019-02-28 16:49:57 +00:00
queuecircleat ( mapeditor : : drawcell , 1 , 0x80D080FF ) ;
2019-02-28 18:01:40 +00:00
color_t cols [ 4 ] = { 0x80D080FF , 0x80D080FF , 0xFFFFFF40 , 0x00000040 } ;
2019-05-15 15:38:49 +00:00
if ( true ) {
2020-07-27 16:49:04 +00:00
shiftmatrix t = rgpushxto0 ( find_mouseh3 ( ) ) ;
2019-05-15 15:38:49 +00:00
for ( int i = 0 ; i < 4 ; i + + )
2019-08-10 20:33:20 +00:00
queueline ( t * cpush0 ( i & 1 , 0.1 ) , t * cpush0 ( i & 1 , - 0.1 ) , cols [ i ] , - 1 , i < 2 ? PPR : : LINE : PPR : : SUPERLINE ) ;
2019-05-15 15:38:49 +00:00
}
if ( front_config = = eFront : : sphere_center ) for ( int i = 0 ; i < 4 ; i + = 2 ) {
2019-08-10 20:33:20 +00:00
auto pt = [ & ] ( ld a , ld b ) {
2020-07-27 16:49:04 +00:00
return direct_exp ( spin ( a * degree ) * cspin ( 0 , 2 , b * degree ) * xtangent ( front_edit ) ) ;
2019-08-10 20:33:20 +00:00
} ;
for ( int ai = 0 ; ai < parallels ; ai + + ) {
ld a = ai * 360 / parallels ;
for ( int b = - 90 ; b < 90 ; b + = 5 ) curvepoint ( pt ( a , b ) ) ;
2020-07-27 16:49:04 +00:00
queuecurve ( d2 , cols [ i + ( ( ai * 4 ) % parallels ! = 0 ) ] , 0 , i < 2 ? PPR : : LINE : PPR : : SUPERLINE ) ;
2019-05-15 15:38:49 +00:00
}
2019-08-10 20:33:20 +00:00
for ( int bi = 1 - meridians ; bi < meridians ; bi + + ) {
ld b = 90 * bi / meridians ;
for ( int a = 0 ; a < = 360 ; a + = 5 ) curvepoint ( pt ( a , b ) ) ;
2020-07-27 16:49:04 +00:00
queuecurve ( d2 , cols [ i + ( bi ! = 0 ) ] , 0 , i < 2 ? PPR : : LINE : PPR : : SUPERLINE ) ;
2019-05-15 15:38:49 +00:00
}
}
2019-08-10 20:33:20 +00:00
transmatrix T ;
if ( front_config = = eFront : : equidistants ) T = Id ;
else if ( front_config = = eFront : : const_x ) T = cspin ( 2 , 0 , M_PI / 2 ) ;
else if ( front_config = = eFront : : const_y ) T = cspin ( 2 , 1 , M_PI / 2 ) ;
else return ;
for ( int i = 0 ; i < 4 ; i + = 2 ) {
2019-05-15 15:38:49 +00:00
for ( int u = 2 ; u < = 20 ; u + + ) {
PRING ( d ) {
2020-07-27 16:49:04 +00:00
curvepoint ( T * xspinpush ( M_PI * d / cgi . S42 , u / 20. ) * zpush0 ( front_edit ) ) ;
2019-05-15 15:38:49 +00:00
}
2020-07-27 16:49:04 +00:00
queuecurve ( d2 , cols [ i + ( u % 5 ! = 0 ) ] , 0 , i < 2 ? PPR : : LINE : PPR : : SUPERLINE ) ;
2019-05-15 15:38:49 +00:00
}
2019-05-26 16:04:02 +00:00
for ( int d = 0 ; d < cgi . S84 ; d + + ) {
2020-07-27 16:49:04 +00:00
for ( int u = 0 ; u < = 20 ; u + + ) curvepoint ( T * xspinpush ( M_PI * d / cgi . S42 , u / 20. ) * zpush ( front_edit ) * C0 ) ;
queuecurve ( d2 , cols [ i + ( d % ( cgi . S84 / drawcell - > type ) ! = 0 ) ] , 0 , i < 2 ? PPR : : LINE : PPR : : SUPERLINE ) ;
2019-05-15 15:38:49 +00:00
}
}
2019-02-28 16:49:57 +00:00
return ;
}
2018-08-28 03:40:15 +00:00
2019-05-26 16:04:02 +00:00
for ( int d = 0 ; d < cgi . S84 ; d + + ) {
unsigned col = ( d % ( cgi . S84 / drawcell - > type ) = = 0 ) ? gridcolor : lightgrid ;
queueline ( d2 * C0 , d2 * xspinpush0 ( M_PI * d / cgi . S42 , 1 ) , col , 4 + vid . linequality ) ;
2018-08-01 09:07:22 +00:00
}
for ( int u = 2 ; u < = 20 ; u + + ) {
PRING ( d ) {
2020-07-27 16:49:04 +00:00
curvepoint ( xspinpush0 ( M_PI * d / cgi . S42 , u / 20. ) ) ;
2016-08-26 09:58:03 +00:00
}
2020-07-27 16:49:04 +00:00
queuecurve ( d2 , ( u % 5 = = 0 ) ? gridcolor : lightgrid , 0 , PPR : : LINE ) ;
2017-07-10 18:47:38 +00:00
}
2018-08-01 09:07:22 +00:00
queueline ( drawtrans * ccenter , drawtrans * coldcenter , gridcolor , 4 + vid . linequality ) ;
2016-08-26 09:58:03 +00:00
}
2017-07-10 18:47:38 +00:00
void drawHandleKey ( int sym , int uni ) ;
2017-12-22 20:57:55 +00:00
2017-12-22 21:34:01 +00:00
static ld brush_sizes [ 10 ] = {
0.001 , 0.002 , 0.005 , 0.0075 , 0.01 , 0.015 , 0.02 , 0.05 , 0.075 , 0.1 } ;
static unsigned texture_colors [ ] = {
11 ,
0x000000FF ,
0xFFFFFFFF ,
0xFF0000FF ,
0xFFFF00FF ,
0x00FF00FF ,
0x00FFFFFF ,
0x0000FFFF ,
0xFF00FFFF ,
0xC0C0C0FF ,
0x808080FF ,
0x404040FF ,
0x804000FF
} ;
2018-08-28 03:39:41 +00:00
bool area_in_pi = false ;
ld compute_area ( hpcshape & sh ) {
ld area = 0 ;
for ( int i = sh . s ; i < sh . e - 1 ; i + + ) {
2019-05-26 16:04:02 +00:00
hyperpoint h1 = cgi . hpc [ i ] ;
hyperpoint h2 = cgi . hpc [ i + 1 ] ;
2018-08-28 03:39:41 +00:00
if ( euclid )
area + = ( h2 [ 1 ] + h1 [ 1 ] ) * ( h2 [ 0 ] - h1 [ 0 ] ) / 2 ;
else {
hyperpoint rh2 = gpushxto0 ( h1 ) * h2 ;
hyperpoint rh1 = gpushxto0 ( h2 ) * h1 ;
// ld a1 = atan2(h1[1], h1[0]);
// ld a2 = atan2(h2[1], h2[0]);
ld b1 = atan2 ( rh1 [ 1 ] , rh1 [ 0 ] ) ;
ld b2 = atan2 ( rh2 [ 1 ] , rh2 [ 0 ] ) ;
// C0 -> H1 -> H2 -> C0
// at C0: (a1-a2)
// at H1: (rh2 - a1 - M_PI)
// at H2: (a2+M_PI - rh1)
// total: rh2 - rh1
2018-11-08 17:18:25 +00:00
// ld z = degree;
2018-08-28 03:39:41 +00:00
ld x = b2 - b1 + M_PI ;
while ( x > M_PI ) x - = 2 * M_PI ;
while ( x < - M_PI ) x + = 2 * M_PI ;
area + = x ;
}
}
return area ;
}
2019-02-28 18:02:01 +00:00
2019-08-15 13:05:43 +00:00
# define EDITING_TRIANGLES (GDIM == 3)
2019-02-28 18:02:01 +00:00
2019-08-09 23:15:41 +00:00
EX void showDrawEditor ( ) {
2019-02-17 17:41:40 +00:00
# if CAP_POLY
2017-07-12 17:50:39 +00:00
cmode = sm : : DRAW ;
2017-07-16 21:00:55 +00:00
gamescreen ( 0 ) ;
2017-07-10 18:47:38 +00:00
drawGrid ( ) ;
2018-07-09 16:39:34 +00:00
if ( callhandlers ( false , hooks_prestats ) ) return ;
2016-08-26 09:58:03 +00:00
2017-06-18 16:52:15 +00:00
if ( ! mouseout ( ) ) getcstat = ' - ' ;
2016-08-26 09:58:03 +00:00
2017-12-17 23:24:56 +00:00
int sg ;
2016-08-26 09:58:03 +00:00
string line1 , line2 ;
2017-12-17 23:24:56 +00:00
usershape * us = NULL ;
2017-12-22 20:57:55 +00:00
bool intexture = false ;
2020-04-17 18:04:33 +00:00
( void ) intexture ;
bool freedraw = drawing_tool ;
2017-12-21 10:36:07 +00:00
# if CAP_TEXTURE
2018-03-17 20:12:46 +00:00
if ( texture : : config . tstate = = texture : : tsActive ) {
2017-12-17 23:24:56 +00:00
sg = 16 ;
line1 = " texture " ;
line2 = " " ;
2018-03-17 20:12:46 +00:00
texture : : config . data . update ( ) ;
2017-12-22 20:57:55 +00:00
intexture = true ;
2020-04-17 18:04:33 +00:00
freedraw = true ;
drawing_tool = false ;
2017-12-17 23:24:56 +00:00
}
2017-12-21 10:36:07 +00:00
# endif
2020-04-17 18:04:33 +00:00
if ( ! freedraw ) {
2017-12-17 23:24:56 +00:00
2017-12-21 10:36:07 +00:00
sg = drawcellShapeGroup ( ) ;
2016-08-26 09:58:03 +00:00
2017-12-17 23:24:56 +00:00
switch ( sg ) {
2018-08-27 17:27:35 +00:00
case sgPlayer :
2017-12-17 23:24:56 +00:00
line1 = XLAT ( " character " ) ;
line2 = csname ( vid . cs ) ;
break ;
2016-08-26 09:58:03 +00:00
2018-08-27 17:27:35 +00:00
case sgMonster :
2017-12-17 23:24:56 +00:00
line1 = XLAT ( " monster " ) ;
line2 = XLAT1 ( minf [ drawcell - > monst ] . name ) ;
break ;
2018-08-27 17:27:35 +00:00
case sgItem :
2017-12-17 23:24:56 +00:00
line1 = XLAT ( " item " ) ;
line2 = XLAT1 ( iinf [ drawcell - > item ] . name ) ;
break ;
2018-08-27 17:27:35 +00:00
case sgFloor :
2019-08-15 13:05:43 +00:00
line1 = GDIM = = 3 ? XLAT ( " pick something " ) : XLAT ( " floor " ) ;
2019-05-15 15:41:57 +00:00
line2 = " # " + its ( drawcellShapeID ( ) ) ;
/* line2 = XLAT(ishept(drawcell) ? "heptagonal" :
ishex1 ( drawcell ) ? " hexagonal #1 " : " hexagonal " ) ; */
break ;
case sgWall :
line1 = XLAT ( " statue " ) ;
2018-08-27 17:27:35 +00:00
line2 = " # " + its ( drawcellShapeID ( ) ) ;
/* line2 = XLAT(ishept(drawcell) ? "heptagonal" :
ishex1 ( drawcell ) ? " hexagonal #1 " : " hexagonal " ) ; */
break ;
2017-12-17 23:24:56 +00:00
}
2016-08-26 09:58:03 +00:00
2017-12-18 22:42:08 +00:00
us = usershapes [ drawcellShapeGroup ( ) ] [ drawcellShapeID ( ) ] ;
2016-08-26 09:58:03 +00:00
}
2019-08-10 20:30:02 +00:00
int fs = editor_fsize ( ) ;
2016-08-26 09:58:03 +00:00
// displayButton(8, 8+fs*9, XLAT("l = lands"), 'l', 0);
displayfr ( 8 , 8 + fs , 2 , vid . fsize , line1 , 0xC0C0C0 , 0 ) ;
2017-12-22 20:57:55 +00:00
2020-04-17 18:04:33 +00:00
if ( ! freedraw ) {
2018-08-27 17:27:35 +00:00
if ( sg = = sgFloor )
2017-12-22 20:57:55 +00:00
displayButton ( 8 , 8 + fs * 2 , line2 + XLAT ( " (r = complex tesselations) " ) , ' r ' , 0 ) ;
else
displayfr ( 8 , 8 + fs * 2 , 2 , vid . fsize , line2 , 0xC0C0C0 , 0 ) ;
2019-08-15 13:05:43 +00:00
displayButton ( 8 , 8 + fs * 3 , XLAT ( GDIM = = 3 ? " l = color group: %1 " : " l = layers: %1 " , its ( dslayer ) ) , ' l ' , 0 ) ;
2017-12-22 20:57:55 +00:00
}
2017-12-17 23:24:56 +00:00
2018-06-22 12:47:24 +00:00
if ( us & & isize ( us - > d [ dslayer ] . list ) ) {
2016-08-26 09:58:03 +00:00
usershapelayer & ds ( us - > d [ dslayer ] ) ;
2019-02-28 18:02:01 +00:00
if ( ! EDITING_TRIANGLES ) {
displayButton ( 8 , 8 + fs * 4 , XLAT ( " 1-9 = rotations: %1 " , its ( ds . rots ) ) , ' 1 ' + ( ds . rots % 9 ) , 0 ) ;
displayButton ( 8 , 8 + fs * 5 , XLAT ( ds . sym ? " 0 = symmetry " : " 0 = asymmetry " ) , ' 0 ' , 0 ) ;
}
2016-08-26 09:58:03 +00:00
2018-06-22 12:47:24 +00:00
displayfr ( 8 , 8 + fs * 7 , 2 , vid . fsize , XLAT ( " %1 vertices " , its ( isize ( ds . list ) ) ) , 0xC0C0C0 , 0 ) ;
2017-06-18 16:52:15 +00:00
displaymm ( ' a ' , 8 , 8 + fs * 8 , 2 , vid . fsize , XLAT ( " a = add v " ) , 0 ) ;
2019-02-28 18:02:01 +00:00
if ( ! EDITING_TRIANGLES ) {
if ( autochoose ) {
displaymm ( ' m ' , 8 , 8 + fs * 9 , 2 , vid . fsize , XLAT ( " m = move v " ) , 0 ) ;
displaymm ( ' d ' , 8 , 8 + fs * 10 , 2 , vid . fsize , XLAT ( " d = delete v " ) , 0 ) ;
}
else {
displayButton ( 8 , 8 + fs * 9 , XLAT ( " m = move v " ) , ' m ' , 0 ) ;
displayButton ( 8 , 8 + fs * 10 , XLAT ( " d = delete v " ) , ' d ' , 0 ) ;
}
displaymm ( ' c ' , 8 , 8 + fs * 11 , 2 , vid . fsize , XLAT ( autochoose ? " autochoose " : " c = choose " ) , 0 ) ;
displayButton ( 8 , 8 + fs * 12 , XLAT ( " b = switch auto " ) , ' b ' , 0 ) ;
2017-06-18 16:52:15 +00:00
}
else {
2019-02-28 18:02:01 +00:00
displayfr ( 8 , 8 + fs * 9 , 2 , vid . fsize , XLAT ( " c = reuse " ) , 0xC0C0C0 , 0 ) ;
displayfr ( 8 , 8 + fs * 10 , 2 , vid . fsize , XLAT ( " d = delete " ) , 0xC0C0C0 , 0 ) ;
2017-06-18 16:52:15 +00:00
}
2016-08-26 09:58:03 +00:00
2019-08-15 13:05:43 +00:00
if ( GDIM = = 2 ) {
2019-02-28 16:49:57 +00:00
displayfr ( 8 , 8 + fs * 14 , 2 , vid . fsize , XLAT ( " t = shift " ) , 0xC0C0C0 , 0 ) ;
displayfr ( 8 , 8 + fs * 15 , 2 , vid . fsize , XLAT ( " y = spin " ) , 0xC0C0C0 , 0 ) ;
}
2019-05-15 15:42:21 +00:00
if ( mousekey = = ' g ' )
2017-12-22 20:23:17 +00:00
displayButton ( 8 , 8 + fs * 16 , XLAT ( " p = grid color " ) , ' p ' , 0 ) ;
else
displayButton ( 8 , 8 + fs * 16 , XLAT ( " p = paint " ) , ' p ' , 0 ) ;
2019-08-15 13:05:43 +00:00
if ( GDIM = = 2 )
2019-02-28 16:49:57 +00:00
displayfr ( 8 , 8 + fs * 17 , 2 , vid . fsize , XLAT ( " z = z-level " ) , 0xC0C0C0 , 0 ) ;
2016-08-26 09:58:03 +00:00
2017-12-17 23:24:56 +00:00
}
2017-12-21 10:36:07 +00:00
# if CAP_TEXTURE
2020-04-17 18:04:33 +00:00
else if ( freedraw ) {
2017-12-22 20:57:55 +00:00
displayButton ( 8 , 8 + fs * 2 , XLAT ( texture : : texturesym ? " 0 = symmetry " : " 0 = asymmetry " ) , ' 0 ' , 0 ) ;
2018-01-04 11:25:02 +00:00
if ( mousekey = = ' g ' )
displayButton ( 8 , 8 + fs * 16 , XLAT ( " p = grid color " ) , ' p ' , 0 ) ;
else
displayButton ( 8 , 8 + fs * 16 , XLAT ( " p = color " ) , ' p ' , 0 ) ;
2020-04-17 18:04:33 +00:00
if ( drawing_tool )
displayButton ( 8 , 8 + fs * 17 , XLAT ( " f = fill " ) + ( dtfill ? " (on) " : " (off) " ) , ' f ' , 0 ) ;
2020-04-18 14:10:56 +00:00
displayButton ( 8 , 8 + fs * 4 , XLAT ( " b = brush size: %1 " , fts ( dtwidth ) ) , ' b ' , 0 ) ;
2017-12-22 20:57:55 +00:00
displayButton ( 8 , 8 + fs * 5 , XLAT ( " u = undo " ) , ' u ' , 0 ) ;
2018-01-04 11:25:02 +00:00
displaymm ( ' d ' , 8 , 8 + fs * 7 , 2 , vid . fsize , XLAT ( " d = draw " ) , 0 ) ;
displaymm ( ' l ' , 8 , 8 + fs * 8 , 2 , vid . fsize , XLAT ( " l = line " ) , 0 ) ;
displaymm ( ' c ' , 8 , 8 + fs * 9 , 2 , vid . fsize , XLAT ( " c = circle " ) , 0 ) ;
2020-04-17 18:04:33 +00:00
if ( drawing_tool )
2020-07-12 19:26:15 +00:00
displaymm ( ' T ' , 8 , 8 + fs * 10 , 10 , vid . fsize , XLAT ( " T = text " ) , 0 ) ;
if ( drawing_tool )
displaymm ( ' e ' , 8 , 8 + fs * 11 , 2 , vid . fsize , XLAT ( " e = erase " ) , 0 ) ;
2018-06-22 12:47:24 +00:00
int s = isize ( texture : : config . data . pixels_to_draw ) ;
2020-07-12 19:26:15 +00:00
if ( s ) displaymm ( 0 , 8 , 8 + fs * 12 , 2 , vid . fsize , its ( s ) , 0 ) ;
2016-08-26 09:58:03 +00:00
}
2017-12-21 10:36:07 +00:00
# endif
2016-08-26 09:58:03 +00:00
else {
2017-08-06 12:50:16 +00:00
displaymm ( ' n ' , 8 , 8 + fs * 5 , 2 , vid . fsize , XLAT ( " 'n' to start " ) , 0 ) ;
2017-10-04 20:27:51 +00:00
displaymm ( ' u ' , 8 , 8 + fs * 6 , 2 , vid . fsize , XLAT ( " 'u' to load current " ) , 0 ) ;
2017-08-06 12:50:16 +00:00
if ( mousekey = = ' a ' | | mousekey = = ' d ' | | mousekey = = ' d ' | |
mousekey = = ' c ' ) mousekey = ' n ' ;
2016-08-26 09:58:03 +00:00
}
2019-02-28 16:49:57 +00:00
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 )
2019-08-10 20:33:20 +00:00
displayfr ( 8 , 8 + fs * 19 , 2 , vid . fsize , XLAT ( front_config = = eFront : : sphere_camera ? " z = camera " : front_config = = eFront : : sphere_center ? " z = spheres " :
nonisotropic & & front_config = = eFront : : equidistants ? " Z = " :
nonisotropic & & front_config = = eFront : : const_x ? " X = " :
nonisotropic & & front_config = = eFront : : const_y ? " Y = " :
" z = equi " ) + " " + fts ( front_edit ) , 0xC0C0C0 , 0 ) ;
2016-08-26 09:58:03 +00:00
2019-05-15 15:42:21 +00:00
displaymm ( ' g ' , vid . xres - 8 , 8 + fs * 4 , 2 , vid . fsize , XLAT ( " g = grid " ) , 16 ) ;
2018-01-05 16:30:03 +00:00
# if CAP_TEXTURE
2020-04-17 18:04:33 +00:00
if ( freedraw ) for ( int i = 0 ; i < 10 ; i + + ) {
2017-12-22 21:34:01 +00:00
if ( 8 + fs * ( 6 + i ) < vid . yres - 8 - fs * 7 )
displayColorButton ( vid . xres - 8 , 8 + fs * ( 6 + i ) , " ### " , 1000 + i , 16 , 1 , dialog : : displaycolor ( texture_colors [ i + 1 ] ) ) ;
2018-01-05 16:30:03 +00:00
2020-04-18 14:10:56 +00:00
if ( displayfr ( vid . xres - 8 - fs * 3 , 8 + fs * ( 6 + i ) , 0 , vid . fsize , its ( i + 1 ) , dtwidth = = brush_sizes [ i ] ? 0xFF8000 : 0xC0C0C0 , 16 ) )
2017-12-22 21:34:01 +00:00
getcstat = 2000 + i ;
}
2017-12-21 10:36:07 +00:00
2020-04-17 18:04:33 +00:00
if ( ! freedraw )
2017-12-17 23:24:56 +00:00
displaymm ( ' e ' , vid . xres - 8 , 8 + fs , 2 , vid . fsize , XLAT ( " e = edit this " ) , 16 ) ;
2017-12-21 10:36:07 +00:00
# endif
2016-08-26 09:58:03 +00:00
2017-06-09 01:41:33 +00:00
if ( ! mouseout ( ) ) {
2019-08-10 20:32:45 +00:00
hyperpoint mh ;
2019-08-15 13:05:43 +00:00
if ( GDIM = = 2 ) {
2020-07-27 16:49:04 +00:00
transmatrix T = inverse ( unshift ( drawtrans ) ) * rgpushxto0 ( ccenter ) ; /* todo? */
mh = spintox ( gpushxto0 ( ccenter ) * coldcenter ) * T * unshift ( mouseh ) ;
2019-08-10 20:32:45 +00:00
}
else
2020-07-27 16:49:04 +00:00
mh = inverse_shift ( drawtrans , find_mouseh3 ( ) ) ;
2019-08-10 20:32:45 +00:00
2019-05-21 22:01:30 +00:00
displayfr ( vid . xres - 8 , vid . yres - 8 - fs * 7 , 2 , vid . fsize , XLAT ( " x: %1 " , fts ( mh [ 0 ] , 4 ) ) , 0xC0C0C0 , 16 ) ;
displayfr ( vid . xres - 8 , vid . yres - 8 - fs * 6 , 2 , vid . fsize , XLAT ( " y: %1 " , fts ( mh [ 1 ] , 4 ) ) , 0xC0C0C0 , 16 ) ;
2019-08-10 20:32:45 +00:00
displayfr ( vid . xres - 8 , vid . yres - 8 - fs * 5 , 2 , vid . fsize , XLAT ( " z: %1 " , fts ( mh [ 2 ] , 4 ) ) , 0xC0C0C0 , 16 ) ;
2019-08-19 10:11:07 +00:00
if ( MDIM = = 4 )
2019-05-21 22:01:30 +00:00
displayfr ( vid . xres - 8 , vid . yres - 8 - fs * 4 , 2 , vid . fsize , XLAT ( " w: %1 " , fts ( mh [ 3 ] , 4 ) ) , 0xC0C0C0 , 16 ) ;
2020-07-27 16:49:04 +00:00
mh = inverse_exp ( shiftless ( mh ) ) ;
2019-08-24 16:14:38 +00:00
displayfr ( vid . xres - 8 , vid . yres - 8 - fs * 3 , 2 , vid . fsize , XLAT ( " r: %1 " , fts ( hypot_d ( 3 , mh ) , 4 ) ) , 0xC0C0C0 , 16 ) ;
2019-08-15 13:05:43 +00:00
if ( GDIM = = 3 ) {
2019-05-21 22:01:30 +00:00
displayfr ( vid . xres - 8 , vid . yres - 8 - fs , 2 , vid . fsize , XLAT ( " ϕ: %1° " , fts ( - atan2 ( mh [ 2 ] , hypot_d ( 2 , mh ) ) / degree , 4 ) ) , 0xC0C0C0 , 16 ) ;
displayfr ( vid . xres - 8 , vid . yres - 8 - fs * 2 , 2 , vid . fsize , XLAT ( " λ: %1° " , fts ( - atan2 ( mh [ 1 ] , mh [ 0 ] ) / degree , 4 ) ) , 0xC0C0C0 , 16 ) ;
2019-04-13 11:04:17 +00:00
}
else {
2019-05-21 22:01:30 +00:00
displayfr ( vid . xres - 8 , vid . yres - 8 - fs * 2 , 2 , vid . fsize , XLAT ( " ϕ: %1° " , fts ( - atan2 ( mh [ 1 ] , mh [ 0 ] ) / degree , 4 ) ) , 0xC0C0C0 , 16 ) ;
2019-04-13 11:04:17 +00:00
}
2016-08-26 09:58:03 +00:00
}
2018-08-28 03:39:41 +00:00
if ( us ) {
2019-05-26 16:04:02 +00:00
cgi . require_usershapes ( ) ;
auto & sh = cgi . ushr [ & us - > d [ dslayer ] ] ;
2018-08-28 03:39:41 +00:00
if ( sh . e > = sh . s + 3 )
2019-05-21 22:01:30 +00:00
displayButton ( vid . xres - 8 , vid . yres - 8 - fs * 8 , XLAT ( " area: %1 " , area_in_pi ? fts ( compute_area ( sh ) / M_PI , 4 ) + " π " : fts ( compute_area ( sh ) , 4 ) ) , ' w ' , 16 ) ;
2018-08-28 03:39:41 +00:00
}
2016-08-26 09:58:03 +00:00
displayFunctionKeys ( ) ;
2017-07-10 18:47:38 +00:00
keyhandler = drawHandleKey ;
2019-02-17 17:41:40 +00:00
# else
popScreen ( ) ;
# endif
2016-08-26 09:58:03 +00:00
}
2019-02-17 17:41:40 +00:00
# if CAP_POLY
2017-10-04 20:27:51 +00:00
void loadShapes ( int sg , int id ) {
delete usershapes [ sg ] [ id ] ;
usershapes [ sg ] [ id ] = NULL ;
initquickqueue ( ) ;
dynamicval < bool > ws ( mmspatial , false ) ;
2020-07-27 16:49:04 +00:00
auto sId = shiftless ( Id ) ;
2017-10-04 20:27:51 +00:00
if ( sg = = 0 ) {
2020-07-27 16:49:04 +00:00
multi : : cpid = id , drawMonsterType ( moPlayer , drawcell , sId , 0xC0C0C0 , 0 , 0xC0C0C0 ) ;
2017-10-04 20:27:51 +00:00
}
else if ( sg = = 1 ) {
2020-07-27 16:49:04 +00:00
drawMonsterType ( eMonster ( id ) , drawcell , sId , minf [ id ] . color , 0 , minf [ id ] . color ) ;
2017-10-04 20:27:51 +00:00
}
else if ( sg = = 2 ) {
2020-07-27 16:49:04 +00:00
drawItemType ( eItem ( id ) , drawcell , sId , iinf [ id ] . color , 0 , false ) ;
2017-10-04 20:27:51 +00:00
}
else {
2020-07-27 16:49:04 +00:00
draw_qfi ( drawcell , sId , 0 , PPR : : FLOOR ) ;
2017-10-04 20:27:51 +00:00
}
sortquickqueue ( ) ;
int layer = 0 ;
initShape ( sg , id ) ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( ptds ) ; i + + ) {
2018-09-04 17:53:42 +00:00
auto pp = dynamic_cast < dqi_poly * > ( & * ptds [ i ] ) ;
if ( ! pp ) continue ;
auto & ptd = * pp ;
2017-10-04 20:27:51 +00:00
2018-09-04 17:53:42 +00:00
int cnt = ptd . cnt ;
2017-10-04 20:27:51 +00:00
usershapelayer * dsCur = & usershapes [ sg ] [ id ] - > d [ layer ] ;
dsCur - > list . clear ( ) ;
2018-09-04 17:53:42 +00:00
dsCur - > color = ptd . color ;
2017-10-04 20:27:51 +00:00
dsCur - > sym = false ;
dsCur - > rots = 1 ;
2019-02-28 16:23:02 +00:00
dsCur - > zlevel = 0 ;
2017-10-04 20:27:51 +00:00
2019-05-26 16:04:02 +00:00
for ( auto & v : cgi . symmetriesAt )
2018-09-04 17:53:42 +00:00
if ( v [ 0 ] = = ptd . offset ) {
2017-10-04 20:27:51 +00:00
dsCur - > rots = v [ 1 ] ;
dsCur - > sym = v [ 2 ] = = 2 ;
}
int d = dsCur - > rots * ( dsCur - > sym ? 2 : 1 ) ;
for ( int i = 0 ; i < cnt / d ; i + + )
2020-07-27 16:49:04 +00:00
dsCur - > list . push_back ( unshift ( ptd . V ) * glhr : : gltopoint ( ( * ptd . tab ) [ i + ptd . offset ] ) ) ;
2017-10-04 20:27:51 +00:00
layer + + ;
if ( layer = = USERLAYERS ) break ;
}
2019-05-26 16:04:02 +00:00
usershape_changes + + ;
2017-10-04 20:27:51 +00:00
}
2019-02-17 17:41:40 +00:00
2016-08-26 09:58:03 +00:00
void applyToShape ( int sg , int id , int uni , hyperpoint mh ) {
bool haveshape = usershapes [ sg ] [ id ] ;
bool xnew = false ;
2017-06-18 16:52:15 +00:00
if ( uni = = ' - ' ) uni = mousekey ;
2016-08-26 09:58:03 +00:00
if ( ! haveshape ) {
2017-10-04 20:27:51 +00:00
if ( uni = = ' n ' )
2016-08-26 09:58:03 +00:00
initShape ( sg , id ) ;
2017-10-04 20:27:51 +00:00
else if ( uni = = ' u ' ) ;
2016-08-26 09:58:03 +00:00
else if ( uni > = ' 0 ' & & uni < = ' 9 ' ) {
initShape ( sg , id ) ;
xnew = true ;
}
else
return ;
}
usershapelayer * dsCur = & usershapes [ sg ] [ id ] - > d [ dslayer ] ;
2017-06-18 16:52:15 +00:00
2016-08-26 09:58:03 +00:00
if ( uni = = ' n ' | | xnew ) {
dsCur - > list . clear ( ) ;
dsCur - > list . push_back ( mh ) ;
2019-05-26 16:04:02 +00:00
usershape_changes + + ;
2016-08-26 09:58:03 +00:00
}
2017-10-04 20:27:51 +00:00
if ( uni = = ' u ' )
loadShapes ( sg , id ) ;
2019-02-28 16:23:02 +00:00
2019-08-15 13:05:43 +00:00
if ( uni = = ' z ' & & haveshape & & GDIM = = 2 )
2019-02-28 16:23:02 +00:00
dialog : : editNumber ( dsCur - > zlevel , - 10 , + 10 , 0.1 , 0 , XLAT ( " z-level " ) ,
XLAT ( " Changing the z-level will make this layer affected by the parallax effect. " ) ) ;
2017-10-04 20:27:51 +00:00
2019-02-28 18:02:01 +00:00
if ( EDITING_TRIANGLES ) {
if ( uni = = ' a ' ) {
dsCur - > list . push_back ( mh ) ;
uni = 0 ;
2019-05-26 16:04:02 +00:00
usershape_changes + + ;
2019-02-28 18:02:01 +00:00
}
else if ( uni = = ' c ' | | uni = = ' d ' | | uni = = ' m ' ) {
hyperpoint best = mh ;
hyperpoint onscr ;
applymodel ( drawtrans * mh , onscr ) ;
println ( hlog , " onscr = " , onscr ) ;
ld dist = HUGE_VAL ;
for ( auto & layer : usershapes [ sg ] [ id ] - > d )
for ( const hyperpoint & h : layer . list ) {
hyperpoint h1 ;
applymodel ( drawtrans * h , h1 ) ;
ld d = sqhypot_d ( 2 , h1 - onscr ) ;
if ( d < dist ) dist = d , best = h ;
}
if ( uni = = ' c ' ) dsCur - > list . push_back ( best ) ;
else if ( uni = = ' d ' ) {
vector < hyperpoint > oldlist = move ( dsCur - > list ) ;
dsCur - > list . clear ( ) ;
int i ;
for ( i = 0 ; i < isize ( oldlist ) ; i + = 3 )
if ( oldlist [ i ] ! = best & & oldlist [ i + 1 ] ! = best & & oldlist [ i + 2 ] ! = best )
dsCur - > list . push_back ( oldlist [ i ] ) ,
dsCur - > list . push_back ( oldlist [ i + 1 ] ) ,
dsCur - > list . push_back ( oldlist [ i + 2 ] ) ;
for ( ; i < isize ( oldlist ) ; i + + )
if ( oldlist [ i ] ! = best )
dsCur - > list . push_back ( oldlist [ i ] ) ;
}
2019-05-26 16:04:02 +00:00
usershape_changes + + ;
2019-02-28 18:02:01 +00:00
uni = 0 ;
}
2019-05-15 15:42:36 +00:00
else if ( uni = = COLORKEY ) dsCur - > color = colortouse ;
2019-02-28 18:02:01 +00:00
else if ( uni ! = ' D ' ) uni = 0 ;
}
2016-08-26 09:58:03 +00:00
if ( uni = = ' a ' & & haveshape ) {
2017-06-18 16:52:15 +00:00
mh = spin ( 2 * M_PI * - ew . rotid / dsCur - > rots ) * mh ;
if ( ew . symid ) mh = Mirror * mh ;
2018-06-22 12:47:24 +00:00
if ( ew . pointid < 0 | | ew . pointid > = isize ( dsCur - > list ) )
ew . pointid = isize ( dsCur - > list ) - 1 , ew . side = 1 ;
2017-06-18 16:52:15 +00:00
dsCur - > list . insert ( dsCur - > list . begin ( ) + ew . pointid + ( ew . side ? 1 : 0 ) , mh ) ;
if ( ew . side ) ew . pointid + + ;
2019-05-26 16:04:02 +00:00
usershape_changes + + ;
2016-08-26 09:58:03 +00:00
}
if ( uni = = ' D ' ) {
delete usershapes [ sg ] [ id ] ;
usershapes [ sg ] [ id ] = NULL ;
}
2017-06-18 16:52:15 +00:00
if ( uni = = ' m ' | | uni = = ' d ' ) {
int i = ew . pointid ;
2018-06-22 12:47:24 +00:00
if ( i < 0 | | i > = isize ( dsCur - > list ) ) return ;
2017-06-18 16:52:15 +00:00
mh = spin ( 2 * M_PI * - ew . rotid / dsCur - > rots ) * mh ;
if ( ew . symid ) mh = Mirror * mh ;
if ( uni = = ' m ' | | uni = = ' M ' )
2016-08-26 09:58:03 +00:00
dsCur - > list [ i ] = mh ;
2017-06-18 16:52:15 +00:00
if ( uni = = ' d ' | | uni = = ' b ' ) {
2016-08-26 09:58:03 +00:00
dsCur - > list . erase ( dsCur - > list . begin ( ) + i ) ;
2017-06-18 16:52:15 +00:00
if ( ew . side = = 1 & & ew . pointid > = i ) ew . pointid - - ;
if ( ew . side = = 0 & & ew . pointid > i ) ew . pointid - - ;
2016-08-26 09:58:03 +00:00
}
2019-05-26 16:04:02 +00:00
usershape_changes + + ;
2016-08-26 09:58:03 +00:00
}
2017-06-18 16:52:15 +00:00
2016-08-26 09:58:03 +00:00
if ( uni = = ' K ' ) {
if ( vid . cs . charid > = 4 ) {
2019-05-26 16:04:02 +00:00
loadShape ( sg , id , cgi . shCatBody , 2 , 0 ) ;
loadShape ( sg , id , cgi . shCatHead , 2 , 1 ) ;
2016-08-26 09:58:03 +00:00
}
else {
2019-05-26 16:04:02 +00:00
if ( ! ( vid . cs . charid & 1 ) ) loadShape ( sg , id , cgi . shPBody , 2 , 0 ) ;
else loadShape ( sg , id , cgi . shFemaleBody , 2 , 0 ) ;
2016-08-26 09:58:03 +00:00
2019-05-26 16:04:02 +00:00
loadShape ( sg , id , cgi . shPSword , 1 , 1 ) ;
2016-08-26 09:58:03 +00:00
if ( vid . cs . charid & 1 )
2019-05-26 16:04:02 +00:00
loadShape ( sg , id , cgi . shFemaleDress , 2 , 2 ) ;
2016-08-26 09:58:03 +00:00
2017-03-23 10:53:57 +00:00
/* if(vid.cs.charid&1)
2019-05-26 16:04:02 +00:00
loadShape ( sg , id , cgi . shPrincessDress , 1 , 3 ) ;
2016-08-26 09:58:03 +00:00
else
2019-05-26 16:04:02 +00:00
loadShape ( sg , id , cgi . shPrinceDress , 2 , 3 ) ; */
2017-03-23 10:53:57 +00:00
2019-05-26 16:04:02 +00:00
loadShape ( sg , id , cgi . shRatCape2 , 1 , 3 ) ;
2016-08-26 09:58:03 +00:00
if ( vid . cs . charid & 1 )
2019-05-26 16:04:02 +00:00
loadShape ( sg , id , cgi . shFemaleHair , 2 , 4 ) ;
2016-08-26 09:58:03 +00:00
else
2019-05-26 16:04:02 +00:00
loadShape ( sg , id , cgi . shPHead , 2 , 4 ) ;
2016-08-26 09:58:03 +00:00
2019-05-26 16:04:02 +00:00
loadShape ( sg , id , cgi . shPFace , 2 , 5 ) ;
2016-08-26 09:58:03 +00:00
}
2019-05-26 16:04:02 +00:00
// loadShape(sg, id, cgi.shWolf, 2, dslayer);
2016-08-26 09:58:03 +00:00
2019-05-26 16:04:02 +00:00
usershape_changes + + ;
2016-08-26 09:58:03 +00:00
}
if ( uni = = ' + ' ) dsCur - > rots + + ;
if ( uni > = ' 1 ' & & uni < = ' 9 ' ) {
dsCur - > rots = uni - ' 0 ' ;
if ( dsCur - > rots = = 9 ) dsCur - > rots = 21 ;
2019-05-26 16:04:02 +00:00
usershape_changes + + ;
2016-08-26 09:58:03 +00:00
}
if ( uni = = ' 0 ' ) {
dsCur - > sym = ! dsCur - > sym ;
2019-05-26 16:04:02 +00:00
usershape_changes + + ;
2016-08-26 09:58:03 +00:00
}
if ( uni = = ' t ' ) {
dsCur - > shift = mh ;
2019-05-26 16:04:02 +00:00
usershape_changes + + ;
2016-08-26 09:58:03 +00:00
}
if ( uni = = ' y ' ) {
dsCur - > spin = mh ;
2019-05-26 16:04:02 +00:00
usershape_changes + + ;
2016-08-26 09:58:03 +00:00
}
if ( uni = = COLORKEY ) dsCur - > color = colortouse ;
}
2019-05-21 21:59:07 +00:00
void writeHyperpoint ( hstream & f , hyperpoint h ) {
println ( f , spaced_of ( & h [ 0 ] , MDIM ) ) ;
2016-08-26 09:58:03 +00:00
}
2019-05-21 21:59:07 +00:00
hyperpoint readHyperpoint ( fhstream & f ) {
2016-08-26 09:58:03 +00:00
hyperpoint h ;
2019-05-21 21:59:07 +00:00
for ( int i = 0 ; i < MDIM ; i + + ) scan ( f , h [ i ] ) ;
2016-08-26 09:58:03 +00:00
return h ;
}
string drawHelpLine ( ) {
return XLAT ( " vector graphics editor " ) ;
}
2017-09-03 19:11:33 +00:00
bool onelayeronly ;
2017-12-14 11:10:40 +00:00
bool loadPicFile ( const string & s ) {
2019-05-21 21:59:07 +00:00
fhstream f ( picfile , " rt " ) ;
if ( ! f . f ) {
2017-12-03 08:52:17 +00:00
addMessage ( XLAT ( " Failed to load pictures from %1 " , picfile ) ) ;
2017-12-14 11:10:40 +00:00
return false ;
2017-12-03 08:52:17 +00:00
}
2019-05-21 21:59:07 +00:00
scanline ( f ) ;
2019-05-21 22:19:03 +00:00
scan ( f , f . vernum ) ;
printf ( " vernum = %x \n " , f . vernum ) ;
if ( f . vernum = = 0 ) {
2017-12-03 08:52:17 +00:00
addMessage ( XLAT ( " Failed to load pictures from %1 " , picfile ) ) ;
2019-05-21 21:59:07 +00:00
return false ;
2017-12-03 08:52:17 +00:00
}
2017-12-22 20:37:30 +00:00
2019-05-21 22:19:03 +00:00
if ( f . vernum > = 0xA0A0 ) {
2018-07-07 09:05:48 +00:00
int tg , wp ;
int nt ;
2019-05-21 21:59:07 +00:00
scan ( f , tg , nt , wp , patterns : : subpattern_flags ) ;
2018-08-28 02:05:32 +00:00
patterns : : whichPattern = patterns : : ePattern ( wp ) ;
2018-08-28 15:17:34 +00:00
set_geometry ( eGeometry ( tg ) ) ;
set_variation ( eVariation ( nt ) ) ;
2018-06-10 22:58:38 +00:00
start_game ( ) ;
2017-12-22 20:37:30 +00:00
}
2017-12-03 08:52:17 +00:00
while ( true ) {
2019-05-21 21:59:07 +00:00
int i , j , l , sym , rots , siz ;
color_t color ;
if ( ! scan ( f , i , j , l , sym , rots , color , siz ) ) break ;
if ( i = = - 1 ) break ;
2017-12-03 08:52:17 +00:00
if ( siz < 0 | | siz > 1000 ) break ;
2017-12-22 20:37:30 +00:00
if ( i > = 4 ) {
2018-08-28 02:05:32 +00:00
if ( i < 8 ) patterns : : whichPattern = patterns : : ePattern ( " xxxxfpzH " [ i ] ) ;
2017-12-22 20:37:30 +00:00
patterns : : subpattern_flags = 0 ;
i = 3 ;
}
2017-12-03 08:52:17 +00:00
initShape ( i , j ) ;
usershapelayer & ds ( usershapes [ i ] [ j ] - > d [ l ] ) ;
2019-05-21 22:19:03 +00:00
if ( f . vernum > = 0xA608 ) scan ( f , ds . zlevel ) ;
2017-12-03 08:52:17 +00:00
ds . shift = readHyperpoint ( f ) ;
ds . spin = readHyperpoint ( f ) ;
ds . list . clear ( ) ;
for ( int i = 0 ; i < siz ; i + + ) {
ds . list . push_back ( readHyperpoint ( f ) ) ;
2019-05-21 21:59:07 +00:00
writeHyperpoint ( hlog , ds . list [ i ] ) ;
2017-12-03 08:52:17 +00:00
}
ds . sym = sym ;
ds . rots = rots ;
ds . color = color ;
}
addMessage ( XLAT ( " Pictures loaded from %1 " , picfile ) ) ;
2019-05-26 16:04:02 +00:00
usershape_changes + + ;
2017-12-14 11:10:40 +00:00
return true ;
2017-12-03 08:52:17 +00:00
}
2017-12-14 11:10:40 +00:00
bool savePicFile ( const string & s ) {
2019-05-21 21:59:07 +00:00
fhstream f ( picfile , " wt " ) ;
if ( ! f . f ) {
2017-12-03 08:52:17 +00:00
addMessage ( XLAT ( " Failed to save pictures to %1 " , picfile ) ) ;
2017-12-14 11:10:40 +00:00
return false ;
2017-12-03 08:52:17 +00:00
}
2019-05-21 21:59:07 +00:00
println ( f , " HyperRogue saved picture " ) ;
2019-05-21 22:19:03 +00:00
println ( f , f . vernum ) ;
if ( f . vernum > = 0xA0A0 )
2019-05-21 21:59:07 +00:00
println ( f , spaced ( geometry , int ( variation ) , patterns : : whichPattern , patterns : : subpattern_flags ) ) ;
2018-08-27 17:27:35 +00:00
for ( int i = 0 ; i < USERSHAPEGROUPS ; i + + ) for ( auto usp : usershapes [ i ] ) {
usershape * us = usp . second ;
2017-12-03 08:52:17 +00:00
if ( ! us ) continue ;
2018-06-22 12:47:24 +00:00
for ( int l = 0 ; l < USERLAYERS ; l + + ) if ( isize ( us - > d [ l ] . list ) ) {
2017-12-03 08:52:17 +00:00
usershapelayer & ds ( us - > d [ l ] ) ;
2019-05-21 21:59:07 +00:00
println ( f , spaced ( i , usp . first , l , ds . sym , ds . rots , ds . color , int ( isize ( ds . list ) ) ) ) ;
print ( f , spaced ( ds . zlevel ) , " " ) ;
2017-12-03 08:52:17 +00:00
writeHyperpoint ( f , ds . shift ) ;
writeHyperpoint ( f , ds . spin ) ;
2019-05-21 21:59:07 +00:00
println ( f ) ;
2018-06-22 12:47:24 +00:00
for ( int i = 0 ; i < isize ( ds . list ) ; i + + )
2017-12-03 08:52:17 +00:00
writeHyperpoint ( f , ds . list [ i ] ) ;
}
}
2019-05-21 21:59:07 +00:00
println ( f , " -1 " ) ;
2017-12-03 08:52:17 +00:00
addMessage ( XLAT ( " Pictures saved to %1 " , picfile ) ) ;
2017-12-14 11:10:40 +00:00
return true ;
2017-12-03 08:52:17 +00:00
}
2017-12-22 21:34:01 +00:00
2017-03-23 10:53:57 +00:00
void drawHandleKey ( int sym , int uni ) {
2017-06-18 16:52:15 +00:00
2019-08-15 13:05:43 +00:00
if ( uni = = PSEUDOKEY_WHEELUP & & GDIM = = 3 & & front_step ) {
2019-05-15 15:38:49 +00:00
front_edit + = front_step * shiftmul ; return ;
}
2019-08-15 13:05:43 +00:00
if ( uni = = PSEUDOKEY_WHEELDOWN & & GDIM = = 3 & & front_step ) {
2019-05-15 15:38:49 +00:00
front_edit - = front_step * shiftmul ; return ;
}
2017-07-10 18:47:38 +00:00
handlePanning ( sym , uni ) ;
2016-08-26 09:58:03 +00:00
2017-12-22 20:23:17 +00:00
if ( uni = = SETMOUSEKEY ) {
2017-12-25 09:26:50 +00:00
if ( mousekey = = newmousekey )
2017-12-22 20:23:17 +00:00
mousekey = ' - ' ;
else
mousekey = newmousekey ;
}
2017-12-03 17:24:34 +00:00
2018-08-28 03:39:41 +00:00
if ( uni = = ' w ' ) area_in_pi = ! area_in_pi ;
2017-12-03 17:24:34 +00:00
if ( uni = = ' r ' ) {
2017-12-09 02:48:30 +00:00
pushScreen ( patterns : : showPattern ) ;
2017-12-03 17:24:34 +00:00
if ( drawplayer )
addMessage ( XLAT ( " Hint: use F7 to edit floor under the player " ) ) ;
}
2016-08-26 09:58:03 +00:00
2020-07-27 16:49:04 +00:00
shiftpoint mh = GDIM = = 2 ? mouseh : find_mouseh3 ( ) ;
hyperpoint mh1 = inverse_shift ( drawtrans , mh ) ;
2017-12-22 20:23:17 +00:00
2018-01-04 11:25:02 +00:00
bool clickused = false ;
2020-07-27 16:49:04 +00:00
if ( ( uni = = ' p ' & & mousekey = = ' g ' ) | | ( uni = = ' g ' & & coldcenter = = ccenter & & ccenter = = mh1 ) ) {
2017-12-22 20:23:17 +00:00
static unsigned grid_colors [ ] = {
8 ,
0x00000040 ,
0xFFFFFF40 ,
0xFF000040 ,
0x0000F040 ,
0x00000080 ,
0xFFFFFF80 ,
0xFF000080 ,
0x0000F080 ,
} ;
dialog : : openColorDialog ( gridcolor , grid_colors ) ;
2018-01-04 11:25:02 +00:00
clickused = true ;
2017-12-22 20:23:17 +00:00
}
2017-12-25 09:26:50 +00:00
char mkuni = uni = = ' - ' ? mousekey : uni ;
if ( mkuni = = ' g ' )
2020-07-27 16:49:04 +00:00
coldcenter = ccenter , ccenter = mh1 , clickused = true ;
2018-01-04 11:25:02 +00:00
2020-07-12 19:26:15 +00:00
if ( uni = = ' d ' | | uni = = ' l ' | | uni = = ' c ' | | uni = = ' e ' | | uni = = ' T ' )
2018-01-04 11:25:02 +00:00
mousekey = uni ;
2017-12-22 20:23:17 +00:00
2020-04-17 18:04:33 +00:00
if ( drawing_tool ) {
if ( sym = = SDLK_F2 ) save_level ( ) ;
if ( sym = = SDLK_F3 ) load_level ( ) ;
2020-04-17 18:18:50 +00:00
if ( sym = = SDLK_F5 ) {
2020-04-17 18:34:49 +00:00
dialog : : push_confirm_dialog ( [ ] {
stop_game ( ) ;
firstland = specialland = laCanvas ;
canvas_default_wall = waInvisibleFloor ;
patterns : : whichCanvas = ' g ' ;
patterns : : canvasback = 0xFFFFFF ;
2020-04-18 14:10:56 +00:00
dtcolor = ( forecolor < < 8 ) | 255 ;
2020-04-17 18:34:49 +00:00
drawplayer = false ;
vid . use_smart_range = 2 ;
start_game ( ) ;
} ,
XLAT ( " Are you sure you want to restart? This will let you draw on a blank screen. " )
) ;
2020-04-17 18:18:50 +00:00
}
2020-04-17 18:04:33 +00:00
}
2018-06-12 22:11:26 +00:00
if ( uni = = ' ' & & ( cheater | | autocheat ) ) {
2020-04-17 18:18:50 +00:00
drawing_tool = ! drawing_tool ;
if ( ! drawing_tool ) {
popScreen ( ) ;
pushScreen ( showMapEditor ) ;
}
2017-07-10 18:47:38 +00:00
}
2016-08-26 09:58:03 +00:00
2019-08-15 13:05:43 +00:00
if ( uni = = ' z ' & & GDIM = = 3 ) {
2019-05-15 15:38:49 +00:00
dialog : : editNumber ( front_edit , 0 , 5 , 0.1 , 0.5 , XLAT ( " z-level " ) , " " ) ;
dialog : : extra_options = [ ] ( ) {
dialog : : addBoolItem ( XLAT ( " The distance from the camera to added points. " ) , front_config = = eFront : : sphere_camera , ' A ' ) ;
dialog : : add_action ( [ ] { front_config = eFront : : sphere_camera ; } ) ;
dialog : : addBoolItem ( XLAT ( " place points at fixed radius " ) , front_config = = eFront : : sphere_center , ' B ' ) ;
dialog : : add_action ( [ ] { front_config = eFront : : sphere_center ; } ) ;
2019-08-10 20:33:20 +00:00
dialog : : addBoolItem ( XLAT ( nonisotropic ? " place points on surfaces of const Z " : " place points on equidistant surfaces " ) , front_config = = eFront : : equidistants , ' C ' ) ;
2019-05-15 15:38:49 +00:00
dialog : : add_action ( [ ] { front_config = eFront : : equidistants ; } ) ;
2019-08-10 20:33:20 +00:00
if ( nonisotropic ) {
dialog : : addBoolItem ( XLAT ( " place points on surfaces of const X " ) , front_config = = eFront : : const_x , ' D ' ) ;
dialog : : add_action ( [ ] { front_config = eFront : : const_x ; } ) ;
dialog : : addBoolItem ( XLAT ( " place points on surfaces of const Y " ) , front_config = = eFront : : const_y , ' E ' ) ;
dialog : : add_action ( [ ] { front_config = eFront : : const_y ; } ) ;
}
2019-05-15 15:38:49 +00:00
dialog : : addSelItem ( XLAT ( " mousewheel step " ) , fts ( front_step ) , ' S ' ) ;
dialog : : add_action ( [ ] {
popScreen ( ) ;
dialog : : editNumber ( front_step , - 10 , 10 , 0.1 , 0.1 , XLAT ( " mousewheel step " ) , " hint: shift for finer steps " ) ;
} ) ;
2019-08-10 20:33:20 +00:00
if ( front_config = = eFront : : sphere_center ) {
dialog : : addSelItem ( XLAT ( " parallels to draw " ) , its ( parallels ) , ' P ' ) ;
dialog : : add_action ( [ ] {
popScreen ( ) ;
dialog : : editNumber ( parallels , 0 , 72 , 1 , 12 , XLAT ( " parallels to draw " ) , " " ) ;
} ) ;
dialog : : addSelItem ( XLAT ( " meridians to draw " ) , its ( meridians ) , ' M ' ) ;
dialog : : add_action ( [ ] {
popScreen ( ) ;
dialog : : editNumber ( meridians , 0 , 72 , 1 , 12 , XLAT ( " meridians to draw " ) , " " ) ;
} ) ;
}
else if ( front_config ! = eFront : : sphere_camera ) {
dialog : : addSelItem ( XLAT ( " range of grid to draw " ) , fts ( equi_range ) , ' R ' ) ;
dialog : : add_action ( [ ] {
popScreen ( ) ;
dialog : : editNumber ( equi_range , 0 , 5 , 0.1 , 1 , XLAT ( " range of grid to draw " ) , " " ) ;
} ) ;
}
2019-05-15 15:38:49 +00:00
} ;
}
2016-08-26 09:58:03 +00:00
if ( sym = = SDLK_F7 ) {
drawplayer = ! drawplayer ;
}
2017-07-22 23:33:27 +00:00
2018-12-13 12:33:08 +00:00
# if CAP_SHOT
else if ( sym = = SDLK_F6 ) {
pushScreen ( shot : : menu ) ;
2016-08-26 09:58:03 +00:00
}
2017-07-22 23:33:27 +00:00
# endif
2017-08-06 12:50:16 +00:00
2017-07-10 18:47:38 +00:00
if ( sym = = SDLK_ESCAPE ) popScreen ( ) ;
2016-08-26 09:58:03 +00:00
if ( sym = = SDLK_F1 ) {
2017-07-10 18:47:38 +00:00
gotoHelp ( drawhelptext ( ) ) ;
2016-08-26 09:58:03 +00:00
}
2017-07-10 18:47:38 +00:00
if ( sym = = SDLK_F10 ) popScreen ( ) ;
2017-03-23 10:53:57 +00:00
2020-04-17 18:04:33 +00:00
( void ) clickused ;
bool freedraw = drawing_tool ;
# if CAP_TEXTURE
bool intexture = texture : : config . tstate = = texture : : tsActive ;
freedraw | = intexture ;
# endif
if ( freedraw ) {
2020-07-04 11:33:14 +00:00
# if CAP_TEXTURE
2020-04-18 14:10:56 +00:00
int tcolor = ( dtcolor > > 8 ) | ( ( dtcolor & 0xFF ) < < 24 ) ;
2020-07-04 11:33:14 +00:00
# endif
2018-01-04 11:25:02 +00:00
2017-12-25 09:26:50 +00:00
if ( uni = = ' - ' & & ! clickused ) {
2020-04-17 18:04:33 +00:00
if ( mousekey = = ' e ' ) {
dt_erase ( mouseh ) ;
clickused = true ;
}
2020-07-12 19:26:15 +00:00
else if ( mousekey = = ' l ' | | mousekey = = ' c ' | | mousekey = = ' T ' ) {
2018-01-04 11:25:02 +00:00
if ( ! holdmouse ) lstart = mouseh , lstartcell = mouseover , holdmouse = true ;
}
2020-07-03 12:42:33 +00:00
# if CAP_TEXTURE
2020-04-17 18:04:33 +00:00
else if ( intexture ) {
2018-03-17 20:12:46 +00:00
if ( ! holdmouse ) texture : : config . data . undoLock ( ) ;
2018-01-04 11:25:02 +00:00
texture : : drawPixel ( mouseover , mouseh , tcolor ) ;
holdmouse = true ; lstartcell = NULL ;
}
2020-07-03 12:42:33 +00:00
# endif
2020-04-17 18:04:33 +00:00
else {
dt_add_free ( mouseh ) ;
holdmouse = true ;
}
2018-01-04 11:25:02 +00:00
}
if ( sym = = PSEUDOKEY_RELEASE ) {
printf ( " release \n " ) ;
2020-07-03 12:42:33 +00:00
# if CAP_TEXTURE
2020-04-17 18:04:33 +00:00
if ( mousekey = = ' l ' & & intexture ) {
2018-03-17 20:12:46 +00:00
texture : : config . data . undoLock ( ) ;
2018-01-04 11:25:02 +00:00
texture : : where = mouseover ;
texture : : drawPixel ( mouseover , mouseh , tcolor ) ;
texture : : drawLine ( mouseh , lstart , tcolor ) ;
lstartcell = NULL ;
}
2020-07-03 12:42:33 +00:00
else
# endif
if ( mousekey = = ' l ' ) {
2020-04-17 18:04:33 +00:00
dt_add_line ( mouseh , lstart , 10 ) ;
lstartcell = NULL ;
}
2020-07-03 12:42:33 +00:00
# if CAP_TEXTURE
2020-04-17 18:04:33 +00:00
else if ( mousekey = = ' c ' & & intexture ) {
2018-03-17 20:12:46 +00:00
texture : : config . data . undoLock ( ) ;
2018-01-04 11:25:02 +00:00
ld rad = hdist ( lstart , mouseh ) ;
2020-04-18 14:10:56 +00:00
int circp = int ( 1 + 3 * ( circlelength ( rad ) / dtwidth ) ) ;
2018-01-04 11:25:02 +00:00
if ( circp > 1000 ) circp = 1000 ;
2020-07-27 16:49:04 +00:00
shiftmatrix T = rgpushxto0 ( lstart ) ;
2018-01-04 11:25:02 +00:00
texture : : where = lstartcell ;
for ( int i = 0 ; i < circp ; i + + )
2018-08-19 14:28:36 +00:00
texture : : drawPixel ( T * xspinpush0 ( 2 * M_PI * i / circp , rad ) , tcolor ) ;
2018-01-04 11:25:02 +00:00
lstartcell = NULL ;
}
2020-07-03 12:42:33 +00:00
# endif
2020-04-17 18:04:33 +00:00
else if ( mousekey = = ' c ' ) {
dt_add_circle ( lstart , mouseh ) ;
lstartcell = NULL ;
}
2020-07-12 19:26:15 +00:00
else if ( mousekey = = ' T ' ) {
static string text = " " ;
dialog : : edit_string ( text , " " , " " ) ;
2020-07-27 16:49:04 +00:00
shiftpoint h = mouseh ;
2020-07-12 19:26:15 +00:00
dialog : : reaction_final = [ h ] {
if ( text ! = " " )
dt_add_text ( h , dtwidth * 50 , text ) ;
} ;
lstartcell = nullptr ;
}
2020-04-17 18:04:33 +00:00
else {
cfree = nullptr ;
cfree_at = nullptr ;
}
2017-12-22 21:34:01 +00:00
}
if ( uni > = 1000 & & uni < 1010 )
2020-04-18 14:10:56 +00:00
dtcolor = texture_colors [ uni - 1000 + 1 ] ;
2017-12-22 21:34:01 +00:00
if ( uni > = 2000 & & uni < 2010 )
2020-04-18 14:10:56 +00:00
dtwidth = brush_sizes [ uni - 2000 ] ;
2017-12-18 22:42:08 +00:00
2020-07-03 12:42:33 +00:00
# if CAP_TEXTURE
2017-12-22 20:57:55 +00:00
if ( uni = = ' 0 ' )
texture : : texturesym = ! texture : : texturesym ;
2017-12-22 19:59:04 +00:00
if ( uni = = ' u ' ) {
2018-03-17 20:12:46 +00:00
texture : : config . data . undo ( ) ;
2017-12-22 19:59:04 +00:00
}
2020-07-03 12:42:33 +00:00
# endif
2019-02-28 16:49:57 +00:00
2017-12-18 22:42:08 +00:00
if ( uni = = ' p ' ) {
2018-01-04 11:25:02 +00:00
if ( ! clickused )
2020-04-18 14:10:56 +00:00
dialog : : openColorDialog ( dtcolor , texture_colors ) ;
2017-12-18 22:42:08 +00:00
}
2020-04-17 18:04:33 +00:00
if ( uni = = ' f ' ) {
2020-04-18 14:10:56 +00:00
if ( dtfill = = dtcolor )
2020-04-17 18:04:33 +00:00
dtfill = 0 ;
else
2020-04-18 14:10:56 +00:00
dtfill = dtcolor ;
2017-12-18 22:42:08 +00:00
}
2017-12-22 21:34:01 +00:00
if ( uni = = ' b ' )
2020-04-18 14:10:56 +00:00
dialog : : editNumber ( dtwidth , 0 , 0.1 , 0.005 , 0.02 , XLAT ( " brush size " ) , XLAT ( " brush size " ) ) ;
2017-12-17 23:24:56 +00:00
}
2017-12-21 10:36:07 +00:00
2017-12-17 23:24:56 +00:00
else {
dslayer % = USERLAYERS ;
2017-12-22 20:37:30 +00:00
2020-07-27 16:49:04 +00:00
applyToShape ( drawcellShapeGroup ( ) , drawcellShapeID ( ) , uni , mh1 ) ;
2017-12-22 20:37:30 +00:00
2017-12-17 23:24:56 +00:00
if ( uni = = ' e ' | | ( uni = = ' - ' & & mousekey = = ' e ' ) ) {
2018-08-17 22:46:45 +00:00
initdraw ( mouseover ? mouseover : cwt . at ) ;
2017-12-17 23:24:56 +00:00
}
if ( uni = = ' l ' ) { dslayer + + ; dslayer % = USERLAYERS ; }
if ( uni = = ' L ' ) { dslayer - - ; if ( dslayer < 0 ) dslayer + = USERLAYERS ; }
if ( uni = = ' l ' - 96 ) onelayeronly = ! onelayeronly ;
if ( uni = = ' c ' ) ew = ewsearch ;
if ( uni = = ' b ' ) autochoose = ! autochoose ;
if ( uni = = ' S ' ) {
2018-08-27 17:27:35 +00:00
for ( int i = 0 ; i < USERSHAPEGROUPS ; i + + ) for ( auto usp : usershapes [ i ] ) {
auto us = usp . second ;
2017-12-17 23:24:56 +00:00
if ( ! us ) continue ;
2018-06-22 12:47:24 +00:00
for ( int l = 0 ; l < USERLAYERS ; l + + ) if ( isize ( us - > d [ l ] . list ) ) {
2017-12-17 23:24:56 +00:00
usershapelayer & ds ( us - > d [ l ] ) ;
2019-05-21 21:59:07 +00:00
println ( hlog , spaced ( " // " , i , usp . first , l , " [ " , ds . color , double ( ds . zlevel ) , " ] " ) ) ;
print ( hlog , " ID, " , us - > d [ l ] . rots , " , " , us - > d [ l ] . sym ? 2 : 1 , " , " ) ;
2019-02-28 16:49:57 +00:00
for ( int i = 0 ; i < isize ( us - > d [ l ] . list ) ; i + + ) {
2019-08-15 13:05:43 +00:00
for ( int d = 0 ; d < GDIM ; d + + ) print ( hlog , fts ( us - > d [ l ] . list [ i ] [ d ] ) , " , " ) ;
2019-05-21 21:59:07 +00:00
print ( hlog , " " ) ;
2019-02-28 16:49:57 +00:00
}
2019-05-21 21:59:07 +00:00
println ( hlog ) ;
2017-12-17 23:24:56 +00:00
}
}
}
if ( uni = = ' p ' ) {
dialog : : openColorDialog ( colortouse ) ;
2017-12-19 13:34:38 +00:00
dialog : : reaction = [ ] ( ) {
drawHandleKey ( COLORKEY , COLORKEY ) ;
} ;
2017-12-17 23:24:56 +00:00
}
if ( sym = = SDLK_F2 )
2018-01-08 22:23:00 +00:00
dialog : : openFileDialog ( picfile , XLAT ( " pics to save: " ) , " .pic " ,
2017-12-17 23:24:56 +00:00
[ ] ( ) {
return savePicFile ( picfile ) ;
} ) ;
if ( sym = = SDLK_F3 )
2018-01-08 22:23:00 +00:00
dialog : : openFileDialog ( picfile , XLAT ( " pics to load: " ) , " .pic " ,
2017-12-17 23:24:56 +00:00
[ ] ( ) {
return loadPicFile ( picfile ) ;
} ) ;
if ( sym = = SDLK_F5 ) {
2018-08-27 17:27:35 +00:00
for ( int i = 0 ; i < USERSHAPEGROUPS ; i + + ) {
for ( auto us : usershapes [ i ] )
if ( us . second ) delete us . second ;
usershapes [ i ] . clear ( ) ;
}
}
2017-12-17 23:24:56 +00:00
}
2016-08-26 09:58:03 +00:00
}
2019-02-17 17:41:40 +00:00
# endif
2017-07-10 18:47:38 +00:00
2020-04-11 18:40:12 +00:00
auto hooks = addHook ( hooks_clearmemory , 0 , [ ] ( ) {
2017-07-10 18:47:38 +00:00
if ( mapeditor : : painttype = = 4 )
mapeditor : : painttype = 0 , mapeditor : : paintwhat = 0 ,
mapeditor : : paintwhat_str = " clear monster " ;
2018-08-17 22:46:45 +00:00
mapeditor : : copysource . at = NULL ;
2017-07-10 18:47:38 +00:00
mapeditor : : undo . clear ( ) ;
2018-06-28 00:49:26 +00:00
if ( ! cheater ) patterns : : displaycodes = false ;
2017-12-09 02:48:30 +00:00
if ( ! cheater ) patterns : : whichShape = 0 ;
2017-07-10 18:47:38 +00:00
modelcell . clear ( ) ;
2020-04-17 18:04:33 +00:00
mapeditor : : dtshapes . clear ( ) ;
mapeditor : : cfree = nullptr ;
mapeditor : : cfree_at = nullptr ;
2020-04-17 18:34:49 +00:00
drawcell = nullptr ;
2018-01-26 00:45:49 +00:00
} ) +
addHook ( hooks_removecells , 0 , [ ] ( ) {
modelcell . clear ( ) ;
2018-08-17 22:46:45 +00:00
set_if_removed ( mapeditor : : copysource . at , NULL ) ;
2020-02-23 01:51:27 +00:00
} ) ;
2017-03-23 10:53:57 +00:00
# endif
2019-08-09 23:15:41 +00:00
EX void initdraw ( cell * c ) {
2019-06-13 16:11:01 +00:00
# if CAP_EDIT
2017-06-18 16:52:15 +00:00
mapeditor : : drawcell = c ;
ew . c = c ;
ew . rotid = 0 ;
ew . symid = 0 ;
ew . pointid = - 1 ;
ew . side = 0 ;
ewsearch = ew ;
2019-05-15 15:38:49 +00:00
ccenter = coldcenter = C0 ;
2019-06-01 14:59:04 +00:00
# endif
2017-06-18 16:52:15 +00:00
}
2017-12-17 23:24:56 +00:00
transmatrix textrans ;
2018-01-04 11:25:02 +00:00
2020-07-27 16:49:04 +00:00
EX void queue_hcircle ( shiftmatrix Ctr , ld radius ) {
2018-01-04 11:25:02 +00:00
vector < hyperpoint > pts ;
2018-08-01 09:07:22 +00:00
int circp = int ( 6 * pow ( 2 , vid . linequality ) ) ;
2018-01-04 11:25:02 +00:00
if ( radius > 0.04 ) circp * = 2 ;
if ( radius > .1 ) circp * = 2 ;
for ( int j = 0 ; j < circp ; j + + )
2020-07-27 16:49:04 +00:00
pts . push_back ( xspinpush0 ( M_PI * j * 2 / circp , radius ) ) ;
2018-08-01 09:07:22 +00:00
for ( int j = 0 ; j < circp ; j + + ) curvepoint ( pts [ j ] ) ;
curvepoint ( pts [ 0 ] ) ;
2020-07-27 16:49:04 +00:00
queuecurve ( Ctr , dtcolor , 0 , PPR : : LINE ) ;
2018-01-04 11:25:02 +00:00
}
2018-01-05 16:30:03 +00:00
2019-02-17 17:41:40 +00:00
# if CAP_POLY
2019-09-06 06:17:02 +00:00
EX bool haveUserShape ( eShapegroup group , int id ) {
2018-08-27 17:27:35 +00:00
# if !CAP_EDIT
return false ;
# else
return usershapes [ group ] . count ( id ) & & usershapes [ group ] [ id ] ;
# endif
}
2019-02-17 17:41:40 +00:00
# endif
2019-01-03 14:12:45 +00:00
2019-02-17 17:41:40 +00:00
# if CAP_TEXTURE
2020-07-27 16:49:04 +00:00
EX void draw_texture_ghosts ( cell * c , const shiftmatrix & V ) {
2019-01-03 14:12:45 +00:00
if ( ! c ) return ;
if ( holdmouse & & ! lstartcell ) return ;
cell * ls = lstartcell ? lstartcell : lmouseover ;
if ( ! ls ) return ;
auto sio = patterns : : getpatterninfo0 ( ls ) ;
auto sih = patterns : : getpatterninfo0 ( c ) ;
if ( sio . id = = sih . id ) {
if ( c = = ls )
2020-07-27 16:49:04 +00:00
textrans = inverse ( V . T * applyPatterndir ( ls , sio ) ) ;
2019-01-03 14:12:45 +00:00
2020-07-27 16:49:04 +00:00
transmatrix mh = textrans * rgpushxto0 ( unshift ( mouseh , V . shift ) ) ;
transmatrix ml = textrans * rgpushxto0 ( unshift ( lstart , V . shift ) ) ;
2019-01-14 21:56:52 +00:00
2019-01-03 14:12:45 +00:00
for ( int j = 0 ; j < = texture : : texturesym ; j + + )
for ( int i = 0 ; i < c - > type ; i + = sih . symmetries ) {
2020-07-27 16:49:04 +00:00
shiftmatrix M2 = V * applyPatterndir ( c , sih ) * spin ( 2 * M_PI * i / c - > type ) ;
2019-01-03 14:12:45 +00:00
if ( j ) M2 = M2 * Mirror ;
switch ( holdmouse ? mousekey : ' d ' ) {
case ' c ' :
queue_hcircle ( M2 * ml , hdist ( lstart , mouseh ) ) ;
break ;
case ' l ' :
2020-04-18 14:10:56 +00:00
queueline ( M2 * mh * C0 , M2 * ml * C0 , dtcolor , 4 + vid . linequality , PPR : : LINE ) ;
2019-01-03 14:12:45 +00:00
break ;
default :
2020-04-18 14:10:56 +00:00
queue_hcircle ( M2 * mh , dtwidth ) ;
2019-01-03 14:12:45 +00:00
}
}
}
}
2019-02-17 17:41:40 +00:00
# endif
2018-08-27 17:27:35 +00:00
2019-02-17 17:41:40 +00:00
# if CAP_POLY
2020-07-27 16:49:04 +00:00
EX bool drawUserShape ( const shiftmatrix & V , eShapegroup group , int id , color_t color , cell * c , PPR prio IS ( PPR : : DEFAULT ) ) {
2017-08-06 12:50:16 +00:00
# if !CAP_EDIT
2017-06-18 16:52:15 +00:00
return false ;
# else
2017-12-03 17:24:34 +00:00
2018-08-28 12:09:36 +00:00
// floors handled separately
if ( c & & c = = drawcell & & editingShape ( group , id ) & & group ! = sgFloor )
2018-08-28 11:45:11 +00:00
drawtrans = V ;
2017-06-18 16:52:15 +00:00
usershape * us = usershapes [ group ] [ id ] ;
if ( us ) {
2019-05-26 16:04:02 +00:00
cgi . require_usershapes ( ) ;
2017-06-18 16:52:15 +00:00
for ( int i = 0 ; i < USERLAYERS ; i + + ) {
2017-09-03 19:11:33 +00:00
if ( i ! = dslayer & & onelayeronly ) continue ;
2017-06-18 16:52:15 +00:00
usershapelayer & ds ( us - > d [ i ] ) ;
2019-05-26 16:04:02 +00:00
hpcshape & sh ( cgi . ushr [ & ds ] ) ;
2017-06-18 16:52:15 +00:00
2019-04-07 01:08:43 +00:00
if ( sh . s ! = sh . e ) {
2019-08-15 13:05:43 +00:00
auto & last = queuepolyat ( mmscale ( V , GDIM = = 3 ? 0 : geom3 : : lev_to_factor ( ds . zlevel ) ) , sh , ds . color ? ds . color : color , prio ) ;
if ( GDIM = = 3 ) {
2019-04-07 01:08:43 +00:00
last . tinf = & user_triangles_texture ;
last . offset_texture = ds . texture_offset ;
}
}
2017-06-18 16:52:15 +00:00
}
}
2018-01-04 11:25:02 +00:00
if ( cmode & sm : : DRAW ) {
2017-12-21 10:36:07 +00:00
2019-02-28 18:02:01 +00:00
if ( c = = drawcell & & EDITING_TRIANGLES & & mapeditor : : editingShape ( group , id ) ) {
if ( ! us ) return false ;
usershapelayer & ds ( us - > d [ mapeditor : : dslayer ] ) ;
for ( int i = 0 ; i < isize ( ds . list ) ; i + + ) {
int j = ( i % 3 = = 2 ? i - 2 : i + 1 ) ;
if ( j < isize ( ds . list ) )
queueline ( V * ds . list [ i ] , V * ds . list [ j ] , 0xFF00FFFF , - 1 , PPR : : SUPERLINE ) ;
2019-12-26 22:38:28 +00:00
queuestr ( V * ds . list [ i ] , 10 , " x " , 0xFF00FF ) ;
2019-02-28 18:02:01 +00:00
}
}
if ( mapeditor : : editingShape ( group , id ) & & ! EDITING_TRIANGLES ) {
2017-06-18 16:52:15 +00:00
2018-06-22 12:47:24 +00:00
/* for(int a=0; a<isize(ds.list); a++) {
2017-12-17 23:24:56 +00:00
hyperpoint P2 = V * ds . list [ a ] ;
int xc , yc , sc ;
getcoord ( P2 , xc , yc , sc ) ;
2019-12-26 22:38:28 +00:00
queuestr ( xc , yc , sc , 10 , " x " ,
2017-12-17 23:24:56 +00:00
a = = 0 ? 0x00FF00 :
2018-06-22 12:47:24 +00:00
a = = isize ( ds . list ) - 1 ? 0xFF0000 :
2017-12-17 23:24:56 +00:00
0xFFFF00 ) ;
} */
if ( ! us ) return false ;
usershapelayer & ds ( us - > d [ mapeditor : : dslayer ] ) ;
2020-07-27 16:49:04 +00:00
hyperpoint mh = inverse_shift ( mapeditor : : drawtrans , mouseh ) ;
2017-12-17 23:24:56 +00:00
for ( int a = 0 ; a < ds . rots ; a + + )
for ( int b = 0 ; b < ( ds . sym ? 2 : 1 ) ; b + + ) {
if ( mouseout ( ) ) break ;
2020-07-27 16:49:04 +00:00
shiftpoint P2 = V * spin ( 2 * M_PI * a / ds . rots ) * ( b ? Mirror * mh : mh ) ;
2017-12-17 23:24:56 +00:00
2019-12-26 22:38:28 +00:00
queuestr ( P2 , 10 , " x " , 0xFF00FF ) ;
2017-12-17 23:24:56 +00:00
}
2018-06-22 12:47:24 +00:00
if ( isize ( ds . list ) = = 0 ) return us ;
2017-12-17 23:24:56 +00:00
2020-07-27 16:49:04 +00:00
shiftpoint Plast = V * spin ( - 2 * M_PI / ds . rots ) * ( ds . sym ? Mirror * ds . list [ 0 ] : ds . list [ isize ( ds . list ) - 1 ] ) ;
2017-12-17 23:24:56 +00:00
int state = 0 ;
int gstate = 0 ;
double dist2 = 0 ;
2020-07-27 16:49:04 +00:00
shiftpoint lpsm ;
2017-12-17 23:24:56 +00:00
for ( int a = 0 ; a < ds . rots ; a + + )
for ( int b = 0 ; b < ( ds . sym ? 2 : 1 ) ; b + + ) {
hyperpoint mh2 = spin ( 2 * M_PI * - ew . rotid / ds . rots ) * mh ;
if ( ew . symid ) mh2 = Mirror * mh2 ;
2020-07-27 16:49:04 +00:00
shiftpoint pseudomouse = V * spin ( 2 * M_PI * a / ds . rots ) * mirrorif ( mh2 , b ) ;
2017-12-17 23:24:56 +00:00
2018-06-22 12:47:24 +00:00
for ( int t = 0 ; t < isize ( ds . list ) ; t + + ) {
int ti = b ? isize ( ds . list ) - 1 - t : t ;
2017-06-18 16:52:15 +00:00
2020-07-27 16:49:04 +00:00
shiftpoint P2 = V * spin ( 2 * M_PI * a / ds . rots ) * mirrorif ( ds . list [ ti ] , b ) ;
2017-12-17 23:24:56 +00:00
if ( ! mouseout ( ) ) {
double d = hdist ( mouseh , P2 ) ;
if ( d < ewsearch . dist )
ewsearch . dist = d ,
ewsearch . rotid = a ,
ewsearch . symid = b ,
ewsearch . pointid = ti ,
ewsearch . c = c ,
ewsearch . side = b ,
state = 1 ,
dist2 = d + hdist ( mouseh , Plast ) - hdist ( P2 , Plast ) ;
else if ( state = = 1 ) {
double dist3 = d + hdist ( mouseh , Plast ) - hdist ( P2 , Plast ) ;
if ( dist3 < dist2 )
ewsearch . side = ! ewsearch . side ;
state = 2 ;
}
2017-06-18 16:52:15 +00:00
}
2017-12-17 23:24:56 +00:00
2019-12-26 22:38:28 +00:00
queuestr ( P2 , 10 , " o " ,
2017-12-17 23:24:56 +00:00
0xC000C0 ) ;
if ( ! mouseout ( ) ) {
if ( gstate = = 1 ) queueline ( lpsm , P2 , 0x90000080 ) , gstate = 0 ;
if ( ti = = ew . pointid ) {
queueline ( pseudomouse , P2 , 0xF0000080 ) ;
2018-07-07 09:05:48 +00:00
if ( ew . side = = ( b = = 1 ) ) queueline ( pseudomouse , Plast , 0x90000080 ) ;
2017-12-17 23:24:56 +00:00
else gstate = 1 , lpsm = pseudomouse ;
}
2017-06-18 16:52:15 +00:00
}
2017-12-17 23:24:56 +00:00
Plast = P2 ;
2017-06-18 16:52:15 +00:00
}
2017-12-17 23:24:56 +00:00
}
if ( gstate = = 1 ) queueline ( lpsm , V * ds . list [ 0 ] , 0x90000080 ) , gstate = 0 ;
if ( state = = 1 ) {
2020-07-27 16:49:04 +00:00
shiftpoint P2 = V * ds . list [ 0 ] ;
2017-12-17 23:24:56 +00:00
if ( hdist ( mouseh , P2 ) + hdist ( mouseh , Plast ) - hdist ( P2 , Plast ) < dist2 )
ewsearch . side = 1 ;
2017-06-18 16:52:15 +00:00
}
}
}
return us ;
# endif
}
2019-02-17 17:41:40 +00:00
# endif
2018-08-28 11:45:11 +00:00
2019-08-09 23:15:41 +00:00
EX void map_settings ( ) {
2018-12-24 14:10:52 +00:00
cmode = sm : : SIDE | sm : : MAYDARK ;
gamescreen ( 1 ) ;
dialog : : init ( XLAT ( " Map settings " ) ) ;
2019-05-03 10:11:40 +00:00
dialog : : addBoolItem_action_neg ( XLAT ( " disable wandering monsters " ) , gen_wandering , ' w ' ) ;
2018-12-24 14:10:52 +00:00
if ( gen_wandering ) {
2019-05-03 10:11:40 +00:00
dialog : : addBoolItem_action_neg ( XLAT ( " disable ghost timer " ) , timerghost , ' g ' ) ;
2018-12-24 14:10:52 +00:00
}
else dialog : : addBreak ( 100 ) ;
2019-05-03 10:11:40 +00:00
dialog : : addBoolItem_action ( XLAT ( " simple pattern generation " ) , reptilecheat , ' p ' ) ;
2019-01-18 20:03:55 +00:00
dialog : : addInfo ( XLAT ( " (e.g. pure Reptile pattern) " ) ) ;
2018-12-24 14:10:52 +00:00
2019-05-03 10:11:40 +00:00
dialog : : addBoolItem_action ( XLAT ( " safety generation " ) , safety , ' s ' ) ;
2019-01-18 20:03:55 +00:00
dialog : : addInfo ( XLAT ( " (no treasure, no dangers) " ) ) ;
2018-12-24 14:10:52 +00:00
2019-01-18 20:03:55 +00:00
dialog : : addBoolItem ( XLAT ( " god mode " ) , autocheat , ' G ' ) ;
2018-12-24 14:10:52 +00:00
dialog : : add_action ( [ ] ( ) { autocheat = true ; } ) ;
2019-01-18 20:03:55 +00:00
dialog : : addInfo ( XLAT ( " (unlock all, allow cheats, normal character display, cannot be turned off!) " ) ) ;
2018-12-24 14:10:52 +00:00
2019-01-18 20:03:55 +00:00
dialog : : addItem ( XLAT ( " change the pattern/color of new Canvas cells " ) , ' c ' ) ;
2019-03-30 22:59:51 +00:00
dialog : : add_action_push ( patterns : : showPrePatternNoninstant ) ;
2020-02-26 00:39:41 +00:00
dialog : : addItem ( XLAT ( " configure WFC " ) , ' W ' ) ;
dialog : : add_action_push ( wfc : : wfc_menu ) ;
2019-01-16 23:59:45 +00:00
2018-12-24 14:10:52 +00:00
dialog : : addBack ( ) ;
dialog : : display ( ) ;
}
2019-08-09 23:15:41 +00:00
EX }
2017-05-27 19:40:40 +00:00
2018-07-19 21:46:58 +00:00
# if CAP_EDIT
2019-08-09 21:39:36 +00:00
EX string levelfile = " hyperrogue.lev " ;
EX const char * loadlevel = NULL ;
EX string picfile = " hyperrogue.pic " ;
2018-07-19 21:46:58 +00:00
2018-07-22 10:50:03 +00:00
# if CAP_COMMANDLINE
2018-07-19 21:46:58 +00:00
int read_editor_args ( ) {
using namespace arg ;
if ( argis ( " -lev " ) ) { shift ( ) ; levelfile = args ( ) ; }
else if ( argis ( " -pic " ) ) { shift ( ) ; picfile = args ( ) ; }
else if ( argis ( " -load " ) ) { PHASE ( 3 ) ; shift ( ) ; mapstream : : loadMap ( args ( ) ) ; }
2020-05-01 10:27:49 +00:00
else if ( argis ( " -d:draw " ) ) { PHASE ( 3 ) ;
# if CAP_EDIT
start_game ( ) ;
mapeditor : : drawing_tool = true ;
mapeditor : : initdraw ( cwt . at ) ;
launch_dialog ( mapeditor : : showDrawEditor ) ;
# endif
}
2019-02-17 17:41:40 +00:00
# if CAP_POLY
2018-07-19 21:46:58 +00:00
else if ( argis ( " -picload " ) ) { PHASE ( 3 ) ; shift ( ) ; mapeditor : : loadPicFile ( args ( ) ) ; }
2019-02-17 17:41:40 +00:00
# endif
2018-07-19 21:46:58 +00:00
else return 1 ;
return 0 ;
}
auto ah_editor = addHook ( hooks_args , 0 , read_editor_args ) ;
# endif
# endif
2018-06-10 23:58:31 +00:00
}