Skip to content

Commit 950f54f

Browse files
committed
feat: allow -C to specify multi-color, custom palette
1 parent 5c082c6 commit 950f54f

File tree

2 files changed

+155
-45
lines changed

2 files changed

+155
-45
lines changed

cmatrix.1

+4-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Locks cmatrix, Unable to quit
3636
Print usage and exit
3737
.TP
3838
.I "\-r"
39-
"Rainbow" mode, rainbow colored character
39+
"Rainbow" mode, rainbow colored characters. Uses colors from -C if multiple are specified, otherwise uses the full rainbow palette.
4040
.TP
4141
.I "\-k"
4242
Every characters change
@@ -62,6 +62,9 @@ Screen update delay 0 - 9, default 4
6262
.I "\-C color"
6363
Use this color for matrix (default green).
6464
Valid colors are green, red, blue, white, yellow, cyan, magenta and black.
65+
Multiple colors can be specified by separating them with commas (e.g., "red,blue,green").
66+
When multiple colors are specified, they are used proportionally.
67+
Repeats are allowed for different mixes (e.g. "red,blue,blue" or "red,red,blue")
6568
.TP
6669
.I "\-M message"
6770
Add a message in the center of cmatrix

cmatrix.c

+151-44
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
typedef struct cmatrix {
8080
int val;
8181
bool is_head;
82+
int color; // For multi-color mode, each character can have a different color
8283
} cmatrix;
8384

8485
/* Global variables */
@@ -92,6 +93,11 @@ int *updates = NULL; /* What does this do again? */
9293
#ifndef _WIN32
9394
volatile sig_atomic_t signal_status = 0; /* Indicates a caught signal */
9495
#endif
96+
int* color_array = NULL; /* Array of color values for multi-color mode */
97+
int num_colors = 0; /* Number of colors in current use (0 when not in multi-color mode) */
98+
int original_num_colors = 0; /* Remember the original number of colors */
99+
int mcolor = COLOR_GREEN; /* Current matrix color */
100+
int rainbow = 0; /* Flag for rainbow mode */
95101

96102
int va_system(char *str, ...) {
97103

@@ -164,7 +170,9 @@ void usage(void) {
164170
printf(" -M [message]: Prints your message in the center of the screen. Overrides -L's default message.\n");
165171
printf(" -u delay (0 - 10, default 4): Screen update delay\n");
166172
printf(" -C [color]: Use this color for matrix (default green)\n");
173+
printf(" Multiple colors can be specified as comma-separated list (e.g. -C red,blue,green)\n");
167174
printf(" -r: rainbow mode\n");
175+
printf(" Will use colors from -C if multiple specified, otherwise full rainbow\n");
168176
printf(" -m: lambda mode\n");
169177
printf(" -k: Characters change while scrolling. (Works without -o opt.)\n");
170178
printf(" -t [tty]: Set tty to use\n");
@@ -189,6 +197,29 @@ void *nmalloc(size_t howmuch) {
189197
return r;
190198
}
191199

200+
/* Parse a color name and return the corresponding COLOR_* constant */
201+
int parse_color(const char* color_name) {
202+
if (!strcasecmp(color_name, "green")) {
203+
return COLOR_GREEN;
204+
} else if (!strcasecmp(color_name, "red")) {
205+
return COLOR_RED;
206+
} else if (!strcasecmp(color_name, "blue")) {
207+
return COLOR_BLUE;
208+
} else if (!strcasecmp(color_name, "white")) {
209+
return COLOR_WHITE;
210+
} else if (!strcasecmp(color_name, "yellow")) {
211+
return COLOR_YELLOW;
212+
} else if (!strcasecmp(color_name, "cyan")) {
213+
return COLOR_CYAN;
214+
} else if (!strcasecmp(color_name, "magenta")) {
215+
return COLOR_MAGENTA;
216+
} else if (!strcasecmp(color_name, "black")) {
217+
return COLOR_BLACK;
218+
} else {
219+
return -1; /* Invalid color */
220+
}
221+
}
222+
192223
/* Initialize the global variables */
193224
void var_init() {
194225
int i, j;
@@ -223,6 +254,7 @@ void var_init() {
223254
for (i = 0; i <= LINES; i++) {
224255
for (j = 0; j <= COLS - 1; j += 2) {
225256
matrix[i][j].val = -1;
257+
matrix[i][j].color = mcolor; // Initialize with default color
226258
}
227259
}
228260

@@ -310,6 +342,27 @@ void resize_screen(void) {
310342
refresh();
311343
}
312344

345+
/**
346+
* Selects a color for a matrix character based on current global program state.
347+
*
348+
* This function uses GLOBAL STATE variables:
349+
* - num_colors: Number of colors in the custom palette
350+
* - color_array: Array of custom color values
351+
* - rainbow: Flag indicating if rainbow mode is active
352+
* - mcolor: Current default color
353+
*
354+
* @return The selected color value (COLOR_* constant)
355+
*/
356+
int select_matrix_color(void) {
357+
if (num_colors > 0 && color_array != NULL && !rainbow) {
358+
/* Multi-color mode - select from custom palette */
359+
return color_array[rand() % num_colors];
360+
} else {
361+
/* Single color mode or no custom palette - use global color */
362+
return mcolor;
363+
}
364+
}
365+
313366
int main(int argc, char *argv[]) {
314367
int i, y, z, optchr, keypress;
315368
int j = 0;
@@ -323,8 +376,6 @@ int main(int argc, char *argv[]) {
323376
int random = 0;
324377
int update = 4;
325378
int highnum = 0;
326-
int mcolor = COLOR_GREEN;
327-
int rainbow = 0;
328379
int lambda = 0;
329380
int randnum = 0;
330381
int randmin = 0;
@@ -356,26 +407,48 @@ int main(int argc, char *argv[]) {
356407
bold = 2;
357408
break;
358409
case 'C':
359-
if (!strcasecmp(optarg, "green")) {
360-
mcolor = COLOR_GREEN;
361-
} else if (!strcasecmp(optarg, "red")) {
362-
mcolor = COLOR_RED;
363-
} else if (!strcasecmp(optarg, "blue")) {
364-
mcolor = COLOR_BLUE;
365-
} else if (!strcasecmp(optarg, "white")) {
366-
mcolor = COLOR_WHITE;
367-
} else if (!strcasecmp(optarg, "yellow")) {
368-
mcolor = COLOR_YELLOW;
369-
} else if (!strcasecmp(optarg, "cyan")) {
370-
mcolor = COLOR_CYAN;
371-
} else if (!strcasecmp(optarg, "magenta")) {
372-
mcolor = COLOR_MAGENTA;
373-
} else if (!strcasecmp(optarg, "black")) {
374-
mcolor = COLOR_BLACK;
410+
if (strchr(optarg, ',')) {
411+
/* Multiple colors specified, parse them */
412+
char *colors_copy = strdup(optarg);
413+
if (!colors_copy) {
414+
c_die("CMatrix: Out of memory!\n");
415+
}
416+
417+
/* Count number of colors */
418+
int color_count = 1;
419+
for (char *p = colors_copy; *p; p++) {
420+
if (*p == ',') color_count++;
421+
}
422+
423+
/* Allocate the color array */
424+
color_array = nmalloc(color_count * sizeof(int));
425+
num_colors = 0;
426+
427+
/* Parse each color */
428+
char *token = strtok(colors_copy, ",");
429+
while (token != NULL) {
430+
int color = parse_color(token);
431+
if (color == -1) {
432+
free(colors_copy);
433+
c_die(" Invalid color selection '%s'\n Valid "
434+
"colors are green, red, blue, "
435+
"white, yellow, cyan, magenta and black.\n", token);
436+
}
437+
color_array[num_colors++] = color;
438+
token = strtok(NULL, ",");
439+
}
440+
original_num_colors = num_colors; // Remember the original count
441+
free(colors_copy);
375442
} else {
376-
c_die(" Invalid color selection\n Valid "
377-
"colors are green, red, blue, "
378-
"white, yellow, cyan, magenta " "and black.\n");
443+
/* Single color specified */
444+
num_colors = 0;
445+
color_array = NULL; /* Ensure color_array is NULL */
446+
mcolor = parse_color(optarg);
447+
if (mcolor == -1) {
448+
c_die(" Invalid color selection\n Valid "
449+
"colors are green, red, blue, "
450+
"white, yellow, cyan, magenta and black.\n");
451+
}
379452
}
380453
break;
381454
case 'c':
@@ -618,42 +691,57 @@ if (console) {
618691
case '!':
619692
mcolor = COLOR_RED;
620693
rainbow = 0;
694+
num_colors = 0;
621695
break;
622696
case '@':
623697
mcolor = COLOR_GREEN;
624698
rainbow = 0;
699+
num_colors = 0;
625700
break;
626701
case '#':
627702
mcolor = COLOR_YELLOW;
628703
rainbow = 0;
704+
num_colors = 0;
629705
break;
630706
case '$':
631707
mcolor = COLOR_BLUE;
632708
rainbow = 0;
709+
num_colors = 0;
633710
break;
634711
case '%':
635712
mcolor = COLOR_MAGENTA;
636713
rainbow = 0;
714+
num_colors = 0;
637715
break;
638716
case 'r':
639717
rainbow = 1;
718+
if (original_num_colors > 0) {
719+
num_colors = original_num_colors; // Restore original count for rainbow
720+
}
640721
break;
641722
case 'm':
642723
lambda = !lambda;
643724
break;
644725
case '^':
645726
mcolor = COLOR_CYAN;
646727
rainbow = 0;
728+
num_colors = 0;
647729
break;
648730
case '&':
649731
mcolor = COLOR_WHITE;
650732
rainbow = 0;
733+
num_colors = 0;
651734
break;
652735
case 'p':
653736
case 'P':
654737
pause = (pause == 0)?1:0;
655738
break;
656-
739+
case '+':
740+
rainbow = 0;
741+
if (original_num_colors > 0) {
742+
num_colors = original_num_colors; // Restore multi-color mode
743+
}
744+
break;
657745
}
658746
}
659747
}
@@ -664,6 +752,7 @@ if (console) {
664752
if (oldstyle) {
665753
for (i = LINES - 1; i >= 1; i--) {
666754
matrix[i][j].val = matrix[i - 1][j].val;
755+
matrix[i][j].color = matrix[i - 1][j].color;
667756
}
668757
random = (int) rand() % (randnum + 8) + randmin;
669758

@@ -683,13 +772,15 @@ if (console) {
683772
matrix[0][j].val = 0;
684773
} else {
685774
matrix[0][j].val = (int) rand() % randnum + randmin;
775+
matrix[0][j].color = select_matrix_color();
686776
}
687777
spaces[j] = (int) rand() % LINES + 1;
688778
}
689779
} else if (random > highnum && matrix[1][j].val != 1) {
690780
matrix[0][j].val = ' ';
691781
} else {
692782
matrix[0][j].val = (int) rand() % randnum + randmin;
783+
matrix[0][j].color = select_matrix_color();
693784
}
694785

695786
} else { /* New style scrolling (default) */
@@ -700,6 +791,10 @@ if (console) {
700791
&& matrix[1][j].val == ' ') {
701792
length[j] = (int) rand() % (LINES - 3) + 3;
702793
matrix[0][j].val = (int) rand() % randnum + randmin;
794+
matrix[0][j].is_head = true;
795+
796+
// Assign a random color to the character head
797+
matrix[0][j].color = select_matrix_color();
703798

704799
spaces[j] = (int) rand() % LINES + 1;
705800
}
@@ -740,6 +835,9 @@ if (console) {
740835
matrix[i][j].val = (int) rand() % randnum + randmin;
741836
matrix[i][j].is_head = true;
742837

838+
// Assign a random color to the new character head
839+
matrix[i][j].color = select_matrix_color();
840+
743841
/* If we're at the top of the column and it's reached its
744842
full length (about to start moving down), we do this
745843
to get it moving. This is also how we keep segments not
@@ -794,28 +892,37 @@ if (console) {
794892
}
795893
} else {
796894
if (rainbow) {
797-
int randomColor = rand() % 6;
798-
799-
switch (randomColor) {
800-
case 0:
801-
mcolor = COLOR_GREEN;
802-
break;
803-
case 1:
804-
mcolor = COLOR_BLUE;
805-
break;
806-
case 2:
807-
mcolor = COLOR_BLACK;
808-
break;
809-
case 3:
810-
mcolor = COLOR_YELLOW;
811-
break;
812-
case 4:
813-
mcolor = COLOR_CYAN;
814-
break;
815-
case 5:
816-
mcolor = COLOR_MAGENTA;
817-
break;
818-
}
895+
if (num_colors > 0 && color_array != NULL) {
896+
// Rainbow mode with custom color palette
897+
mcolor = color_array[rand() % num_colors];
898+
} else {
899+
// Standard rainbow mode with predefined colors
900+
int randomColor = rand() % 6;
901+
902+
switch (randomColor) {
903+
case 0:
904+
mcolor = COLOR_GREEN;
905+
break;
906+
case 1:
907+
mcolor = COLOR_BLUE;
908+
break;
909+
case 2:
910+
mcolor = COLOR_BLACK;
911+
break;
912+
case 3:
913+
mcolor = COLOR_YELLOW;
914+
break;
915+
case 4:
916+
mcolor = COLOR_CYAN;
917+
break;
918+
case 5:
919+
mcolor = COLOR_MAGENTA;
920+
break;
921+
}
922+
}
923+
} else if (num_colors > 0) {
924+
// Multi-color mode - use stored character colors
925+
mcolor = matrix[i][j].color;
819926
}
820927
attron(COLOR_PAIR(mcolor));
821928
if (matrix[i][j].val == 1) {

0 commit comments

Comments
 (0)