? FOUR SEASONS SHOT (Page 1) ● SmileBASIC Source Forums

Sign In

Register
*Usernames are case-sensitive
Forgot my password
This is the development website, where we test out new features. This isn't the place you're looking for! Go here

FOUR SEASONS SHOT

  • #1 ✎ 258 Y____ Head Admin Gardening I like to garden! Hobbies Reading I like to read books! Hobbies Drawing I like to draw! Hobbies OPTION STRICT '====== ' INIT '====== @__INIT_ENTRY 'constants VAR _MENUSTATE%=1,_GAMESTATE%=2,_NOACTIONSTATE%=3 VAR _CURRENTSTATE% = _NOACTIONSTATE% 'setup VAR I FOR I=3 TO 0 STEP -1 GPAGE 0,I GCLS NEXT ACLS TRUE,TRUE,FALSE SPCLIP LOAD "GRP4:YUKA.GRP",0 EXEC "PRG1:INPUT.PRG" 'Subsystem Initialization '======================== GOSUB @TIME_INIT '=SAVE= @SAVE_INIT DIM ID_YUKA=1DIM ID_YUKA_U=2DIM ID_YUKA_PJ=3DIM ID_YUKA_98=4DIM ID_YUKA_U98=5DIM ID_REIMU=6DIM ID_LILY_W=7DIM ID_LILY_B=8DIM ID_RUMIA=9DIM ID_CIRNO=10DIM ID_DAIYOSEI=11DIM ID_MEILING=12DIM ID_KOAKUMA=13DIM ID_PATCHOLI=14DIM ID_SAKUYA=15DIM ID_REMILIA=16DIM ID_FLANDRE=17DIM ID_WRIGGLE=18DIM ID_MYSTIA=19DIM ID_KEINE=20DIM ID_KEINE_EX=21DIM ID_MOKOU=22DIM ID_TEWI=23DIM ID_REISEN=24DIM ID_EIRIN=25DIM ID_KAGUYA=26DIM ID_LETTY=27DIM ID_ALICE=28DIM ID_CHEN=29DIM ID_RAN=30DIM ID_YUKARI=31DIM ID_YOUMU=32DIM ID_YUYUKO=33DIM ID_AYA=34DIM ID_KOMACHI=35DIM ID_EIKI=36DIM ID_MEDICINE=37DIM ID_MINORIKO=38DIM ID_SHIZUHA=39DIM ID_HINA=40DIM ID_MOMIJI=41 REM -replace 'DATA' -replace "`"`n|[ \n]|`"," -split "[`",]" | % {$c=0}{write-host "DIM ID_$_=$c" -nonewline;$c++} DIM CHARACTER_TABLE$[0] RESTORE @CHARACTER_TABLE VAR RDSTR$ READ RDSTR$ WHILE RDSTR$ != "\\" PUSH CHARACTER_TABLE$, RDSTR$ READ RDSTR$ WEND '=SHOT= VAR PL_CAN_FIRE = TRUE VAR MASK_PLAYER% = &b1100 VAR MASK_ENEMYBULLET% = &b0100 VAR MASK_ENEMY% = &b1010 VAR MASK_PLAYERBULLET%= &b0010 'dynamic allocation range VAR BULLET_ID_LOW% = 256 VAR BULLET_ID_HIGH% = 511 'shot damage classes VAR DAMAGE_LIGHT% = 1 VAR DAMAGE_MID% = 2 VAR DAMAGE_HEAVY% = 3 'special damage classes VAR DAMAGE_EXTRA% = 5 VAR DAMAGE_LUNATIC% = 10 VAR DAMAGE_OHKO% = 999 '=GAME= DIM MAX_VELOCITY# = 3.5 DIM PL_ACCELERATION# = 1.5 DIM PLAYER_MAX_HEALTH = 10 VAR GAME_PX VAR GAME_PY VAR GAME_PVX VAR GAME_PVY VAR PLAYER_ID VAR GAME_FRICTION_COEF# = 0.62 VAR GAME_PL_CHAR = ID_YUKA VAR INVINCIBILITY_ON_SPAWN = 360 '# invincibility frames '============================ 'End Subsystem Initialization 'sprite definitions GOSUB @DEFINECHAR DIM SAVEFILE$ = "TXT:4SS.SAV" IF CHKFILE(SAVEFILE$) THEN READ_SAVEDATA LOAD(SAVEFILE$,0) ELSE NEW_SAVEDATA ENDIF VAR CURSOR%, INPUTS%, MENU_NEEDS_LOADING% DIM MENU_OPTIONS$[0] VAR COMPLETE_STAGE% 'game progress '====== ' MAIN '====== VAR OK% = 1 NEW_STATE _MENUSTATE% WHILE OK% 'graphics sync VSYNC 'input INPUTS% = INPUT_GET(0, 0.01) IF _CURRENTSTATE% == _MENUSTATE% THEN IF MENU_NEEDS_LOADING% THEN READ_MENU "@MAIN_MENU_ITEMS" MENU_NEEDS_LOADING% = FALSE ENDIF INPUTS% = INPUT_GET(3, 0.01) DRAW_MAIN_MENU UPDATE_CURSOR(INPUTS%) IF INPUTS% AND VAR("1:INPUT_MENU_CONTINUE") THEN MENU_SELECT "MAIN_MENU_", UPDATE_CURSOR(0) ELSEIF _CURRENTSTATE% == _GAMESTATE% THEN EVAL_TIMERS CALL SPRITE ENDIF WEND '============== ' LIBRARY '============== '============== '====== ' STDL '====== DEF FREE() DIM NEW[0] RETURN NEW END DEF FREE$() DIM NEW$[0] RETURN NEW$ END DEF PLEASE DIE END '12Me21 fast split DEF SPLIT$(S$,D$) VAR LD%=LEN(D$) DIM R$[1] VAR N%=INSTR(S$,N%) IF N%==-1 THEN R$[0]=S$ RETURN R$ ENDIF R$[0]=LEFT$(S$,N%) @L VAR L%=N%+LD% N%=INSTR(L%,S$,D$) IF N%==-1 THEN PUSH R$,MID$(S$,L%,&H7FFFFFFF) RETURN R$ ENDIF PUSH R$,MID$(S$,L%,N%-L%) GOTO @L END DEF WRITE STRING$ VAR I%=0,FG% = #TWHITE, BG% = 0 FOR I% = 0 TO LEN(STRING$) - 1 IF STRING$[I%] == "\" THEN 'handle special escapes INC I% IF STRING$[I%] == "c" THEN 'color INC I% FG% = VAL("&h"+STRING$[I%]) INC I% BG% = VAL("&h"+STRING$[I%]) COLOR FG%,BG% ELSEIF STRING$[I%] == "n" THEN 'newline PRINT ELSEIF STRING$[I%] == "\" THEN 'escape \ PRINT "\"; ELSEIF STRING$[I%] == "t" THEN 'shift columns INC I% PRINT " "*VAL("&h"+STRING$[I%]); ELSEIF STRING$[I%] == "u" THEN 'character code INC I% PRINT CHR$(VAL("&h"+STRING$[I%]+STRING$[I%+1]+STRING$[I%+2]+STRING$[I%+3])) INC I%, 3 ENDIF ELSE 'print char PRINT STRING$[I%]; ENDIF NEXT END DEF FIRST_WORD(STR$) IF INSTR(STR$,"_") >= 0 THEN RETURN LEFT$(STR$, INSTR(STR$,"_")) ELSE RETURN STR$ ENDIF END DEF DIST_2D(X1#, Y1#, X2#, Y2#) RETURN SQR(POW(X1# - X2#,2)+POW(Y1# - Y2#,2)) END '====== ' TIME '====== @TIME_INIT DIM TIMERS_COUNT%[0] DIM TIMERS_CALLBACK$[0] DIM TIMERS_LASTUPDATE% = MAINCNT RETURN DEF NEW_TIMER DELAY%, CALLBACK$ PUSH TIMERS_COUNT%, MAINCNT + DELAY% PUSH TIMERS_CALLBACK$, CALLBACK$ 'feel the power of sort_according SORT TIMERS_COUNT%, TIMERS_CALLBACK$ END DEF EVAL_TIMERS IF LEN(TIMERS_COUNT%) < 1 THEN RETURN VAR T_TIME% VAR I% FOR I% = 0 TO LEN(TIMERS_COUNT%) - 1 T_TIME% = TIMERS_COUNT%[I%] - MAINCNT IF T_TIME% <= 0 THEN PLEASE SHIFT(TIMERS_COUNT%) CALL SHIFT(TIMERS_CALLBACK$) ENDIF NEXT END '====== ' SMAN '====== DEF NEW_STATE NEXTSTATE% _CURRENTSTATE% = NEXTSTATE% IF NEXTSTATE% == _MENUSTATE% THEN MENU_NEEDS_LOADING% = TRUE ENDIF END '====== ' MENU '====== 'READ_MENU(label_string$) 'Reads simple menu options terminated in "\\" DEF READ_MENU LABEL$ VAR ENTRY$ FREE$ OUT MENU_OPTIONS$ RESTORE LABEL$ READ ENTRY$ WHILE ENTRY$ != "\\" PUSH MENU_OPTIONS$, ENTRY$ READ ENTRY$ WEND END DEF UPDATE_CURSOR(INPUTS%) VAR MAX% = LEN(MENU_OPTIONS$) IF INPUTS% AND VAR("1:INPUT_MENU_UP") THEN CURSOR% = CURSOR% - 1 IF INPUTS% AND VAR("1:INPUT_MENU_DOWN") THEN CURSOR% = CURSOR% + 1 IF CURSOR% < 0 THEN CURSOR% = MAX% - 1 CURSOR% = CURSOR% MOD MAX% RETURN CURSOR% END DEF DRAW_MAIN_MENU CURSOR% CLS ?"" ?"  (     ?"    | ?" ?" |   | î‹»    | ?"   | î‹»    (  .    ?"         ?" ?" |   î‹»  î‹»     ?"    (     ?"    | | ?"" DRAW_MENU_OPTIONS CURSOR%, "\tc\ta%S\n", "\ta\ta>\cFC %S \cF0\n" END DEF DRAW_MENU_OPTIONS CURSOR%, FORMATSTRING$, SELECTFORMAT$ VAR I% = 0 FOR I% = 0 TO LEN(MENU_OPTIONS$) - 1 IF I% == CURSOR% THEN WRITE FORMAT$(SELECTFORMAT$, MENU_OPTIONS$[I%]) ELSE WRITE FORMAT$(FORMATSTRING$, MENU_OPTIONS$[I%]) ENDIF NEXT END DEF MENU_SELECT PREFIX$, CURSORPOS% VAR FN$ = PREFIX$ + STR$(CURSORPOS%) CALL FN$ END @MAIN_MENU_ITEMS DATA "START" DATA "GALLERY" DATA "OPTIONS" DATA "EXIT" DATA "\\" DEF MAIN_MENU_0 CLS NEW_STATE _GAMESTATE% 'should launch a stage select menu 'TEMP SPAWN_PLAYER END DEF MAIN_MENU_1 GALLERY_MODE END DEF MAIN_MENU_2 OPTIONS_MODE END DEF MAIN_MENU_3 STOP END '====== ' CHAR '====== 'animation (use "UV+" or 10) @WALKUP DATA 4 DATA 3, 0,0 DATA 3,24,0 DATA 3,48,0 DATA 3,24,0 @WALKRIGHT DATA 4 DATA 3, 0,0 DATA 3,24,0 DATA 3,48,0 DATA 3,24,0 @WALKDOWN DATA 4 DATA 3, 0,0 DATA 3,24,0 DATA 3,48,0 DATA 3,24,0 @WALKLEFT DATA 4 DATA 3, 0,0 DATA 3,24,0 DATA 3,48,0 DATA 3,24,0 @DEFINECHAR SPDEF 1,0,0,24,32 'YUKA SPDEF 2,72,0,24,32 'YUKA_U SPDEF 3,144,0,24,32 'YUKA_PJ SPDEF 4,0,128,24,32 'YUKA_98 SPDEF 5,72,128,24,32 'YUKA_U98 RETURN '====== ' ANIM '====== 'ANIM_DISPELL '1:up, 2:right, 3:down, 4:left DEF ANIM_DISPELL IDX%, CURRENT_MOVEMENT%, LAST_MOVEMENT% VAR U%, V% IF CURRENT_MOVEMENT% != LAST_MOVEMENT% THEN SPCHR IDX% OUT U%, V% 'find anim row IF CURRENT_MOVEMENT% > 0 THEN SPCHR IDX%, 72 * (U% DIV 72), 128 * (V% DIV 128) + 32 * (CURRENT_MOVEMENT% - 1), 24, 32 ELSE SPCHR IDX%, 72 * (U% DIV 72), V%, 24, 32 ENDIF IF CURRENT_MOVEMENT% == 1 THEN SPANIM IDX%, "UV+", "@WALKUP",0 ELSEIF CURRENT_MOVEMENT% == 2 THEN SPANIM IDX%, "UV+", "@WALKRIGHT",0 ELSEIF CURRENT_MOVEMENT% == 3 THEN SPANIM IDX%, "UV+", "@WALKDOWN",0 ELSEIF CURRENT_MOVEMENT% == 4 THEN SPANIM IDX%, "UV+", "@WALKLEFT",0 ELSEIF CURRENT_MOVEMENT% == 0 THEN ?"NOMOVE" SPANIM IDX%, "UV+", 4, 24, 0, 0 ENDIF ENDIF END DEF ANIM_GET_DIR(IDX%) VAR U%, V% SPCHR IDX% OUT U%,V% RETURN (V% MOD 128) DIV 32 + 1 '1:up, 2:right, 3:down, 4:left END DEF ANIM_VEC_TO_DIR(X#, Y#) IF X# == Y# && X# == 0 THEN RETURN 0 IF ABS(X#) > ABS(Y#) THEN RETURN 3 - SGN(X#) ELSEIF ABS(Y#) > ABS(X#) THEN RETURN 2 - SGN(Y#) ELSE RETURN 3 - SGN(X#) ENDIF END '====== ' SHOT '====== DEF RESET_PL_SHOT PL_CAN_FIRE = TRUE END DEF CREATE_DANMAKU X%, Y%, ANGLE#, COUNT%, SPREAD#, SPEED#, SPRITEDEF%, MASK%, DAMAGE% VAR THIS_ANGLE#, IDX% FOR THIS_ANGLE# = ANGLE# - SPREAD# * (COUNT% - 1)/2.0 TO ANGLE# + SPREAD# * (COUNT% - 1)/2.0 STEP SPREAD# IDX% = SPSET(BULLET_ID_LOW%,BULLET_ID_HIGH%,SPRITEDEF%) 'TODO check IDX% is valid SPVAR IDX%, 0, THIS_ANGLE# SPVAR IDX%, 1, SPEED# SPVAR IDX%, 6, DAMAGE% SPHOME IDX%, 8, 8 SPCOL IDX%, 1, 1, 15, 15, TRUE, MASK% SPOFS IDX%, X%, Y% SPFUNC IDX%, "BULLET_FN" NEXT END 'Bullets won't actually handle despawning: 'The colliding entity has to clear them. 'This is to make sure that the colliding entity 'actually gets the collision message 'well, we COULD set a flag somewhere, but... DEF BULLET_FN VAR X#, Y#, ANG#, MAG# SPOFS CALLIDX OUT X#, Y# SPVAR CALLIDX, 0 OUT ANG# SPVAR CALLIDX, 1 OUT MAG# 'possibly do collision vectors here SPOFS CALLIDX, X# + COS(ANG#)*MAG#, Y# + SIN(ANG#)*MAG# 'despawn IF ABS(X# - GAME_PX) > 400 || ABS(Y# - GAME_PVY) > 240 THEN SPCLR CALLIDX ENDIF END DEF CHAR_SHOOT CHAR%, X%, Y%, ANGLE#, MASK% 'for assigning bullet sprites mostly 'hm... this should probably be optimized in a table IF CHAR% == ID_YUKA || CHAR% == ID_YUKA_U THEN CREATE_DANMAKU X%, Y%, ANGLE#, 3, RAD(20), 5.35, 0, MASK%, DAMAGE_HEAVY% ENDIF IF CHAR% == ID_YUKA_PJ || CHAR% == ID_YUKA_98 || CHAR% == ID_YUKA_U98 THEN 'TODO ENDIF IF CHAR% == ID_REIMU THEN CREATE_DANMAKU X%, Y%, ANGLE#, 1, 0, 5.35, 0, MASK%, DAMAGE_LIGHT% ENDIF END '====== ' NPCS '====== DEF TEMPSPAWN SPAWN_ENEMY ID_YUKA_PJ, RND(400), RND(200) END DEF SPAWN_ENEMY CHAR_ID%, X%, Y% 'TODO 'needs to set spvar 7 to character id maybe VAR IDX% = SPSET(CHAR_ID%) SPOFS IDX%, X%, Y% SPHOME IDX%, 12, 16 'enemy hitboxes are the body rect (larger than the player's) SPCOL IDX%, 2, 4, 20, 24,, MASK_ENEMY% SPVAR IDX%, 7, CHAR_ID% 'save the character with the sprite 'IMPORTANT! 'behavior is assigned by character name prefix. 'change prefix to assign different behavior to colliding prefixes SPFUNC IDX%, FIRST_WORD(CHARACTER_TABLE$[CHAR_ID%])+"_ENEMY_FN" NEW_TIMER 30, "TEMPSPAWN" END DEF GENERIC_FOLLOW_PLAYER IDX% VAR X#, Y# SPOFS IDX% OUT X#, Y# VAR PLAYER_DISTANCE% = DIST_2D(X#, Y#, GAME_PX, GAME_PY) IF PLAYER_DISTANCE% > 16 && PLAYER_DISTANCE% < 400 THEN VAR MX#, MY# UNITVECTOR GAME_PX - X#, GAME_PY - Y# OUT MX#, MY# SPVAR IDX%, 0, MX# * MAX_VELOCITY# SPVAR IDX%, 1, MY# * MAX_VELOCITY# 'animate VAR LAST_DIR% = ANIM_GET_DIR(IDX%) 'make do with current face VAR CUR_DIR% = ANIM_VEC_TO_DIR(MX#, -MY#) ANIM_DISPELL IDX%, CUR_DIR%, LAST_DIR% ENDIF GAME_ENTITY_PHYSICS IDX% END DEF GENERIC_SHOOT_PLAYER IDX% VAR X%, Y% SPOFS IDX% OUT X%, Y% VAR ANG# = ATAN(Y% - GAME_PY, X% - GAME_PX) CHAR_SHOOT SPVAR(IDX%,7), X%, Y%, ANG#, MASK_ENEMYBULLET% END DEF HANDLE_COLLISION IDX% VAR COL_ID% = SPHITSP(IDX%,BULLET_ID_LOW%,BULLET_ID_HIGH%) IF COL_ID% >= BULLET_ID_LOW% THEN 'add damage SPVAR IDX%, 6, SPVAR(IDX%, 6) + SPVAR(COL_ID%, 6) ' despawn bullet SPCLR COL_ID% 'is this safe? should be now but be careful about deallocating... ENDIF END DEF CHECK_HEALTH IDX%, HP% IF SPVAR(IDX%, 6) > HP% THEN NEW_RAGDOLL IDX%, SPVAR(IDX%,0), SPVAR(IDX%,1) ENDIF END 'character types DEF YUKA_ENEMY_FN 'TODO GENERIC_FOLLOW_PLAYER CALLIDX HANDLE_COLLISION CALLIDX CHECK_HEALTH CALLIDX, 24 END DEF REIMU_ENEMY_FN 'TODO HANDLE_COLLISION CALLIDX CHECK_HEALTH CALLIDX, 16 END DEF LILY_ENEMY_FN 'TODO HANDLE_COLLISION CALLIDX CHECK_HEALTH CALLIDX, 2 END DEF RUMIA_ENEMY_FN GENERIC_FOLLOW_PLAYER CALLIDX HANDLE_COLLISION CALLIDX CHECK_HEALTH CALLIDX, 2 END '====== ' GAME '====== DEF SPAWN_PLAYER VAR U%, V% PLAYER_ID = SPSET(GAME_PL_CHAR) SPHOME PLAYER_ID, 12, 16 SPCHR PLAYER_ID OUT U%, V% SPCHR PLAYER_ID, 72 * (U% DIV 72), 128 * (V% DIV 128) + 32 * (2), 24, 32 'reset sprite to this char-south ANIM_DISPELL PLAYER_ID, 0, 3 'face south GAME_PVX = 0 : GAME_PVY = 0 'velocity 0 SPOFS PLAYER_ID, GAME_PX, GAME_PY 'set to last position? RESET_PL_SHOT 'reset the RoF limit SPCOL PLAYER_ID, 7, 11, 10, 10, MASK_PLAYER% ' SPVAR PLAYER_ID, 6, 10 'health SPFUNC PLAYER_ID, "PLAYER_FN" 'attach player callback to this new sprite 'TEMP SPAWN_ENEMY ID_YUKA_PJ, RND(400), RND(200) END DEF PLAYER_FN VAR DVX#, DVY#, X%, Y%, FX#, FY# VAR LAST_DIR% = ANIM_VEC_TO_DIR(GAME_PVX, -GAME_PVY) 'movement INPUT_READ_JOY INPUTS%, "INPUT_P1_JOY1" OUT DVX#, DVY# GAME_PVX = GAME_PVX + DVX# * PL_ACCELERATION# GAME_PVY = GAME_PVY - DVY# * PL_ACCELERATION# GAME_PVX = APPLY_FRICTION(GAME_PVX,1) GAME_PVY = APPLY_FRICTION(GAME_PVY,1) GAME_PVX = MIN(ABS(GAME_PVX), MAX_VELOCITY#) * SGN(GAME_PVX) GAME_PVY = MIN(ABS(GAME_PVY), MAX_VELOCITY#) * SGN(GAME_PVY) 'integrate velocity 'this is probably how this works GAME_PX = GAME_PX + GAME_PVX GAME_PY = GAME_PY + GAME_PVY 'animate VAR CUR_DIR% = ANIM_VEC_TO_DIR(DVX#, DVY#) ANIM_DISPELL CALLIDX, CUR_DIR%, LAST_DIR% 'handle collision? 'shooting IF INPUTS% AND VAR("1:INPUT_P1_JOY2") && PL_CAN_FIRE THEN INPUT_READ_JOY INPUTS%, "INPUT_P1_JOY2" OUT FX#, FY# CHAR_SHOOT GAME_PL_CHAR, GAME_PX, GAME_PY, ATAN(-FY#, FX#), MASK_PLAYERBULLET% PL_CAN_FIRE = FALSE NEW_TIMER 5, "RESET_PL_SHOT" ENDIF HANDLE_COLLISION CALLIDX IF SPVAR(CALLIDX,6) >= PLAYER_MAX_HEALTH THEN NEW_RAGDOLL CALLIDX, GAME_PVX, GAME_PVY NEW_TIMER 90, "SPAWN_PLAYER" ENDIF 'TEMP SPOFS CALLIDX, GAME_PX, GAME_PY END DEF NEW_RAGDOLL IDX%, VX, VY 'conform to physics entity expectations SPVAR IDX%, 0, VX SPVAR IDX%, 1, VY VAR U%, V% SPCHR IDX% OUT U%, V% SPCHR IDX%, 72 * (U% DIV 72) + 24, 128 * (V% DIV 128) + 32, 24, 32 SPANIM IDX%, "UV+", 1,0,0 SPANIM IDX%, "R", -5, 90,1 'class change to "CORPSE" SPFUNC IDX%, "CORPSE_FN" 'start fade animation SPANIM IDX%, "C", -60, RGB(255,192,192,192), -60, RGB(0,0,0,0), 1 END 'a deceased entity that will slowly fade and then be freed 'still bounces around and stuff DEF CORPSE_FN GAME_ENTITY_PHYSICS CALLIDX 'broken somewhere VAR VX# = SPVAR(CALLIDX,0), VY# = SPVAR(CALLIDX,1) 'corpses slide more. probably relevant for explosive hits SPVAR CALLIDX, 0, APPLY_FRICTION(VX#,0.5) SPVAR CALLIDX, 1, APPLY_FRICTION(VY#,0.5) 'if the fade is over discard the (now invisible) sprite IF SPCOLOR(CALLIDX) == 0 THEN SPCLR CALLIDX ENDIF END DEF APPLY_FRICTION(N#, MULT#) IF ABS(N#) >= GAME_FRICTION_COEF# * MULT# THEN N# = N# - SGN(N#) * GAME_FRICTION_COEF# * MULT# ELSE N# = 0 ENDIF RETURN N# END 'Uses spvar[0] for x velocity 'Uses spvar[1] for y velocity DEF GAME_ENTITY_PHYSICS IDX VAR X#, Y# SPOFS IDX OUT X#, Y# SPOFS IDX, X# + SPVAR(IDX,0), Y# + SPVAR(IDX,1) 'might have to handle collision eventually END '====== ' SAVE '====== VAR UNLOCK_STRING$=CHR$(0)*16 DEF NEW_SAVEDATA UNLOCK_STRING$=CHR$(0)*16 HIGH_UNLOCKBIT ID_YUKA END DEF WRITE_SAVEDATA VAR SAVESTRING$ = CHR$(COMPLETE_STAGE%) + UNLOCK_STRING$ SAVE SAVEFILE$, SAVESTRING$ END DEF READ_SAVEDATA STRING$ COMPLETE_STAGE% = ASC(POP(STRING$)) UNLOCK_STRING$ = STRING$ END DEF HIGH_UNLOCKBIT ID% VAR CHAR% = (ID% - 1) DIV 16 VAR BITNO% = (ID% MOD 16) -1 UNLOCK_STRING$[CHAR%] = CHR$(ASC(UNLOCK_STRING$[CHAR%]) OR BITNO%) END DEF IS_UNLOCKED ID% VAR CHAR% = (ID% - 1) DIV 16 VAR BITNO% = (ID% MOD 16) -1 RETURN ASC(UNLOCK_STRING$[CHAR%]) AND BITNO% END @CHARACTER_TABLE DATA "YUKA","YUKA_U","YUKA_PJ","YUKA_98", "YUKA_U98","REIMU","LILY_W","LILY_B" DATA "RUMIA","CIRNO","DAIYOSEI","MEILING", "KOAKUMA","PATCHOLI","SAKUYA","REMILIA" DATA "FLANDRE" DATA "WRIGGLE","MYSTIA","KEINE", "KEINE_EX","MOKOU","TEWI","REISEN" DATA "EIRIN","KAGUYA" DATA "LETTY","ALICE", "CHEN","RAN","YUKARI","YOUMU" DATA "YUYUKO" DATA "AYA","KOMACHI", "EIKI","MEDICINE" DATA "MINORIKO","SHIZUHA","HINA","NITORI","MOMIJI" DATA "\\" REM -replace 'DATA' -replace "`"`n|[ \n]|`"," -split "[`",]" | % {$c=0}{write-host "DIM ID_$_=$c" -nonewline;$c++} @CHARACTER_TITLES DATA "Yuuka Kazami, Flower Master of the Four Seasons" DATA "Yuuka Kazami, Flower Master of the Four Seasons" DATA "Yuuka, Youkai Moe" DATA "Yuuka, Beauty of Everlasting Darkness" DATA "Yuuka, Beauty of Everlasting Darkness" DATA "Reimu Hakurei, Shrine Maiden of Paradise" DATA "Lily White, Fairy Herald of Spring" DATA "Lily White, Yama Cosplay Fanatic" DATA "Rumia, Youkai of the Dusk" DATA "Cirno, Ice Fairy of the Lake" DATA "Daiyousei, Great Fairy of the Lake" 'should go unused DATA "Meiling Hong, Gate Keeper of Scarlet Devil" DATA "Koakuma, Library Assistant of Scarlet Devil" DATA "Patchouli Knowledge, The Immobile Library" DATA "Sakuya Izayoi, Perfect and Elegant Maid" DATA "Remilia Scarlet, The Scarlet Devil" DATA "Flandre Scarlet, Sister of the Devil" DATA "Wriggle Nightbug, Firefly in the Dark" DATA "Mystia Lorelei, Singing Night Sparrow" DATA "Keine Kamishirasawa, History-Eating Half-Beast" DATA "Keine Kamishirasawa, History-Eating Half-Beast" DATA "Mokou Fujiwara, Crimson Hourai Immortal" DATA "Tewi Inaba, Lucky Rabbit of the Earth" DATA "Reisen U. Inaba, Lunatic Moon Rabbit" DATA "Eirin Yagokoro, Hourai Pharmacist" DATA "Kaguya Houraisan, Eternal Princess" DATA "Letty Whiterock, Youkai of Winter" DATA "Alice Margatroid, Seven-Colored Puppeteer" DATA "Chen, Shikigami of the Shikigami of the Gap" DATA "Ran Yakumo, Shikigami of the Gap" DATA "Yukari Yakumo, Youkai of Boundaries" DATA "Youmu Konpaku, Half-Phantom Gardener" DATA "Yuyuko Saigyouji, Dreaming Ghost Beauty" DATA "Aya Shameimaru, Crow Tengu Reporter" DATA "Medicine Melancholy, Little Sweet Poison" DATA "Komachi Onozuka, Guide of the Sanzu River" DATA "Eiki Shiki, Yama of Xanadu" DATA "Minoriko Aki, Symbol of Abundance and Harvest" DATA "Shizuha Aki, Symbol of Loneliness and Demise" DATA "Hina Kagiyama, Nagashi-bina of the Hidden God" DATA "Nitori Kawashiro, Super Youkai Warhead" DATA "Momiji Inubashiri, Petty Patrol Tengu" DATA "\\" '====== ' MAPS '====== 'arena stages @ARENA1 DATA"oooooooooooooooooooooooooooooooo" DATA"oooooooooooooooooooooooooooooooo" DATA"oo oo" DATA"oo oo" DATA"oo x x oo" DATA"oo oo" DATA"oo o o oo" DATA"oo B oo" DATA"oo oo" DATA"oo oo" DATA"oo $ oo" DATA"oo oo" DATA"oo oo" DATA"oo o o oo" DATA"oo oo" DATA"oo x x oo" DATA"oo oo" DATA"oo oo" DATA"oooooooooooooooooooooooooooooooo" DATA"oooooooooooooooooooooooooooooooo" Posted
  • #2 ✎ 258 Y____ Head Admin Gardening I like to garden! Hobbies Reading I like to read books! Hobbies Drawing I like to draw! Hobbies INPUT.PRG 'Constants DIM INPUT_BTN_AS_ANALOG = &h10000000 DIM INPUT_ANALOG_AS_BTN = &h20000000 DIM PAD_V_U = &h10000, PAD_V_D = &h20000 DIM PAD_H_L = &h40000, PAD_H_R = &h80000 DIM CPAD = &h100000 DIM XPAD = &h200000 'Control definitions DIM INPUT_MENU_CONTINUE = #A DIM INPUT_MENU_BACK = #B DIM INPUT_MENU_UP = #UP + INPUT_ANALOG_AS_BTN + PAD_V_U DIM INPUT_MENU_DOWN = #DOWN + INPUT_ANALOG_AS_BTN + PAD_V_D DIM INPUT_MENU_LEFT = #LEFT + INPUT_ANALOG_AS_BTN + PAD_H_L DIM INPUT_MENU_RIGHT = #RIGHT + INPUT_ANALOG_AS_BTN + PAD_H_R DIM INPUT_P1_UP = 0 DIM INPUT_P1_DOWN = 0 DIM INPUT_P1_LEFT = 0 DIM INPUT_P1_RIGHT = 0 DIM INPUT_P1_BUTTON1 = 0 DIM INPUT_P1_BUTTON2 = 0 DIM INPUT_P1_BUTTON3 = 0 DIM INPUT_P1_BUTTON4 = 0 DIM INPUT_P1_JOY1 = INPUT_BTN_AS_ANALOG + #UP + #DOWN + #LEFT + #RIGHT + CPAD DIM INPUT_P1_JOY2 = INPUT_BTN_AS_ANALOG + #A + #B + #X + #Y DIM INPUT_P1_JOY3 = 0 DIM INPUT_P1_JOY4 = 0 'UNITVECTOR x, y OUT unit_x, unit_y 'normalizes vector components <x,y> 'to unit vector magnitudes COMMON DEF UNITVECTOR X,Y OUT UX,UY VAR ANGLE# = ATAN(Y, X) UX = COS(ANGLE#) UY = SIN(ANGLE#) END COMMON DEF ANALOG_TO_BTN(SX,SY) VAR ANGLE = DEG(ATAN(SY,SX) + 2*PI() * (SY<0)) IF ABS(ANGLE - 0) < 45 THEN INPUTFLAGS% = #RIGHT ELSEIF ABS(ANGLE - 45) < 45 THEN INPUTFLAGS% = #DOWN OR #RIGHT ELSEIF ABS(ANGLE - 90) < 45 THEN INPUTFLAGS% = #DOWN ELSEIF ABS(ANGLE - 135) < 45 THEN INPUTFLAGS% = #DOWN OR #LEFT ELSEIF ABS(ANGLE - 180) < 45 THEN INPUTFLAGS% = #LEFT ELSEIF ABS(ANGLE - 225) < 45 THEN INPUTFLAGS% = #UP OR #LEFT ELSEIF ABS(ANGLE - 270) < 45 THEN INPUTFLAGS% = #UP ELSEIF ABS(ANGLE - 315) < 45 THEN INPUTFLAGS% = #UP OR #RIGHT ENDIF RETURN INPUTFLAGS% END COMMON DEF BTN_TO_ANALOG U%,D%,L%,R% OUT X,Y 'clever, but probably slow. consider exchange with a lookup. UNITVECTOR R% - L%, U% - D% OUT X, Y END 'INPUT_READ_JOY input_bitstring%, mask_variable$ OUT x, y 'gets joystick position information 'with a current input from INPUT_GET() and 'a INPUT_PX_JOY# variable as string as mask COMMON DEF INPUT_READ_JOY INPUT%,JOY$ OUT X,Y IF !CHKVAR(JOY$) THEN 'LOG "[READ ANALOG]Bad joystick " + JOY$ X = 0:Y = 0 RETURN ENDIF VAR JOYMASK% = VAR(JOY$) INPUT% = INPUT% AND JOYMASK% IF JOYMASK% AND CPAD AND INPUT% THEN STICK OUT X, Y INPUT_NORMALIZE_JOY X, Y, INPUT_CPAD_MAX(), 1.0 OUT X, Y ELSEIF JOYMASK% AND XPAD THEN 'assumes XON EXPAD STICKEX OUT X, Y ELSEIF JOYMASK% AND INPUT_BTN_AS_ANALOG THEN IF INPUT% AND (#UP OR #DOWN OR #LEFT OR #RIGHT) THEN BTN_TO_ANALOG INPUT% AND #UP, INPUT% AND #DOWN, INPUT% AND #LEFT, INPUT% AND #RIGHT OUT X, Y ELSEIF INPUT% AND (#A OR #B OR #Y OR #X) THEN BTN_TO_ANALOG INPUT% AND #X, INPUT% AND #B, INPUT% AND #Y, INPUT% AND #A OUT X, Y ELSE X = 0:Y = 0 ENDIF ENDIF END 'INPUT_GET(BUTTON_FEATURE, ANALOG_THRESHOLD) 'Replacement for BUTTON() 'BUTTON_FEATURE specification as in BUTTON() 'ANALOG_THRESHOLD can be used to ignore small inputs COMMON DEF INPUT_GET(BUTTON_FEATURE%, ANALOG_THRESHOLD#) VAR INPUTFLAGS% = BUTTON(BUTTON_FEATURE%) STICK OUT SX, SY INC INPUTFLAGS%, (SX*SX+SY*SY > ANALOG_THRESHOLD#*ANALOG_THRESHOLD#) * CPAD IF INPUTFLAGS% AND CPAD THEN INPUTFLAGS% = INPUTFLAGS% OR (ANALOG_TO_BTN(SX,SY) << LOG(PAD_V_U,2)) 'PAD_X_X offset ENDIF RETURN INPUTFLAGS% END 'INPUT_GET_MP(TERMINAL_ID, BUTTON_FEATURE, JOY_THRESHOLD) 'Replacement for BUTTON() 'JOY_THRESHOLD can be used to ignore small inputs COMMON DEF INPUT_GET_MP(TERMINAL_ID%, BUTTON_FEATURE%, JOY_THRESHOLD#) VAR INPUTFLAGS% = BUTTON(BUTTON_FEATURE%, TERMINAL_ID%) STICK TERMINAL_ID% OUT SX, SY INC INPUTFLAGS%, (SX*SX+SY*SY > JOY_THRESHOLD#*JOY_THRESHOLD#) * CPAD IF INPUTFLAGS% AND CPAD THEN INPUTFLAGS% = INPUTFLAGS% OR (ANALOG_TO_BTN(SX,SY) << LOG(PAD_V_U,2)) 'PAD_X_X offset ENDIF RETURN INPUTFLAGS% END COMMON DEF INPUT_CONFIGURE INPUT_NAME$ IF CHKVAR(INPUT_NAME$) && LEFT$(INPUT_NAME$,7) == "INPUT_P" || LEFT(INPUT_NAME$,10) == "INPUT_MENU" THEN SET_INPUT_KEYS INPUT_NAME$, INPUT_GET(.1) ENDIF 'LOG "[INPUT CONFIG]BAD INPUT NAME " + INPUT_NAME$ END DEF SET_INPUT_KEYS INPUT_NAME$, KEYS% VAR(INPUT_NAME$) = KEYS% END COMMON DEF INPUT_NORMALIZE_JOY SX#, SY#, SOURCE_MAX#, NEW_MAX# OUT NX#, NY# NX# = SX# * NEW_MAX#/SOURCE_MAX# NY# = SY# * NEW_MAX#/SOURCE_MAX# END DIM CPAD_MAX = 0.875 COMMON DEF INPUT_CPAD_MAX() RETURN CPAD_MAX END 'INPUT_CALIBRATE_CPAD(output_callback$) 'Probably bad, experimental. 'Do not use. Circle pad should be configured from 3DS home menu. DEF INPUT_CALIBRATE_CPAD OUTPUT_CALLBACK$ IF OUTPUT_CALLBACK$ THEN CALL OUTPUT_CALLBACK$, "Return the circle pad to neutral position" ENDIF WAIT 30 VAR CENTER_X,CENTER_Y STICK OUT CENTER_X,CENTER_Y IF OUTPUT_CALLBACK$ THEN CALL OUTPUT_CALLBACK$, "Push the circle pad up as far as it can go" ENDIF VAR SSX,SSY, MAX_Y = 0 WAIT 15 REPEAT STICK OUT SSX, SSY MAX_Y = MAX(MAX_Y, SSY) UNTIL SSX == 0.0 && SSY != 0.0 CPAD_MAX = SSY IF OUTPUT_CALLBACK$ THEN CALL OUTPUT_CALLBACK$, "Calibration complete" ENDIF END Posted
  • #3 ✎ 258 Y____ Head Admin Gardening I like to garden! Hobbies Reading I like to read books! Hobbies Drawing I like to draw! Hobbies Order I wrote this: I wrote INPUT.PRG first, because I knew I wanted nice abstractions for joy vs. button input. Specifically, since this is a "twin-stick" shooter, I wanted to handle the face (ABYX) buttons as a joystick. I wrote about half of this file to begin with, including INPUT_GET() and INPUT_READ_JOY(). I later filled in ANALOG_TO_BTN and UNITVECTOR and other important conversion functions once I had a test file for actually using it (to move a sprite). The control definitions should really be in the main game file, but it somehow ended up like this and isn't a priority to fix. This input library is fairly complicated for what it is. If you don't care about input configuration and things like that, you probably won't even have to think about writing input handling routines. Still, it's nice to know what buttons you plan to use. This is a library file, but libraries in SB are annoying, and eventually I'll just inline it with the rest for publication, probably. the structure of the main file is like this (in present, incomplete form) OPTION STRICT '= Initialization = REM screen clearing LOAD "assets" REM instantiate global variables (constants) REM sprite definitions '= Main = WHILE OK% REM main loop VSYNC REM get input REM state handling 'not a good thing to for general purpose 'just use two loops REM game state: REM evaluate timers REM call sprite calbacks WEND if you didn't catch that, the entirety of my main loop is essentially VSYNC B=BUTTON() EVAL_TIMERS CALL SPRITE I wrote the "menu state" handler first and went back after filling in basic player functionality and the Timer Subsystem to add that body. Following that is all the supporting functions: REM = Standard Library Functions = DEF FREE() DEF FREE$() 'useful for clearing arrays DEF PLEASE DIE END 'the timer system has a mandatory return off 'an array that must be discarded. DEF SPLIT$() 'split a string into an array: 'useful for save files DEF WRITE 'I wrote a custom printing function for 'menus so that I could handle colors easily DEF FIRST_WORD 'just a parsing assistant for trickiness 'regarding tying character names to AI callbacks DEF DIST_2D '2d distance function. should be obvious. REM = Timer Module = 'A Timer system is ALWAYS useful. 'This one stores a time that the timer expires 'and a function to call when that happens. 'makes player respawning, shot rates, events 'etc. really easy. REM = State Manager = 'One function for handling game state changes 'allowing menu items to be loaded REM = Menu Module = 'Functions for handling simple 'menu item loading, menu navigation, 'title menu printing, calling a function 'when menu option is selected REM = Character/Sprite Definition = 'Animation data for the sprite set 'Sprite definitions. REM = Animation Module = 'Determines how to animate a sprite given 'its direction, and provides functions for 'finding out a sprite's direction REM = Shooting Subsystem = 'Handles spawning bullets + data for character shot type 'also a bullet callback responsible for moving them REM = NPC / Enemy Behavior Module = 'Handles spawning enemies and provides 'behavior for them 'as well as specification for enemy type-unique traits 'some "entity" components such as collision behavior 'that apply to players is defined here too REM = Game Module = 'Player handling, entity handling 'physics 'In my game, the player callback actually handles 'input -> movement REM = Savefile Management Module = 'for dealing with save files 'contains common data for tracking game figures REM = Map Subsystem = 'Loading and displaying maps 'as well as data for in-game maps Posted