'Standard Miles Tag Gun/Receiver Processor (with LCD display) 'DIY Laser Tag Game System 'Code Version: 3.15 'Words Used = 3988 'Revision Date: 3 April 2005 'By Jim Robertson [email: thelightbrain@yahoo.com] 'Schematics and Information: http://lightbrain.8m.com/mtdesign.htm 'All rights reserved. No commercial products may be based on this code. 'Written for PICBasic Pro Compiler version 2.45 (www.melabs.com) 'Processor=PIC16F648A (MCLR=OFF; OSC=INTRC) 'Revision Information ' 3.01 Initial release. ' 3.12 ' - Fixed Health Configuration ' - Fixed Hit Delay feature ' - Added "Kevlar" feature ' - Added diagnostic (test) modes: send glitch & send near miss ' - Updated comments ' - Optimized various code sections ' - Redefined System Messages ' - Added ability to receive ammo from armorer (rounds,clips,RPGs) ' - Added ability to receive Health from medic ' - Added Cloning functions (send and receive all configuration parameters) ' -- GameID, TeamID, PlayerID are not cloned ' - Fixed delay timings ' - Fixed reload delay timing ' - Added Scorekeeping (scores are cleared by reconfigure) ' - Added "friendly fire" on/off capability ' - Added checksum to clone data packet ' - Decreased carrier duty cycle to 12% ' - Software filtering of erroneous input signals ' -- Allows solid operation in high IRI/EMI environments ' - Fixed TeamID changes when hit received ' - Reordered config parameters for Mini MilesTag compatability ' 3.13 ' - Changed: Kevlar value is now reset by restart command ' - Changed: Clip is now FULL following restart command ' - Removed: "end of reload" sound ' 3.14 ' - Added: Gladiator Mode ' - Added: Gladiator Mode functions are Cloned ' - Changed: Increased carrier duty cycle to 20% (increase range) ' - Changed: Code ready for possible switch to 56K operation ' - Changed: Display shows "Tags" instead of "Health" in Gladiator Mode ' - Added: Score Download Mode ' 3.15 ' - Fixed: G-mode notloading/saving to EEPROM ' - Fixed: Rounds per clip now 1 to 251 (251 = unlimited) 'These values are only set during chip programming. EEPROM 0, [0] 'game ID EEPROM 1, [32] 'team ID EEPROM 2, [1] 'player ID EEPROM 3, [100] 'full_health EEPROM 4, [2] 'hit_delay in seconds EEPROM 5, [25] 'Gun Hit Points EEPROM 6, [99] 'clips EEPROM 7, [20] 'full clip EEPROM 8, [255] 'fire sel EEPROM 9, [50] 'cyclic delay (in ms) EEPROM 10, [3] 'reload time (in seconds) EEPROM 11, [0] 'friendly fire enable EEPROM 12, [0] 'kevlar service life (in hits) EEPROM 13, [0] 'rocket en EEPROM 14, [35] 'ammo2 RPG Hit Points EEPROM 15, [3] 'initial number of rockets EEPROM 16, [1] 'muzzle flash enable EEPROM 17, [1] 'restart opponent enable EEPROM 18, [1] 'sound enable EEPROM 19, [0] 'G-mode enable EEPROM 20, [4] 'G-tags '************************************************************* '************************************************************* '******************** DEFINE CONSTANTS *********************** '************************************************************* '************************************************************* sys_msg CON %00000000 'team value - System Message team1 CON %00100000 'team value - Red team2 CON %01000000 'team value - Blue team3 CON %01100000 'team value - Yellow team4 CON %10000000 'team value - Green team5 CON %10100000 'team value - Black team6 CON %11000000 'team value - White team7 CON %11100000 'team value - Purple player0 CON $00 player1 CON $01 player2 CON $02 player3 CON $03 player4 CON $04 player5 CON $05 player6 CON $06 player7 CON $07 player8 CON $08 player9 CON $09 player10 CON $0A player11 CON $0B player12 CON $0C player13 CON $0D player14 CON $0E player15 CON $0F player16 CON $10 player17 CON $11 player18 CON $12 player19 CON $13 player20 CON $14 player21 CON $15 player22 CON $16 player23 CON $17 player24 CON $18 player25 CON $19 player26 CON $1A player27 CON $1B player28 CON $1C player29 CON $1D player30 CON $1E player31 CON $1F '************************************************************** '-------------------- Valid Player Hits ----------------------- '************************************************************** resurrect CON 0 'ammo value - RESURRECT (restart player) ' 1 to 100 = Player Damage Hits '101 to 200 = Base Damage Hits '201 to 254 = Undefined reset_base CON 255 '************************************************************** '------------------ Valid System Messages --------------------- '************************************************************** msg_Clone CON $00 'Clone Transmit Header msg_Health CON $01 'Add Health msg_Rounds CON $02 'Add Rounds msg_Clips CON $04 'Add Clips msg_RPGs CON $04 'Add RPGs msg_NPhit CON $05 'Non-player Hit msg_Disable CON $06 'Disable Weapon msg_CodeA CON $07 'Secure Code A msg_CodeB CON $08 'Secure Code B msg_GodGun CON $09 'God Gun Functions msg_ColDam CON $0A 'Collateral Damage msg_Mode CON $0B 'Mode Select (Type of Game) msg_12 CON $0E 'Undefined msg_13 CON $0F 'Undefined msg_14 CON $0E 'Undefined msg_15 CON $0F 'Undefined msg_scoreTx CON $10 'Score Transmit Header msg_scoreReq CON $11 'Put gun in Score Download mode msg_scoreClr CON $12 'Clear scores '************************************************************* '************************************************************* '******************** PIN ASSIGNMENTS ************************ '************************************************************* '************************************************************* '------------------ PORT A PIN ASSIGNMENTS ------------------- ' PortA.0 LCD DB4 (config switch) ' PortA.1 LCD DB5 (future trigger) ' PortA.2 LCD DB6 (future modesel) ' PortA.3 LCD DB7 (future reload) ' PortA.4 LCD RS ' PortA.5 IR Detector Input ' PortA.6 Undefined ' PortA.7 Undefined '------------------ PORT B PIN ASSIGNMENTS ------------------- Symbol trigger = PORTB.0 'trigger button Symbol reload = PORTB.1 'mode/menu button Symbol modesel = PORTB.2 'reload button Symbol Lcde = PORTB.3 'lcd enable line Symbol tone = PORTB.4 'peizo indicator Symbol backlight = PORTB.5 'LCD Backlight Symbol muzzle = PORTB.6 'muzzle flash LED Symbol mod_out = PORTB.7 'IR mod output (40KHz) '************************************************************* '************************************************************* '******************** DEFINE VARIABLES *********************** '************************************************************* '************************************************************* bad_data VAR BIT i_am_dead VAR BIT game_bit VAR BIT '(0=GameA; 1=GameB) parity VAR BIT sound_bit VAR BIT ' 1=enabled sound muzzle_bit VAR BIT ' 1=enabled muzzle flash rocket_bit VAR BIT ' 1=enabled RPG restart_bit VAR BIT ' 1=enabled restart mode friend_fire VAR BIT ' 1=friendly fire hits allowed gladiator_bit VAR BIT hit_detect VAR BYTE clips VAR BYTE ' # of clips remaining 'fullclip VAR BYTE ' # of rounds in full clip rockets VAR BYTE ' # of RPG rounds remaining ammo VAR BYTE 'ammo1 VAR BYTE ' Hit Point value for Gun 'ammo2 VAR BYTE ' Hit Point value for RPG delay VAR BYTE 'button repeat delay rounds VAR BYTE ' # of rounds remaining messageID VAR BYTE 'fire_sel VAR BYTE init_rocket VAR BYTE 'rel_time VAR BYTE vdelay VAR BYTE vcount VAR BYTE vcount2 VAR BYTE databyte VAR BYTE weapon VAR BYTE player VAR BYTE myplayer VAR BYTE team VAR BYTE myteam VAR BYTE butvar1 VAR BYTE ' button repeat variable butvar2 VAR BYTE ' button repeat variable butvar3 VAR BYTE ' button repeat variable length VAR BYTE message VAR BYTE temp VAR BYTE temp2 VAR BYTE temp4 VAR BYTE temp5 VAR BYTE bit_counter VAR BYTE databyte1 VAR BYTE damage VAR BYTE score_refID VAR BYTE 'Reference ID to prevent duplicate score downloads paritycount VAR BYTE itemID VAR BYTE 'register used for configuration item VAR BYTE 'register used for configuration item_min VAR BYTE 'register used for configuration item_max VAR BYTE 'register used for configuration item_step VAR BYTE 'register used for configuration 'hit_delay VAR BYTE full_health VAR BYTE 'full health = 5 to 250 points kevlar VAR BYTE ' kevlar protection remaining modcount VAR BYTE 'cyclic VAR BYTE checksum VAR BYTE max_health VAR WORD health VAR WORD temp3 VAR WORD tempteam VAR WORD config_item VAR BYTE[32] BANK1 score VAR BYTE[32] BANK2 ' Player scores up to 255 hits GoTo initialize '************************************************************* '************************************************************* '***************** ASSEMBLY CODE ROUTINES ******************** '************************************************************* '************************************************************* Asm ;--------------------------------------------- _send_header movlw 96 ; 2400uS pulse 96 (133 for 56K mod) movwf _modcount Call mod_on_40 Return _send_space movlw 24 ; 600uS space 24 (33 for 56K mod) movwf _modcount space_loop Call rtrn ;(4) delay 4 cycles Call rtrn ;(4) delay 4 cycles Call rtrn ;(4) delay 4 cycles Call rtrn ;(4) delay 4 cycles Call rtrn ;(4) delay 4 cycles GoTo $+1 ;(2) delay 2 cycles decfsz _modcount,F ;(1) GoTo space_loop ;(2) Return _send_one movlw 48 ; 1200uS pulse 48 (67 for 56K mod) movwf _modcount Call mod_on_40 rlf _databyte,F Return _send_zero movlw 24 ; 600uS pulse 24 (33 for 56K mod) movwf _modcount Call mod_on_40 rlf _databyte,F Return mod_on_40 bsf PORTB,7 ;(1) Call rtrn ;(4) delay 4 cycles bcf PORTB,7 ;(1) duty cycle = 20% GoTo $+1 ;(2) delay 2 cycles Call rtrn ;(4) delay 4 cycles GoTo $+1 ;(2) delay 2 cycles Call rtrn ;(4) delay 4 cycles Call rtrn ;(4) delay 4 cycles decfsz _modcount,F ;(1) GoTo mod_on_40 ;(2) (25uS = 40.0KHz) Return ;mod_on_56 ; bsf PORTB,7 ;(1) ; GoTo $+1 ;(2) delay 2 cycles ; nop ;(1) delay 1 cycle ; bcf PORTB,7 ;(1) duty cycle = 22% ; GoTo $+1 ;(2) delay 2 cycles ; Call rtrn ;(4) delay 4 cycles ; Call rtrn ;(4) delay 4 cycles ; decfsz _modcount,F ;(1) ; GoTo mod_on_40 ;(2) (18uS = 55.5KHz) ; Return ;--------------------------------------------- _get_pulse movlw 255 ; max header pulse=264uS movwf _length header_loop Call rtrn ;(4) delay 4 cycles GoTo $+1 ;(2) delay 2 cycles btfsc PORTA,5 ;(2) check for end of header Return ; end of header found decfsz _length,F ;(1) GoTo header_loop ;(2) GoTo too_long ; header was too long Return too_long movlw 1 movwf _length Return ;--------------------------------------------- _get_bit movlw 250 movwf _length wait_edge2 ; wait for edge btfss PORTA,5 ;(2) GoTo measure_bit ; Call rtrn ;(4) delay 4 cycles nop ;(1) decfsz _length,F ;(1) GoTo wait_edge2 ;(2) GoTo bad_bit ; space was too long measure_bit ; check if header (2400uS pulse) movlw 255 ; max header pulse=264uS movwf _length bit_loop Call rtrn ;(4) delay 4 cycles GoTo $+1 ;(2) delay 2 cycles btfsc PORTA,5 ;(2) check for end of bit Return ; end of bit found decfsz _length,F ;(1) GoTo bit_loop ;(2) bad_bit bsf _bad_data rtrn Return ;------------------------------------------------- _eeread bsf STATUS, 5 ; Bank 1 bsf 0x9C, 0 ; EE Read bcf STATUS, 5 ; Bank 0 Return _eewrite bsf STATUS, 5 ; Bank 1 bsf 0x9C, 2 ; Enable write bcf 0x0B, 7 ; Disable INTs movlw 0x55 ; movwf 0x9D ; Write 55h movlw 0xAA ; movwf 0x9D ; Write AAh bsf 0x9C, 1 ; Set WR bit--begin write bcf STATUS, 5 ; Bank 0 Return ;------------------------------------------------- ;----------Vulnerable Pause Routine--------------- ;------------------------------------------------- _vpause ;call with desired ms delay in "vdelay" bcf _hit_detect, 0 vpauseloop clrwdt ;(1) movlw 200 ;(1) movwf _vcount ;(1) vpauseloop2 ; 1ms loop (5 x 200) + 6 btfss PORTA,5 ;(2) (1) is IR input low? GoTo vpausehit ; (2) yes, go check for data decfsz _vcount,F ;(1) GoTo vpauseloop2 ;(2) decfsz _vdelay,F ;(1) subtract 1 from vdelay GoTo vpauseloop ;(2) repeat 1ms delay Return ; vdelay = 0 so return vpausehit ;if hit during pause bsf _hit_detect, 0 Return EndAsm '************************************************************* '************************************************************* '****************** SYSTEM MESSAGE MODE ********************** '************************************************************* '************************************************************* sys_msg_handler: Branch player,[clone_in,health_in,rounds_in,clips_in,RPGs_in,NP_hit] no_action: IF player = msg_scoreReq Then score_download IF player = msg_scoreClr Then clear_scores GoTo start '------------------------------------------------------------ clone_in: 'Receive Clone Parameters checksum = 0 temp = 0 For itemID = 3 TO 20 ' 15 parameters to receive GoSub clone_wait_edge config_item[itemID] = databyte checksum = checksum + databyte Next itemID GoSub clone_wait_edge IF checksum != databyte Then error LCDOut $FE,1 'clear LCD LCDOut $FE,$80,"Clone OK" Pause 500 GoSub three_beep GoTo save_now error: LCDOut $FE,1 'clear LCD LCDOut $FE,$80,"Error" 'unsuccessful transfer High tone Pause 1000 Low tone GoTo start '------------------------------------------------------------ health_in: health = health + databyte MIN 100 GoTo refill_exit '------------------------------------------------------------ rounds_in: rounds = rounds + databyte MIN 98 'max of 98 rounds since 99 = unlimited GoTo refill_exit '------------------------------------------------------------ clips_in: clips = clips + databyte MIN 98 'max of 98 clips since 99 = unlimited Write 7,clips GoTo refill_exit '------------------------------------------------------------ RPGs_in: rockets = rockets + databyte MIN 98 'max of 98 rockets (RPG rounds) since 99 = unlimited Write 11,rockets GoTo refill_exit '------------------------------------------------------------ NP_hit: 'Non Player Hit damage = databyte & %00011111 damage = damage * 2 GoSub i_m_hit GoTo start '------------------------------------------------------------ refill_exit: Pause 250 GoSub update_disp GoSub two_beep GoTo start '------------------------------------------ '------------------------------------------ '------------------------------------------ show_team: temp = team / 32 Branch temp,[tmname0,tmname1,tmname2,tmname3,tmname4,tmname5,tmname6,tmname7] tmname0: LCDOut "Sys" Return tmname1: LCDOut "Red" Return tmname2: LCDOut "Blu" Return tmname3: LCDOut "Yel" Return tmname4: LCDOut "Grn" Return tmname5: LCDOut "Blk" Return tmname6: LCDOut "Wht" Return tmname7: LCDOut "Pur" Return '************************************************************* '************************************************************* '******************** INITIALIZATION ************************* '************************************************************* '************************************************************* initialize: CMCON = 7 'turn off comparators Poke $81,$7F 'turn on PORT B pull ups TRISA = %00100001 'set PortA directions TRISB = %00000111 PORTB = %00000000 clear_scores: For temp = 0 TO 31 score[temp] = 0 Next temp reconfig: For itemID = 0 TO 20 EEADR = itemID Call eeread config_item[itemID] = EEDATA Next itemID game_bit = config_item[0] myteam = config_item[1] myplayer = config_item[2] full_health = config_item[3] Symbol hit_delay = config_item[4] Symbol ammo1 = config_item[5] clips = config_item[6] Symbol fullclip = config_item[7] Symbol fire_sel = config_item[8] Symbol cyclic = config_item[9] Symbol rel_time = config_item[10] friend_fire = config_item[11] kevlar = config_item[12] rocket_bit = config_item[13] Symbol ammo2 = config_item[14] rockets = config_item[15] muzzle_bit = config_item[16] restart_bit = config_item[17] sound_bit = config_item[18] gladiator_bit = config_item[19] Symbol g_tags = config_item[20] team = myteam player = myplayer health = full_health + 100 max_health = 350 rounds = fullclip butvar1 = 0 'clear button variable butvar2 = 0 'clear button variable butvar3 = 0 'clear button variable Startup_screen: LCDOut $FE, 1 'clear LCD LCDOut $FE,$80,"MilesTag" 'line 1 LCDOut $FE,$C0,"Ver 3.15" 'line 2 Pause 1000 'version screen hold time TRISA.0 = 1 IF PORTA.0 = 1 Then live_power_up 'use jumper or keyswitch health = 100 GoTo deadandgone live_power_up: i_am_dead = 0 start: GoSub update_disp '************************************************************* '************************************************************* '********************* MAIN PROGRAM ************************** '************************************************************* '************************************************************* menu_gun: 'GUN FIRING SCREEN Pause 200 menu_gun_loop: IF PORTA.5 = 1 Then menu_gun_pass: GoSub check_hit menu_gun_pass: Button trigger,0,fire_sel,4,butvar1,1,shoot_pri Button modesel,0,255,10,butvar2,1,menu_rocket Button reload,0,255,10,butvar3,1,loadclip GoTo menu_gun_loop '----------------------------------------------------------- menu_rocket: 'RPG FIRING SCREEN IF rocket_bit = 0 Then menu_restart 'IF i_am_dead = 1 Then menu_gun_loop LCDOut $FE,1 'clear LCD LCDOut $FE,$81,"RPG" LCDOut $FE,$85,DEC rockets Pause 200 menu_rocket_loop: IF PORTA.5 = 1 Then menu_rkt_pass: GoSub check_hit menu_rkt_pass: Button trigger,0,255,10,butvar1,1,shoot_sec Button modesel,0,255,10,butvar2,1,menu_restart Button reload,0,255,10,butvar3,1,lamp2 GoTo menu_rocket_loop lamp2: 'use reload button to toggle LCD backlight Toggle backlight Pause 250 GoTo menu_rocket_loop '----------------------------------------------------------- menu_restart: 'RESTART OPPONENT SCREEN IF restart_bit = 0 Then menu_config IF friend_fire = 1 Then menu_config 'IF i_am_dead = 1 Then menu_gun_loop LCDOut $FE,1 'clear LCD LCDOut $FE,$80,"Restart" LCDOut $FE,$C0,"Player" Pause 200 menu_restart_loop: IF PORTA.5 = 1 Then menu_restart_pass: GoSub check_hit menu_restart_pass: Button trigger,0,255,10,butvar1,1,send_restart Button modesel,0,255,10,butvar2,1,menu_config Button reload,0,255,10,butvar3,1,lamp3 GoTo menu_restart_loop lamp3: 'use reload button to toggle LCD backlight Toggle backlight Pause 250 GoTo menu_restart_loop '----------------------------------------------------------- menu_config: 'CONFIG GUN SCREEN TRISA.0 = 1 IF PORTA.0 = 0 Then start 'use jumper or keyswitch to enable config modes LCDOut $FE,1 'clear LCD LCDOut $FE,$81,"Config" Pause 200 menu_config_loop: Button trigger,0,255,10,butvar1,1,config_gun0 Button modesel,0,255,10,butvar2,1,start Button reload,0,255,10,butvar3,1,lamp4 GoTo menu_config_loop lamp4: 'use reload button to toggle LCD backlight Toggle backlight Pause 300 GoTo menu_config_loop '*********************************************************** '----------------------------------------------------------- shoot_pri: IF i_am_dead = 1 Then menu_gun_loop IF rounds = 0 Then noammo ammo = ammo1 GoSub send_data IF rounds = 251 Then shoot_pri_unlim rounds = rounds - 1 shoot_pri_unlim: GoSub update_rounds vdelay = cyclic Call vpause IF hit_detect = 0 Then contin_shoot GoSub check_hit contin_shoot: GoTo menu_gun_loop '----------------------------------------------------------- shoot_sec: IF i_am_dead = 1 Then menu_gun IF rockets = 0 Then noammo ammo = ammo2 GoSub send_data IF rockets = 99 Then shoot_sec_unlim rockets = rockets - 1 shoot_sec_unlim: GoSub update_disp ' Write 15,rockets Pause 200 GoTo menu_gun '----------------------------------------------------------- send_restart: ammo = resurrect GoSub send_data Pause 200 GoTo menu_restart_loop '----------------------------------------------------------- loadclip: IF rounds > 0 Then disregard IF clips = 0 Then noammo IF clips = 99 Then clip_unlim clips = clips - 1 'Write 6,clips clip_unlim: 'High backlight LCDOut $FE,1 'clear LCD LCDOut $FE,$81,"Reload" LCDOut $FE,$C0 For temp4 = 1 TO 8 LCDOut 255 For temp5 = 1 TO rel_time vdelay = 100 Call vpause IF hit_detect = 0 Then contin_reload GoSub check_hit contin_reload: Next temp5 Next temp4 rounds = fullclip 'Low backlight 'IF sound_bit = 0 Then start 'Sound tone,[50,10,100,10] 'Low tone GoTo start disregard: 'use reload button to toggle LCD backlight (deleted) Toggle backlight Pause 200 GoTo menu_gun '*********************************************************** '*********************************************************** '*********************************************************** check_hit: 'subroutine bad_data = 0 paritycount = 0 ;------------------------------------------------ test_header: 'check for valid header pulse Call get_pulse temp = 255 - length IF temp > 205 Then good_header 'if header pulse is bad - try again Return good_header IF temp > 245 Then nearmiss 'header too long GoSub shift_data_in IF bad_data = 1 Then nearmiss databyte1 = databyte GoSub shift_data_in IF bad_data = 1 Then nearmiss ;------------------------------------------------ check_parity: Call get_bit IF bad_data = 1 Then nearmiss temp = 255 - length IF temp > 150 Then nearmiss IF temp < 30 Then nearmiss IF temp > 88 Then paritycount = paritycount + 1 IF paritycount.0 = 1 Then Game_B_parity_odd Game_A_parity_even: IF game_bit = 0 Then process_data GoTo nearmiss Game_B_parity_odd: IF game_bit = 1 Then process_data GoTo nearmiss ;------------------------------------------------ nearmiss: 'sound warning - bad data IF i_am_dead = 1 Then deadandgone High tone Pause 250 Low tone Return '*********************************************************** process_data: team = databyte1 & %11100000 player = databyte1 & %00011111 IF team = sys_msg Then sys_msg_handler IF friend_fire = 1 Then team_bypass IF team = myteam Then nearmiss IF databyte = resurrect Then resurrect_hit team_bypass: IF i_am_dead = 1 Then deadandgone IF databyte > 200 Then player_control IF databyte > 100 Then nearmiss 'base hit weapon_hit: damage = databyte score[player] = score[player] + 1 GoSub i_m_hit GoTo start '----------------------------------------- resurrect_hit: i_am_dead = 0 Low tone health = full_health + 100 'initial health value GoSub three_beep GoTo reconfig '----------------------------------------- player_control: 'Not implemented in this version GoTo nearmiss '----------------------------------------- deadandgone: i_am_dead = 1 High tone GoSub update_disp wait_resurrection: IF PORTA.5 = 1 Then deadpass GoSub check_hit deadpass: GoTo wait_resurrection '************************************************************* '************************************************************* '****************** CONFIGURATION MODE *********************** '************************************************************* '************************************************************* config_gun0: 'CHANGE GAME ID LCDOut $FE,1 'clear LCD LCDOut $FE,$80,"Game" config_rcvr0a: IF game_bit = 1 Then LCDOut $FE,$C0,"B" Else LCDOut $FE,$C0,"A" EndIF Pause 200 config_rcvr_loop0: Button trigger,0,255,10,butvar1,1,change_gameID Button modesel,0,255,10,butvar2,1,config_gun1 GoTo config_rcvr_loop0 '------------------------------------------------------------ change_gameID: IF game_bit = 0 Then game_bit = 1 Else game_bit = 0 EndIF config_item[0] = game_bit GoTo config_rcvr0a '############################################################ '############################################################ config_gun1: 'CHANGE TEAM ID LCDOut $FE,$80,"Team" config_rcvr1a: team = myteam LCDOut $FE,$C0 'clear LCD GoSub show_team Pause 200 config_rcvr_loop1: Button trigger,0,255,10,butvar1,1,change_team Button modesel,0,255,10,butvar2,1,config_gun1_exit GoTo config_rcvr_loop1 '------------------------------------------------------------ change_team: tempteam = myteam + 32 IF tempteam > 244 Then reset_team myteam = tempteam GoTo config_rcvr1a reset_team: myteam = 32 GoTo config_rcvr1a Config_gun1_exit: config_item[1] = myteam '############################################################ '############################################################ config_gun2: 'CHANGE PLAYER ID itemID = 2 item_min = 0 item_max = 31 item_step = 1 LCDOut $FE,$80,"Player" GoSub change_value player = config_item[itemID] '############################################################ '############################################################ config_gun30: 'TOGGLE GLADIATOR MODE itemID = 19 LCDOut $FE,$80,"G-Mode" GoSub config_switch gladiator_bit = config_item[itemID] IF gladiator_bit = 0 Then config_gun3 '############################################################ '############################################################ config_gun31: 'CHANGE GLADIATOR MODE TAGS itemID = 20 item_min = 2 item_max = 20 item_step = 1 LCDOut $FE,$80,"G-Tags" GoSub change_value 'g_tags = config_item[itemID] GoTo config_gun7 '############################################################ '############################################################ config_gun3: 'CHANGE FULL HEALTH VALUE itemID = 3 item_min = 5 item_max = max_health - 100 item_step = 5 LCDOut $FE,$80,"Health" GoSub change_value full_health = config_item[itemID] '############################################################ '############################################################ config_gun5: 'CHANGE KEVLAR VALUE (service life in hits) itemID = 12 item_min = 0 item_max = 30 item_step = 1 LCDOut $FE,$80,"Kevlar" GoSub change_value kevlar = config_item[itemID] '############################################################ '############################################################ config_gun6: 'CHANGE GUN HIT POINTS itemID = 5 item_min = 1 item_max = 100 item_step = 1 LCDOut $FE,$80,"Gun HP" GoSub change_value ammo1 = config_item[itemID] '############################################################ '############################################################ config_gun7: 'CHANGE AVAILABLE CLIPS (99=unlimited) itemID = 6 item_min = 1 item_max = 99 item_step = 1 LCDOut $FE,$80,"Clips " GoSub change_value clips = config_item[itemID] '############################################################ '############################################################ config_gun8: 'CHANGE ROUNDS PER CLIP (99=unlimited) itemID = 7 item_min = 1 item_max = 251 item_step = 1 LCDOut $FE,$80,"Rounds" GoSub change_value fullclip = config_item[itemID] '############################################################ '############################################################ config_gun9: 'TOGGLE ROCKETS IF gladiator_bit = 1 Then 'Disable rockets in "Gladiator Mode" rocket_bit = 0 GoTo config_gun12 EndIF 'LCDOut $FE,1 'clear LCD itemID = 13 LCDOut $FE,$80,"RPG " GoSub config_switch rocket_bit = config_item[itemID] IF rocket_bit = 0 Then config_gun12 '############################################################ '############################################################ config_gun10: 'CHANGE ROCKET HIT POINTS itemID = 14 item_min = 5 item_max = 200 item_step = 5 LCDOut $FE,$80,"RPG HP" GoSub change_value ammo2 = config_item[itemID] '############################################################ '############################################################ config_gun11: 'CHANGE AVAILABLE ROCKETS (99=unlimited) itemID = 15 item_min = 1 item_max = 99 item_step = 1 LCDOut $FE,$80,"RPGs " GoSub change_value rockets = config_item[itemID] '############################################################ '############################################################ config_gun12: 'CHANGE FIRING MODE itemID = 8 IF fire_sel = 255 Then config_item[itemID] = 0 Else config_item[itemID] = 1 EndIF LCDOut $FE,$80,"F-Auto" GoSub config_switch IF config_item[itemID] = 0 Then fire_sel = 255 Else fire_sel = 1 EndIF '############################################################ '############################################################ config_gun4: 'CHANGE HIT DELAY TIME (max 20 seconds) itemID = 4 item_min = 0 item_max = 20 item_step = 1 LCDOut $FE,$80,"HitDly" GoSub change_value hit_delay = config_item[itemID] '############################################################ '############################################################ config_gun13: 'CHANGE CYCLIC RATE itemID = 9 item_min = 10 item_max = 200 item_step = 5 LCDOut $FE,$80,"Cyclic" GoSub change_value cyclic = config_item[itemID] '############################################################ '############################################################ config_gun14: 'CHANGE RELOAD DELAY (1 to 30 Seconds) itemID = 10 item_min = 1 item_max = 30 item_step = 1 LCDOut $FE,$80,"Reload" GoSub change_value rel_time = config_item[itemID] '############################################################ '############################################################ config_gun15: 'TOGGLE MUZZLE FLASH itemID = 16 LCDOut $FE,$80,"Muzzle" GoSub config_switch muzzle_bit = config_item[itemID] '############################################################ '############################################################ config_gun16: 'TOGGLE RESTART itemID = 17 LCDOut $FE,$80,"Restrt" GoSub config_switch restart_bit = config_item[itemID] '############################################################ '############################################################ config_rcvr17: 'TOGGLE SOUND itemID = 18 LCDOut $FE,$80,"Sound " GoSub config_switch sound_bit = config_item[itemID] '############################################################ '############################################################ config_rcvr18: 'TOGGLE FRIENDLY FIRE itemID = 11 LCDOut $FE,$80,"FrFire" GoSub config_switch sound_bit = config_item[itemID] '############################################################ '############################################################ config_clone: 'SEND CLONE PARAMETERS LCDOut $FE,1 'clear LCD LCDOut $FE,$80,"Clone " Pause 200 clone_loop: Button trigger,0,255,10,butvar1,1,send_clone Button modesel,0,255,10,butvar2,1,save_config GoTo clone_loop send_clone checksum = 0 messageID = msg_clone GoSub send_data_sys_msg For itemID = 3 TO 20 databyte = config_item[itemID] checksum = checksum + databyte GoSub send_byte Next itemID databyte = checksum GoSub send_byte GoSub beep GoTo config_clone _________________________________________ _________________________________________ save_config: save_configa: LCDOut $FE,$80,"Save ?" Pause 200 save_config_loop: Button trigger,0,255,10,butvar1,1,save_now Button modesel,0,255,10,butvar2,1,config_gun0 GoTo save_config_loop save_now: For itemID = 0 TO 19 eeadr = itemID eedata = config_item[itemID] Call eewrite Pause 50 Next itemID GoTo reconfig '************************************************************* '************************************************************* '********************** SUBROUTINES ************************** '************************************************************* '************************************************************* send_data: 'send 17 bits (player | team) then (ammo) then (parity bit) databyte = myplayer | myteam GoTo first_byte send_data_sys_msg: databyte = messageID first_byte: paritycount = 0 Call send_header 'send header pulse GoSub send_byte second_byte: databyte = ammo GoSub send_byte parity_bit: Call send_space IF game_bit = 1 Then Game_B_parity_oddx Game_A_parity_evenx: IF paritycount.0 = 1 Then 'check if paritycount is odd Call send_one 'if so, send one to make even Else Call send_zero EndIF GoTo parity_exit Game_B_parity_oddx: IF paritycount.0 = 1 Then 'check if paritycount is odd Call send_zero Else Call send_one 'if not, send one to make odd EndIF GoTo parity_exit parity_exit: IF sound_bit = 0 Then flash_only High tone flash_only: IF muzzle_bit = 0 Then no_flash High muzzle no_flash: Pause 25 Low tone : Low muzzle Pause 1 Return '----------------------------------------------------------- send_byte: 'send 8 bits (databyte) For bit_counter = 1 TO 8 'send 8 data bits MSB first Call send_space 'space between data pulses IF databyte.7 = 1 Then trans1 Call send_zero GoTo bypassx trans1: paritycount = paritycount + 1 Call send_one bypassx: Next bit_counter Return '----------------------------------------------------------- shift_data_in: 'get 8 bits of data and place in "databyte" variable For bit_counter = 1 TO 8 databyte = databyte * 2 'rotate left Call get_bit IF bad_data = 0 Then pass1 Return pass1: temp = 255 - length IF temp < 150 AND temp > 30 Then pass2 bad_data = 1 Return pass2: IF temp > 88 Then shiftone shiftzero: databyte.0 = 0 GoTo bypass shiftone: paritycount = paritycount + 1 databyte.0 = 1 bypass: Next bit_counter Return '----------------------------------------------------------- clone_wait_edge: ' wait for edge @ btfsc PORTA,5 @ GoTo _clone_wait_edge For bit_counter = 1 TO 8 ' 8 bits to receive databyte = databyte * 2 ' rotate left Call get_bit IF bad_data = 1 Then error temp = 255 - length IF temp > 150 Then error ' is bit within tolerance? IF temp < 30 Then error IF temp > 88 Then shiftone_c shiftzero_c: databyte.0 = 0 GoTo bypass_c shiftone_c: databyte.0 = 1 bypass_c: Next bit_counter Return '----------------------------------------------------------- noammo: IF sound_bit = 0 Then start Sound tone,[100,10,50,10] Low tone GoTo start '----------------------------------------------------------- i_m_hit: score[player] = score[player] + 1 IF gladiator_bit = 0 Then normal_hit IF score[player] = g_tags Then deadandgone GoTo g_hit normal_hit: IF kevlar = 0 Then no_kevlar damage = damage / 2 'kevlar reduces damage by half kevlar = kevlar - 1 'reduce kevlar effective life 'Write 5,kevlar no_kevlar: health = (health - damage) MAX 100 'damage = databyte IF health = 100 Then deadandgone g_hit: GoSub hit_sound GoSub update_disp IF hit_delay = 0 Then hd_bypass 'Hit Delay prevents shoot or hit High backlight LCDOut $FE,1 'clear LCD LCDOut $FE,$82,"WAIT" temp3 = 1000 * hit_delay Pause temp3 Low backlight GoTo start hd_bypass: Return '------------------------------------------ update_disp: LCDOut $FE,1 'clear LCD LCDOut $FE,$80,"R",DEC3 rounds LCDOut $FE,$85,"C",DEC2 clips temp = health - 100 IF gladiator_bit = 1 Then LCDOut $FE,$C0,"T",DEC2 score[player] Else LCDOut $FE,$C0,DEC3 temp EndIF GoSub show_team LCDOut DEC2 player Return update_rounds: LCDOut $FE,$81,DEC3 rounds 'set LCD cursor position Return '------------------------------------------ score_download: 'DOWNLOAD PLAYER SCORES LCDOut $FE,1 'clear LCD LCDOut $FE,$80,"ScoreTx" Pause 200 score_loop: Button trigger,0,255,10,butvar1,1,send_score Button modesel,0,255,10,butvar2,1,start GoTo clone_loop send_score checksum = 0 messageID = msg_scoreTx GoSub send_data_sys_msg databyte = myteam | myplayer GoSub send_byte For itemID = 0 TO 31 databyte = score[itemID] checksum = checksum + databyte GoSub send_byte Next itemID databyte = checksum GoSub send_byte GoSub beep GoTo score_download '----------------------------------------- change_value: '3-digit value LCDOut $FE,$C0,DEC3 config_item[itemID] Pause 200 change_value_loop: Button trigger,0,10,10,butvar1,1,inc_value Button modesel,0,255,10,butvar2,1,escape1 Button reload,0,255,10,butvar3,1,lamp_cv GoTo change_value_loop escape1: Return lamp_cv: 'use reload button to toggle LCD backlight Toggle backlight Pause 250 GoTo change_value_loop inc_value: config_item[itemID] = config_item[itemID] + item_step IF config_item[itemID] > item_max Then reset_value GoTo change_value reset_value: config_item[itemID] = item_min GoTo change_value '----------------------------------------------------------- config_switch: IF config_item[itemID] = 1 Then LCDOut $FE,$C0,"On " Else LCDOut $FE,$C0,"Off" EndIF Pause 200 config_switch_loop: Button trigger,0,255,10,butvar1,1,toggle_config_switch Button modesel,0,255,10,butvar2,1,escape2 Button reload,0,255,10,butvar3,1,lamp_cs GoTo config_switch_loop escape2: Return lamp_cs: 'use reload button to toggle LCD backlight Toggle backlight Pause 250 GoTo config_switch_loop toggle_config_switch: IF config_item[itemID] = 1 Then config_item[itemID] = 0 Else config_item[itemID] = 1 EndIF GoTo config_switch '----------------------------------------- hit_sound: Sound tone,[50,10] Low tone Return '----------------------------------------- three_beep: High tone Pause 30 Low tone Pause 50 two_beep: High tone Pause 30 Low tone Pause 50 beep: High tone Pause 30 Low tone Return '****************************************************** End