allow neko to scratch the walls of the monitor

This commit is contained in:
Virt 2025-04-15 14:16:10 +02:00
commit 8892e69e93
3 changed files with 116 additions and 26 deletions

2
README
View file

@ -19,6 +19,8 @@ neko with the `--type` flag. The bitmaps were obtained and modified from here
(use the wayback machine to access it): (use the wayback machine to access it):
https://users.frii.com/suzannem/neko/ https://users.frii.com/suzannem/neko/
Neko will also scratch the sides of your monitor with this fork, if one is nearby.
Refer to the man page or `--help` command to see how to use this fork and which Refer to the man page or `--help` command to see how to use this fork and which
options are new or no longer available. options are new or no longer available.

View file

@ -65,6 +65,12 @@ This option lets you set the fur of neko. You can choose by a plain single color
.RE .RE
. .
.P .P
\fB\-\-wall\fR \fBnone\fR|\fBleft\fR|\fBright\fR|\fBboth\fR
.RS
Set which walls neko is allowed to scratch. By default, neko will any wall if she feels like it.
.RE
.
.P
\fB\-\-idle-sleep\fR \fIseconds\fR \fB\-\-idle-sleep\fR \fIseconds\fR
.RS .RS
Set the time in seconds after which neko will go to sleep when the user is Set the time in seconds after which neko will go to sleep when the user is

134
wayneko.c
View file

@ -33,6 +33,7 @@ const char usage[] =
" --background-colour 0xRRGGBB[AA]\n" " --background-colour 0xRRGGBB[AA]\n"
" --outline-colour 0xRRGGBB[AA]\n" " --outline-colour 0xRRGGBB[AA]\n"
" --type plain|striped|random\n" " --type plain|striped|random\n"
" --wall none|left|right|both\n"
" --idle-sleep seconds\n" " --idle-sleep seconds\n"
" --sleep-phase seconds-seconds\n" " --sleep-phase seconds-seconds\n"
" --awake-phase seconds-seconds\n" " --awake-phase seconds-seconds\n"
@ -74,6 +75,18 @@ enum Neko
NEKO_RUN_RIGHT_2, NEKO_RUN_RIGHT_2,
NEKO_RUN_LEFT_1, NEKO_RUN_LEFT_1,
NEKO_RUN_LEFT_2, NEKO_RUN_LEFT_2,
NEKO_WALL_RIGHT_1,
NEKO_WALL_RIGHT_2,
NEKO_WALL_LEFT_1,
NEKO_WALL_LEFT_2,
};
// lsb is right, next bit is left
enum Wall {
WALL_NONE = 0,
WALL_RIGHT,
WALL_LEFT,
WALL_BOTH
}; };
const uint16_t animation_timeout = 200; /* milliseconds */ const uint16_t animation_timeout = 200; /* milliseconds */
@ -84,6 +97,7 @@ bool follow_pointer = false; // TODO: implement this again
bool recreate_surface_on_close = false; bool recreate_surface_on_close = false;
enum zwlr_layer_shell_v1_layer layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; enum zwlr_layer_shell_v1_layer layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
float start_position = 0.5; float start_position = 0.5;
enum Wall wall_behaviour = WALL_BOTH;
struct ext_idle_notifier_v1 *idle_notifier = NULL; struct ext_idle_notifier_v1 *idle_notifier = NULL;
uint32_t neko_idle_timeout_ms = 180000; /* 3 minutes. */ uint32_t neko_idle_timeout_ms = 180000; /* 3 minutes. */
@ -150,6 +164,7 @@ struct Surface surface = { 0 };
const uint32_t desired_surface_height = neko_size; const uint32_t desired_surface_height = neko_size;
const uint8_t neko_x_advance = 15; const uint8_t neko_x_advance = 15;
const uint32_t neko_x_wall_attraction = 400;
int ret = EXIT_SUCCESS; int ret = EXIT_SUCCESS;
bool loop = true; bool loop = true;
@ -772,9 +787,9 @@ static void atlas_composite_neko (struct Buffer *buffer, enum Neko neko_type, ui
); );
} }
static bool animation_can_run_left (void) static bool animation_can_run_left (bool tight)
{ {
return surface.neko_x > neko_x_advance; return surface.neko_x > (tight ? 0 : neko_x_advance);
} }
static void animation_neko_do_run_left (void) static void animation_neko_do_run_left (void)
@ -783,9 +798,9 @@ static void animation_neko_do_run_left (void)
animation_ticks_until_next_frame = 0; animation_ticks_until_next_frame = 0;
} }
static bool animation_can_run_right (void) static bool animation_can_run_right (bool tight)
{ {
return surface.neko_x < surface.width - neko_size - neko_x_advance; return surface.neko_x < surface.width - neko_size - (tight ? 0 : neko_x_advance);
} }
static void animation_neko_do_run_right (void) static void animation_neko_do_run_right (void)
@ -794,16 +809,20 @@ static void animation_neko_do_run_right (void)
animation_ticks_until_next_frame = 0; animation_ticks_until_next_frame = 0;
} }
static void animation_neko_advance_left (void) static void animation_neko_advance_left (bool tight)
{ {
surface.prev_neko_x = surface.neko_x; surface.prev_neko_x = surface.neko_x;
surface.neko_x -= neko_x_advance;
if (tight) surface.neko_x = 0;
else surface.neko_x -= neko_x_advance;
} }
static void animation_neko_advance_right (void) static void animation_neko_advance_right (bool tight)
{ {
surface.prev_neko_x = surface.neko_x; surface.prev_neko_x = surface.neko_x;
surface.neko_x += neko_x_advance;
if (tight) surface.neko_x = (uint16_t) surface.width - neko_size;
else surface.neko_x += neko_x_advance;
} }
static void animation_neko_do_stare (bool quick) static void animation_neko_do_stare (bool quick)
@ -842,6 +861,18 @@ static void animation_neko_do_scratch (void)
animation_ticks_until_next_frame = 0; animation_ticks_until_next_frame = 0;
} }
static void animation_neko_do_wall_left (void)
{
current_neko = current_neko == NEKO_WALL_LEFT_1 ? NEKO_WALL_LEFT_2 : NEKO_WALL_LEFT_1;
animation_ticks_until_next_frame = 0;
}
static void animation_neko_do_wall_right (void)
{
current_neko = current_neko == NEKO_WALL_RIGHT_1 ? NEKO_WALL_RIGHT_2 : NEKO_WALL_RIGHT_1;
animation_ticks_until_next_frame = 0;
}
static bool animtation_neko_wants_sleep (void) static bool animtation_neko_wants_sleep (void)
{ {
/* Neko likes to sleep at night. */ /* Neko likes to sleep at night. */
@ -875,12 +906,12 @@ static bool animation_next_state_with_hotspot (uint32_t x)
case NEKO_SHOCK: case NEKO_SHOCK:
case NEKO_RUN_LEFT_1: case NEKO_RUN_LEFT_1:
case NEKO_RUN_LEFT_2: case NEKO_RUN_LEFT_2:
if (!animation_can_run_left()) if (!animation_can_run_left(false))
{ {
animation_neko_do_stare(true); animation_neko_do_stare(true);
return true; return true;
} }
animation_neko_advance_left(); animation_neko_advance_left(false);
animation_neko_do_run_left(); animation_neko_do_run_left();
return true; return true;
@ -896,12 +927,12 @@ static bool animation_next_state_with_hotspot (uint32_t x)
case NEKO_SHOCK: case NEKO_SHOCK:
case NEKO_RUN_RIGHT_1: case NEKO_RUN_RIGHT_1:
case NEKO_RUN_RIGHT_2: case NEKO_RUN_RIGHT_2:
if (!animation_can_run_right()) if (!animation_can_run_right(false))
{ {
animation_neko_do_stare(true); animation_neko_do_stare(true);
return true; return true;
} }
animation_neko_advance_right(); animation_neko_advance_right(false);
animation_neko_do_run_right(); animation_neko_do_run_right();
return true; return true;
@ -972,19 +1003,31 @@ static bool animation_next_state_awake (void)
break; break;
case 4: case 4:
if (!animation_can_run_left()) if (!animation_can_run_left(false))
return false; return false;
animation_neko_advance_left(); animation_neko_advance_left(false);
animation_neko_do_run_left(); animation_neko_do_run_left();
break; break;
case 5: case 5:
if (!animation_can_run_right()) if (!animation_can_run_right(false))
return false; return false;
animation_neko_advance_right(); animation_neko_advance_right(false);
animation_neko_do_run_right(); animation_neko_do_run_right();
break; break;
case 6:
case 7:
case 8:
case 9:
if (surface.neko_x == 0 && (wall_behaviour & WALL_LEFT))
animation_neko_do_wall_left();
else if (surface.neko_x + neko_size == surface.width && (wall_behaviour & WALL_RIGHT))
animation_neko_do_wall_right();
else
return false;
break;
default: default:
return false; return false;
} }
@ -992,23 +1035,30 @@ static bool animation_next_state_awake (void)
case NEKO_RUN_RIGHT_1: case NEKO_RUN_RIGHT_1:
case NEKO_RUN_RIGHT_2: case NEKO_RUN_RIGHT_2:
if ( animation_can_run_right() && rand() % 4 != 0 ) bool attracted_right = surface.width - surface.neko_x + neko_size < neko_x_wall_attraction;
{
if (!animation_can_run_right(false) && animation_can_run_right(true) && rand() % 8 != 0) {
animation_neko_do_run_right(); animation_neko_do_run_right();
animation_neko_advance_right(); animation_neko_advance_right(true);
} } else if ( animation_can_run_right(false) && rand() % (attracted_right ? 8 : 4) != 0 ) {
else animation_neko_do_run_right();
animation_neko_advance_right(false);
} else
animation_neko_do_stare(false); animation_neko_do_stare(false);
return true; return true;
case NEKO_RUN_LEFT_1: case NEKO_RUN_LEFT_1:
case NEKO_RUN_LEFT_2: case NEKO_RUN_LEFT_2:
if ( animation_can_run_left() && rand() % 4 != 0 ) bool attracted_left = surface.neko_x < neko_x_wall_attraction;
{
if (!animation_can_run_left(false) && animation_can_run_left(true) && rand() % 8 != 0) {
animation_neko_do_run_left(); animation_neko_do_run_left();
animation_neko_advance_left(); animation_neko_advance_left(true);
} } else if ( animation_can_run_left(false) && rand() % (attracted_left ? 8 : 4) != 0 ) {
else animation_neko_do_run_left();
animation_neko_advance_left(false);
} else
animation_neko_do_stare(false); animation_neko_do_stare(false);
return true; return true;
@ -1028,6 +1078,22 @@ static bool animation_next_state_awake (void)
animation_neko_do_scratch(); animation_neko_do_scratch();
return true; return true;
case NEKO_WALL_LEFT_1:
case NEKO_WALL_LEFT_2:
if ( rand() % 12 == 0 )
animation_neko_do_stare(false);
else
animation_neko_do_wall_left();
return true;
case NEKO_WALL_RIGHT_1:
case NEKO_WALL_RIGHT_2:
if ( rand() % 12 == 0 )
animation_neko_do_stare(false);
else
animation_neko_do_wall_right();
return true;
case NEKO_THINK: case NEKO_THINK:
if ( rand() % 2 == 0 ) if ( rand() % 2 == 0 )
animation_neko_do_stare(false); animation_neko_do_stare(false);
@ -1456,6 +1522,22 @@ int main (int argc, char *argv[])
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
else if ( strcmp(argv[i], "--wall") == 0 )
{
const char *t = get_argument(argc, argv, &i);
if ( t == NULL )
return EXIT_FAILURE;
if (strcmp(t, "none") == 0) wall_behaviour = WALL_NONE;
else if (strcmp(t, "right") == 0) wall_behaviour = WALL_RIGHT;
else if (strcmp(t, "left") == 0) wall_behaviour = WALL_LEFT;
else if (strcmp(t, "both") == 0) wall_behaviour = WALL_BOTH;
else
{
fprintf(stderr, "ERROR: Unknown argument '%s' for flag '--wall'.\n", t);
return EXIT_FAILURE;
}
}
else if ( strcmp(argv[i], "--follow-pointer") == 0 ) else if ( strcmp(argv[i], "--follow-pointer") == 0 )
{ {
fprintf(stderr, "ERROR: Functionality for flag '--follow-pointer' is not yet implemented in this fork.\n"); fprintf(stderr, "ERROR: Functionality for flag '--follow-pointer' is not yet implemented in this fork.\n");