Release 2026-11-04-r2 · SHA256 e2cb9ef5996dd8874c730752a759efe354cc2934ce7e37f16d6923cd102d23ce · Click a line number for a direct link.
1 .ifndef WITH_COSMETIC_UI2 .equ WITH_COSMETIC_UI,03 .endif4 .ifndef WITH_REFINEMENTS5 .equ WITH_REFINEMENTS,06 .endif7| Actual preseason modal. Native controller input and native font/canvas.8| Persistent transactions use the independently checked234000 engine.9| WorkE000..E7FF, speculativeE800..EFFF. Modal-only state/textF100..F1FF,10| free-agent ownership bitsetF200..F267. Rebuild native menu context on exit.11 .equ WORK,0xFFFFE00012 .equ CLUB,0xFFFFF10013 .equ SCREEN,0xFFFFF10214 .equ SEL,0xFFFFF10415 .equ SOURCE,0xFFFFF10616 .equ LEAGUE,0xFFFFF10817 .equ ERROR,0xFFFFF10A18 .equ COUNT,0xFFFFF10C19 .equ PAGE,0xFFFFF10E20 .equ UID,0xFFFFF11021 .equ ENABLED,0xFFFFF11222 .equ TEXT,0xFFFFF16023 .equ USED,0xFFFFF20024 .equ OVR_SORTED,0x23BA0025 .equ POSX,0xFFFFB02826 .equ POSY,0xFFFFB02A27 .equ ATTR,0xFFFFB02C28 .equ VALUE,0xFFFFF85C29 .text30 .globl _start31_start:32 bra.w enter33 .if WITH_COSMETIC_UI34 bra.w money35 bra.w player_text36 .else37 .endif38enter:39 tst.w 0xFFFFF06C40 beq.w ordinary41 tst.w 0xFFFFF84C42 bne.w ordinary43 cmpi.l #0x5345534E,0xFFFFE3E044 bne.s empty_header45 tst.w 0xFFFFE3E846 bne.w ordinary47 bra.s eligible_header48empty_header:49 cmpi.w #2,0xFFFFE3F0 | Fresh native boot has no SESN header yet.50 bne.w ordinary51eligible_header:52 jsr 0x25400053 move.w VALUE,ENABLED54 move.w 0xFFFFF06A,LEAGUE55 move.w 0xFFFFD04C,CLUB56 cmpi.w #31,CLUB57 bhi.w ordinary58 tst.w ENABLED59 beq.s load_record60 jsr 0x2FC004 | Native canvas writes E36A: BEFORE work load.61load_record:62 move.w LEAGUE,%d063 lea WORK,%a064 jsr 0x23401865 tst.l %d066 bmi.w load_error67 bne.s loaded68 tst.w ENABLED69 beq.w ordinary70 lea 0x238000,%a071 lea WORK,%a172 move.w #511,%d073initial_copy:74 move.l (%a0)+,(%a1)+75 dbra %d0,initial_copy76 move.w LEAGUE,%d077 move.b %d0,WORK+578 lea WORK,%a079 jsr 0x23400480 move.w %d0,WORK+1681 not.w %d082 move.w %d0,WORK+1883 bsr.w save84 beq.w load_error85loaded:86 moveq #0,%d087 move.b WORK+6,%d088 cmp.w ENABLED,%d089 beq.s enabled_ready90 move.w ENABLED,%d391 addq.w #3,%d392 move.w LEAGUE,%d093 lea WORK,%a094 moveq #0,%d495 jsr 0x23402096 cmpi.l #1,%d097 bne.w load_error98 bsr.w save99 beq.w load_error100enabled_ready:101 tst.w ENABLED102 beq.w continue_game103 clr.w SCREEN104 clr.w SEL105 clr.w SOURCE106 clr.w ERROR107 bsr.w redraw108 bclr #2,0xFFFFBF78109 move.w #0x18,0xFFFFBD26110 move.w #0x79,-(%sp)111 jsr 0x11156112release:113 jsr 0x175D8114 jsr 0x11340115 move.w %d3,-(%sp) | D3 is held input; D0 includes idle direction8.116 jsr 0x11358117 or.w (%sp)+,%d3118 tst.w %d3119 bne.s release120 bra.w loop121load_error:122 | Fail closed. No invalid roster/funds are allowed into a native match.123 jsr MENU_FORCE124 jsr 0x236028125 moveq #1,%d0126 rts127ordinary:128 moveq #0,%d0129 rts130continue_game:131 jsr MENU_FORCE132 jsr 0x236028133 moveq #0,%d0134 rts135save:136 move.w LEAGUE,%d0137 lea WORK,%a0138 jsr 0x23401C139 tst.l %d0140 rts141keys:142 jsr 0x175D8143 jsr 0x11340144 move.w %d1,-(%sp)145 jsr 0x11358146 or.w (%sp)+,%d1147 rts148loop:149 bsr.s keys150 .if WITH_REFINEMENTS151 btst #4,%d1 | Xbox A = native B: same back convention.152 bne.w back153 btst #7,%d1 | Start finishes the root; backs out of lists.154 beq.s not_start155 tst.w SCREEN156 bne.w back157 bra.w ready158not_start:159 .endif160 btst #6,%d1161 bne.w back162 .if !WITH_REFINEMENTS163 btst #5,%d1164 bne.w back165 .endif166 btst #0,%d1167 bne.w up168 btst #1,%d1169 bne.w down170 tst.w SCREEN171 beq.s select_key172 cmpi.w #1,SCREEN173 bne.s select_key174 btst #2,%d1175 bne.w previous_source176 btst #3,%d1177 bne.w next_source178select_key:179 .if WITH_REFINEMENTS180 andi.w #0x20,%d1 | Xbox B = native C selects/buys/sells.181 .else182 andi.w #0x90,%d1 | Fresh Start or native pass B.183 .endif184 beq.s loop185 tst.w SCREEN186 bne.w trade187 move.w SEL,%d0188 cmpi.w #2,%d0189 beq.w ready190 addq.w #1,%d0191 move.w %d0,SCREEN192 clr.w SEL193 clr.w ERROR194 bra.w redraw_loop195back:196 tst.w SCREEN197 beq.w load_error198 clr.w SCREEN199 clr.w SEL200 clr.w ERROR201 bra.w redraw_loop202up:203 tst.w SEL204 beq.w loop205 subq.w #1,SEL206 bra.w redraw_loop207down:208 move.w COUNT,%d0209 subq.w #1,%d0210 cmp.w SEL,%d0211 bls.w loop212 addq.w #1,SEL213 bra.w redraw_loop214previous_source:215 subq.w #1,SOURCE216 bpl.s source_ready217 move.w #32,SOURCE218 bra.s source_ready219next_source:220 addq.w #1,SOURCE221 cmpi.w #33,SOURCE222 blo.s source_ready223 clr.w SOURCE224source_ready:225 clr.w SEL226 clr.w ERROR227 bra.w redraw_loop228trade:229 tst.w COUNT230 beq.w loop231 move.w SEL,%d0232 bsr.w uid_at233 cmpi.w #0xFFFF,%d0234 beq.w loop235 move.w %d0,UID236 move.w %d0,%d2237 move.w CLUB,%d1238 cmpi.w #2,SCREEN239 beq.s sell_action240 moveq #1,%d3241 bra.s perform_trade242sell_action:243 moveq #0,%d3244perform_trade:245 move.w LEAGUE,%d0246 moveq #0,%d4247 lea WORK,%a0248 jsr 0x234020249 cmpi.l #1,%d0250 bne.w refused251 bsr.w save252 beq.w load_error253 clr.w ERROR254 bra.w redraw_loop255refused:256 move.w #4,ERROR257 cmpi.w #1,SCREEN258 bne.w redraw_loop259 move.w CLUB,%d0260 cmp.w SOURCE,%d0261 bne.s not_owned262 move.w #5,ERROR263 bra.w redraw_loop264not_owned:265 mulu.w #52,%d0266 lea WORK+32,%a0267 adda.l %d0,%a0268 cmpi.w #0xFFFF,50(%a0)269 beq.s check_money270 move.w #2,ERROR271 bra.w redraw_loop272check_money:273 move.w UID,%d0274 jsr 0x234000275 move.w CLUB,%d1276 lsl.w #2,%d1277 lea WORK+1696,%a0278 cmp.l (%a0,%d1.w),%d0279 bls.w redraw_loop280 move.w #3,ERROR281 bra.w redraw_loop282ready:283 move.w LEAGUE,%d0284 moveq #2,%d3285 moveq #0,%d4286 lea WORK,%a0287 jsr 0x234020288 cmpi.l #2,%d0289 beq.w continue_game290 cmpi.l #1,%d0291 bne.w refused292 bsr.w save293 beq.w load_error294 bra.w continue_game295redraw_loop:296 bsr.w redraw297 bra.w loop298299| A2=actual source/user row, or free-agent map. No fictional placeholder slots.300row:301 move.w SOURCE,%d0302 cmpi.w #2,SCREEN303 bne.s source_row304 move.w CLUB,%d0305source_row:306 mulu.w #52,%d0307 lea WORK+32,%a2308 adda.l %d0,%a2309 rts310clear_membership:311 lea USED,%a0312 moveq #25,%d0313clear_used:314 clr.l (%a0)+315 dbra %d0,clear_used316 rts317build_used:318 bsr.s clear_membership319 lea WORK+32,%a1320 move.w #831,%d3321used_next:322 moveq #0,%d0323 move.w (%a1)+,%d0324 cmpi.w #831,%d0325 bhi.s used_skip326 move.w %d0,%d1327 lsr.w #3,%d0328 andi.w #7,%d1329 lea USED,%a0330 bset %d1,(%a0,%d0.w)331used_skip:332 dbra %d3,used_next333 rts334is_free:335 move.w %d0,%d1336 lsr.w #3,%d1337 move.w %d0,%d2338 andi.w #7,%d2339 lea USED,%a0340 btst %d2,(%a0,%d1.w)341 bne.s unavailable342 lea 0x239B80,%a0343 cmpi.b #0xFF,(%a0,%d0.w)344 rts345unavailable:346 cmp.w %d0,%d0 | Z1 unavailable; Z0 means available.347 rts348count:349 clr.w COUNT350 tst.w SCREEN351 bne.s roster_count352 move.w #3,COUNT353 rts354roster_count:355 cmpi.w #1,SCREEN356 bne.s club_count357 cmpi.w #32,SOURCE358 bne.s club_count359 bsr.s build_used360 moveq #0,%d0361free_count:362 bsr.s is_free363 beq.s free_count_next364 addq.w #1,COUNT365free_count_next:366 addq.w #1,%d0367 cmpi.w #832,%d0368 blo.s free_count369 rts370club_count:371 bsr.w clear_membership372 bsr.w row373 moveq #25,%d3374club_count_next:375 moveq #0,%d0376 move.w (%a2)+,%d0377 cmpi.w #831,%d0378 bhi.s counted379 move.w %d0,%d1380 lsr.w #3,%d0381 andi.w #7,%d1382 lea USED,%a0383 bset %d1,(%a0,%d0.w)384 addq.w #1,COUNT385 dbra %d3,club_count_next386counted:387 rts388| Project the current source membership through a separate global OVR order.389| Never reorder WORK's persistent roster slots: native lineups/stat identities390| retain their role-aware layout. Equal OVR sorts by canonical UID.391uid_at:392 cmp.w COUNT,%d0393 bhs.s uid_missing394 move.w %d0,%d4395 moveq #0,%d5396 cmpi.w #1,SCREEN397 bne.s uid_scan_start398 cmpi.w #32,SOURCE399 bne.s uid_scan_start400 moveq #1,%d5401uid_scan_start:402 lea OVR_SORTED,%a3403 moveq #0,%d6404uid_scan:405 moveq #0,%d0406 move.w (%a3)+,%d0407 tst.w %d5408 beq.s uid_membership409 bsr.w is_free410 beq.s uid_scan_next411 bra.s uid_available412uid_membership:413 move.w %d0,%d1414 lsr.w #3,%d1415 move.w %d0,%d2416 andi.w #7,%d2417 lea USED,%a0418 btst %d2,(%a0,%d1.w)419 beq.s uid_scan_next420uid_available:421 subq.w #1,%d4422 bmi.s uid_done423uid_scan_next:424 addq.w #1,%d6425 cmpi.w #831,%d6426 blo.s uid_scan427uid_missing:428 move.w #0xFFFF,%d0429uid_done:430 rts431432redraw:433 bsr.w count434 move.w COUNT,%d0435 cmp.w SEL,%d0436 bhi.s selection_valid437 subq.w #1,%d0438 bpl.s clamp_selection439 moveq #0,%d0440clamp_selection:441 move.w %d0,SEL442selection_valid:443 move.w #0x8000,ATTR444 moveq #3,%d7445clear_line:446 move.w %d7,POSY447 move.w #1,POSX448 lea blank(%pc),%a1449 jsr 0x11BA4450 addq.w #1,%d7451 cmpi.w #27,%d7452 blo.s clear_line453 move.w #1,POSY454 move.w #10,POSX455 lea title(%pc),%a1456 jsr 0x11BA4457 move.w #3,POSY458 move.w #3,POSX459 lea budget(%pc),%a1460 jsr 0x11BA4461 move.w CLUB,%d0462 lsl.w #2,%d0463 lea WORK+1696,%a0464 move.l (%a0,%d0.w),%d0465 .if WITH_COSMETIC_UI466 lea TEXT,%a0467 bsr.w money468 .else469 lea TEXT+9,%a0470 moveq #7,%d1471 bsr.w decimal472 lea TEXT+2,%a0473 moveq #7,%d1474 bsr.w trim_zeroes475 move.w #9,TEXT476 .endif477 lea TEXT,%a1478 jsr 0x11BA4479 .if WITH_COSMETIC_UI480 move.w #4,POSY481 move.w #3,POSX482 lea club_label(%pc),%a1483 jsr 0x11BA4484 .else485 move.w #23,POSX486 .endif487 move.w CLUB,%d0488 bsr.w club_name489 tst.w SCREEN490 bne.w draw_roster491 moveq #0,%d7492draw_home:493 move.w %d7,%d0494 mulu.w #3,%d0495 addi.w #10,%d0496 move.w %d0,POSY497 move.w #8,POSX498 move.w #0x8000,ATTR499 cmp.w SEL,%d7500 bne.s home_colour501 move.w #0xE000,ATTR502home_colour:503 cmp.w SEL,%d7504 bne.s home_label505 move.w #6,POSX506 lea marker(%pc),%a1507 jsr 0x11BA4508 move.w #8,POSX509home_label:510 move.w %d7,%d0511 lsl.w #2,%d0512 lea home_labels(%pc),%a0513 movea.l (%a0,%d0.w),%a1514 jsr 0x11BA4515 addq.w #1,%d7516 cmpi.w #3,%d7517 blo.s draw_home518 bra.w draw_footer519draw_roster:520 move.w #5,POSY521 move.w #3,POSX522 lea selling(%pc),%a1523 cmpi.w #2,SCREEN524 beq.s roster_title525 lea buying(%pc),%a1526roster_title:527 jsr 0x11BA4528 move.w #6,POSY529 move.w #3,POSX530 move.w SOURCE,%d0531 cmpi.w #2,SCREEN532 bne.s source_name533 move.w CLUB,%d0534source_name:535 bsr.w club_name536 move.w #7,POSY537 move.w #3,POSX538 lea columns(%pc),%a1539 jsr 0x11BA4540 move.w SEL,%d0541 andi.w #0xFFF8,%d0542 move.w %d0,PAGE543 moveq #0,%d7544 tst.w COUNT545 bne.s draw_player546 move.w #10,POSY547 move.w #3,POSX548 lea empty(%pc),%a1549 jsr 0x11BA4550 bra.w draw_footer551draw_player:552 move.w PAGE,%d0553 add.w %d7,%d0554 cmp.w COUNT,%d0555 bhs.w draw_footer556 bsr.w uid_at557 bsr.w player_text558 move.w #0x8000,ATTR559 move.w PAGE,%d0560 add.w %d7,%d0561 cmp.w SEL,%d0562 bne.s player_colour563 move.w #0xE000,ATTR564player_colour:565 move.w %d7,%d0566 mulu.w #2,%d0567 addi.w #9,%d0568 move.w %d0,POSY569 move.w PAGE,%d0570 add.w %d7,%d0571 cmp.w SEL,%d0572 bne.s no_player_marker573 move.w #1,POSX574 lea marker(%pc),%a1575 jsr 0x11BA4576no_player_marker:577 move.w #3,POSX578 lea TEXT,%a1579 jsr 0x11BA4580 addq.w #1,%d7581 cmpi.w #8,%d7582 blo.s draw_player583draw_footer:584 move.w #0x8000,ATTR585 move.w #25,POSY586 move.w #1,POSX587 lea help(%pc),%a1588 .if WITH_REFINEMENTS589 tst.w SCREEN590 beq.s help_ready591 lea help_buy(%pc),%a1592 cmpi.w #1,SCREEN593 beq.s help_ready594 lea help_sell(%pc),%a1595help_ready:596 .endif597 jsr 0x25D004598 jsr 0x11BA4599 tst.w ERROR600 beq.s draw_done601 move.w #24,POSY602 move.w #1,POSX603 move.w ERROR,%d0604 subq.w #1,%d0605 lsl.w #2,%d0606 lea error_labels(%pc),%a0607 movea.l (%a0,%d0.w),%a1608 jsr 0x11BA4609draw_done:610 jsr 0x25D000611 rts612613club_name:614 cmpi.w #32,%d0615 bne.s actual_club616 lea free_agents(%pc),%a1617 jmp 0x11BA4618actual_club:619 lsl.w #2,%d0620 lea 0x30E,%a0621 movea.l (%a0,%d0.w),%a1622 adda.w 4(%a1),%a1623 jmp 0x11BA4624625player_text:626 move.w %d0,UID627 lea TEXT+2,%a0628 moveq #35,%d1629text_clear:630 move.b #32,(%a0)+631 dbra %d1,text_clear632 move.w #38,TEXT633 move.w UID,%d0634 lsl.w #2,%d0635 lea 0x238800,%a0636 movea.l (%a0,%d0.w),%a1637 move.w (%a1)+,%d1638 subq.w #3,%d1639 cmpi.w #19,%d1640 bls.s name_size641 moveq #19,%d1642name_size:643 lea TEXT+2,%a0644name_copy:645 move.b (%a1)+,%d2646 beq.s name_done647 move.b %d2,(%a0)+648 dbra %d1,name_copy649name_done:650 move.w UID,%d0651 lea 0x239B80,%a0652 moveq #0,%d1653 move.b (%a0,%d0.w),%d1654 lea roles(%pc),%a0655 move.b (%a0,%d1.w),TEXT+23656 lea 0x239EC0,%a0657 moveq #0,%d1658 move.b (%a0,%d0.w),%d1659 move.l %d1,%d0660 lea TEXT+27,%a0661 moveq #2,%d1662 .if WITH_COSMETIC_UI663 bsr.w decimal664 .else665 bsr.s decimal666 .endif667 lea TEXT+25,%a0668 moveq #2,%d1669 bsr.w trim_zeroes670 move.w UID,%d0671 jsr 0x234000672 .if WITH_COSMETIC_UI673 lea TEXT+48,%a0674 bsr.w money675 cmpi.w #10,%d1676 bhi.s price_overflow677 lea TEXT+38,%a0678 suba.w %d1,%a0679 lea TEXT+50,%a1680 subq.w #1,%d1681 bra.s price_copy682price_overflow:683 | Immutable OVR0..99 prices fit10. Fail visibly without touching adjacent684 | fields even if a diagnostic/corrupt price exceeds that declared bound.685 .else686 lea TEXT+33,%a0687 moveq #5,%d1688 bsr.s decimal689 .endif690 lea TEXT+28,%a0691 .if WITH_COSMETIC_UI692 lea money_overflow(%pc),%a1693 moveq #9,%d1694price_copy:695 move.b (%a1)+,(%a0)+696 dbra %d1,price_copy697 .else698 moveq #5,%d1699 bsr.w trim_zeroes700 .endif701 rts702 .if WITH_COSMETIC_UI703704 .else705 .endif706trim_zeroes:707 subq.w #2,%d1708trim_next:709 cmpi.b #48,(%a0)710 bne.s trim_done711 move.b #32,(%a0)+712 dbra %d1,trim_next713trim_done:714 rts715decimal:716 movem.l %d2-%d4,-(%sp)717 subq.w #1,%d1718decimal_digit:719 move.l %d0,%d2720 swap %d0721 andi.l #0xFFFF,%d0722 divu.w #10,%d0723 move.w %d0,%d3724 clr.w %d0725 move.w %d2,%d0726 divu.w #10,%d0727 move.w %d0,%d2728 swap %d0729 addi.b #48,%d0730 move.b %d0,-(%a0)731 move.w %d3,%d0732 swap %d0733 move.w %d2,%d0734 dbra %d1,decimal_digit735 movem.l (%sp)+,%d2-%d4736 rts737 .if WITH_COSMETIC_UI738| Unsigned32-bit internal units -> whole USD at1000 dollars per unit.739| No multiplication: group the units, then append .000. This supports even740| UINT32_MAX as $4.294.967.295.000 without overflowing32-bit arithmetic.741| D0=input preserved; A0=packet destination preserved (21bytes incl terminator).742| D1=payload length returned; all other registers preserved. No persistent RAM.743money:744 move.w %sr,-(%sp)745 movem.l %d0/%d2-%d6/%a0-%a2,-(%sp)746 move.l %d0,%d5747 movea.l %a0,%a2748 suba.w #12,%sp749 movea.l %sp,%a1750 lea 10(%sp),%a0751 moveq #10,%d1752 bsr.w decimal753 moveq #10,%d2754money_skip:755 cmpi.w #1,%d2756 beq.s money_digits757 cmpi.b #48,(%a1)758 bne.s money_digits759 addq.l #1,%a1760 subq.w #1,%d2761 bra.s money_skip762money_digits:763 lea 2(%a2),%a0764 move.b #36,(%a0)+765 tst.l %d5766 bne.s money_groups767 move.b #48,(%a0)+768 bra.s money_done769money_groups:770 move.l %d2,%d3771 divu.w #3,%d3772 swap %d3773 tst.w %d3774 bne.s money_copy775 moveq #3,%d3776money_copy:777 move.b (%a1)+,(%a0)+778 subq.w #1,%d2779 beq.s money_thousands780 subq.w #1,%d3781 bne.s money_copy782 move.b #46,(%a0)+783 moveq #3,%d3784 bra.s money_copy785money_thousands:786 move.b #46,(%a0)+787 move.b #48,(%a0)+788 move.b #48,(%a0)+789 move.b #48,(%a0)+790money_done:791 clr.b (%a0)792 move.l %a0,%d1793 sub.l %a2,%d1794 move.w %d1,(%a2)795 subq.w #2,%d1796 adda.w #12,%sp797 movem.l (%sp)+,%d0/%d2-%d6/%a0-%a2798 move.w (%sp)+,%sr799 rts800money_overflow: .ascii "$OVERFLOW "801 .even802club_label: .word 8803 .ascii "Club: "804805 .else806 .endif807roles: .ascii "GLCRFD"808 .even809home_labels: .long buy,sell,start810error_labels: .long blocked,full_roster,no_money,position_needed,already_owned811title: .word 22812 .ascii "PRESEASON TRANSFERS "813 .even814budget: .word 10815 .ascii "Budget: "816buy: .word 14817 .ascii "Buy players "818sell: .word 14819 .ascii "Sell players"820start: .word 18821 .ascii "Ready for season"822buying: .word 38823 .ascii "Buy: Left/Right changes source club "824 .even825selling: .word 20826 .ascii "Sell your players "827 .even828 .if WITH_COSMETIC_UI829columns: .word 38830 .ascii "PLAYER P OVR PRICE USD"831 .if (.-columns)!=38832 .error "Currency column header must remain36 native characters"833 .endif834 .else835columns: .word 34836 .ascii "PLAYER P OVR PRICE"837 .endif838 .even839help:840 .if WITH_REFINEMENTS841 .word 34842 .ascii "A Back B Select Start Ready "843 .even844help_buy: .word 34845 .ascii "A/Start Back B Buy L/R Club "846 .even847help_sell: .word 34848 .ascii "A/Start Back B Sell "849 .even850 .else851 .word 32852 .ascii "Start/Pass: Select A/C: Back"853 .endif854 .even855blocked: .word 42856 .ascii "Transfer blocked by budget/roster rules "857 .even858blank: .word 40859 .ascii " "860 .even861862full_roster: .word 36863 .ascii "Roster full - sell a player first "864 .even865no_money: .word 34866 .ascii "Not enough money for this player"867 .even868position_needed: .word 36869 .ascii "Club needs this position or player"870 .even871already_owned: .word 30872 .ascii "Already plays for your club "873 .even874empty: .word 22875 .ascii "No available players"876 .even877free_agents: .word 14878 .ascii "Free agents "879marker: .word 4880 .ascii "* "881