Still new to Java/android so trying to figure out the best way to code a multilevel if statement. What I'm trying to do is for a combat system that needs to check if player/npc is alive. If they are alive it then will check to see if they scored a critical hit. If they didn't critical hit then will see if they hit or missed.
combat = mydbhelper.getCombat();
startManagingCursor(combat);
if (playerCurHp == 0) {
combat.moveToPosition(11);
npcCombatStory = combat.getString(combat.getColumnIndex(dbhelper.KEY_COMBATDESC));
} else {
if (playerCritFlag.equals("Critical")) {
combat.moveToPosition(2);
playerCombatStory = combat.getString(combat.getColumnIndex(dbhelper.KEY_COMBATDESC));
} else {
if (playerHitFlag.equals("Hit")) {
combat.moveToPosition(1);
playerCombatStory = combat.getString(combat.getColumnIndex(dbhelper.KEY_COMBATDESC));
}
if (playerHitFlag.equals("Miss")) {
combat.moveToPosition(3);
playerCombatStory = combat.getString(combat.getColumnIndex(dbhelper.KEY_COMBATDESC));
}
}
}
if (npcCurHp == 0) {
combat.moveToPosition(10);
npcCombatStory = combat.getString(combat.getColumnIndex(dbhelper.KEY_COMBATDESC));
} else {
if (npcCritFlag.equals("Critical")) {
combat.moveToPosition(5);
npcCombatStory = combat.getString(combat.getColumnIndex(dbhelper.KEY_COMBATDESC));
} else {
if (npcHitFlag.equals("Hit")) {
combat.moveToPosition(4);
npcCombatStory = combat.getString(combat.getColumnIndex(dbhelper.KEY_COMBATDESC));
}
if(npcHitFlag.equals("Miss")) {
combat.moveToPosition(6);
npcCombatStory = combat.getString(combat.getColumnIndex(dbhelper.KEY_COMBATDESC));
}
}
}
Is what I'm using. Was working when I had the if statements all separate. But it would check each one and do actions I don't need (If they hit, pull String, if crit pull another, then if dead pull again). Trying to make it stop when it finds the "Flag" that matches. When doing my rolls if the player hits it sets the flag to "Hit" like below code.
Random attackRandom = new Random();
int attackRoll = attackRandom.nextInt(100);
totalAtt = attackRoll + bonusAttack + weaponAtt + stanceAtt;
Random defensiveRandom = new Random();
int defenseRoll = defensiveRandom.nextInt(100);
npcDef = defenseRoll + npcDodge + npcBonusDodge;
if (totalAtt > npcDef) {
playerHitFlag = "Hit";
playerDamage();
} else {
playerHitFlag = "Miss";
npcAttack();
}
At the end it takes these playerCombatStory and npcCombatStory strings and uses them to setText to show the player what happened on that turn of combat.
I think you are looking for the else if statement:
if (condition) {
}
else if (other_condition) {
}
else if (another_condition) {
}
else {
// There can only be one else statement in a given if-else block
}
Your question isn't clear. But meaningful advice can still be offered.
Personally, I find this code hard to read. I think it'll be hard to maintain in the future as your logic becomes more complex.
I think you need to decouple the logic of what's done from how you decide. Encapsulate what's done in a Command object and use a map or state machine to look up what to do.
I would change the type of npcCritFlag to int or enum. Then use switch statement with case
This should look much better and easier to understand
Related
When doing defensive programming, I often have some early-return code. In addition, I need to write some log warning that the function returns because of what problem.
void f(A a) {
var b = a.b;
if (b == null) {
Log.warn('f skip running since b==null');
return;
}
var c = some_func(b);
if (c == null) {
Log.warn('f skip running since c==null');
return;
}
another_func(c);
}
I know I can use null-aware operators like ?. but it cannot print warnings when it is null.
I have also tried another approach:
void f(A a) {
var errorMessage = fCore(a);
if (errorMessage!=null) Log.warn(errorMessage);
}
String fCore(A a) {
var b = a.b;
if (b == null) {
return 'f skip running since b==null';
}
var c = some_func(b);
if (c == null) {
return 'f skip running since c==null';
}
another_func(c);
return null
}
But that is also kind of verbose.
Is there a better approach? Thanks!
EDIT
I call it like:
void outer_func() {
one_func();
f(); // even if f skip running, I want two_func still run, etc
two_func();
...
}
Thus, I cannot simply do something like throw LogWarnException('...') and catch at outermost function.
I need to pick contacts in my app and would like to exclude those which are stored in my SIM card. Is it possible with ACTION_PICK?
No, it's not possible
Unfortunately, it's not possible for now.
To proof it, let's dive into source code of ContanctsListActivity.
Here's an onCreate() method of the Activity. In it, ContactApp reads Intent(ACTION_PICK) we passing to it and handles it respectively:
#Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
mIconSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
mContactsPrefs = new ContactsPreferences(this);
mPhotoLoader = new ContactPhotoLoader(this, R.drawable.ic_contact_list_picture);
// Resolve the intent
final Intent intent = getIntent();
// Allow the title to be set to a custom String using an extra on the intent
String title = intent.getStringExtra(UI.TITLE_EXTRA_KEY);
if (title != null) {
setTitle(title);
}
String action = intent.getAction();
String component = intent.getComponent().getClassName();
// When we get a FILTER_CONTACTS_ACTION, it represents search in the context
// of some other action. Let's retrieve the original action to provide proper
// context for the search queries.
if (UI.FILTER_CONTACTS_ACTION.equals(action)) {
mSearchMode = true;
mShowSearchSnippets = true;
Bundle extras = intent.getExtras();
if (extras != null) {
mInitialFilter = extras.getString(UI.FILTER_TEXT_EXTRA_KEY);
String originalAction =
extras.getString(ContactsSearchManager.ORIGINAL_ACTION_EXTRA_KEY);
if (originalAction != null) {
action = originalAction;
}
String originalComponent =
extras.getString(ContactsSearchManager.ORIGINAL_COMPONENT_EXTRA_KEY);
if (originalComponent != null) {
component = originalComponent;
}
} else {
mInitialFilter = null;
}
}
Log.i(TAG, "Called with action: " + action);
mMode = MODE_UNKNOWN;
if (UI.LIST_DEFAULT.equals(action) || UI.FILTER_CONTACTS_ACTION.equals(action)) {
.....
else if (Intent.ACTION_PICK.equals(action)) {
// XXX These should be showing the data from the URI given in
// the Intent.
final String type = intent.resolveType(this);
if (Contacts.CONTENT_TYPE.equals(type)) {
mMode = MODE_PICK_CONTACT;
} else if (People.CONTENT_TYPE.equals(type)) {
mMode = MODE_LEGACY_PICK_PERSON;
} else if (Phone.CONTENT_TYPE.equals(type)) {
mMode = MODE_PICK_PHONE;
} else if (Phones.CONTENT_TYPE.equals(type)) {
mMode = MODE_LEGACY_PICK_PHONE;
} else if (StructuredPostal.CONTENT_TYPE.equals(type)) {
mMode = MODE_PICK_POSTAL;
} else if (ContactMethods.CONTENT_POSTAL_TYPE.equals(type)) {
mMode = MODE_LEGACY_PICK_POSTAL;
}
....
// VERY LONG IF WITH DIFFERENT MODE-SELECTION
....
}
.....
if (mMode == MODE_JOIN_CONTACT) {
setContentView(R.layout.contacts_list_content_join);
} else if (mSearchMode) {
setContentView(R.layout.contacts_search_content);
} else if (mSearchResultsMode) {
setContentView(R.layout.contacts_list_search_results);
} else {
setContentView(R.layout.contacts_list_content);
}
setupListView();
...
}
It's very long method (and I also suggest to check setupListView() method), but pretty straightforward. And, as you can see, there's no parameter you can pass to specify source of contacts you want to pick from. Only thing you can configure here is the particular mMode ContactsApp to use (MODE_PICK_CONTACT, MODE_PICK_PHONE, etc.) - but unfortunately number of possible modes is very limited by 6 and non of them suits you.
(If anyone needs to pass mMode to ContanctsListActivity - use intent's setType() method, for example: intent.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE);)
Workaround
As a workaround - as tiny sunlight's suggested in comments - render non-SIM contacts within the app and pick the one you needed from there.
How to get all android contacts but without those which are on SIM - this link looks like most promising one explaining how to query cursor with all contacts, apart from SIM ones.
I hope, it helps
I am using some example code from the internet that manages music. One section of the code is a way of pausing music and preparing it to play again. I am not understanding a double bracket notation. I thought it may have been a fancy way of doing an If-Else, but my equivalent snippet of code does not work, however, the code with the double brackets works perfectly. What exactly does it mean when you add two open brackets to an If-statement?
Here is the snippet of code
// previousMusic should always be something valid
if (currentMusic != -1) {{
previousMusic = currentMusic;
Log.d(TAG, "Music is paused");
}
currentMusic = -1;
Log.d(TAG, "Paused music is prepared to play again (if necessary)");
}
Here is what I thought it could have meant. It does not work as intended, so this is not the same actually.
// previousMusic should always be something valid
if (currentMusic != -1) {
previousMusic = currentMusic;
Log.d(TAG, "Music is paused");
} else {
currentMusic = -1;
Log.d(TAG, "Paused music is prepared to play again");
}
Thank you in advance for the explanation.
hat exactly does it mean when you add two open brackets to an If-statement?
Nothing special really it is just a block of code where you put your previousMusic = currentMusic in another scope of the method.
It is like saying:
if (currentMusic != -1) {
previousMusic = currentMusic;
Log.d(TAG, "Music is paused");
currentMusic = -1;
Log.d(TAG, "Paused music is prepared to play again (if necessary)");
}
But if you make a variable inside the block of code then you cant access it outside the block because the scope of the variable is only accessible to the block of code.
if(1==1)
{
int i2;
{
int i;
i2= 1; //can access from top level scope
}
i = 0; //compile time error cant access the variable in the block of code
}
I hope you are aware about the scope of variables.
Example 1:
if(some condition){
{ // x is born here
int x = 32;
} // x is dead here
// not allowed!
Log.d(TAG,"Value is: " + x);
}
Example 2:
if(some condition){
int x = 32;
// totally legit!
Log.d(TAG,"Value is: " + x);
}
See the subtle difference between the two?
In Example 1, the nested {} limit the scope of x. The variable x is available for use only till the closing brace } of its corresponding opening brace {
The correct way to understand that code is:
if (currentMusic != -1) {
{
previousMusic = currentMusic;
Log.d(TAG, "Music is paused");
}
currentMusic = -1;
Log.d(TAG, "Paused music is prepared to play again (if necessary)");
}
When you put a braces in your code, you just create a new scope to handle your variables.
in android Asmack i want to set invisible user.
and i used from every mode but it didn't works. after that i used from Type ..
when i set type unavailable, it works . but there is a problem .. my pocket listener doesn't work .. and i cant get any thing from user .. What can i do .. Thanks a lot.
Type type = Presence.Type.available;
Mode OWN = Mode.available;
if (DB_STATUS.avibilaty.toString().equals("")) {
OWN = Mode.available;
} else if (DB_STATUS.avibilaty.toString().equals("away")) {
OWN = Mode.away;
} else if (DB_STATUS.avibilaty.toString().equals(
"available")) {
OWN = Mode.available;
} else if (DB_STATUS.avibilaty.toString().equals(
"unavailable")) {
type = Presence.Type.unavailable;
} else if (DB_STATUS.avibilaty.toString().equals("busy")) {
OWN = Mode.dnd;
}
Presence presence = new Presence(type);
presence.setMode(OWN);
I create a room and it gets successfully made. And my onRoomCreated method gets called...
#Override
public void onRoomCreated(int statusCode, Room room) {
mRoomId = room.getRoomId();
Intent i = Games.RealTimeMultiplayer.getWaitingRoomIntent(gApiClient, room, 2);
startActivityForResult(i, RC_WAITING_ROOM);
}
Then in my onActivityResult...
Room r = data.getExtras().getParcelable(Multiplayer.EXTRA_ROOM);
ArrayList<String> invitees = new ArrayList<String>();
for (Participant p : r.getParticipants()) {
invitees.add(p.getPlayer().getPlayerId()); //<---NULL POINTER!
}
I get that null pointer. Why?
EDIT: The android docs say this about the getPlayer() method...
Returns the Player that this participant represents. Note that this may be null if the identity of the player is unknown. This occurs in automatching scenarios where some players are not permitted to see the real identity of others.
That is why I am getting null, because my room is through auto-matching.
Now the question is. How can I create a turnbasedgame using only participant IDs? Not Player IDs
Now that I see what you are asking more clearly (my fault, not yours), here is how I do it:
(for clarification I use LibGDX, so may be some interface stuff you don't need, and I am still using GamesClient not the new API methods, but is for all intents the same)
First, the final call I look to start my game is onRoomConnected
#Override
public void onRoomConnected(int statusCode, Room room) {
//dLog("onRoomConnected");
mRoomCurrent = room;
mParticipants = room.getParticipants();
mMyID = room.getParticipantId(aHelper.getGamesClient().getCurrentPlayerId());
//dLog("The id is " + mMyID);
try {
bWaitRoomDismissedFromCode = true;
finishActivity(RC_WAITING_ROOM);
} catch (Exception e) {
//dLog("would have errored out in waiting room");
}
//tell the Game the room is connected
if (statusCode == GamesClient.STATUS_OK) {
theGameInterface.onRoomConnected(room.getParticipantIds(), mMyID, room.getCreationTimestamp() );
} else {
leaveRoom();
}
}
So, now have all the participantIDs.. now in my Game code (where I sent that List of Ids), I sort the list of IDs so that in determining Player order, it is the same methodology for all Players. First I build my opponents.
private void buildOpponents() {
// this creates a new opponent with a View on the Stage()
//sort the participants the same for all players
sortParticipantIDs();
for (String s : mParticipantIds) {
if(s.contains(mMyID) || mMyID.contains(s)) continue;
newOpponentWindow ow = new newOpponentWindow(s, MyAssetManager.getMySkin(), getStage());
Opponent o = new Opponent(this, s);
mapOpponents.put(s, o);
o.setWindow(ow);
getStage().addActor(ow);
}
setOpponentWindowPositions();
}
Then after some more setup I start Play and my first Time through, I have chosen that whoever is the top ID gets the honor of starting (I find this randomizes play enough, without having to do another method.. .but you can let the top ID do another method, and send that out to the other Players) Note this checks over my Opponents to determine Starting Player if someone leaves the room later in the game as well.
private boolean determineIfStartingBidder() {
Collections.sort(mParticipantIds);
// now look thru list
// if the number is mine then return true
// if the number is not mine.. and opponent is not Out of Game or Disconnected.. then return false
for (String s : mParticipantIds) {
if(s.contains(mMyID) || mMyID.contains(s)){
return true;
}
if(mapOpponents.get(s).getCurrentState() == currentState.DISCONNECTED || mapOpponents.get(s).getCurrentState() == currentState.OUTOFGAME ||
mapOpponents.get(s).getCurrentState() == currentState.LOSTGAME) {
continue;
}
return false;
}
return false;
}
Then in your game logic, just go through your ParticipantID list in whatever manner makes sense to pass the baton around! This works well, since all the calls for passing messages require the ParticipantID, and are there for easy grab n go!
Prior Answer Below ------------------------------------------------
try
data.getParcelableExtra(Multiplayer.EXTRA_ROOM);
no need for the getExtras