One approach would be to mirror the BASIC ROM into RAM where it can easily be modified, and then simply NOP the instructions that perform the color change.
I outline the technique used to mirror the ROMS into RAM in this post
Mapping the 64 seems to indicate the BASIC PRINT routing is located at $AAA0, and eventually calls the Kernal CHROUT. I would start by disassembling the PRINT logic at $AAA0 with an eye toward where the color is output, and then override as desired.
Maybe you could peek the color at the specified address before you print it. Else, if color ram has different colors at each character location where you want to print, the next idea would be to poke the characters at screenmem (which does not affect colorram). I also think that you can define a function using DEF FN() that peeks and pokes characters (i.e. emulating PRINT) and not change the colorram. That would be an exercise for the reader to find out.
See DEF FN
Of course the drawback is that this is very very slow.
The "problem" with a screen text rendering routine that also sets the color of each character cell it outputs is performance. It requires two writes for each character, but only one is required if you want to keep whatever color(s) are already assigned.
If you are looking to improve the performance of the PRINT used in BASIC by foregoing unnecessary writes to the color RAM, then there are at least two approaches that should work.
- You can copy BASIC to RAM and then modify the PRINT routine in place, as recommended by @Geo... This will not survive a cold start.
- You can adapt your basic program to call a bespoke print routine, written in ML, which only sets the character and leaves the color unchanged. Such a routine can be loaded via your BASIC program, access with the BASIC USR() function, and naturally unaffected by system restarts.
NOTE: You could also build the process of patching BASIC into your BASIC program so that just running it re-creates the environment after a restart. I think my preference for #2 is just based on adding new ML code is more straightforward than patching.