25 #include <QMutexLocker>
41 const int x,
const dirs direction)
50 if ( direction >=
DOWN ) {
59 waddstr (window, qPrintable(
arrows[SOUTH]));
61 waddstr (window, qPrintable(
arrows[NORTH]));
63 (void)wmove(window, y, x);
70 const static QString dir_chars[] = {
79 switch ( direction ) {
82 case NORTH: left = dir_chars[
WEST]; right = dir_chars[
EAST];
break;
83 case SOUTH: left = dir_chars[
EAST]; right = dir_chars[
WEST];
break;
84 case EAST: left = dir_chars[
NORTH]; right = dir_chars[
SOUTH];
break;
85 case WEST: left = dir_chars[
SOUTH]; right = dir_chars[
NORTH];
break;
87 mvwaddstr(window, y-1, 0, qPrintable(left));
88 mvwaddstr(window, y-1,
SCREEN_SIZE*2+1, qPrintable(right));
91 mvwaddstr(window, y, 0, qPrintable(
arrows[
EAST]));
97 static const QString action_strings[] = {
108 waddstr(
actionWin, qPrintable(action_strings[i]));
131 waddstr(
notifyWin, qPrintable(tr(
"Enter input: ")));
139 str = QString::fromUtf8(temp_str);
148 return ( z_dif == 0 ) ?
170 case LIQUID:
switch ( sub ) {
178 default:
switch ( sub ) {
182 case DIAMOND:
return color | A_BOLD;
184 case SUB_DUST:
return color | A_BOLD | A_REVERSE;
196 default:
return color;
237 static bool step_trigger =
true;
239 step_trigger = !step_trigger;
246 if ( ch != KEY_MOUSE ) {
263 if (
'a'<=ch && ch<=
'z' ) {
269 Notify(tr(
"Unknown key. Press 'H' for help."));
271 Notify(QString(
"Pressed key code: %1.").arg(ch));
333 Notify(tr(
"Inventory reorganized."));
345 Notify(tr(
"%1 focus is set.").
350 Notify(tr(
"%1 focus is set.").
377 if ( getmouse(&mevent) == ERR )
return;
378 if ( wenclose(
leftWin, mevent.y, mevent.x) ) {
379 if ( not wmouse_trafo(
leftWin, &mevent.y, &mevent.x,
false) )
return;
381 Notify(tr(
"Your inventory."));
388 Notify(tr(
"Left window, Down view."));
392 }
else if ( wenclose(
notifyWin, mevent.y, mevent.x) ) {
393 Notify(tr(
"Notifications area."));
394 }
else if ( wenclose(
actionWin, mevent.y, mevent.x) ) {
395 wmouse_trafo(
actionWin, &mevent.y, &mevent.x,
false);
397 }
else if ( wenclose(
minimapWin, mevent.y, mevent.x) ) {
398 if (not wmouse_trafo(
minimapWin, &mevent.y, &mevent.x,
false))
return;
408 Notify((0 <= shred_x && shred_x < w->NumShreds() &&
409 0 <= shred_y && shred_y < w->NumShreds() ) ?
412 tr(
"You can't see that far.") );
413 }
else if ( wenclose(
hudWin, mevent.y, mevent.x) ) {
414 if ( not wmouse_trafo(
hudWin, &mevent.y, &mevent.x,
false) )
return;
417 if ( not (
IsScreenWide() && 0 <= mevent.x && mevent.x <=
'z'-
'a' ) ) {
418 Notify(tr(
"Information: left - player, right - focused thing."));
422 if ( inv ==
nullptr )
return;
423 Notify( tr(
"In inventory at slot '%1': %2.").
424 arg(
char(mevent.x +
'a')).
425 arg( inv->
Number(mevent.x) ?
428 }
else if ( wenclose(
rightWin, mevent.y, mevent.x) ) {
429 if ( not wmouse_trafo(
rightWin, &mevent.y, &mevent.x,
false) )
return;
433 Notify(tr(
"Opened inventory."));
438 Notify(tr(
"Right window, %1 view.").
454 Notify(tr(
"Nothing here. Click on something to get information."));
459 if ( command.length()==1 && command.at(0)!=
'.' ) {
466 Notify(tr(
"Block blink is now %1.").
467 arg(blinkOn ? tr(
"on") : tr(
"off")));
470 Notify(tr(
"Terminal height: %1 lines, width: %2 chars.").
471 arg(LINES).arg(COLS));
535 const int kind = block.
Kind();
536 const int sub = block.
Sub();
537 wattrset(window,
Color(kind, sub));
569 if ( focused !=
nullptr ) {
577 if ( focused !=
nullptr ) {
590 qPrintable(tr(
"Creative Mode\nxyz: %1, %2, %3. YX: %4, %5.")
596 static const int player_health_char =
ascii ?
'@' : 0x2665;
603 if ( breath != 100 ) {
604 static const int player_breath_char =
ascii ?
'o' : 0x00b0;
607 static const QString satiation_strings[] = {
610 satiation_strings[1],
614 static const int satiation_colors[] = {
622 wcolor_set(
hudWin, satiation_colors[satiation_state],
nullptr);
623 mvwaddstr(
hudWin, 1,1, qPrintable(satiation_strings[satiation_state]));
632 (focused->
IsAnimal() ==
nullptr) ?
'+' :
'*',
635 const QString name = focused->
FullName();
636 mvwaddstr(
hudWin, 1, left_border-name.length() - 1,
638 const QString note = focused->
GetNote();
640 const int width = qMin(36, note.length() + 2);
641 (void)wmove(
hudWin, 2, left_border - width - 1);
642 if ( note.length()+2 <= width ) {
643 wprintw(
hudWin,
"~:%s", qPrintable(note));
645 wprintw(
hudWin,
"~:%s ...", qPrintable(note.left(width - 6)));
657 for (
int i=inv->
Size()-1; i>=0; --i) {
660 mvwaddch(
hudWin, 0, x,
'a'+i);
661 switch ( inv->
Number(i) ) {
664 case 1: mvwaddch(
hudWin, 1, x,
684 for (
int i=i_start; i <= i_start+4; ++i, waddch(
minimapWin,
'\n'))
685 for (
int j=j_start; j <= j_start+4; ++j) {
697 mvwaddstr(
minimapWin, 0, 1, qPrintable(tr(
"Minimap")));
712 (void)wmove(window, 1, 1);
725 for (
int j=start_y; j<end_y; ++j, waddstr(window,
"\n_")) {
727 for (
int i=start_x; i<end_x; ++i ) {
749 mvwaddstr(window,
player->
Y()-start_y+1, (
player->
X()-start_x)*2+2,
783 arrow_X = (pX - begin_x)*2 + 1;
788 x_start = SCREEN_SIZE - 1 + begin_x;
794 arrow_X = (SCREEN_SIZE - pX + begin_x)*2 - 1;
800 x_end = SCREEN_SIZE + begin_y;
805 arrow_X = (pY - begin_y)*2 + 1;
810 x_start = SCREEN_SIZE - 1 + begin_y;
816 arrow_X = (SCREEN_SIZE - pY + begin_y)*2 - 1;
826 int k = k_start - block_y + 1;
827 *x = x_start + x_step * (block_x-1)/2;
828 for (*z=z_start; *z!=z_end &&
w->
GetBlock(i, j, k)->
838 for (*x=x_start; *x!=x_end; *x+=x_step) {
839 for (*z=z_start; *z!=z_end &&
w->
GetBlock(i, j, k)->
859 const int arrow_Y = k_start + 1 -
player->
Z();
862 const int ch = (
shiftFocus == 1 ) ?
'^' :
'v';
865 mvwaddch(
rightWin, q, SCREEN_SIZE*2+1, ch);
875 if ( inv ==
nullptr )
return;
877 const int start = inv->
Start();
879 for (
int i=0; i<inv->
Size(); ++i) {
880 shift += ( start == i && i != 0 );
882 mvwprintw(window, 2+i+shift, 1,
"%c) ",
'a'+i);
883 const int number = inv->
Number(i);
885 wattrset(window, COLOR_PAIR(
BLACK_BLACK) | A_BOLD);
890 wprintw(window,
"[%c]%s",
895 const QString str = block->
GetNote();
896 if ( not str.isEmpty() ) {
897 const int x = getcurx(window);
899 if ( str.length() <= width ) {
900 wprintw(window,
" ~:%s", qPrintable(str));
902 wprintw(window,
" ~:%s ...", qPrintable(str.left(width - 4)));
906 mvwprintw(window, 2+i+shift, 53,
"%5hu mz", inv->
GetInvWeight(i));
909 QString full_weight = tr(
"Full weight: %1 mz").
910 arg(inv->
Weight(), 6, 10, QChar(
' '));
911 mvwprintw(window, 2+inv->
Size()+shift,
912 SCREEN_SIZE*2 + 1 - full_weight.length(), qPrintable(full_weight));
916 mvwhline(window, 2+start, 1, ACS_HLINE,
SCREEN_SIZE*2);
918 mvwprintw(window, 0, 1,
"[%c] %s",
CharName( block->
Kind(), block->
Sub()),
920 tr(
"Your inventory") : block->
FullName()) );
932 if (
fileToShow->open(QIODevice::ReadOnly | QIODevice::Text) ) {
934 waddstr(window, qPrintable(
935 QString::fromLocal8Bit(
fileToShow->readAll().constData())) );
947 Notify(tr(
"There is no such file."));
952 fputs(qPrintable(QString(
"%1 %2\n").arg(
w->
TimeOfDayStr()).arg(str)),
956 switch ( str.at(str.size()-1).unicode() ) {
958 case '*':
if (
flashOn ) flash();
break;
959 case '^':
if (
beepOn ) beep();
break;
961 static int notification_repeat_count = 1;
963 ++notification_repeat_count;
965 qPrintable(str), notification_repeat_count);
967 notification_repeat_count = 1;
979 waddstr(
leftWin, qPrintable(tr(
"You die.\nWaiting for respawn...")));
999 notifyLog(fopen(qPrintable(
home_path +
"log.txt"),
"at")),
1001 shiftFocus(settings.value(
"focus_shift", 0).toInt()),
1002 fileToShow(nullptr),
1003 beepOn (settings.value(
"beep_on", false).toBool()),
1004 flashOn(settings.value(
"flash_on", true ).toBool()),
1005 ascii(_ascii && settings.value(
"ascii", true).toBool() ),
1006 blinkOn(not _ascii || settings.value(
"blink_on", true).toBool()),
1008 ascii ?
'^' : 0x2191,
1009 ascii ?
'v' : 0x2193,
1010 ascii ?
'>' : 0x2192,
1011 ascii ?
'<' : 0x2190
1013 screen(newterm(
nullptr, stdout, stdin)),
1020 nodelay(stdscr, FALSE);
1023 keypad(stdscr, TRUE);
1024 mousemask(BUTTON1_CLICKED | BUTTON1_RELEASED,
nullptr);
1025 memset(windows, 0,
sizeof(windows));
1026 if ( LINES < 41 && IsScreenWide() ) {
1027 printf(
"Make your terminal height to be at least 41 lines.\n");
1030 }
else if ( LINES < 39 ) {
1031 printf(
"Make your terminal height to be at least 39 lines.\n");
1035 const int colors[] = {
1046 init_pair(i, colors[(i-1)/8], colors[(i-1)%8]);
1049 if ( IsScreenWide() ) {
1053 hudWin = newwin(3, preferred_width,
SCREEN_SIZE+2, left_border);
1054 notifyWin = newwin(0, 0,
SCREEN_SIZE+5,left_border+33);
1057 actionWin = newwin(7, 20,
SCREEN_SIZE+5, left_border+12);
1058 }
else if ( COLS >= preferred_width/2 ) {
1062 notifyWin = newwin(0, 0,
SCREEN_SIZE+2+2, left_border+15);
1063 actionWin = newwin(7, 15,
SCREEN_SIZE+2, left_border);
1065 puts(qPrintable(tr(
"Set your terminal width at least %1 chars.").
1070 scrollok(notifyWin, TRUE);
1072 if ( not PrintFile(stdscr,
":/texts/splash.txt") ) {
1073 addstr(
"Free-Roaming Elementary Game\nby mmaulwurff\n");
1075 addstr(qPrintable(tr(
"\nVersion %1.\n\nPress any key.").arg(VER)));
1079 SetActionMode(static_cast<actions>
1080 (settings.value(
"action_mode",
ACTION_USE).toInt()));
1082 Notify(tr(
"--- Game started. Press 'H' for help. ---"));
1083 if ( not IsScreenWide() ) {
1084 Notify(tr(
"For better gameplay set your"));
1085 Notify(tr(
"terminal width at least %1 chars.").arg(preferred_width));
1089 connect(wor, SIGNAL(UpdatesEnded()), SLOT(Print()), Qt::DirectConnection);
1094 disconnect(
w, SIGNAL(UpdatesEnded()),
this, SLOT(
Print()));
1120 const int percent,
const bool value_position_right)
1124 value_position_right ?
"[..........]%hd" :
"%3hd[..........]",percent);
1126 mvwaddstr(
hudWin, 0, x + (value_position_right ? 1 : 4),
1127 qPrintable(QString(10, QChar(ch)).left(percent/10)));
int GetNormalStartY() const
void DisplayFile(QString path) override
Screen(World *, Player *, int &error, bool ascii)
bool Obtain(int src, int dest=0, int num=1)
Tries to get block number num from outer inventory.
const int MAX_DURABILITY
10 bits to store durability in file, signed.
virtual QString FullName() const
static dirs TurnRight(dirs dir)
int GetMinimapStartX() const
void UpdateAround(int, int, int, int) override
static int CoordInShred(const int x)
Get local coordinate.
static char CharName(int kind, int sub)
virtual void ActionXyz(int *x, int *y, int *z) const
Used to get player focus coordinates from screen.
bool Damage() const
Returns true if xyz are in world bounds.
int GetUsingInInventory() const
void PrintNormal(WINDOW *, dirs) const
bool PrintFile(WINDOW *, QString const &file_name)
Returns false when file does not exist, otherwise true.
void PrintQuickInventory()
void ExamineOnNormalScreen(int x, int y, int z, int step) const
shred_type GetTypeOfShred() const
World provides global physics and shred connection.
void Shake()
Stacks items in inventory if possible.
int shiftFocus
Can be -1, 0, 1 for low, normal, and high focus.
char PrintBlock(const Block &, WINDOW *) const
void PassString(QString &) const override
Block * GetFocusedBlock() const
Returns nullptr if block is not player->Visible().
int BreathPercent() const
This returns player breath reserve. On error returns -100.
Shred * GetShredByPos(int x, int y) const
long GetLongitude() const
char CharNumber(int z) const
static int Color(int kind, int sub)
const QChar arrows[WEST+1]
void ProcessCommand(QString command)
void SetCreativeMode(bool turn)
char CharNumberFront(int x, int y) const
static sub_groups GetSubGroup(int sub)
Provides curses (text-based graphics interface) screen for freg.
dirs GetDir() const
This returns current player direction (see enum dirs in header.h)
virtual Inventory * HasInventory()
int GetInvWeight(int i) const
static void PrintVerticalDirection(WINDOW *, int y, int x, dirs)
Block * ShowBlock(int slot) const
int Color(int kind, int sub) const
void UpdatePlayer() override
virtual int Start() const
Inventory * PlayerInventory() const
Returns nullptr if there is no inventory, otherwise returns inventory.
int SatiationPercent() const
Can be > 100 if player is gorged. On error returns -100.
Keyboard input thread for curses screen for freg.
int UsingType() const
This returns how player is using something now.
void ActionXyz(int *x, int *y, int *z) const override
int GetNormalStartX() const
bool Visible(int x, int y, int z) const
This returns true if block at (x, y, z) is visible to player.
bool GetCreativeMode() const
ulong Time() const
Returns time in seconds since world creation.
void StopUseAll()
Closes backpack, chests, etc.
Block * GetBlock(int x, int y, int z) const
void SetActionMode(actions mode)
Provides declaration for class Inventory for freg.
void ProcessCommand(QString command)
virtual Animal * IsAnimal()
static QString ShredTypeName(shred_type)
bool GetEvernight() const
void ExitReceived()
This is emitted when input receives exit key.
void HorizontalArrows(WINDOW *, int y, dirs) const
static constexpr quint64 UniqueIntFromString(const char *const chars)
void MovePlayerDiag(dirs dir1, dirs dir2) const
static QString DirString(dirs)
void InventoryAction(int num) const
void UpdateAll() override
QString TimeOfDayStr() const
const Block * GetBlock() const
times_of_day PartOfDay() const
void PrintFront(dirs direction, int x=-1, int y=0) const
void Notify(QString) const override
void Arrows(WINDOW *, int x, int y, dirs) const
virtual int Weight() const
void PrintBar(int x, int color, int ch, int percent, bool value_position_right=true)
Can print health, breath and other bars on hudWin.
int GetMinimapStartY() const
static bool IsScreenWide()
Provides block ability to contain other blocks inside.
This class provides base for all screens for freg.
Shred * GetShred(int i, int j) const
int UsingSelfType() const
This returns how player is using himself.
void Backpack()
Tries to switch usingSelfType from NO to OPEN.
Block * GetBlock(const int x, const int y, const int z) const
int GetDurability() const
const int MAX_NOTE_LENGTH
int ColorShred(shred_type) const
void PrintInv(WINDOW *, const Block *, const Inventory *) const
static int CoordOfShred(const int x)
Get shred coordinate in loaded zone (from 0 to numShreds).
void Update(int, int, int) override
This class contains information specific to player and interface for manipulating him...
Block without special physics and attributes.
void MovePlayer(dirs dir)
const int QUICK_INVENTORY_X_SHIFT
virtual QString InvFullName(int num) const
static dirs TurnLeft(dirs dir)
Provides definition for class Block.
QString WorldName() const
void Throw(int src, int dest=0, int num=1)
Tries to throw (drop out) block number num from inventory.