void S9xApplyCommand()

in cores/snes/controls.cpp [2034:2713]


void S9xApplyCommand (s9xcommand_t cmd, int16 data1, int16 data2)
{
	int	i;

	switch (cmd.type)
	{
		case S9xNoMapping:
			return;

		case S9xButtonJoypad:
			if (cmd.button.joypad.toggle)
			{
				if (!data1)
					return;

				uint16	r = cmd.button.joypad.buttons;

				if (cmd.button.joypad.turbo)	joypad[cmd.button.joypad.idx].toggleturbo ^= r;
				if (cmd.button.joypad.sticky)	joypad[cmd.button.joypad.idx].togglestick ^= r;
			}
			else
			{
				uint16	r, s, t, st;

				s = t = st = 0;
				r = cmd.button.joypad.buttons;
				st = r & joypad[cmd.button.joypad.idx].togglestick & joypad[cmd.button.joypad.idx].toggleturbo;
				r ^= st;
				t  = r & joypad[cmd.button.joypad.idx].toggleturbo;
				r ^= t;
				s  = r & joypad[cmd.button.joypad.idx].togglestick;
				r ^= s;

				if (cmd.button.joypad.turbo && cmd.button.joypad.sticky)
				{
					uint16	x = r; r = st; st = x;
					x = s; s = t; t = x;
				}
				else
				if (cmd.button.joypad.turbo)
				{
					uint16	x = r; r = t; t = x;
					x = s; s = st; st = x;
				}
				else
				if (cmd.button.joypad.sticky)
				{
					uint16	x = r; r = s; s = x;
					x = t; t = st; st = x;
				}

				if (data1)
				{
					if (!Settings.UpAndDown) // if up+down isn't allowed,
					{
						if (cmd.button.joypad.buttons & (SNES_LEFT_MASK | SNES_RIGHT_MASK))
						{
							// if we're pressing left or right, then unpress and unturbo them both first
							// so we don't end up hittnig left AND right accidentally.
							// Note though that the user can still do it on purpose, if Settings.UpAndDown = true.
							// This is a feature, look up glitches in tLoZ:aLttP to find out why.
							joypad[cmd.button.joypad.idx].buttons &= ~(SNES_LEFT_MASK | SNES_RIGHT_MASK);
							joypad[cmd.button.joypad.idx].turbos  &= ~(SNES_LEFT_MASK | SNES_RIGHT_MASK);
						}

						if (cmd.button.joypad.buttons & (SNES_UP_MASK | SNES_DOWN_MASK))
						{
							// and ditto for up/down
							joypad[cmd.button.joypad.idx].buttons &= ~(SNES_UP_MASK | SNES_DOWN_MASK);
							joypad[cmd.button.joypad.idx].turbos  &= ~(SNES_UP_MASK | SNES_DOWN_MASK);
						}
					}

					joypad[cmd.button.joypad.idx].buttons |= r;
					joypad[cmd.button.joypad.idx].turbos  |= t;
					joypad[cmd.button.joypad.idx].buttons ^= s;
					joypad[cmd.button.joypad.idx].buttons &= ~(joypad[cmd.button.joypad.idx].turbos & st);
					joypad[cmd.button.joypad.idx].turbos  ^= st;
				}
				else
				{
					joypad[cmd.button.joypad.idx].buttons &= ~r;
					joypad[cmd.button.joypad.idx].buttons &= ~(joypad[cmd.button.joypad.idx].turbos & t);
					joypad[cmd.button.joypad.idx].turbos  &= ~t;
				}
			}

			return;

		case S9xButtonMouse:
			i = 0;
			if (cmd.button.mouse.left )	i |= 0x40;
			if (cmd.button.mouse.right)	i |= 0x80;

			if (data1)
				mouse[cmd.button.mouse.idx].buttons |=  i;
			else 
				mouse[cmd.button.mouse.idx].buttons &= ~i;

			return;

		case S9xButtonSuperscope:
			i = 0;
			if (cmd.button.scope.fire         )	i |= SUPERSCOPE_FIRE;
			if (cmd.button.scope.cursor       )	i |= SUPERSCOPE_CURSOR;
			if (cmd.button.scope.pause        )	i |= SUPERSCOPE_PAUSE;
			if (cmd.button.scope.aim_offscreen)	i |= SUPERSCOPE_OFFSCREEN;

			if (data1)
			{
				superscope.phys_buttons |= i;

				if (cmd.button.scope.turbo)
				{
					superscope.phys_buttons ^= SUPERSCOPE_TURBO;

					if (superscope.phys_buttons & SUPERSCOPE_TURBO)
						superscope.next_buttons |= superscope.phys_buttons & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR);
					else
						superscope.next_buttons &= ~(SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR);
				}

				superscope.next_buttons |= i & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR | SUPERSCOPE_PAUSE);

            if ((superscope.next_buttons & (SUPERSCOPE_FIRE | SUPERSCOPE_CURSOR)) && curcontrollers[1] == SUPERSCOPE && !(superscope.phys_buttons & SUPERSCOPE_OFFSCREEN))
						DoGunLatch(superscope.x, superscope.y);
			}
			else
			{
				superscope.phys_buttons &= ~i;
				superscope.next_buttons &= SUPERSCOPE_OFFSCREEN | ~i;
			}

			return;

		case S9xButtonJustifier:
			i = 0;
			if (cmd.button.justifier.trigger)	i |= JUSTIFIER_TRIGGER;
			if (cmd.button.justifier.start  )	i |= JUSTIFIER_START;
			if (cmd.button.justifier.aim_offscreen)	justifier.offscreen[cmd.button.justifier.idx] = data1 ? 1 : 0;
			i >>= cmd.button.justifier.idx;

			if (data1)
				justifier.buttons |=  i;
			else
				justifier.buttons &= ~i;

			return;

		case S9xButtonCommand:
			if (((enum command_numbers) cmd.button.command) >= LAST_COMMAND)
			{
				fprintf(stderr, "Unknown command %04x\n", cmd.button.command);
				return;
			}

			if (!data1)
			{
				switch (i = cmd.button.command)
				{
					case EmuTurbo:
						Settings.TurboMode = FALSE;
						break;
				}
			}
			else
			{
				switch ((enum command_numbers) (i = cmd.button.command))
				{
					case ExitEmu:
						S9xExit();
						break;

					case Reset:
						S9xReset();
						break;

					case SoftReset:
						S9xSoftReset();
						break;

					case EmuTurbo:
						Settings.TurboMode = TRUE;
						break;

					case ToggleEmuTurbo:
						Settings.TurboMode = !Settings.TurboMode;
						DisplayStateChange("Turbo mode", Settings.TurboMode);
						break;

					case ClipWindows:
						Settings.DisableGraphicWindows = !Settings.DisableGraphicWindows;
						DisplayStateChange("Graphic clip windows", !Settings.DisableGraphicWindows);
						break;

					case Debugger:
					#ifdef DEBUGGER
						CPU.Flags |= DEBUG_MODE_FLAG;
					#endif
						break;

					case IncFrameRate:
						if (Settings.SkipFrames == AUTO_FRAMERATE)
							Settings.SkipFrames = 1;
						else
						if (Settings.SkipFrames < 10)
							Settings.SkipFrames++;

						if (Settings.SkipFrames == AUTO_FRAMERATE)
							S9xSetInfoString("Auto frame skip");
						else
						{
							sprintf(buf, "Frame skip: %d", Settings.SkipFrames - 1);
							S9xSetInfoString(buf);
						}

						break;

					case DecFrameRate:
						if (Settings.SkipFrames <= 1)
							Settings.SkipFrames = AUTO_FRAMERATE;
						else
						if (Settings.SkipFrames != AUTO_FRAMERATE)
							Settings.SkipFrames--;

						if (Settings.SkipFrames == AUTO_FRAMERATE)
							S9xSetInfoString("Auto frame skip");
						else
						{
							sprintf(buf, "Frame skip: %d", Settings.SkipFrames - 1);
							S9xSetInfoString(buf);
						}

						break;

					case IncEmuTurbo:
						if (Settings.TurboSkipFrames < 20)
							Settings.TurboSkipFrames += 1;
						else
						if (Settings.TurboSkipFrames < 200)
							Settings.TurboSkipFrames += 5;
						sprintf(buf, "Turbo frame skip: %d", Settings.TurboSkipFrames);
						S9xSetInfoString(buf);
						break;

					case DecEmuTurbo:
						if (Settings.TurboSkipFrames > 20)
							Settings.TurboSkipFrames -= 5;
						else
						if (Settings.TurboSkipFrames > 0)
							Settings.TurboSkipFrames -= 1;
						sprintf(buf, "Turbo frame skip: %d", Settings.TurboSkipFrames);
						S9xSetInfoString(buf);
						break;

					case IncFrameTime: // Increase emulated frame time by 1ms
						Settings.FrameTime += 1000;
						sprintf(buf, "Emulated frame time: %dms", Settings.FrameTime / 1000);
						S9xSetInfoString(buf);
						break;

					case DecFrameTime: // Decrease emulated frame time by 1ms
						if (Settings.FrameTime >= 1000)
							Settings.FrameTime -= 1000;
						sprintf(buf, "Emulated frame time: %dms", Settings.FrameTime / 1000);
						S9xSetInfoString(buf);
						break;

					case IncTurboSpeed:
						if (turbo_time >= 120)
							break;
						turbo_time++;
						sprintf(buf, "Turbo speed: %d", turbo_time);
						S9xSetInfoString(buf);
						break;

					case DecTurboSpeed:
						if (turbo_time <= 1)
							break;
						turbo_time--;
						sprintf(buf, "Turbo speed: %d", turbo_time);
						S9xSetInfoString(buf);
						break;

					case LoadFreezeFile:
						S9xUnfreezeGame(S9xChooseFilename(TRUE));
						break;

					case SaveFreezeFile:
						S9xFreezeGame(S9xChooseFilename(FALSE));
						break;

					case LoadOopsFile:
					{
						char	filename[PATH_MAX + 1];
						char	drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];

						_splitpath(Memory.ROMFilename, drive, dir, def, ext);
						snprintf(filename, PATH_MAX + 1, "%s%s%s.%.*s", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, _MAX_EXT - 1, "oops");

						if (S9xUnfreezeGame(filename))
						{
							sprintf(buf, "%s.%.*s loaded", def, _MAX_EXT - 1, "oops");
							S9xSetInfoString (buf);
						}
						else
							S9xMessage(S9X_ERROR, S9X_FREEZE_FILE_NOT_FOUND, "Oops file not found");

						break;
					}

					case Pause:
						Settings.Paused = !Settings.Paused;
						DisplayStateChange("Pause", Settings.Paused);
					#if defined(NETPLAY_SUPPORT) && !defined(__WIN32__)
						S9xNPSendPause(Settings.Paused);
					#endif
						break;

					case QuickLoad000:
					case QuickLoad001:
					case QuickLoad002:
					case QuickLoad003:
					case QuickLoad004:
					case QuickLoad005:
					case QuickLoad006:
					case QuickLoad007:
					case QuickLoad008:
					case QuickLoad009:
					case QuickLoad010:
					{
						char	filename[PATH_MAX + 1];
						char	drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];

						_splitpath(Memory.ROMFilename, drive, dir, def, ext);
						snprintf(filename, PATH_MAX + 1, "%s%s%s.%03d", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, i - QuickLoad000);

						if (S9xUnfreezeGame(filename))
						{
							sprintf(buf, "%s.%03d loaded", def, i - QuickLoad000);
							S9xSetInfoString(buf);
						}
						else
							S9xMessage(S9X_ERROR, S9X_FREEZE_FILE_NOT_FOUND, "Freeze file not found");

						break;
					}

					case QuickSave000:
					case QuickSave001:
					case QuickSave002:
					case QuickSave003:
					case QuickSave004:
					case QuickSave005:
					case QuickSave006:
					case QuickSave007:
					case QuickSave008:
					case QuickSave009:
					case QuickSave010:
					{
						char	filename[PATH_MAX + 1];
						char	drive[_MAX_DRIVE + 1], dir[_MAX_DIR + 1], def[_MAX_FNAME + 1], ext[_MAX_EXT + 1];

						_splitpath(Memory.ROMFilename, drive, dir, def, ext);
						snprintf(filename, PATH_MAX + 1, "%s%s%s.%03d", S9xGetDirectory(SNAPSHOT_DIR), SLASH_STR, def, i - QuickSave000);

						sprintf(buf, "%s.%03d saved", def, i - QuickSave000);
						S9xSetInfoString(buf);

						S9xFreezeGame(filename);
						break;
					}

					case SaveSPC:
						S9xDumpSPCSnapshot();
						break;

					case SoundChannel0:
					case SoundChannel1:
					case SoundChannel2:
					case SoundChannel3:
					case SoundChannel4:
					case SoundChannel5:
					case SoundChannel6:
					case SoundChannel7:
						S9xToggleSoundChannel(i - SoundChannel0);
						sprintf(buf, "Sound channel %d toggled", i - SoundChannel0);
						S9xSetInfoString(buf);
						break;

					case SoundChannelsOn:
						S9xToggleSoundChannel(8);
						S9xSetInfoString("All sound channels on");
						break;

					case ToggleBG0:
						Settings.BG_Forced ^= 1;
						DisplayStateChange("BG#0", !(Settings.BG_Forced & 1));
						break;

					case ToggleBG1:
						Settings.BG_Forced ^= 2;
						DisplayStateChange("BG#1", !(Settings.BG_Forced & 2));
						break;

					case ToggleBG2:
						Settings.BG_Forced ^= 4;
						DisplayStateChange("BG#2", !(Settings.BG_Forced & 4));
						break;

					case ToggleBG3:
						Settings.BG_Forced ^= 8;
						DisplayStateChange("BG#3", !(Settings.BG_Forced & 8));
						break;

					case ToggleSprites:
						Settings.BG_Forced ^= 16;
						DisplayStateChange("Sprites", !(Settings.BG_Forced & 16));
						break;

					case ToggleTransparency:
						Settings.Transparency = !Settings.Transparency;
						DisplayStateChange("Transparency effects", Settings.Transparency);
						break;

					case SwapJoypads:
						if ((curcontrollers[0] != NONE && !(curcontrollers[0] >= JOYPAD0 && curcontrollers[0] <= JOYPAD7)))
						{
							S9xSetInfoString("Cannot swap pads: port 1 is not a joypad");
							break;
						}

						if ((curcontrollers[1] != NONE && !(curcontrollers[1] >= JOYPAD0 && curcontrollers[1] <= JOYPAD7)))
						{
							S9xSetInfoString("Cannot swap pads: port 2 is not a joypad");
							break;
						}

						newcontrollers[1] = curcontrollers[0];
						newcontrollers[0] = curcontrollers[1];

						strcpy(buf, "Swap pads: P1=");
						i = 14;
						if (newcontrollers[0] == NONE)
						{
							strcpy(buf + i, "<none>");
							i += 6;
						}
						else
						{
							sprintf(buf + i, "Joypad%d", newcontrollers[0] - JOYPAD0 + 1);
							i += 7;
						}

						strcpy(buf + i, " P2=");
						i += 4;
						if (newcontrollers[1] == NONE)
							strcpy(buf + i, "<none>");
						else
							sprintf(buf + i, "Joypad%d", newcontrollers[1] - JOYPAD0 + 1);

						S9xSetInfoString(buf);
						break;

					case SeekToFrame:
						break;

					case LAST_COMMAND:
						break;
				}
			}

			return;

		case S9xPointer:
			if (cmd.pointer.aim_mouse0)
			{
				mouse[0].cur_x = data1;
				mouse[0].cur_y = data2;
			}

			if (cmd.pointer.aim_mouse1)
			{
				mouse[1].cur_x = data1;
				mouse[1].cur_y = data2;
			}

			if (cmd.pointer.aim_scope)
			{
				superscope.x   = data1;
				superscope.y   = data2;
			}

			if (cmd.pointer.aim_justifier0)
			{
				justifier.x[0] = data1;
				justifier.y[0] = data2;
			}

			if (cmd.pointer.aim_justifier1)
			{
				justifier.x[1] = data1;
				justifier.y[1] = data2;
			}

			return;

		case S9xButtonPseudopointer:
			if (data1)
			{
				if (cmd.button.pointer.UD)
				{
					if (!pseudopointer[cmd.button.pointer.idx].V_adj)
						pseudopointer[cmd.button.pointer.idx].V_adj = cmd.button.pointer.UD * ptrspeeds[cmd.button.pointer.speed_type];
					pseudopointer[cmd.button.pointer.idx].V_var = (cmd.button.pointer.speed_type == 0);
				}

				if (cmd.button.pointer.LR)
				{
					if (!pseudopointer[cmd.button.pointer.idx].H_adj)
						pseudopointer[cmd.button.pointer.idx].H_adj = cmd.button.pointer.LR * ptrspeeds[cmd.button.pointer.speed_type];
					pseudopointer[cmd.button.pointer.idx].H_var = (cmd.button.pointer.speed_type == 0);
				}
			}
			else
			{
				if (cmd.button.pointer.UD)
				{
					pseudopointer[cmd.button.pointer.idx].V_adj = 0;
					pseudopointer[cmd.button.pointer.idx].V_var = false;
				}

				if (cmd.button.pointer.LR)
				{
					pseudopointer[cmd.button.pointer.idx].H_adj = 0;
					pseudopointer[cmd.button.pointer.idx].H_var = false;
				}
			}

			return;

		case S9xAxisJoypad:
		{
			uint16	pos, neg;

			switch (cmd.axis.joypad.axis)
			{
				case 0: neg = SNES_LEFT_MASK;	pos = SNES_RIGHT_MASK;	break;
				case 1: neg = SNES_UP_MASK;		pos = SNES_DOWN_MASK;	break;
				case 2: neg = SNES_Y_MASK;		pos = SNES_A_MASK;		break;
				case 3: neg = SNES_X_MASK;		pos = SNES_B_MASK;		break;
				case 4: neg = SNES_TL_MASK;		pos = SNES_TR_MASK;		break;
				default: return;
			}

			if (cmd.axis.joypad.invert)
				data1 = -data1;

			uint16	p, r;

			p = r = 0;
			if (data1 >  ((cmd.axis.joypad.threshold + 1) *  127))
				p |= pos;
			else
				r |= pos;

			if (data1 <= ((cmd.axis.joypad.threshold + 1) * -127))
				p |= neg;
			else
				r |= neg;

			joypad[cmd.axis.joypad.idx].buttons |= p;
			joypad[cmd.axis.joypad.idx].buttons &= ~r;
			joypad[cmd.axis.joypad.idx].turbos  &= ~(p | r);

			return;
		}

		case S9xAxisPseudopointer:
			if (data1 == 0)
			{
				if (cmd.axis.pointer.HV)
				{
					pseudopointer[cmd.axis.pointer.idx].V_adj = 0;
					pseudopointer[cmd.axis.pointer.idx].V_var = false;
				}
				else
				{
					pseudopointer[cmd.axis.pointer.idx].H_adj = 0;
					pseudopointer[cmd.axis.pointer.idx].H_var = false;
				}
			}
			else
			{
				if (cmd.axis.pointer.invert)
					data1 = -data1;

				if (cmd.axis.pointer.HV)
				{
					if (!pseudopointer[cmd.axis.pointer.idx].V_adj)
						pseudopointer[cmd.axis.pointer.idx].V_adj = (int16) ((int32) data1 * ptrspeeds[cmd.axis.pointer.speed_type] / 32767);
					pseudopointer[cmd.axis.pointer.idx].V_var = (cmd.axis.pointer.speed_type == 0);
				}
				else
				{
					if (!pseudopointer[cmd.axis.pointer.idx].H_adj)
						pseudopointer[cmd.axis.pointer.idx].H_adj = (int16) ((int32) data1 * ptrspeeds[cmd.axis.pointer.speed_type] / 32767);
					pseudopointer[cmd.axis.pointer.idx].H_var = (cmd.axis.pointer.speed_type == 0);
				}
			}

			return;

		case S9xAxisPseudobuttons:
			if (data1 >  ((cmd.axis.button.threshold + 1) *  127))
			{
				if (!pseudobuttons[cmd.axis.button.posbutton])
				{
					pseudobuttons[cmd.axis.button.posbutton] = 1;
					S9xReportButton(PseudoButtonBase + cmd.axis.button.posbutton, true);
				}
			}
			else
			{
				if (pseudobuttons[cmd.axis.button.posbutton])
				{
					pseudobuttons[cmd.axis.button.posbutton] = 0;
					S9xReportButton(PseudoButtonBase + cmd.axis.button.posbutton, false);
				}
			}

			if (data1 <= ((cmd.axis.button.threshold + 1) * -127))
			{
				if (!pseudobuttons[cmd.axis.button.negbutton])
				{
					pseudobuttons[cmd.axis.button.negbutton] = 1;
					S9xReportButton(PseudoButtonBase + cmd.axis.button.negbutton, true);
				}
			}
			else
			{
				if (pseudobuttons[cmd.axis.button.negbutton])
				{
					pseudobuttons[cmd.axis.button.negbutton] = 0;
					S9xReportButton(PseudoButtonBase + cmd.axis.button.negbutton, false);
				}
			}

			return;

		case S9xButtonPort:
		case S9xAxisPort:
		case S9xPointerPort:
			S9xHandlePortCommand(cmd, data1, data2);
			return;

		case S9xButtonMulti:
			if (cmd.button.multi_idx >= (int) multis.size())
				return;

			if (multis[cmd.button.multi_idx]->multi_press && !data1)
				return;

			i = ApplyMulti(multis[cmd.button.multi_idx], 0, data1);
			if (i >= 0)
			{
				struct exemulti	*e = new struct exemulti;
				e->pos    = i;
				e->data1  = data1 != 0;
				e->script = multis[cmd.button.multi_idx];
				exemultis.insert(e);
			}

			return;

		default:
			fprintf(stderr, "WARNING: Unknown command type %d\n", cmd.type);
			return;
	}
}